36
37:- module(check,
38 [ check/0, 39 list_undefined/0, 40 list_undefined/1, 41 list_autoload/0, 42 list_redefined/0, 43 list_cross_module_calls/0, 44 list_cross_module_calls/1, 45 list_void_declarations/0, 46 list_trivial_fails/0, 47 list_trivial_fails/1, 48 list_format_errors/0, 49 list_format_errors/1, 50 list_strings/0, 51 list_strings/1, 52 list_rationals/0, 53 list_rationals/1 54 ]). 55:- autoload(library(apply),[maplist/2]). 56:- autoload(library(lists),[member/2,append/3]). 57:- autoload(library(occurs),[sub_term/2]). 58:- autoload(library(option),[merge_options/3,option/3]). 59:- autoload(library(pairs),
60 [group_pairs_by_key/2,map_list_to_pairs/3,pairs_values/2]). 61:- autoload(library(prolog_clause),
62 [clause_info/4,predicate_name/2,clause_name/2]). 63:- autoload(library(prolog_code),[pi_head/2]). 64:- autoload(library(prolog_codewalk),
65 [prolog_walk_code/1,prolog_program_clause/2]). 66:- autoload(library(prolog_format),[format_types/2]). 67
68
69:- set_prolog_flag(generate_debug_info, false). 70
71:- multifile
72 trivial_fail_goal/1,
73 string_predicate/1,
74 valid_string_goal/1,
75 checker/2. 76
77:- dynamic checker/2. 78
79
91
92:- predicate_options(list_undefined/1, 1,
93 [ module_class(list(oneof([user,library,system])))
94 ]). 95
109
110check :-
111 checker(Checker, Message),
112 print_message(informational,check(pass(Message))),
113 catch(Checker,E,print_message(error,E)),
114 fail.
115check.
116
131
132:- thread_local
133 undef/2. 134
135list_undefined :-
136 list_undefined([]).
137
138list_undefined(Options) :-
139 merge_options(Options,
140 [ module_class([user])
141 ],
142 WalkOptions),
143 call_cleanup(
144 prolog_walk_code([ undefined(trace),
145 on_trace(found_undef)
146 | WalkOptions
147 ]),
148 collect_undef(Grouped)),
149 ( Grouped == []
150 -> true
151 ; print_message(warning, check(undefined_procedures, Grouped))
152 ).
153
155
156:- public
157 found_undef/3,
158 collect_undef/1. 159
160collect_undef(Grouped) :-
161 findall(PI-From, retract(undef(PI, From)), Pairs),
162 keysort(Pairs, Sorted),
163 group_pairs_by_key(Sorted, Grouped).
164
165found_undef(To, _Caller, From) :-
166 goal_pi(To, PI),
167 ( undef(PI, From)
168 -> true
169 ; compiled(PI)
170 -> true
171 ; not_always_present(PI)
172 -> true
173 ; assertz(undef(PI,From))
174 ).
175
176compiled(system:'$call_cleanup'/0). 177compiled(system:'$catch'/0).
178compiled(system:'$cut'/0).
179compiled(system:'$reset'/0).
180compiled(system:'$call_continuation'/1).
181compiled(system:'$shift'/1).
182compiled(system:'$shift_for_copy'/1).
183compiled('$engines':'$yield'/0).
184
189
190not_always_present(_:win_folder/2) :-
191 \+ current_prolog_flag(windows, true).
192not_always_present(_:win_add_dll_directory/2) :-
193 \+ current_prolog_flag(windows, true).
194
195
196goal_pi(M:Head, M:Name/Arity) :-
197 functor(Head, Name, Arity).
198
209
210list_autoload :-
211 setup_call_cleanup(
212 ( current_prolog_flag(access_level, OldLevel),
213 current_prolog_flag(autoload, OldAutoLoad),
214 set_prolog_flag(access_level, system),
215 set_prolog_flag(autoload, false)
216 ),
217 list_autoload_(OldLevel),
218 ( set_prolog_flag(access_level, OldLevel),
219 set_prolog_flag(autoload, OldAutoLoad)
220 )).
221
222list_autoload_(SystemMode) :-
223 ( setof(Lib-Pred,
224 autoload_predicate(Module, Lib, Pred, SystemMode),
225 Pairs),
226 print_message(informational,
227 check(autoload(Module, Pairs))),
228 fail
229 ; true
230 ).
231
232autoload_predicate(Module, Library, Name/Arity, SystemMode) :-
233 predicate_property(Module:Head, undefined),
234 check_module_enabled(Module, SystemMode),
235 ( \+ predicate_property(Module:Head, imported_from(_)),
236 functor(Head, Name, Arity),
237 '$find_library'(Module, Name, Arity, _LoadModule, Library),
238 referenced(Module:Head, Module, _)
239 -> true
240 ).
241
242check_module_enabled(_, system) :- !.
243check_module_enabled(Module, _) :-
244 \+ import_module(Module, system).
245
249
250referenced(Term, Module, Ref) :-
251 Goal = Module:_Head,
252 current_predicate(_, Goal),
253 '$get_predicate_attribute'(Goal, system, 0),
254 \+ '$get_predicate_attribute'(Goal, imported, _),
255 nth_clause(Goal, _, Ref),
256 '$xr_member'(Ref, Term).
257
263
264list_redefined :-
265 setup_call_cleanup(
266 ( current_prolog_flag(access_level, OldLevel),
267 set_prolog_flag(access_level, system)
268 ),
269 list_redefined_,
270 set_prolog_flag(access_level, OldLevel)).
271
272list_redefined_ :-
273 current_module(Module),
274 Module \== system,
275 current_predicate(_, Module:Head),
276 \+ predicate_property(Module:Head, imported_from(_)),
277 ( global_module(Super),
278 Super \== Module,
279 '$c_current_predicate'(_, Super:Head),
280 \+ redefined_ok(Head),
281 '$syspreds':'$defined_predicate'(Super:Head),
282 \+ predicate_property(Super:Head, (dynamic)),
283 \+ predicate_property(Super:Head, imported_from(Module)),
284 functor(Head, Name, Arity)
285 -> print_message(informational,
286 check(redefined(Module, Super, Name/Arity)))
287 ),
288 fail.
289list_redefined_.
290
291redefined_ok('$mode'(_,_)).
292redefined_ok('$pldoc'(_,_,_,_)).
293redefined_ok('$pred_option'(_,_,_,_)).
294redefined_ok('$table_mode'(_,_,_)).
295redefined_ok('$tabled'(_,_)).
296redefined_ok('$exported_op'(_,_,_)).
297redefined_ok('$autoload'(_,_,_)).
298
299global_module(user).
300global_module(system).
301
307
308list_cross_module_calls :-
309 list_cross_module_calls([]).
310
311list_cross_module_calls(Options) :-
312 call_cleanup(
313 list_cross_module_calls_guarded(Options),
314 retractall(cross_module_call(_,_,_))).
315
316list_cross_module_calls_guarded(Options) :-
317 merge_options(Options,
318 [ module_class([user])
319 ],
320 WalkOptions),
321 prolog_walk_code([ trace_reference(_),
322 trace_condition(cross_module_call),
323 on_trace(write_call)
324 | WalkOptions
325 ]).
326
327:- thread_local
328 cross_module_call/3. 329
330:- public
331 cross_module_call/2,
332 write_call/3. 333
334cross_module_call(Callee, Context) :-
335 \+ same_module_call(Callee, Context).
336
337same_module_call(Callee, Context) :-
338 caller_module(Context, MCaller),
339 Callee = (MCallee:_),
340 ( ( MCaller = MCallee
341 ; predicate_property(Callee, exported)
342 ; predicate_property(Callee, built_in)
343 ; predicate_property(Callee, public)
344 ; clause_property(Context.get(clause), module(MCallee))
345 ; predicate_property(Callee, multifile)
346 )
347 -> true
348 ).
349
350caller_module(Context, MCaller) :-
351 Caller = Context.caller,
352 ( Caller = (MCaller:_)
353 -> true
354 ; Caller == '<initialization>',
355 MCaller = Context.module
356 ).
357
358write_call(Callee, Caller, Position) :-
359 cross_module_call(Callee, Caller, Position),
360 !.
361write_call(Callee, Caller, Position) :-
362 ( cross_module_call(_,_,_)
363 -> true
364 ; print_message(warning, check(cross_module_calls))
365 ),
366 asserta(cross_module_call(Callee, Caller, Position)),
367 print_message(warning,
368 check(cross_module_call(Callee, Caller, Position))).
369
373
374list_void_declarations :-
375 P = _:_,
376 ( predicate_property(P, undefined),
377 ( '$get_predicate_attribute'(P, meta_predicate, Pattern),
378 print_message(warning,
379 check(void_declaration(P, meta_predicate(Pattern))))
380 ; void_attribute(Attr),
381 '$get_predicate_attribute'(P, Attr, 1),
382 print_message(warning,
383 check(void_declaration(P, Attr)))
384 ),
385 fail
386 ; predicate_property(P, discontiguous),
387 \+ (predicate_property(P, number_of_clauses(N)), N > 0),
388 print_message(warning,
389 check(void_declaration(P, discontiguous))),
390 fail
391 ; true
392 ).
393
394void_attribute(public).
395void_attribute(volatile).
396void_attribute(det).
397
408
409:- thread_local
410 trivial_fail/2. 411
412list_trivial_fails :-
413 list_trivial_fails([]).
414
415list_trivial_fails(Options) :-
416 merge_options(Options,
417 [ module_class([user]),
418 infer_meta_predicates(false),
419 autoload(false),
420 evaluate(false),
421 trace_reference(_),
422 on_trace(check_trivial_fail)
423 ],
424 WalkOptions),
425
426 prolog_walk_code([ source(false)
427 | WalkOptions
428 ]),
429 findall(CRef, retract(trivial_fail(clause(CRef), _)), Clauses),
430 ( Clauses == []
431 -> true
432 ; print_message(warning, check(trivial_failures)),
433 prolog_walk_code([ clauses(Clauses)
434 | WalkOptions
435 ]),
436 findall(Goal-From, retract(trivial_fail(From, Goal)), Pairs),
437 keysort(Pairs, Sorted),
438 group_pairs_by_key(Sorted, Grouped),
439 maplist(report_trivial_fail, Grouped)
440 ).
441
446
447trivial_fail_goal(pce_expansion:pce_class(_, _, template, _, _, _)).
448trivial_fail_goal(pce_host:property(system_source_prefix(_))).
449
450:- public
451 check_trivial_fail/3. 452
453check_trivial_fail(MGoal0, _Caller, From) :-
454 ( MGoal0 = M:Goal,
455 atom(M),
456 callable(Goal),
457 predicate_property(MGoal0, interpreted),
458 \+ predicate_property(MGoal0, dynamic),
459 \+ predicate_property(MGoal0, multifile),
460 \+ trivial_fail_goal(MGoal0)
461 -> ( predicate_property(MGoal0, meta_predicate(Meta))
462 -> qualify_meta_goal(MGoal0, Meta, MGoal)
463 ; MGoal = MGoal0
464 ),
465 ( clause(MGoal, _)
466 -> true
467 ; assertz(trivial_fail(From, MGoal))
468 )
469 ; true
470 ).
471
472report_trivial_fail(Goal-FromList) :-
473 print_message(warning, check(trivial_failure(Goal, FromList))).
474
478
479qualify_meta_goal(M:Goal0, Meta, M:Goal) :-
480 functor(Goal0, F, N),
481 functor(Goal, F, N),
482 qualify_meta_goal(1, M, Meta, Goal0, Goal).
483
484qualify_meta_goal(N, M, Meta, Goal0, Goal) :-
485 arg(N, Meta, ArgM),
486 !,
487 arg(N, Goal0, Arg0),
488 arg(N, Goal, Arg),
489 N1 is N + 1,
490 ( module_qualified(ArgM)
491 -> add_module(Arg0, M, Arg)
492 ; Arg = Arg0
493 ),
494 meta_goal(N1, Meta, Goal0, Goal).
495meta_goal(_, _, _, _).
496
497add_module(Arg, M, M:Arg) :-
498 var(Arg),
499 !.
500add_module(M:Arg, _, MArg) :-
501 !,
502 add_module(Arg, M, MArg).
503add_module(Arg, M, M:Arg).
504
505module_qualified(N) :- integer(N), !.
506module_qualified(:).
507module_qualified(^).
508
509
524
525list_strings :-
526 list_strings([module_class([user])]).
527
528list_strings(Options) :-
529 ( prolog_program_clause(ClauseRef, Options),
530 clause(Head, Body, ClauseRef),
531 \+ ( predicate_indicator(Head, PI),
532 string_predicate(PI)
533 ),
534 make_clause(Head, Body, Clause),
535 findall(T,
536 ( sub_term(T, Head),
537 string(T)
538 ; Head = M:_,
539 goal_in_body(Goal, M, Body),
540 ( valid_string_goal(Goal)
541 -> fail
542 ; sub_term(T, Goal),
543 string(T)
544 )
545 ), Ts0),
546 sort(Ts0, Ts),
547 member(T, Ts),
548 message_context(ClauseRef, T, Clause, Context),
549 print_message(warning,
550 check(string_in_clause(T, Context))),
551 fail
552 ; true
553 ).
554
555make_clause(Head, true, Head) :- !.
556make_clause(Head, Body, (Head:-Body)).
557
574
575list_rationals :-
576 list_rationals([module_class([user])]).
577
578list_rationals(Options) :-
579 ( option(arithmetic(DoArith), Options, false),
580 prolog_program_clause(ClauseRef, Options),
581 clause(Head, Body, ClauseRef),
582 make_clause(Head, Body, Clause),
583 findall(T,
584 ( sub_term(T, Head),
585 rational(T),
586 \+ integer(T)
587 ; Head = M:_,
588 goal_in_body(Goal, M, Body),
589 nonvar(Goal),
590 ( DoArith == false,
591 valid_rational_goal(Goal)
592 -> fail
593 ; sub_term(T, Goal),
594 rational(T),
595 \+ integer(T)
596 )
597 ), Ts0),
598 sort(Ts0, Ts),
599 member(T, Ts),
600 message_context(ClauseRef, T, Clause, Context),
601 print_message(warning,
602 check(rational_in_clause(T, Context))),
603 fail
604 ; true
605 ).
606
607
608valid_rational_goal(_ is _).
609valid_rational_goal(_ =:= _).
610valid_rational_goal(_ < _).
611valid_rational_goal(_ > _).
612valid_rational_goal(_ =< _).
613valid_rational_goal(_ >= _).
614
615
620
621list_format_errors :-
622 list_format_errors([module_class([user])]).
623
624list_format_errors(Options) :-
625 ( prolog_program_clause(ClauseRef, Options),
626 clause(Head, Body, ClauseRef),
627 make_clause(Head, Body, Clause),
628 Head = M:_,
629 goal_in_body(Goal, M, Body),
630 format_warning(Goal, Msg),
631 message_context(ClauseRef, Goal, Clause, Context),
632 print_message(warning, check(Msg, Goal, Context)),
633 fail
634 ; true
635 ).
636
637format_warning(system:format(_Format, Args), Msg) :-
638 nonvar(Args),
639 \+ is_list(Args),
640 Msg = format_argv(Args).
641format_warning(system:format(Format, Args), Msg) :-
642 ground(Format),
643 ( is_list(Args)
644 -> length(Args, ArgC)
645 ; nonvar(Args)
646 -> ArgC = 1
647 ),
648 E = error(Formal,_),
649 catch(format_types(Format, Types), E, true),
650 ( var(Formal)
651 -> length(Types, TypeC),
652 TypeC =\= ArgC,
653 Msg = format_argc(TypeC, ArgC)
654 ; Msg = format_template(Formal)
655 ).
656format_warning(system:format(_Stream, Format, Args), Msg) :-
657 format_warning(system:format(Format, Args), Msg).
658format_warning(prolog_debug:debug(_Channel, Format, Args), Msg) :-
659 format_warning(system:format(Format, Args), Msg).
660
661
665
666goal_in_body(M:G, M, G) :-
667 var(G),
668 !.
669goal_in_body(G, _, M:G0) :-
670 atom(M),
671 !,
672 goal_in_body(G, M, G0).
673goal_in_body(G, M, Control) :-
674 nonvar(Control),
675 control(Control, Subs),
676 !,
677 member(Sub, Subs),
678 goal_in_body(G, M, Sub).
679goal_in_body(G, M, G0) :-
680 callable(G0),
681 ( atom(M)
682 -> TM = M
683 ; TM = system
684 ),
685 predicate_property(TM:G0, meta_predicate(Spec)),
686 !,
687 ( strip_goals(G0, Spec, G1),
688 simple_goal_in_body(G, M, G1)
689 ; arg(I, Spec, Meta),
690 arg(I, G0, G1),
691 extend(Meta, G1, G2),
692 goal_in_body(G, M, G2)
693 ).
694goal_in_body(G, M, G0) :-
695 simple_goal_in_body(G, M, G0).
696
697simple_goal_in_body(G, M, G0) :-
698 ( atom(M),
699 callable(G0),
700 predicate_property(M:G0, imported_from(M2))
701 -> G = M2:G0
702 ; G = M:G0
703 ).
704
705control((A,B), [A,B]).
706control((A;B), [A,B]).
707control((A->B), [A,B]).
708control((A*->B), [A,B]).
709control((\+A), [A]).
710
711strip_goals(G0, Spec, G) :-
712 functor(G0, Name, Arity),
713 functor(G, Name, Arity),
714 strip_goal_args(1, G0, Spec, G).
715
716strip_goal_args(I, G0, Spec, G) :-
717 arg(I, G0, A0),
718 !,
719 arg(I, Spec, M),
720 ( extend(M, A0, _)
721 -> arg(I, G, '<meta-goal>')
722 ; arg(I, G, A0)
723 ),
724 I2 is I + 1,
725 strip_goal_args(I2, G0, Spec, G).
726strip_goal_args(_, _, _, _).
727
728extend(I, G0, G) :-
729 callable(G0),
730 integer(I), I>0,
731 !,
732 length(L, I),
733 extend_list(G0, L, G).
734extend(0, G, G).
735extend(^, G, G).
736
737extend_list(M:G0, L, M:G) :-
738 !,
739 callable(G0),
740 extend_list(G0, L, G).
741extend_list(G0, L, G) :-
742 G0 =.. List,
743 append(List, L, All),
744 G =.. All.
745
746
750
751message_context(ClauseRef, Term, Clause, file_term_position(File, TermPos)) :-
752 clause_info(ClauseRef, File, Layout, _Vars),
753 ( Term = _:Goal,
754 prolog_codewalk:subterm_pos(Goal, Clause, ==, Layout, TermPos)
755 ; prolog_codewalk:subterm_pos(Term, Clause, ==, Layout, TermPos)
756 ),
757 !.
758message_context(ClauseRef, _String, _Clause, file(File, Line, -1, _)) :-
759 clause_property(ClauseRef, file(File)),
760 clause_property(ClauseRef, line_count(Line)),
761 !.
762message_context(ClauseRef, _String, _Clause, clause(ClauseRef)).
763
764
765:- meta_predicate
766 predicate_indicator(:, -). 767
768predicate_indicator(Module:Head, Module:Name/Arity) :-
769 functor(Head, Name, Arity).
770predicate_indicator(Module:Head, Module:Name//DCGArity) :-
771 functor(Head, Name, Arity),
772 DCGArity is Arity-2.
773
778
779string_predicate(_:'$pldoc'/4).
780string_predicate(pce_principal:send_implementation/3).
781string_predicate(pce_principal:pce_lazy_get_method/3).
782string_predicate(pce_principal:pce_lazy_send_method/3).
783string_predicate(pce_principal:pce_class/6).
784string_predicate(prolog_xref:pred_comment/4).
785string_predicate(prolog_xref:module_comment/3).
786string_predicate(pldoc_process:structured_comment//2).
787string_predicate(pldoc_process:structured_command_start/3).
788string_predicate(pldoc_process:separator_line//0).
789string_predicate(pldoc_register:mydoc/3).
790string_predicate(http_header:separators/1).
791
797
799valid_string_goal(system:format(S)) :- string(S).
800valid_string_goal(system:format(S,_)) :- string(S).
801valid_string_goal(system:format(_,S,_)) :- string(S).
802valid_string_goal(system:string_codes(S,_)) :- string(S).
803valid_string_goal(system:string_code(_,S,_)) :- string(S).
804valid_string_goal(system:throw(msg(S,_))) :- string(S).
805valid_string_goal('$dcg':phrase(S,_,_)) :- string(S).
806valid_string_goal('$dcg':phrase(S,_)) :- string(S).
807valid_string_goal(system: is(_,_)). 808valid_string_goal(system: =:=(_,_)).
809valid_string_goal(system: >(_,_)).
810valid_string_goal(system: <(_,_)).
811valid_string_goal(system: >=(_,_)).
812valid_string_goal(system: =<(_,_)).
814valid_string_goal(dcg_basics:string_without(S,_,_,_)) :- string(S).
815valid_string_goal(git:read_url(S,_,_)) :- string(S).
816valid_string_goal(tipc:tipc_subscribe(_,_,_,_,S)) :- string(S).
817valid_string_goal(charsio:format_to_chars(Format,_,_)) :- string(Format).
818valid_string_goal(charsio:format_to_chars(Format,_,_,_)) :- string(Format).
819valid_string_goal(codesio:format_to_codes(Format,_,_)) :- string(Format).
820valid_string_goal(codesio:format_to_codes(Format,_,_,_)) :- string(Format).
821
822
823 826
846
847checker(list_undefined, 'undefined predicates').
848checker(list_trivial_fails, 'trivial failures').
849checker(list_format_errors, 'format/2,3 and debug/3 templates').
850checker(list_redefined, 'redefined system and global predicates').
851checker(list_void_declarations, 'predicates with declarations but without clauses').
852checker(list_autoload, 'predicates that need autoloading').
853
854
855 858
859:- multifile
860 prolog:message/3. 861
862prolog:message(check(pass(Comment))) -->
863 [ 'Checking ~w ...'-[Comment] ].
864prolog:message(check(find_references(Preds))) -->
865 { length(Preds, N)
866 },
867 [ 'Scanning for references to ~D possibly undefined predicates'-[N] ].
868prolog:message(check(undefined_procedures, Grouped)) -->
869 [ 'The predicates below are not defined. If these are defined', nl,
870 'at runtime using assert/1, use :- dynamic Name/Arity.', nl, nl
871 ],
872 undefined_procedures(Grouped).
873prolog:message(check(undefined_unreferenced_predicates)) -->
874 [ 'The predicates below are not defined, and are not', nl,
875 'referenced.', nl, nl
876 ].
877prolog:message(check(undefined_unreferenced(Pred))) -->
878 predicate(Pred).
879prolog:message(check(autoload(Module, Pairs))) -->
880 { module_property(Module, file(Path))
881 },
882 !,
883 [ 'Into module ~w ('-[Module] ],
884 short_filename(Path),
885 [ ')', nl ],
886 autoload(Pairs).
887prolog:message(check(autoload(Module, Pairs))) -->
888 [ 'Into module ~w'-[Module], nl ],
889 autoload(Pairs).
890prolog:message(check(redefined(In, From, Pred))) -->
891 predicate(In:Pred),
892 redefined(In, From).
893prolog:message(check(cross_module_calls)) -->
894 [ 'Qualified calls to private predicates'-[] ].
895prolog:message(check(cross_module_call(Callee, _Caller, Location))) -->
896 { pi_head(PI, Callee) },
897 [ ' '-[] ],
898 '$messages':swi_location(Location),
899 [ 'Cross-module call to ~p'-[PI] ].
900prolog:message(check(trivial_failures)) -->
901 [ 'The following goals fail because there are no matching clauses.' ].
902prolog:message(check(trivial_failure(Goal, Refs))) -->
903 { map_list_to_pairs(sort_reference_key, Refs, Keyed),
904 keysort(Keyed, KeySorted),
905 pairs_values(KeySorted, SortedRefs)
906 },
907 goal(Goal),
908 [ ', which is called from'-[], nl ],
909 referenced_by(SortedRefs).
910prolog:message(check(string_in_clause(String, Context))) -->
911 '$messages':swi_location(Context),
912 [ 'String ~q'-[String] ].
913prolog:message(check(rational_in_clause(String, Context))) -->
914 '$messages':swi_location(Context),
915 [ 'Rational ~q'-[String] ].
916prolog:message(check(Msg, Goal, Context)) -->
917 '$messages':swi_location(Context),
918 { pi_head(PI, Goal) },
919 [ nl, ' '-[] ],
920 predicate(PI),
921 [ ': '-[] ],
922 check_message(Msg).
923prolog:message(check(void_declaration(P, Decl))) -->
924 predicate(P),
925 [ ' is declared as ~p, but has no clauses'-[Decl] ].
926
927undefined_procedures([]) -->
928 [].
929undefined_procedures([H|T]) -->
930 undefined_procedure(H),
931 undefined_procedures(T).
932
933undefined_procedure(Pred-Refs) -->
934 { map_list_to_pairs(sort_reference_key, Refs, Keyed),
935 keysort(Keyed, KeySorted),
936 pairs_values(KeySorted, SortedRefs)
937 },
938 predicate(Pred),
939 [ ', which is referenced by', nl ],
940 referenced_by(SortedRefs).
941
942redefined(user, system) -->
943 [ '~t~30| System predicate redefined globally' ].
944redefined(_, system) -->
945 [ '~t~30| Redefined system predicate' ].
946redefined(_, user) -->
947 [ '~t~30| Redefined global predicate' ].
948
949goal(user:Goal) -->
950 !,
951 [ '~p'-[Goal] ].
952goal(Goal) -->
953 !,
954 [ '~p'-[Goal] ].
955
956predicate(Module:Name/Arity) -->
957 { atom(Module),
958 atom(Name),
959 integer(Arity),
960 functor(Head, Name, Arity),
961 predicate_name(Module:Head, PName)
962 },
963 !,
964 [ '~w'-[PName] ].
965predicate(Module:Head) -->
966 { atom(Module),
967 callable(Head),
968 predicate_name(Module:Head, PName)
969 },
970 !,
971 [ '~w'-[PName] ].
972predicate(Name/Arity) -->
973 { atom(Name),
974 integer(Arity)
975 },
976 !,
977 predicate(user:Name/Arity).
978
979autoload([]) -->
980 [].
981autoload([Lib-Pred|T]) -->
982 [ ' ' ],
983 predicate(Pred),
984 [ '~t~24| from ' ],
985 short_filename(Lib),
986 [ nl ],
987 autoload(T).
988
992
993sort_reference_key(Term, key(M:Name/Arity, N, ClausePos)) :-
994 clause_ref(Term, ClauseRef, ClausePos),
995 !,
996 nth_clause(Pred, N, ClauseRef),
997 strip_module(Pred, M, Head),
998 functor(Head, Name, Arity).
999sort_reference_key(Term, Term).
1000
1001clause_ref(clause_term_position(ClauseRef, TermPos), ClauseRef, ClausePos) :-
1002 arg(1, TermPos, ClausePos).
1003clause_ref(clause(ClauseRef), ClauseRef, 0).
1004
1005
1006referenced_by([]) -->
1007 [].
1008referenced_by([Ref|T]) -->
1009 ['\t'], prolog:message_location(Ref),
1010 predicate_indicator(Ref),
1011 [ nl ],
1012 referenced_by(T).
1013
1014predicate_indicator(clause_term_position(ClauseRef, _)) -->
1015 { nonvar(ClauseRef) },
1016 !,
1017 predicate_indicator(clause(ClauseRef)).
1018predicate_indicator(clause(ClauseRef)) -->
1019 { clause_name(ClauseRef, Name) },
1020 [ '~w'-[Name] ].
1021predicate_indicator(file_term_position(_,_)) -->
1022 [ '(initialization)' ].
1023predicate_indicator(file(_,_,_,_)) -->
1024 [ '(initialization)' ].
1025
1026
1027short_filename(Path) -->
1028 { short_filename(Path, Spec)
1029 },
1030 [ '~q'-[Spec] ].
1031
1032short_filename(Path, Spec) :-
1033 absolute_file_name('', Here),
1034 atom_concat(Here, Local0, Path),
1035 !,
1036 remove_leading_slash(Local0, Spec).
1037short_filename(Path, Spec) :-
1038 findall(LenAlias, aliased_path(Path, LenAlias), Keyed),
1039 keysort(Keyed, [_-Spec|_]).
1040short_filename(Path, Path).
1041
1042aliased_path(Path, Len-Spec) :-
1043 setof(Alias, Spec^(user:file_search_path(Alias, Spec)), Aliases),
1044 member(Alias, Aliases),
1045 Term =.. [Alias, '.'],
1046 absolute_file_name(Term,
1047 [ file_type(directory),
1048 file_errors(fail),
1049 solutions(all)
1050 ], Prefix),
1051 atom_concat(Prefix, Local0, Path),
1052 remove_leading_slash(Local0, Local),
1053 atom_length(Local, Len),
1054 Spec =.. [Alias, Local].
1055
1056remove_leading_slash(Path, Local) :-
1057 atom_concat(/, Local, Path),
1058 !.
1059remove_leading_slash(Path, Path).
1060
1061check_message(format_argc(Expected, InList)) -->
1062 [ 'Template requires ~w arguments, got ~w'-[Expected, InList] ].
1063check_message(format_template(Formal)) -->
1064 { message_to_string(error(Formal, _), Msg) },
1065 [ 'Invalid template: ~s'-[Msg] ].
1066check_message(format_argv(Args)) -->
1067 [ 'Arguments are not in a list (deprecated): ~p'-[Args] ]