View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  1985-2012, University of Amsterdam
    7                              VU University Amsterdam
    8    All rights reserved.
    9
   10    Redistribution and use in source and binary forms, with or without
   11    modification, are permitted provided that the following conditions
   12    are met:
   13
   14    1. Redistributions of source code must retain the above copyright
   15       notice, this list of conditions and the following disclaimer.
   16
   17    2. Redistributions in binary form must reproduce the above copyright
   18       notice, this list of conditions and the following disclaimer in
   19       the documentation and/or other materials provided with the
   20       distribution.
   21
   22    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   23    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   24    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   25    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   26    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   27    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   28    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   29    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   30    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   32    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   33    POSSIBILITY OF SUCH DAMAGE.
   34*/
   35
   36:- module(check,
   37        [ check/0,                      % run all checks
   38          list_undefined/0,             % list undefined predicates
   39          list_undefined/1,             % +Options
   40          list_autoload/0,              % list predicates that need autoloading
   41          list_redefined/0,             % list redefinitions
   42          list_void_declarations/0,     % list declarations with no clauses
   43          list_trivial_fails/0,         % list goals that trivially fail
   44          list_trivial_fails/1,         % +Options
   45          list_strings/0,               % list string objects in clauses
   46          list_strings/1                % +Options
   47        ]).   48:- use_module(library(lists)).   49:- use_module(library(pairs)).   50:- use_module(library(option)).   51:- use_module(library(apply)).   52:- use_module(library(prolog_codewalk)).   53:- use_module(library(occurs)).   54
   55:- set_prolog_flag(generate_debug_info, false).   56
   57:- multifile
   58       trivial_fail_goal/1,
   59       string_predicate/1,
   60       valid_string_goal/1,
   61       checker/2.   62
   63:- dynamic checker/2.

Consistency checking

This library provides some consistency checks for the loaded Prolog program. The predicate make/0 runs list_undefined/0 to find undefined predicates in `user' modules.

See also
- gxref/0 provides a graphical cross referencer
- PceEmacs performs real time consistency checks while you edit
- library(prolog_xref) implements `offline' cross-referencing
- library(prolog_codewalk) implements `online' analysis */
   78:- predicate_options(list_undefined/1, 1,
   79                     [ module_class(list(oneof([user,library])))
   80                     ]).
 check is det
Run all consistency checks defined by checker/2. Checks enabled by default are:
   96check :-
   97    checker(Checker, Message),
   98    print_message(informational,check(pass(Message))),
   99    catch(Checker,E,print_message(error,E)),
  100    fail.
  101check.
 list_undefined is det
 list_undefined(+Options) is det
Report undefined predicates. This predicate finds undefined predciates by decompiling and analyzing the body of all clauses. Options:
module_class(+Classes)
Process modules of the given Classes. The default for classes is [user]. For example, to include the libraries into the examination, use [user,library].
See also
- gxref/0 provides a graphical cross-referencer.
- make/0 calls list_undefined/0
  118:- thread_local
  119    undef/2.  120
  121list_undefined :-
  122    list_undefined([]).
  123
  124list_undefined(Options) :-
  125    merge_options(Options,
  126                  [ module_class([user])
  127                  ],
  128                  WalkOptions),
  129    prolog_walk_code([ undefined(trace),
  130                       on_trace(found_undef)
  131                     | WalkOptions
  132                     ]),
  133    findall(PI-From, retract(undef(PI, From)), Pairs),
  134    (   Pairs == []
  135    ->  true
  136    ;   print_message(warning, check(undefined_predicates)),
  137        keysort(Pairs, Sorted),
  138        group_pairs_by_key(Sorted, Grouped),
  139        maplist(report_undefined, Grouped)
  140    ).
  141
  142:- public found_undef/3.  143
  144found_undef(To, _Caller, From) :-
  145    goal_pi(To, PI),
  146    (   undef(PI, From)
  147    ->  true
  148    ;   compiled(PI)
  149    ->  true
  150    ;   assertz(undef(PI,From))
  151    ).
  152
  153compiled(system:'$call_cleanup'/0).     % compiled to VM instructions
  154compiled(system:'$catch'/0).
  155compiled(system:'$cut'/0).
  156compiled(system:'$reset'/0).
  157compiled(system:'$call_continuation'/1).
  158compiled(system:'$shift'/1).
  159
  160goal_pi(M:Head, M:Name/Arity) :-
  161    functor(Head, Name, Arity).
  162
  163report_undefined(PI-FromList) :-
  164    print_message(warning, check(undefined(PI, FromList))).
 list_autoload is det
Report predicates that may be auto-loaded. These are predicates that are not defined, but will be loaded on demand if referenced.
See also
- autoload/0
To be done
- This predicate uses an older mechanism for finding undefined predicates. Should be synchronized with list undefined.
  178list_autoload :-
  179    setup_call_cleanup(
  180        ( current_prolog_flag(access_level, OldLevel),
  181          current_prolog_flag(autoload, OldAutoLoad),
  182          set_prolog_flag(access_level, system),
  183          set_prolog_flag(autoload, false)
  184        ),
  185        list_autoload_(OldLevel),
  186        ( set_prolog_flag(access_level, OldLevel),
  187          set_prolog_flag(autoload, OldAutoLoad)
  188        )).
  189
  190list_autoload_(SystemMode) :-
  191    (   setof(Lib-Pred,
  192              autoload_predicate(Module, Lib, Pred, SystemMode),
  193              Pairs),
  194        print_message(informational,
  195                      check(autoload(Module, Pairs))),
  196        fail
  197    ;   true
  198    ).
  199
  200autoload_predicate(Module, Library, Name/Arity, SystemMode) :-
  201    predicate_property(Module:Head, undefined),
  202    check_module_enabled(Module, SystemMode),
  203    (   \+ predicate_property(Module:Head, imported_from(_)),
  204        functor(Head, Name, Arity),
  205        '$find_library'(Module, Name, Arity, _LoadModule, Library),
  206        referenced(Module:Head, Module, _)
  207    ->  true
  208    ).
  209
  210check_module_enabled(_, system) :- !.
  211check_module_enabled(Module, _) :-
  212    \+ import_module(Module, system).
 referenced(+Predicate, ?Module, -ClauseRef) is nondet
True if clause ClauseRef references Predicate.
  218referenced(Term, Module, Ref) :-
  219    Goal = Module:_Head,
  220    current_predicate(_, Goal),
  221    '$get_predicate_attribute'(Goal, system, 0),
  222    \+ '$get_predicate_attribute'(Goal, imported, _),
  223    nth_clause(Goal, _, Ref),
  224    '$xr_member'(Ref, Term).
 list_redefined
Lists predicates that are defined in the global module user as well as in a normal module; that is, predicates for which the local definition overrules the global default definition.
  232list_redefined :-
  233    setup_call_cleanup(
  234        ( current_prolog_flag(access_level, OldLevel),
  235          set_prolog_flag(access_level, system)
  236        ),
  237        list_redefined_,
  238        set_prolog_flag(access_level, OldLevel)).
  239
  240list_redefined_ :-
  241    current_module(Module),
  242    Module \== system,
  243    current_predicate(_, Module:Head),
  244    \+ predicate_property(Module:Head, imported_from(_)),
  245    (   global_module(Super),
  246        Super \== Module,
  247        '$c_current_predicate'(_, Super:Head),
  248        \+ redefined_ok(Head),
  249        '$syspreds':'$defined_predicate'(Super:Head),
  250        \+ predicate_property(Super:Head, (dynamic)),
  251        \+ predicate_property(Super:Head, imported_from(Module)),
  252        functor(Head, Name, Arity)
  253    ->  print_message(informational,
  254                      check(redefined(Module, Super, Name/Arity)))
  255    ),
  256    fail.
  257list_redefined_.
  258
  259redefined_ok('$mode'(_,_)).
  260redefined_ok('$pldoc'(_,_,_,_)).
  261redefined_ok('$pred_option'(_,_,_,_)).
  262
  263global_module(user).
  264global_module(system).
 list_void_declarations is det
List predicates that have declared attributes, but no clauses.
  270list_void_declarations :-
  271    P = _:_,
  272    (   predicate_property(P, undefined),
  273        (   '$get_predicate_attribute'(P, meta_predicate, Pattern),
  274            print_message(warning,
  275                          check(void_declaration(P, meta_predicate(Pattern))))
  276        ;   void_attribute(Attr),
  277            '$get_predicate_attribute'(P, Attr, 1),
  278            print_message(warning,
  279                          check(void_declaration(P, Attr)))
  280        ),
  281        fail
  282    ;   true
  283    ).
  284
  285void_attribute(public).
  286void_attribute(volatile).
 list_trivial_fails is det
 list_trivial_fails(+Options) is det
List goals that trivially fail because there is no matching clause. Options:
module_class(+Classes)
Process modules of the given Classes. The default for classes is [user]. For example, to include the libraries into the examination, use [user,library].
  299:- thread_local
  300    trivial_fail/2.  301
  302list_trivial_fails :-
  303    list_trivial_fails([]).
  304
  305list_trivial_fails(Options) :-
  306    merge_options(Options,
  307                  [ module_class([user]),
  308                    infer_meta_predicates(false),
  309                    autoload(false),
  310                    evaluate(false),
  311                    trace_reference(_),
  312                    on_trace(check_trivial_fail)
  313                  ],
  314                  WalkOptions),
  315
  316    prolog_walk_code([ source(false)
  317                     | WalkOptions
  318                     ]),
  319    findall(CRef, retract(trivial_fail(clause(CRef), _)), Clauses),
  320    (   Clauses == []
  321    ->  true
  322    ;   print_message(warning, check(trivial_failures)),
  323        prolog_walk_code([ clauses(Clauses)
  324                         | WalkOptions
  325                         ]),
  326        findall(Goal-From, retract(trivial_fail(From, Goal)), Pairs),
  327        keysort(Pairs, Sorted),
  328        group_pairs_by_key(Sorted, Grouped),
  329        maplist(report_trivial_fail, Grouped)
  330    ).
 trivial_fail_goal(:Goal)
Multifile hook that tells list_trivial_fails/0 to accept Goal as valid.
  337trivial_fail_goal(pce_expansion:pce_class(_, _, template, _, _, _)).
  338trivial_fail_goal(pce_host:property(system_source_prefix(_))).
  339
  340:- public
  341    check_trivial_fail/3.  342
  343check_trivial_fail(MGoal0, _Caller, From) :-
  344    (   MGoal0 = M:Goal,
  345        atom(M),
  346        callable(Goal),
  347        predicate_property(MGoal0, interpreted),
  348        \+ predicate_property(MGoal0, dynamic),
  349        \+ predicate_property(MGoal0, multifile),
  350        \+ trivial_fail_goal(MGoal0)
  351    ->  (   predicate_property(MGoal0, meta_predicate(Meta))
  352        ->  qualify_meta_goal(MGoal0, Meta, MGoal)
  353        ;   MGoal = MGoal0
  354        ),
  355        (   clause(MGoal, _)
  356        ->  true
  357        ;   assertz(trivial_fail(From, MGoal))
  358        )
  359    ;   true
  360    ).
  361
  362report_trivial_fail(Goal-FromList) :-
  363    print_message(warning, check(trivial_failure(Goal, FromList))).
 qualify_meta_goal(+Module, +MetaSpec, +Goal, -QualifiedGoal)
Qualify a goal if the goal calls a meta predicate
  369qualify_meta_goal(M:Goal0, Meta, M:Goal) :-
  370    functor(Goal0, F, N),
  371    functor(Goal, F, N),
  372    qualify_meta_goal(1, M, Meta, Goal0, Goal).
  373
  374qualify_meta_goal(N, M, Meta, Goal0, Goal) :-
  375    arg(N, Meta,  ArgM),
  376    !,
  377    arg(N, Goal0, Arg0),
  378    arg(N, Goal,  Arg),
  379    N1 is N + 1,
  380    (   module_qualified(ArgM)
  381    ->  add_module(Arg0, M, Arg)
  382    ;   Arg = Arg0
  383    ),
  384    meta_goal(N1, Meta, Goal0, Goal).
  385meta_goal(_, _, _, _).
  386
  387add_module(Arg, M, M:Arg) :-
  388    var(Arg),
  389    !.
  390add_module(M:Arg, _, MArg) :-
  391    !,
  392    add_module(Arg, M, MArg).
  393add_module(Arg, M, M:Arg).
  394
  395module_qualified(N) :- integer(N), !.
  396module_qualified(:).
  397module_qualified(^).
 list_strings is det
 list_strings(+Options) is det
List strings that appear in clauses. This predicate is used to find portability issues for changing the Prolog flag double_quotes from codes to string, creating packed string objects. Warnings may be suppressed using the following multifile hooks:
See also
- Prolog flag double_quotes.
  415list_strings :-
  416    list_strings([module_class([user])]).
  417
  418list_strings(Options) :-
  419    (   prolog_program_clause(ClauseRef, Options),
  420        clause(Head, Body, ClauseRef),
  421        \+ ( predicate_indicator(Head, PI),
  422             string_predicate(PI)
  423           ),
  424        make_clause(Head, Body, Clause),
  425        findall(T,
  426                (   sub_term(T, Head),
  427                    string(T)
  428                ;   Head = M:_,
  429                    goal_in_body(Goal, M, Body),
  430                    (   valid_string_goal(Goal)
  431                    ->  fail
  432                    ;   sub_term(T, Goal),
  433                        string(T)
  434                    )
  435                ), Ts0),
  436        sort(Ts0, Ts),
  437        member(T, Ts),
  438        message_context(ClauseRef, T, Clause, Context),
  439        print_message(warning,
  440                      check(string_in_clause(T, Context))),
  441        fail
  442    ;   true
  443    ).
  444
  445make_clause(Head, true, Head) :- !.
  446make_clause(Head, Body, (Head:-Body)).
 goal_in_body(-G, +M, +Body) is nondet
True when G is a goal called from Body.
  452goal_in_body(M:G, M, G) :-
  453    var(G),
  454    !.
  455goal_in_body(G, _, M:G0) :-
  456    atom(M),
  457    !,
  458    goal_in_body(G, M, G0).
  459goal_in_body(G, M, Control) :-
  460    nonvar(Control),
  461    control(Control, Subs),
  462    !,
  463    member(Sub, Subs),
  464    goal_in_body(G, M, Sub).
  465goal_in_body(G, M, G0) :-
  466    callable(G0),
  467    (   atom(M)
  468    ->  TM = M
  469    ;   TM = system
  470    ),
  471    predicate_property(TM:G0, meta_predicate(Spec)),
  472    !,
  473    (   strip_goals(G0, Spec, G1),
  474        simple_goal_in_body(G, M, G1)
  475    ;   arg(I, Spec, Meta),
  476        arg(I, G0, G1),
  477        extend(Meta, G1, G2),
  478        goal_in_body(G, M, G2)
  479    ).
  480goal_in_body(G, M, G0) :-
  481    simple_goal_in_body(G, M, G0).
  482
  483simple_goal_in_body(G, M, G0) :-
  484    (   atom(M),
  485        callable(G0),
  486        predicate_property(M:G0, imported_from(M2))
  487    ->  G = M2:G0
  488    ;   G = M:G0
  489    ).
  490
  491control((A,B), [A,B]).
  492control((A;B), [A,B]).
  493control((A->B), [A,B]).
  494control((A*->B), [A,B]).
  495control((\+A), [A]).
  496
  497strip_goals(G0, Spec, G) :-
  498    functor(G0, Name, Arity),
  499    functor(G,  Name, Arity),
  500    strip_goal_args(1, G0, Spec, G).
  501
  502strip_goal_args(I, G0, Spec, G) :-
  503    arg(I, G0, A0),
  504    !,
  505    arg(I, Spec, M),
  506    (   extend(M, A0, _)
  507    ->  arg(I, G, '<meta-goal>')
  508    ;   arg(I, G, A0)
  509    ),
  510    I2 is I + 1,
  511    strip_goal_args(I2, G0, Spec, G).
  512strip_goal_args(_, _, _, _).
  513
  514extend(I, G0, G) :-
  515    callable(G0),
  516    integer(I), I>0,
  517    !,
  518    length(L, I),
  519    extend_list(G0, L, G).
  520extend(0, G, G).
  521extend(^, G, G).
  522
  523extend_list(M:G0, L, M:G) :-
  524    !,
  525    callable(G0),
  526    extend_list(G0, L, G).
  527extend_list(G0, L, G) :-
  528    G0 =.. List,
  529    append(List, L, All),
  530    G =.. All.
  531
  532
  533message_context(ClauseRef, String, Clause, file_term_position(File, StringPos)) :-
  534    clause_info(ClauseRef, File, TermPos, _Vars),
  535    prolog_codewalk:subterm_pos(String, Clause, ==, TermPos, StringPos),
  536    !.
  537message_context(ClauseRef, _String, _Clause, file(File, Line, -1, _)) :-
  538    clause_property(ClauseRef, file(File)),
  539    clause_property(ClauseRef, line_count(Line)),
  540    !.
  541message_context(ClauseRef, _String, _Clause, clause(ClauseRef)).
  542
  543
  544:- meta_predicate
  545    predicate_indicator(:, -).  546
  547predicate_indicator(Module:Head, Module:Name/Arity) :-
  548    functor(Head, Name, Arity).
  549predicate_indicator(Module:Head, Module:Name//DCGArity) :-
  550    functor(Head, Name, Arity),
  551    DCGArity is Arity-2.
 string_predicate(:PredicateIndicator)
Multifile hook to disable list_strings/0 on the given predicate. This is typically used for facts that store strings.
  558string_predicate(_:'$pldoc'/4).
  559string_predicate(pce_principal:send_implementation/3).
  560string_predicate(pce_principal:pce_lazy_get_method/3).
  561string_predicate(pce_principal:pce_lazy_send_method/3).
  562string_predicate(pce_principal:pce_class/6).
  563string_predicate(prolog_xref:pred_comment/4).
  564string_predicate(prolog_xref:module_comment/3).
  565string_predicate(pldoc_process:structured_comment//2).
  566string_predicate(pldoc_process:structured_command_start/3).
  567string_predicate(pldoc_process:separator_line//0).
  568string_predicate(pldoc_register:mydoc/3).
  569string_predicate(http_header:separators/1).
 valid_string_goal(+Goal) is semidet
Multifile hook that qualifies Goal as valid for list_strings/0. For example, format("Hello world~n") is considered proper use of string constants.
  577% system predicates
  578valid_string_goal(system:format(S)) :- string(S).
  579valid_string_goal(system:format(S,_)) :- string(S).
  580valid_string_goal(system:format(_,S,_)) :- string(S).
  581valid_string_goal(system:string_codes(S,_)) :- string(S).
  582valid_string_goal(system:string_code(_,S,_)) :- string(S).
  583valid_string_goal(system:throw(msg(S,_))) :- string(S).
  584valid_string_goal('$dcg':phrase(S,_,_)) :- string(S).
  585valid_string_goal('$dcg':phrase(S,_)) :- string(S).
  586valid_string_goal(system: is(_,_)).     % arithmetic allows for "x"
  587valid_string_goal(system: =:=(_,_)).
  588valid_string_goal(system: >(_,_)).
  589valid_string_goal(system: <(_,_)).
  590valid_string_goal(system: >=(_,_)).
  591valid_string_goal(system: =<(_,_)).
  592% library stuff
  593valid_string_goal(dcg_basics:string_without(S,_,_,_)) :- string(S).
  594valid_string_goal(git:read_url(S,_,_)) :- string(S).
  595valid_string_goal(tipc:tipc_subscribe(_,_,_,_,S)) :- string(S).
  596valid_string_goal(charsio:format_to_chars(Format,_,_)) :- string(Format).
  597valid_string_goal(charsio:format_to_chars(Format,_,_,_)) :- string(Format).
  598valid_string_goal(codesio:format_to_codes(Format,_,_)) :- string(Format).
  599valid_string_goal(codesio:format_to_codes(Format,_,_,_)) :- string(Format).
  600
  601
  602                 /*******************************
  603                 *        EXTENSION HOOKS       *
  604                 *******************************/
 checker(:Goal, +Message:text)
Register code validation routines. Each clause defines a Goal which performs a consistency check executed by check/0. Message is a short description of the check. For example, assuming the my_checks module defines a predicate list_format_mistakes/0:
:- multifile check:checker/2.
check:checker(my_checks:list_format_mistakes,
              "errors with format/2 arguments").

The predicate is dynamic, so you can disable checks with retract/1. For example, to stop reporting redefined predicates:

retract(check:checker(list_redefined,_)).
  626checker(list_undefined,         'undefined predicates').
  627checker(list_trivial_fails,     'trivial failures').
  628checker(list_redefined,         'redefined system and global predicates').
  629checker(list_void_declarations, 'predicates with declarations but without clauses').
  630checker(list_autoload,          'predicates that need autoloading').
  631
  632
  633                 /*******************************
  634                 *            MESSAGES          *
  635                 *******************************/
  636
  637:- multifile
  638    prolog:message/3.  639
  640prolog:message(check(pass(Comment))) -->
  641    [ 'Checking ~w ...'-[Comment] ].
  642prolog:message(check(find_references(Preds))) -->
  643    { length(Preds, N)
  644    },
  645    [ 'Scanning for references to ~D possibly undefined predicates'-[N] ].
  646prolog:message(check(undefined_predicates)) -->
  647    [ 'The predicates below are not defined. If these are defined', nl,
  648      'at runtime using assert/1, use :- dynamic Name/Arity.', nl, nl
  649    ].
  650prolog:message(check(undefined(Pred, Refs))) -->
  651    { map_list_to_pairs(sort_reference_key, Refs, Keyed),
  652      keysort(Keyed, KeySorted),
  653      pairs_values(KeySorted, SortedRefs)
  654    },
  655    predicate(Pred),
  656    [ ', which is referenced by', nl ],
  657    referenced_by(SortedRefs).
  658prolog:message(check(undefined_unreferenced_predicates)) -->
  659    [ 'The predicates below are not defined, and are not', nl,
  660      'referenced.', nl, nl
  661    ].
  662prolog:message(check(undefined_unreferenced(Pred))) -->
  663    predicate(Pred).
  664prolog:message(check(autoload(Module, Pairs))) -->
  665    { module_property(Module, file(Path))
  666    },
  667    !,
  668    [ 'Into module ~w ('-[Module] ],
  669    short_filename(Path),
  670    [ ')', nl ],
  671    autoload(Pairs).
  672prolog:message(check(autoload(Module, Pairs))) -->
  673    [ 'Into module ~w'-[Module], nl ],
  674    autoload(Pairs).
  675prolog:message(check(redefined(In, From, Pred))) -->
  676    predicate(In:Pred),
  677    redefined(In, From).
  678prolog:message(check(trivial_failures)) -->
  679    [ 'The following goals fail because there are no matching clauses.' ].
  680prolog:message(check(trivial_failure(Goal, Refs))) -->
  681    { map_list_to_pairs(sort_reference_key, Refs, Keyed),
  682      keysort(Keyed, KeySorted),
  683      pairs_values(KeySorted, SortedRefs)
  684    },
  685    goal(Goal),
  686    [ ', which is called from'-[], nl ],
  687    referenced_by(SortedRefs).
  688prolog:message(check(string_in_clause(String, Context))) -->
  689    prolog:message_location(Context),
  690    [ 'String ~q'-[String] ].
  691prolog:message(check(void_declaration(P, Decl))) -->
  692    predicate(P),
  693    [ ' is declared as ~p, but has no clauses'-[Decl] ].
  694
  695
  696redefined(user, system) -->
  697    [ '~t~30| System predicate redefined globally' ].
  698redefined(_, system) -->
  699    [ '~t~30| Redefined system predicate' ].
  700redefined(_, user) -->
  701    [ '~t~30| Redefined global predicate' ].
  702
  703goal(user:Goal) -->
  704    !,
  705    [ '~p'-[Goal] ].
  706goal(Goal) -->
  707    !,
  708    [ '~p'-[Goal] ].
  709
  710predicate(Module:Name/Arity) -->
  711    { atom(Module),
  712      atom(Name),
  713      integer(Arity),
  714      functor(Head, Name, Arity),
  715      predicate_name(Module:Head, PName)
  716    },
  717    !,
  718    [ '~w'-[PName] ].
  719predicate(Module:Head) -->
  720    { atom(Module),
  721      callable(Head),
  722      predicate_name(Module:Head, PName)
  723    },
  724    !,
  725    [ '~w'-[PName] ].
  726predicate(Name/Arity) -->
  727    { atom(Name),
  728      integer(Arity)
  729    },
  730    !,
  731    predicate(user:Name/Arity).
  732
  733autoload([]) -->
  734    [].
  735autoload([Lib-Pred|T]) -->
  736    [ '    ' ],
  737    predicate(Pred),
  738    [ '~t~24| from ' ],
  739    short_filename(Lib),
  740    [ nl ],
  741    autoload(T).
 sort_reference_key(+Reference, -Key) is det
Create a stable key for sorting references to predicates.
  747sort_reference_key(Term, key(M:Name/Arity, N, ClausePos)) :-
  748    clause_ref(Term, ClauseRef, ClausePos),
  749    !,
  750    nth_clause(Pred, N, ClauseRef),
  751    strip_module(Pred, M, Head),
  752    functor(Head, Name, Arity).
  753sort_reference_key(Term, Term).
  754
  755clause_ref(clause_term_position(ClauseRef, TermPos), ClauseRef, ClausePos) :-
  756    arg(1, TermPos, ClausePos).
  757clause_ref(clause(ClauseRef), ClauseRef, 0).
  758
  759
  760referenced_by([]) -->
  761    [].
  762referenced_by([Ref|T]) -->
  763    ['\t'], prolog:message_location(Ref),
  764            predicate_indicator(Ref),
  765    [ nl ],
  766    referenced_by(T).
  767
  768predicate_indicator(clause_term_position(ClauseRef, _)) -->
  769    { nonvar(ClauseRef) },
  770    !,
  771    predicate_indicator(clause(ClauseRef)).
  772predicate_indicator(clause(ClauseRef)) -->
  773    { clause_name(ClauseRef, Name) },
  774    [ '~w'-[Name] ].
  775predicate_indicator(file_term_position(_,_)) -->
  776    [ '(initialization)' ].
  777predicate_indicator(file(_,_,_,_)) -->
  778    [ '(initialization)' ].
  779
  780
  781short_filename(Path) -->
  782    { short_filename(Path, Spec)
  783    },
  784    [ '~q'-[Spec] ].
  785
  786short_filename(Path, Spec) :-
  787    absolute_file_name('', Here),
  788    atom_concat(Here, Local0, Path),
  789    !,
  790    remove_leading_slash(Local0, Spec).
  791short_filename(Path, Spec) :-
  792    findall(LenAlias, aliased_path(Path, LenAlias), Keyed),
  793    keysort(Keyed, [_-Spec|_]).
  794short_filename(Path, Path).
  795
  796aliased_path(Path, Len-Spec) :-
  797    setof(Alias, Spec^(user:file_search_path(Alias, Spec)), Aliases),
  798    member(Alias, Aliases),
  799    Term =.. [Alias, '.'],
  800    absolute_file_name(Term,
  801                       [ file_type(directory),
  802                         file_errors(fail),
  803                         solutions(all)
  804                       ], Prefix),
  805    atom_concat(Prefix, Local0, Path),
  806    remove_leading_slash(Local0, Local),
  807    atom_length(Local, Len),
  808    Spec =.. [Alias, Local].
  809
  810remove_leading_slash(Path, Local) :-
  811    atom_concat(/, Local, Path),
  812    !.
  813remove_leading_slash(Path, Path)