Merged
Conversation
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR is the initial implementation of a Debug Adapter Protocol-based debug engine for CodeQL. Implementing the DAP allows us to take advantage of all of VS Code's existing UI around debugging, including configuration via
launch.json, the "Start Debugging" and "Start Without Debugging" commands, and the Debug Console. Later, we'll build further UI on top of this work, and perhaps add some advanced debugging features.For now, our DAP implementation runs in the extension process, and invokes the query server via the same code that we were already using for "Run Query" and other local query commands. The existing commands do not go through the debug adapter yet. Instead, I've added a few new commands under the canary flag, and I've enabled the regular VS Code "Start Debugging" (F5) and "Start Without Debugging" (Ctrl-F5) commands to work for CodeQL.
Configuration
In "launch.json", there is a new available debug configuration type, named "codeql". Its configuration options are as follows:
query- The path to the query to debug. This query will be treated as the root query of the compilation, even when doing quick eval. Thus, the quick eval selection can now be in a different file from the actual query, allowing debugging of queries that extend abstract class, instantiate parameterized modules, etc. Ifqueryis undefined, the currently active ".ql" file will be used, just like the "Run Query" command.database- The path to the target database directory. Ifdatabaseis undefined, the currently selected database from the database panel will be used, just like the "Run Query" command.extensionPacks- An array of the pack names (not paths) of the extension packs to use. Each of these packs must be findable along theadditionalPackspath. An empty array specifies that no extension packs are to be used. IfextensionPacksis undefined, the default depends on thecodeQL.useExtensionPackssetting: If true, then all extension packs in the current workspace will be used. If false, no extension packs will be used.additionalPacks- An array of paths to search for additional library packs. This is equivalent to the--additional-packsCLI option. IfadditionalPacksis undefined, the default is to use the list of root folders in the current workspace, as we already do for the other commands.quickEval- A boolean value to specify whether to perform a quickeval of the current selection instead of a regular query evaluation. Users will rarely set this explicitly in "launch.json". It exists primarily so that the new "CodeQL: Debug Selection" command can force it to true.Commands
The "CodeQL: Run Query" and "CodeQL: Quick Evaluation" commands work exactly as before. They ignore any debug configuration, and do not start a debug session. Later, once we're more confident in the debugger UX, we'll make all of those commands go through the debug configuration.
If a "codeql" debug configuration is selected on the Debug panel, hitting F5 ("Start Debugging") will launch a debug session with the active debug configuration. This will bring up the VS Code debug toolbar, and will evaluate the configured query against the configured database. Results are displayed in the results view as before, and the query history panel is updated. The most visible change is that all of the query server log output will now go to the Debug Console. The Debug Console is specific to that debug session, so you don't have to search through the query server output pane to make sure you're looking at the right query run.
The debug session will stay active after evaluation is complete. It can be terminated by clicking the stop (red square) button on the debug toolbar, or hitting Shift-F5.
Hitting Ctrl-F5 ("Start Without Debuggin") with a "codeql" debug configuration active will evaluate the query, display the results, and immediately terminate the debug session. This is most similar to the behavior of the existing "Run Query" command.
While a "codeql" debug session is active, the "CodeQL: Debug Selection" command will perform a quickeval of the current selection, in the context of the active debug session. If no debug session is active, but a "codeql" debug configuration is selected in the Debug panel, then this command launches a new debug session with that debug configuration to perform the quickeval.
While a "codeql" debug session is active, the "Continue" (F5) command will re-evaluate the entire query.
The "Step Into", "Steo Out", and "Step Over" commands don't do anything (yet).
Code Changes
package.jsonhas been updated to provide the "codeql" debug configuration type. Note that this is available even without the canary flag, but any attempt to start a CodeQL debug session will display an error stating that the feature is not yet available. It also adds the new commands.debug-configuration.tsresolves the debug configuration from "launch.json" to the actual launch parameters needed by the debug engine. VS Code calls theresolveDebugConfiguration()function to fill in defaults before any${...}variables are resolved, and then callsresolveDebugConfigurationWithSubstitutedVariables()to give us a chance to finalize the launch configuration after variable substitution. It is in the latter function that we determine the quickeval context if needed, and validate that the user has specified a query and a database.debug-protocol.tsdefines a few custom messages we've added beyond the standard DAP messages. We've added one new request (to run a quickeval with a specific selection), and two events (one at the start of evaluation that reports the output directory and quickeval context, and one at the end of evaluation that reports the evaluation time and any error message).debug-session.tsis the actual implementation of the DAP, using a helper library provided by VS Code. This is actually pretty simple, since it just invokes the query server to do the heavy lifting.debugger-factory.tsimplements the factory that createsDebugSessionobjects when VS Code starts a new debug session.debugger-ui.tsimplements the new debugger commands, and handles the display of results after each successful evaluation.local-databases-ui.tsdoesn't really do anything new, but I did have to update how it handles progress when prompting the user to select a database. Before, it assumed that it always had a progress callback provided by the invoking command. However, when invoked during debug launch to fill in a missingdatabaseproperty on the configuration, it needs to create its own progress bar if it has to load a database.local-databases.tsnow separates the creation of aDatabaseItemfrom the registration of aDatabaseItemin the list of available databases. This allows a debug configuration to specify a path to a database that might not be present in the database manager for the current workspace.local-queries.tsandrun-queries-shared.tsgot a bit of refactoring around how we compute query configuration. I've split updetermineSelectedQuery()so that each configuration property (query, quickeval, etc.) can be computed independently. I also removed the assumption that the quickeval selection is in the same document as the actual query being compiled.Tests
The new debugger tests I've added exercise the new commands, and validate that we evaluation the correct files and selections, and get the correct number of results. This is all done via a
DebugControllerclass that turns the event-driven style of the debug adapter into anasync/awaitbased sequential style. The test issues debugger commands, then asserts that they caused the expected events.I've also added new flavors to the existing query tests to perform the same evaluation while going through the debugger instead of
localQueries. This also uses theDebugControllerwhen using the debugger.