Skip to content

Instantly share code, notes, and snippets.

@JanWielemaker
Created August 15, 2017 14:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JanWielemaker/dd8c8e378bcfc00ba48022a9fbcef07f to your computer and use it in GitHub Desktop.
Save JanWielemaker/dd8c8e378bcfc00ba48022a9fbcef07f to your computer and use it in GitHub Desktop.
Find references to a predicate
:- use_module(library(prolog_codewalk)).
:- meta_predicate findrefs(:).
:- thread_local hit/1.
findrefs(To) :-
resolve(To, Target),
prolog_walk_code(
[ module_class([user]),
infer_meta_predicates(true),
trace_reference(Target),
on_trace(hit)
]),
findall(Location, retract(hit(Location)), Refs),
print_message(informational, references(Target, Refs)).
resolve(M:Name/Arity, Target) :-
atom(Name),
integer(Arity),
!,
functor(Head, Name, Arity),
resolve(M:Head, Target).
resolve(M:Head, Target) :-
callable(Head),
!,
( predicate_property(M:Head, imported_from(M2))
-> Target = M2:Head
; Target = M:Head
).
resolve(To, _) :-
type_error(callable, To).
hit(_Callee, _Caller, Location) :-
assert(hit(Location)).
prolog:message(references(Target, Refs)) -->
{ map_list_to_pairs(sort_reference_key, Refs, Keyed),
keysort(Keyed, KeySorted),
pairs_values(KeySorted, SortedRefs),
length(SortedRefs, Count)
},
[ 'The predicate '-[] ],
predicate(Target),
[ ' is referenced from ~D locations'-[Count], nl ],
referenced_by(SortedRefs).
predicate(Module:Head) -->
{ atom(Module),
callable(Head),
predicate_name(Module:Head, PName)
},
!,
[ '~w'-[PName] ].
%! sort_reference_key(+Reference, -Key) is det.
%
% Create a stable key for sorting references to predicates.
sort_reference_key(Term, key(M:Name/Arity, N, ClausePos)) :-
clause_ref(Term, ClauseRef, ClausePos),
!,
nth_clause(Pred, N, ClauseRef),
strip_module(Pred, M, Head),
functor(Head, Name, Arity).
sort_reference_key(Term, Term).
clause_ref(clause_term_position(ClauseRef, TermPos), ClauseRef, ClausePos) :-
arg(1, TermPos, ClausePos).
clause_ref(clause(ClauseRef), ClauseRef, 0).
referenced_by([]) -->
[].
referenced_by([Ref|T]) -->
['\t'], prolog:message_location(Ref),
predicate_indicator(Ref),
[ nl ],
referenced_by(T).
predicate_indicator(clause_term_position(ClauseRef, _)) -->
{ nonvar(ClauseRef) },
!,
predicate_indicator(clause(ClauseRef)).
predicate_indicator(clause(ClauseRef)) -->
{ clause_name(ClauseRef, Name) },
[ '~w'-[Name] ].
predicate_indicator(file_term_position(_,_)) -->
[ '(initialization)' ].
predicate_indicator(file(_,_,_,_)) -->
[ '(initialization)' ].
@JanWielemaker
Copy link
Author

For example, load a program and do

?- findrefs(member/2).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment