Skip to content
Snippets Groups Projects
Commit f0631932 authored by Michele Alberti's avatar Michele Alberti
Browse files

[ivette] Reproduce the 'Go to caller' functionality of the current GUI.

parent 58b71ec1
No related branches found
No related tags found
No related merge requests found
...@@ -501,6 +501,7 @@ export interface MultipleSelection { ...@@ -501,6 +501,7 @@ export interface MultipleSelection {
/** A select action on multiple locations. */ /** A select action on multiple locations. */
export interface MultipleSelect { export interface MultipleSelect {
readonly index: number;
readonly locations: Location[]; readonly locations: Location[];
} }
...@@ -546,7 +547,10 @@ function isSingleSelect(a: SelectionActions): a is SingleSelect { ...@@ -546,7 +547,10 @@ function isSingleSelect(a: SelectionActions): a is SingleSelect {
} }
function isMultipleSelect(a: SelectionActions): a is MultipleSelect { function isMultipleSelect(a: SelectionActions): a is MultipleSelect {
return (a as MultipleSelect).locations !== undefined; return (
(a as MultipleSelect).locations !== undefined &&
(a as MultipleSelect).index !== undefined
);
} }
function isNthSelect(a: SelectionActions): a is NthSelect { function isNthSelect(a: SelectionActions): a is NthSelect {
...@@ -644,12 +648,13 @@ function reducer(s: Selection, action: SelectionActions): Selection { ...@@ -644,12 +648,13 @@ function reducer(s: Selection, action: SelectionActions): Selection {
if (isMultipleSelect(action)) { if (isMultipleSelect(action)) {
if (action.locations.length === 0) if (action.locations.length === 0)
return s; return s;
const selection = selectLocation(s, action.locations[0]); const index = action.index > 0 ? action.index : 0;
const selection = selectLocation(s, action.locations[index]);
return { return {
...selection, ...selection,
multiple: { multiple: {
allSelections: action.locations, allSelections: action.locations,
index: 0, index,
}, },
}; };
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
import React from 'react'; import React from 'react';
import _ from 'lodash';
import * as Server from 'frama-c/server'; import * as Server from 'frama-c/server';
import * as States from 'frama-c/states'; import * as States from 'frama-c/states';
...@@ -57,8 +58,8 @@ async function loadAST( ...@@ -57,8 +58,8 @@ async function loadAST(
}); });
} catch (err) { } catch (err) {
PP.error( PP.error(
'Fail to retrieve the AST of function', theFunction, `Fail to retrieve the AST of function '${theFunction}' ` +
'marker:', theMarker, err, `and marker '${theMarker}':`, err,
); );
} }
})(); })();
...@@ -72,7 +73,7 @@ async function functionCallers(functionName: string) { ...@@ -72,7 +73,7 @@ async function functionCallers(functionName: string) {
const locations = data.map(([fct, marker]) => ({ function: fct, marker })); const locations = data.map(([fct, marker]) => ({ function: fct, marker }));
return locations; return locations;
} catch (err) { } catch (err) {
PP.error(`Fail to retrieve callers of function ${functionName}.`, err); PP.error(`Fail to retrieve callers of function '${functionName}':`, err);
return []; return [];
} }
} }
...@@ -91,7 +92,7 @@ const ASTview = () => { ...@@ -91,7 +92,7 @@ const ASTview = () => {
const [theme, setTheme] = Dome.useGlobalSetting('ASTview.theme', 'default'); const [theme, setTheme] = Dome.useGlobalSetting('ASTview.theme', 'default');
const [fontSize, setFontSize] = Dome.useGlobalSetting('ASTview.fontSize', 12); const [fontSize, setFontSize] = Dome.useGlobalSetting('ASTview.fontSize', 12);
const [wrapText, setWrapText] = Dome.useSwitch('ASTview.wrapText', false); const [wrapText, setWrapText] = Dome.useSwitch('ASTview.wrapText', false);
const markers = States.useSyncArray(markerInfo); const markersInfo = States.useSyncArray(markerInfo);
const theFunction = selection?.current?.function; const theFunction = selection?.current?.function;
const theMarker = selection?.current?.marker; const theMarker = selection?.current?.marker;
...@@ -129,26 +130,42 @@ const ASTview = () => { ...@@ -129,26 +130,42 @@ const ASTview = () => {
} }
} }
function onContextMenu(id: key<'#markerInfo'>) { async function onContextMenu(id: key<'#markerInfo'>) {
const items = []; const items = [];
const marker = markers.find((e) => e.key === id); const selectedMarkerInfo = markersInfo.find((e) => e.key === id);
if (marker?.kind === 'function') { switch (selectedMarkerInfo?.kind) {
items.push({ case 'function': {
label: `Go to definition of ${marker.name}`, items.push({
onClick: () => { label: `Go to definition of ${selectedMarkerInfo.name}`,
const location = { function: marker.name }; onClick: () => {
updateSelection({ location }); const location = { function: selectedMarkerInfo.name };
}, updateSelection({ location });
}); },
} });
if (marker?.kind === 'declaration' && marker?.name) { break;
items.push({ }
label: 'Go to callers', case 'declaration': {
onClick: async () => { if (selectedMarkerInfo?.name) {
const locations = await functionCallers(marker.name); const locations = await functionCallers(selectedMarkerInfo.name);
updateSelection({ locations }); const locationsByFunction = _.groupBy(locations, (e) => e.function);
}, _.forEach(locationsByFunction,
}); (e) => {
const callerName = e[0].function;
items.push({
label:
`Go to caller ${callerName} ` +
`${e.length > 1 ? `(${e.length} call sites)` : ''}`,
onClick: () => updateSelection({
locations,
index: locations.findIndex((l) => l.function === callerName),
}),
});
});
}
break;
}
default:
break;
} }
if (items.length > 0) if (items.length > 0)
Dome.popupMenu(items); Dome.popupMenu(items);
......
...@@ -25,18 +25,18 @@ const LocationsTable = () => { ...@@ -25,18 +25,18 @@ const LocationsTable = () => {
const model = React.useMemo(() => ( const model = React.useMemo(() => (
new CompactModel<number, LocationId>(({ id }: LocationId) => id) new CompactModel<number, LocationId>(({ id }: LocationId) => id)
), []); ), []);
const multiple: States.MultipleSelection = selection?.multiple; const multipleSelections = selection?.multiple;
const numberOfSelections = multiple?.allSelections?.length; const numberOfSelections = multipleSelections?.allSelections?.length;
// Updates [[model]] with the current multiple selection. // Updates [[model]] with the current multiple selections.
React.useEffect(() => { React.useEffect(() => {
if (numberOfSelections > 0) { if (numberOfSelections > 0) {
const data: LocationId[] = const data: LocationId[] =
multiple.allSelections.map((d, i) => ({ ...d, id: i })); multipleSelections.allSelections.map((d, i) => ({ ...d, id: i }));
model.replaceAllDataWith(data); model.replaceAllDataWith(data);
} else } else
model.clear(); model.clear();
}, [numberOfSelections, multiple, model]); }, [numberOfSelections, multipleSelections, model]);
// Callbacks // Callbacks
const onTableSelection = React.useCallback( const onTableSelection = React.useCallback(
...@@ -45,7 +45,7 @@ const LocationsTable = () => { ...@@ -45,7 +45,7 @@ const LocationsTable = () => {
); );
const reload = () => { const reload = () => {
const location = multiple.allSelections[multiple.index]; const location = multipleSelections.allSelections[multipleSelections.index];
updateSelection({ location }); updateSelection({ location });
}; };
...@@ -62,7 +62,7 @@ const LocationsTable = () => { ...@@ -62,7 +62,7 @@ const LocationsTable = () => {
<IconButton <IconButton
icon="ANGLE.LEFT" icon="ANGLE.LEFT"
onClick={() => updateSelection('MULTIPLE_PREV')} onClick={() => updateSelection('MULTIPLE_PREV')}
enabled={numberOfSelections > 1 && multiple?.index > 0} enabled={numberOfSelections > 1 && multipleSelections?.index > 0}
title="Previous location" title="Previous location"
/> />
<IconButton <IconButton
...@@ -70,7 +70,7 @@ const LocationsTable = () => { ...@@ -70,7 +70,7 @@ const LocationsTable = () => {
onClick={() => updateSelection('MULTIPLE_NEXT')} onClick={() => updateSelection('MULTIPLE_NEXT')}
enabled={ enabled={
numberOfSelections > 1 && numberOfSelections > 1 &&
multiple?.index < numberOfSelections - 1 multipleSelections?.index < numberOfSelections - 1
} }
title="Next location" title="Next location"
/> />
...@@ -82,8 +82,9 @@ const LocationsTable = () => { ...@@ -82,8 +82,9 @@ const LocationsTable = () => {
`location${numberOfSelections > 1 ? 's' : ''}` `location${numberOfSelections > 1 ? 's' : ''}`
} }
> >
{multiple?.allSelections.length === 0 ? {multipleSelections?.allSelections.length === 0 ?
'0 / 0' : `${multiple?.index + 1} / ${numberOfSelections}`} '0 / 0' :
`${multipleSelections?.index + 1} / ${numberOfSelections}`}
</Label> </Label>
<Space /> <Space />
<IconButton <IconButton
...@@ -95,7 +96,7 @@ const LocationsTable = () => { ...@@ -95,7 +96,7 @@ const LocationsTable = () => {
</TitleBar> </TitleBar>
<Table <Table
model={model} model={model}
selection={multiple?.index} selection={multipleSelections?.index}
onSelection={onTableSelection} onSelection={onTableSelection}
> >
<Column <Column
...@@ -118,9 +119,9 @@ const LocationsTable = () => { ...@@ -118,9 +119,9 @@ const LocationsTable = () => {
export default () => ( export default () => (
<Component <Component
id="frama-c.selection" id="frama-c.locations"
label="Locations" label="Locations"
title="Browse a selection of multiple locations" title="Browse multiple locations"
> >
<LocationsTable /> <LocationsTable />
</Component> </Component>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment