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-2020, University of Amsterdam
    7                              VU University Amsterdam
    8                              CWI, Amsterdam
    9    All rights reserved.
   10
   11    Redistribution and use in source and binary forms, with or without
   12    modification, are permitted provided that the following conditions
   13    are met:
   14
   15    1. Redistributions of source code must retain the above copyright
   16       notice, this list of conditions and the following disclaimer.
   17
   18    2. Redistributions in binary form must reproduce the above copyright
   19       notice, this list of conditions and the following disclaimer in
   20       the documentation and/or other materials provided with the
   21       distribution.
   22
   23    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   24    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   25    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   26    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   27    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   28    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   29    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   30    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   31    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   33    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   34    POSSIBILITY OF SUCH DAMAGE.
   35*/
   36
   37:- module(check,
   38        [ check/0,                      % run all checks
   39          list_undefined/0,             % list undefined predicates
   40          list_undefined/1,             % +Options
   41          list_autoload/0,              % list predicates that need autoloading
   42          list_redefined/0,             % list redefinitions
   43          list_cross_module_calls/0,	% List Module:Goal usage
   44          list_cross_module_calls/1,    % +Options
   45          list_void_declarations/0,     % list declarations with no clauses
   46          list_trivial_fails/0,         % list goals that trivially fail
   47          list_trivial_fails/1,         % +Options
   48          list_format_errors/0,         % list calls to format with wrong args
   49          list_format_errors/1,		% +Options
   50          list_strings/0,               % list string objects in clauses
   51          list_strings/1,               % +Options
   52          list_rationals/0,		% list rational objects in clauses
   53          list_rationals/1              % +Options
   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.

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 */
   92:- predicate_options(list_undefined/1, 1,
   93                     [ module_class(list(oneof([user,library,system])))
   94                     ]).
 check is det
Run all consistency checks defined by checker/2. Checks enabled by default are:
  110check :-
  111    checker(Checker, Message),
  112    print_message(informational,check(pass(Message))),
  113    catch(Checker,E,print_message(error,E)),
  114    fail.
  115check.
 list_undefined is det
 list_undefined(+Options) is det
Report undefined predicates. This predicate finds undefined predicates 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
  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
  154% The following predicates are used from library(prolog_autoload).
  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).     % compiled to VM instructions
  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).
 not_always_present(+PI) is semidet
True when some predicate is known to be part of the state but is not available in this version.
  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).
 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.
  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).
 referenced(+Predicate, ?Module, -ClauseRef) is nondet
True if clause ClauseRef references Predicate.
  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).
 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.
  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).
 list_cross_module_calls is det
List calls from one module to another using Module:Goal where the callee is not defined exported, public or multifile, i.e., where the callee should be considered private.
  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))).
 list_void_declarations is det
List predicates that have declared attributes, but no clauses.
  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).
 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].
  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    ).
 trivial_fail_goal(:Goal)
Multifile hook that tells list_trivial_fails/0 to accept Goal as valid.
  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))).
 qualify_meta_goal(+Module, +MetaSpec, +Goal, -QualifiedGoal)
Qualify a goal if the goal calls a meta predicate
  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(^).
 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.
  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)).
 list_rationals is det
 list_rationals(+Options) is det
List rational numbers that appear in clauses. This predicate is used to find portability issues for changing the Prolog flag rational_syntax to natural, creating rational numbers from <integer>/<nonneg>. Options:
module_class(+Classes)
Determines the modules classes processed. By default only user code is processed. See prolog_program_clause/2.
arithmetic(+Bool)
If true (default false) also warn on rationals appearing in arithmetic expressions.
See also
- Prolog flag rational_syntax and prefer_rationals.
  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(_ >= _).
 list_format_errors is det
 list_format_errors(+Options) is det
List argument errors for format/2,3.
  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).
 goal_in_body(-G, +M, +Body) is nondet
True when G is a goal called from Body.
  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.
 message_context(+ClauseRef, +Term, +Clause, -Pos) is det
Find an as accurate as possible location for Term in Clause.
  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.
 string_predicate(:PredicateIndicator)
Multifile hook to disable list_strings/0 on the given predicate. This is typically used for facts that store strings.
  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).
 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.
  798% system predicates
  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(_,_)).     % arithmetic allows for "x"
  808valid_string_goal(system: =:=(_,_)).
  809valid_string_goal(system: >(_,_)).
  810valid_string_goal(system: <(_,_)).
  811valid_string_goal(system: >=(_,_)).
  812valid_string_goal(system: =<(_,_)).
  813% library stuff
  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                 /*******************************
  824                 *        EXTENSION HOOKS       *
  825                 *******************************/
 checker(:Goal, +Message:text) is nondet
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,_)).
  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                 /*******************************
  856                 *            MESSAGES          *
  857                 *******************************/
  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).
 sort_reference_key(+Reference, -Key) is det
Create a stable key for sorting references to predicates.
  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] ]