...
 
Commits (27)
......@@ -77,5 +77,9 @@ module.exports = {
"react/destructuring-assignment": "off",
// Allow console errors and warnings
"no-console": ["error", { allow: ["warn", "error"] }],
// Disallow the use of var in favor of let and const
"no-var": "error",
// Do not favor default import
"import/prefer-default-export": "off",
}
};
......@@ -45,9 +45,9 @@ export const getCallers: Server.GetRequest<
[ Json.key<'#fct'>, Json.key<'#stmt'> ][]
>= getCallers_internal;
/** Dead code. */
/** Unreachable and non terminating statements. */
export interface deadCode {
/** List of unreachable statements of a function */
/** List of unreachable statements. */
unreachable: marker[];
/** List of reachable but non terminating statements. */
nonTerminating: marker[];
......@@ -78,7 +78,7 @@ const getDeadCode_internal: Server.GetRequest<Json.key<'#fct'>,deadCode> = {
input: Json.jKey<'#fct'>('#fct'),
output: jDeadCode,
};
/** Get the list of unreachable statements and non terminating statements in a function */
/** Get the lists of unreachable and of non terminating statements in a function */
export const getDeadCode: Server.GetRequest<Json.key<'#fct'>,deadCode>= getDeadCode_internal;
/* ------------------------------------- */
......@@ -21,7 +21,7 @@
"@babel/preset-react": "^7.9.4",
"@babel/preset-typescript": "^7.9.0",
"@hot-loader/react-dom": "^16.13.0",
"@types/codemirror": "^0.0.89",
"@types/codemirror": "^0.0.97",
"@types/cytoscape": "^3.14.5",
"@types/lodash": "^4.14.149",
"@types/node": "12.12.21",
......
This diff is collapsed.
This diff is collapsed.
......@@ -42,12 +42,12 @@ function callstackToString(callstack: API.callstack): string {
function buildCxtMenu(
commands: Cxtcommand[],
content? : JSX.Element,
action? : () => void,
content?: JSX.Element,
action?: () => void,
) {
commands.push({
content: content ? renderToString(content) : '',
select: action || (() => {}),
select: action || (() => { }),
enabled: !!action,
});
}
......@@ -226,8 +226,7 @@ class Dive {
receiveGraph(data: any): Cytoscape.CollectionReturnValue {
let newNodes = this.cy.collection();
for (const node of data.nodes)
{
for (const node of data.nodes) {
if (typeof node.range === 'number')
node.stops = `0% ${node.range}% ${node.range}% 100%`;
......@@ -271,8 +270,7 @@ class Dive {
}
}
for (const dep of data.deps)
{
for (const dep of data.deps) {
const src = this.cy.$id(dep.src);
const dst = this.cy.$id(dep.dst);
const isRoot = dst?.data('is_root');
......@@ -308,7 +306,7 @@ class Dive {
set layout(layout: string) {
let extendedOptions = {};
if (layout in layouts)
extendedOptions = (layouts as {[key: string]: object})[layout];
extendedOptions = (layouts as { [key: string]: object })[layout];
this._layout = layout;
this.layoutOptions = {
name: layout,
......@@ -323,7 +321,7 @@ class Dive {
recomputeLayout(newNodes?: Cytoscape.Collection): void {
if (this.layoutOptions && this.cy.container() &&
(newNodes === undefined || !newNodes.empty())) {
(newNodes === undefined || !newNodes.empty())) {
this.cy.layout({
animationEasing: 'ease-in-out-quad',
/* Do not move new nodes */
......@@ -438,8 +436,11 @@ class Dive {
node.unselectify();
}
selectLocation(location: States.Location, doExplore: boolean) {
if (location !== this.selectedLocation) {
selectLocation(location: States.Location | undefined, doExplore: boolean) {
if (!location) {
// Reset whole graph if no location is selected.
this.clear();
} else if (location !== this.selectedLocation) {
this.selectedLocation = location;
const selectNode = this.cy.$('node:selected');
const writes = selectNode?.data()?.writes;
......@@ -475,7 +476,7 @@ const GraphView = () => {
const [selection, updateSelection] = States.useSelection();
const [lock, flipLock] = Dome.useSwitch('dive.lock', false);
const [selectionMode, flipSelectionMode] =
Dome.useGlobalSetting('dive.selectionMode', 'follow');
Dome.useGlobalSetting('dive.selectionMode', 'follow');
function setCy(cy: Cytoscape.Core) {
if (cy !== dive.cy)
......@@ -503,8 +504,7 @@ const GraphView = () => {
};
// Updates the graph according to the selected marker.
if (selection?.current)
dive.selectLocation(selection?.current, !lock);
dive.selectLocation(selection?.current, !lock);
}, [dive, lock, selection, updateSelection]);
// Layout selection
......@@ -523,14 +523,14 @@ const GraphView = () => {
// Selection mode
const selectMode = (id?: boolean) => id && flipSelectionMode(id);
const modes =
[{ id: 'follow', label: 'Follow selection' },
{ id: 'add', label: 'Add selection to the graph' },
];
const modes = [
{ id: 'follow', label: 'Follow selection' },
{ id: 'add', label: 'Add selection to the graph' },
];
const checkMode =
(item: { id: string }) => (
{ checked: item.id === selectionMode, ...item }
);
(item: { id: string }) => (
{ checked: item.id === selectionMode, ...item }
);
const modeMenu = () => {
Dome.popupMenu(modes.map(checkMode), selectMode);
};
......@@ -583,7 +583,7 @@ export default () => (
id="dive.graph"
label="Data-flow graph"
title={'Data dependency graph according to an Eva analysis.\nNodes color ' +
'represents the precision of the values inferred by Eva.'}
'represents the precision of the values inferred by Eva.'}
>
<GraphView />
</Component>
......
......@@ -478,7 +478,7 @@ async function _launch() {
const logger = (text: string | string[]) => {
buffer.append(text);
if (text.indexOf('\n') >= 0) {
buffer.scroll(undefined, undefined);
buffer.scroll();
}
};
process?.stdout?.on('data', logger);
......
// --------------------------------------------------------------------------
// --- Frama-C Utilities
// --------------------------------------------------------------------------
/**
* @packageDocumentation
* @module frama-c/utils
*/
import * as Dome from 'dome';
import * as DomeBuffers from 'dome/text/buffers';
import * as KernelData from 'api/kernel/data';
const PP = new Dome.PP('Utils');
// --------------------------------------------------------------------------
// --- Print Utilities
// --------------------------------------------------------------------------
/**
* Print text containing tags into buffer.
* @param buffer Rich text buffer to print into.
* @param contents Actual text containing tags.
* @param options Specify particular marker options.
*/
export function printTextWithTags(
buffer: DomeBuffers.RichTextBuffer,
contents: KernelData.text,
options?: DomeBuffers.MarkerProps,
) {
if (Array.isArray(contents)) {
let marker = false;
const tag = contents.shift();
if (tag) {
if (Array.isArray(tag)) {
contents.unshift(tag);
} else {
buffer.openTextMarker({ id: tag, ...options ?? {} });
marker = true;
}
}
contents.forEach((txt) => printTextWithTags(buffer, txt, options));
if (marker) {
marker = false;
buffer.closeTextMarker();
}
} else if (typeof contents === 'string') {
buffer.append(contents);
} else {
PP.error('Unexpected text', contents);
}
}
......@@ -4,6 +4,7 @@
import React from 'react';
import * as States from 'frama-c/states';
import * as Utils from 'frama-c/utils';
import { Vfill } from 'dome/layout/boxes';
import { RichTextBuffer } from 'dome/text/buffers';
......@@ -25,7 +26,9 @@ const ASTinfo = () => {
React.useEffect(() => {
buffer.clear();
buffer.printTextWithTags(data, { css: 'color: blue' });
if (data) {
Utils.printTextWithTags(buffer, data, { css: 'color: blue' });
}
}, [buffer, data]);
// Callbacks
......
......@@ -6,14 +6,13 @@ import React from 'react';
import _ from 'lodash';
import * as Server from 'frama-c/server';
import * as States from 'frama-c/states';
import * as Utils from 'frama-c/utils';
import * as Dome from 'dome';
import { key } from 'dome/data/json';
import { RichTextBuffer } from 'dome/text/buffers';
import { Text } from 'dome/text/editors';
import { IconButton } from 'dome/controls/buttons';
import { Component, TitleBar } from 'frama-c/LabViews';
import { printFunction, markerInfo } from 'api/kernel/ast';
import { getCallers, getDeadCode } from 'api/plugins/eva/general';
......@@ -47,19 +46,16 @@ async function loadAST(
(async () => {
try {
const data = await Server.send(printFunction, theFunction);
buffer.operation(() => {
buffer.clear();
if (!data) {
buffer.log('// No code for function', theFunction);
}
buffer.printTextWithTags(data);
if (theMarker)
buffer.scroll(theMarker, undefined);
});
buffer.clear();
if (!data) {
buffer.log('// No code for function', theFunction);
}
Utils.printTextWithTags(buffer, data);
if (theMarker)
buffer.scroll(theMarker);
} catch (err) {
PP.error(
`Fail to retrieve the AST of function '${theFunction}' ` +
`and marker '${theMarker}':`, err,
'Fail to obtain AST', theFunction, theMarker, err,
);
}
})();
......@@ -122,21 +118,21 @@ const ASTview = () => {
// Hook: marker scrolling
React.useEffect(() => {
if (theMarker) buffer.scroll(theMarker, undefined);
if (theMarker) buffer.scroll(theMarker);
}, [buffer, theMarker]);
// Callbacks
const zoomIn = () => fontSize < 48 && setFontSize(fontSize + 2);
const zoomOut = () => fontSize > 4 && setFontSize(fontSize - 2);
function onTextSelection(id: key<'#markerInfo'>) {
function onTextSelection(id: string) {
if (selection.current) {
const location = { ...selection.current, marker: id };
updateSelection({ location });
}
}
async function onContextMenu(id: key<'#markerInfo'>) {
async function onContextMenu(id: string) {
const items = [];
const selectedMarkerInfo = markersInfo.find((e) => e.key === id);
if (selectedMarkerInfo?.var === 'function') {
......
......@@ -48,7 +48,8 @@
"dome": [ "src/dome/src/renderer/dome.js" ],
"dome/system": [ "src/dome/src/misc/system.js" ],
"dome/misc/*": [ "src/dome/src/misc/*"],
"dome/*": [ "src/dome/src/renderer/*" ]
"dome/*": [ "src/dome/src/renderer/*" ],
"codemirror/lib/codemirror.js": ["node_modules/@types/codemirror/index.d.ts"],
},
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
......
......@@ -993,10 +993,10 @@
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==
"@types/codemirror@^0.0.89":
version "0.0.89"
resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-0.0.89.tgz#c3627a8a85a2b3a61110f05ab1949f92451e8662"
integrity sha512-kLw8yUzz1dTAHQh+WYA/2Ka7YZUf5h3oHzgwP48xhbfmqqxrfp9lWuP9Ro26SUDHTthVl5afAa+DabsL1KD5oQ==
"@types/codemirror@^0.0.97":
version "0.0.97"
resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-0.0.97.tgz#6f2d8266b7f1b34aacfe8c77221fafe324c3d081"
integrity sha512-n5d7o9nWhC49DjfhsxANP7naWSeTzrjXASkUDQh7626sM4zK9XP2EVcHp1IcCf/IPV6c7ORzDUDF3Bkt231VKg==
dependencies:
"@types/tern" "*"
......
......@@ -18,7 +18,7 @@ STRING=$*
if
[ ! -e $FILE ] ||
! (diff --brief --ignore-space-change $FILE - <<< "$STRING")
! (diff --brief --ignore-space-change $FILE - >/dev/null <<< "$STRING")
then
mkdir -p $(dirname "$FILE")
echo $STRING > "$FILE"
......