import { useMemo } from 'react'; import { useDebugPointer } from '../../api/queries/debug'; import { ApiError } from '../../api/client'; import { EmptyState } from '../../components/ui/EmptyState'; import { ErrorState } from '../../components/ui/ErrorState'; import { LoadingState } from '../../components/ui/LoadingState'; import type { PointerLocationView, PointerValueView, PointerFieldEntryView, } from '../../api/types'; interface PointerAnalysisPanelProps { file: string; functionName: string; } export function PointerAnalysisPanel({ file, functionName, }: PointerAnalysisPanelProps) { const { data, isLoading, error } = useDebugPointer(file, functionName); if (isLoading) { return ; } if (error) { if (error instanceof ApiError && error.status === 404) { return ( ); } return ; } if ( !data || (data.values.length === 0 && data.field_reads.length === 0 && data.field_writes.length === 0) ) { return ( ); } return (

Per-Value Points-To

{data.values.length} value {data.values.length === 1 ? '' : 's'} · {data.location_count}{' '} location {data.location_count === 1 ? '' : 's'}
{data.values.length === 0 ? (

All SSA values point to nothing tracked.

) : ( )}
{data.field_reads.length > 0 && ( )} {data.field_writes.length > 0 && ( )}
); } function PointerValueTable({ values, locations, }: { values: PointerValueView[]; locations: PointerLocationView[]; }) { const locById = useMemo(() => { const map = new Map(); for (const loc of locations) map.set(loc.id, loc); return map; }, [locations]); return ( {values.map((v) => ( ))}
Value Name Points-To
v{v.ssa_value} {v.var_name ?? '-'} {v.is_top ? ( ⊤ (top) ) : ( v.points_to.map((id) => ( )) )}
); } function LocationChip({ loc }: { loc?: PointerLocationView }) { if (!loc) { return ( ? ); } const className = loc.kind === 'Top' ? 'cap-badge cap-badge-sink' : loc.kind === 'Field' ? 'cap-badge cap-badge-sanitizer' : 'cap-badge cap-badge-source'; return ( {loc.display} ); } function FieldEntriesBlock({ title, entries, emptyHint, }: { title: string; entries: PointerFieldEntryView[]; emptyHint: string; }) { return (

{title}

{entries.length} entr{entries.length === 1 ? 'y' : 'ies'}
{entries.length === 0 ? (

{emptyHint}

) : ( {entries.map((e, i) => ( ))}
Target Field
{e.param_index === null ? 'self' : `param[${e.param_index}]`} {e.field}
)}
); }