diff --git a/CMPUT-416_README.md b/CMPUT-416_README.md new file mode 100644 index 0000000..a7349f7 --- /dev/null +++ b/CMPUT-416_README.md @@ -0,0 +1,11 @@ +# Installation Instructions +1. Download this extension's VSIX file [here](https://drive.google.com/file/d/1anBbOCuIVtiLCy3rwROPmjVB4wl4AyWz/view?usp=sharing). +1. Open [Visual Studio Code](https://code.visualstudio.com/download). +1. Navigate to the Extensions menu (it looks like 4 blocks, one of which has yet to be put in place). +1. Make sure you don't have an extension called "Debug Visualizer". + * If you do, uninstall it. +1. Click the three horizontal dots in the top right of that menu. +1. Select "Install from VSIX...". +1. Select the file you downloaded in the first step. +1. Restart Visual Studio Code. +1. You should see a new extension in the Extensions menu called "CodeQL Visualizer" with the ludicrous version number 416.0.0. diff --git a/README.md b/README.md index f989f99..77c988e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # VS Code Debug Visualizer +### For CMPUT 416 +See [CMPUT-416_README.md](CMPUT-416_README.md) for installation instructions. This extension has been modified to support the primary project extension, found [here](https://github.com/CodeQL-Visualization/vscode-codeql) (the cmput416-visualization branch). + [![](https://img.shields.io/static/v1?style=social&label=Sponsor&message=%E2%9D%A4&logo=GitHub&color&link=%3Curl%3E)](https://github.com/sponsors/hediet) [![](https://img.shields.io/static/v1?style=social&label=Donate&message=%E2%9D%A4&logo=Paypal&color&link=%3Curl%3E)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ZP5F38L4C88UY&source=url) [![](https://img.shields.io/twitter/follow/hediet_dev.svg?style=social)](https://twitter.com/intent/follow?screen_name=hediet_dev) diff --git a/data-extraction/src/js/helpers/createGraph.ts b/data-extraction/src/js/helpers/createGraph.ts index 77aa6d4..8d08dfb 100644 --- a/data-extraction/src/js/helpers/createGraph.ts +++ b/data-extraction/src/js/helpers/createGraph.ts @@ -27,6 +27,7 @@ export function createGraph( nodes: [], edges: [], }; + let idCounter = 1; const ids = new Map(); function getId(item: T): string { diff --git a/data-extraction/tsconfig.json b/data-extraction/tsconfig.json index 3bcd10e..72f9f36 100644 --- a/data-extraction/tsconfig.json +++ b/data-extraction/tsconfig.json @@ -10,7 +10,8 @@ "declaration": true, "declarationMap": true, "newLine": "LF", - "sourceMap": true + "sourceMap": true, + "composite": true }, "include": ["./src/**/*"] } diff --git a/demos/python/graph.py b/demos/python/graph.py index 6a178df..0658663 100644 --- a/demos/python/graph.py +++ b/demos/python/graph.py @@ -21,7 +21,7 @@ id = str(i) graph["nodes"].append({"id": id, "label": id}) # connects the node to a random edge - targetId = str(randint(1, i - 1)) + targetId = str(randint(1, i - 1)) graph["edges"].append({"from": id, "to": targetId}) json_graph = dumps(graph) print("i is " + str(i)) diff --git a/extension/package.json b/extension/package.json index d39de5b..f136515 100644 --- a/extension/package.json +++ b/extension/package.json @@ -1,10 +1,10 @@ { "name": "debug-visualizer", "private": true, - "displayName": "Debug Visualizer", - "description": "A visual watch window that lets you visualize your data structures while debugging.", + "displayName": "CodeQL Visualizer", + "description": "A visual watch window that lets you visualize CodeQL query data.", "icon": "docs/logo.drawio.png", - "version": "2.0.6", + "version": "416.0.0", "license": "GPL-3.0", "engines": { "vscode": "^1.46.0" @@ -36,10 +36,8 @@ "Other" ], "activationEvents": [ - "onCommand:vscode-debug-visualizer.new-visualizer", - "onCommand:vscode-debug-visualizer.visualizer-set-expression", - "onDebug", - "onWebviewPanel:debugVisualizer" + "*", + "onCommand:vscode-debug-visualizer.codeql-visualizer" ], "main": "./dist/extension.js", "contributes": { @@ -48,6 +46,10 @@ "command": "vscode-debug-visualizer.new-visualizer", "title": "Debug Visualizer: New View" }, + { + "command": "vscode-debug-visualizer.codeql-visualizer", + "title": "Debug Visualizer: Visualize CodeQL File" + }, { "command": "vscode-debug-visualizer.visualizer-set-expression", "title": "Debug Visualizer: Use Selection as Expression" @@ -61,7 +63,7 @@ } ], "configuration": { - "title": "Debug Visualizer", + "title": "CodeQL Visualizer", "properties": { "debugVisualizer.useChromeKioskMode": { "type": "boolean", diff --git a/extension/src/EvaluationWatchService/CodeQLService.ts b/extension/src/EvaluationWatchService/CodeQLService.ts new file mode 100644 index 0000000..61f749e --- /dev/null +++ b/extension/src/EvaluationWatchService/CodeQLService.ts @@ -0,0 +1,110 @@ +import { + EvaluationWatchService, + EvaluationWatcher, + EvaluationWatcherOptions, +} from "./EvaluationWatchService"; +import { observable, autorun, action } from "mobx"; +import { Disposable } from "@hediet/std/disposable"; +import { DataExtractorId, GraphNode, GraphVisualizationData } from "@hediet/debug-visualizer-data-extraction"; +import { DataExtractionState, CompletionItem } from "../webviewContract"; +import { hotClass } from "@hediet/node-reload"; +import { TaintVisNode } from "../vis-helpers"; + +@hotClass(module) +export class CodeQLWatchService implements EvaluationWatchService { + public readonly dispose = Disposable.fn(); + private watcher : CodeQLWatcher; + + constructor() { + this.watcher = new CodeQLWatcher('', this, {preferredDataExtractor: undefined}); + this.dispose.track({ + dispose: autorun(() => { + this.watcher.refresh(); + }), + }); + } + + public createEvaluationWatcher( + expression: string, + options: EvaluationWatcherOptions + ): EvaluationWatcher { + this.refresh(this.watcher); + return this.watcher; + } + + public createCodeQLGraph(graphData: any) { + const graph : GraphVisualizationData = { + kind: { graph: true }, + nodes: [], + edges: [] + }; + + const result = { + kind: "data", + result: { + availableExtractors: [], + usedExtractor: { + id: "generic" as any, + name: "Generic", + priority: 1, + }, + data: graph, + }, + } as DataExtractionState; + + graph.nodes = graphData.nodes; + graph.edges = graphData.edges; + + this.watcher._state = result; + } + + get languageId(): string | undefined { + return undefined; + } + + public async refresh(w: CodeQLWatcher): Promise { + } + + public async getCompletions( + text: string, + column: number + ): Promise { + return []; + } +} + +class CodeQLWatcher implements EvaluationWatcher { + constructor( + public readonly expression: string, + private readonly source: CodeQLWatchService, + options: EvaluationWatcherOptions + ) { + this._preferredDataExtractor = options.preferredDataExtractor; + } + + @observable + private _preferredDataExtractor: DataExtractorId | undefined = undefined; + + public get preferredDataExtractor(): DataExtractorId | undefined { + return this._preferredDataExtractor; + } + + @action + public setPreferredDataExtractor(id: DataExtractorId | undefined): void { + this._preferredDataExtractor = id; + this.refresh(); + } + + public refresh(): void { + this.source.refresh(this); + } + + @observable + public _state: DataExtractionState = { kind: "error", message:"Unexpected error" }; + public get state(): DataExtractionState { + return this._state; + } + + public dispose(): void { + } +} diff --git a/extension/src/EvaluationWatchService/index.ts b/extension/src/EvaluationWatchService/index.ts index 4062c46..8449299 100644 --- a/extension/src/EvaluationWatchService/index.ts +++ b/extension/src/EvaluationWatchService/index.ts @@ -1,2 +1,3 @@ export * from "./EvaluationWatchServiceImpl"; export * from "./EvaluationWatchService"; +export * from "./CodeQLService"; diff --git a/extension/src/debugger/VsCodeDebuggerView.ts b/extension/src/debugger/VsCodeDebuggerView.ts index bf864b0..a725dd7 100644 --- a/extension/src/debugger/VsCodeDebuggerView.ts +++ b/extension/src/debugger/VsCodeDebuggerView.ts @@ -18,6 +18,7 @@ export class VsCodeDebuggerView { } public get activeFrameId(): number | undefined { + console.log("move"); if (!this._activeDebugSession) { return undefined; } else { diff --git a/extension/src/extension.ts b/extension/src/extension.ts index 48375f4..3fd8364 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -1,4 +1,4 @@ -import { window, ExtensionContext, commands } from "vscode"; +import { window, ExtensionContext, commands, extensions } from "vscode"; import { Disposable } from "@hediet/std/disposable"; import { enableHotReload, @@ -17,107 +17,62 @@ import { WebviewServer } from "./webview/WebviewServer"; import { Config } from "./Config"; import { VsCodeDebugger } from "./debugger/VsCodeDebugger"; import { VsCodeDebuggerView } from "./debugger/VsCodeDebuggerView"; -import { EvaluationWatchServiceImpl } from "./EvaluationWatchService"; +import { CodeQLWatchService } from "./EvaluationWatchService"; +import { TaintVisNode } from "./vis-helpers"; import { ComposedEvaluationEngine, JsEvaluationEngine, GenericEvaluationEngine, ConfiguredEvaluationEngine, } from "./EvaluationWatchService/EvaluationEngine"; +let fs = require('fs'); -export function activate(context: ExtensionContext) { - context.subscriptions.push( - hotRequireExportedFn(module, Extension, Extension => new Extension()) - ); -} - -export function deactivate() {} - -export class Extension { +export class CodeQLVisExtension { public readonly dispose = Disposable.fn(); private readonly config = new Config(); - private readonly debugger = this.dispose.track(new VsCodeDebugger()); - private readonly debuggerView = this.dispose.track( - new VsCodeDebuggerView(this.debugger) - ); - public readonly dataSource = new EvaluationWatchServiceImpl( - this.debuggerView, - new ComposedEvaluationEngine([ - new ConfiguredEvaluationEngine(this.config), - new JsEvaluationEngine(), - new GenericEvaluationEngine(), - ]) - ); + public readonly dataSource = new CodeQLWatchService(); private readonly server = new WebviewServer(this.dataSource, this.config); private readonly views = this.dispose.track( new InternalWebviewManager(this.server, this.config) ); - constructor() { + public produceVis(path: string) { if (getReloadCount(module) > 0) { const i = this.dispose.track(window.createStatusBarItem()); i.text = "reload" + getReloadCount(module); i.show(); } - this.dispose.track( - commands.registerCommand( - "vscode-debug-visualizer.new-visualizer", - () => { - this.views.createNew(); - } - ) - ); - - this.dispose.track( - commands.registerCommand( - "vscode-debug-visualizer.visualizer-set-expression", - () => { - const editor = window.activeTextEditor; - if (!editor) { - return; - } + // The API for creating graph + fs.readFile(path, 'utf8', (err: any, data: any) =>{ + if (err){ + console.log(err); + } else { - const selection = editor.selection; + let obj = JSON.parse(data); //now it an object + console.log(obj); - let selectedText; - if (selection.isEmpty) { - const lineText = editor.document.lineAt(selection.start) - .text; - const regexp = /`(.*)`/g; - selectedText = ""; - let match; - while ((match = regexp.exec(lineText))) { - if ( - match.index <= selection.start.character && - selection.start.character <= - match.index + match[0].length - ) { - selectedText = match[1]; - } - } - } else { - selectedText = editor.document.getText(selection); - } + this.views.createNew(); + + this.dataSource.createCodeQLGraph(obj); - if (!selectedText) { - return; - } - - const connections = [...this.server.connections.values()]; - const latestConnection = - connections[connections.length - 1]; + }}); + } +} +const extension: CodeQLVisExtension = new CodeQLVisExtension(); - if (latestConnection) { - latestConnection.setExpression(selectedText); - } else { - this.views.createNew(selectedText); - } - } - ) - ); +export function activate(context: ExtensionContext) { + const command = 'vscode-debug-visualizer.codeql-visualizer' + const commandHandler = (path: string) => { + console.log("Reading from path: " + path); + extension.produceVis(path); } + context.subscriptions.push(commands.registerCommand(command, commandHandler)); } + +export function deactivate() {} + + diff --git a/extension/src/vis-helpers.ts b/extension/src/vis-helpers.ts new file mode 100644 index 0000000..5e396c6 --- /dev/null +++ b/extension/src/vis-helpers.ts @@ -0,0 +1,6 @@ +export type TaintVisNode = { + uniqueID: string; + label: string; + tainted: boolean; + children: TaintVisNode[]; +} \ No newline at end of file diff --git a/extension/src/webview/InternalWebviewManager.ts b/extension/src/webview/InternalWebviewManager.ts index 312547c..0ae4210 100644 --- a/extension/src/webview/InternalWebviewManager.ts +++ b/extension/src/webview/InternalWebviewManager.ts @@ -3,6 +3,7 @@ import { WebviewServer } from "./WebviewServer"; import { Disposable } from "@hediet/std/disposable"; import { WindowWithWebviewData } from "../webviewContract"; import { Config } from "../Config"; +import webpack = require("webpack"); export const debugVisualizer = "debugVisualizer"; @@ -36,9 +37,14 @@ export class InternalWebviewManager { } public createNew(expression: string | undefined = undefined) { + // Get rid of the existing webviews since they'll just duplicate our updated visualization + for (const panel of this.openedWebviews.keys()) { + panel.dispose(); + } + const webviewPanel = window.createWebviewPanel( debugVisualizer, - "Debug Visualizer", + "CodeQL Visualizer", ViewColumn.Two, { enableScripts: true, diff --git a/extension/src/webview/WebviewConnection.ts b/extension/src/webview/WebviewConnection.ts index 094db82..79e2452 100644 --- a/extension/src/webview/WebviewConnection.ts +++ b/extension/src/webview/WebviewConnection.ts @@ -28,6 +28,15 @@ export class WebviewConnection { ) { let authenticated = false; + this.watcher = this.dispose.track( + evaluationWatchService.createEvaluationWatcher( + '', + { + preferredDataExtractor: undefined, + } + ) + ); + function throwIfNotAuthenticated() { if (!authenticated) { throw new RequestHandlingError("Not authenticated"); diff --git a/extension/tsconfig.json b/extension/tsconfig.json index c13016f..cdbd6d7 100644 --- a/extension/tsconfig.json +++ b/extension/tsconfig.json @@ -8,7 +8,8 @@ "rootDir": "src", "strict": true, "skipLibCheck": true, - "experimentalDecorators": true + "experimentalDecorators": true, + "composite": true }, "include": [ "src/**/*", diff --git a/webview/src/components/GUI.tsx b/webview/src/components/GUI.tsx index 010799a..7b66c7c 100644 --- a/webview/src/components/GUI.tsx +++ b/webview/src/components/GUI.tsx @@ -22,9 +22,9 @@ export class GUI extends React.Component<{ model: Model }> { height: "100%", }} > -
+ {/*
-
+
*/}