1/***************************************************************************** 2 * This file is part of the Prolog Development Tool (PDT) 3 * 4 * WWW: http://sewiki.iai.uni-bonn.de/research/pdt/start 5 * Mail: pdt@lists.iai.uni-bonn.de 6 * Copyright (C): 2004-2012, CS Dept. III, University of Bonn 7 * 8 * All rights reserved. This program is made available under the terms 9 * of the Eclipse Public License v1.0 which accompanies this distribution, 10 * and is available at http://www.eclipse.org/legal/epl-v10.html 11 * 12 ****************************************************************************/ 13 14:- module( pdt_search, 15 [ find_predicate_reference/9 % (+Functor,+Arity,?DefFile,?DefModule,?RefModule,?RefName,?RefArity,?RefFile,?RefLine,?PropertyList) 16 , update_predicate_reference_search_term_to_context/5 17 , find_categorized_predicate_definitions/11 % (+EnclFile,+SelectionLine, +Term, -Functor, -Arity, -This, -DeclOrDef, -DefiningEntity, -FullPath, -Line, -Properties,-Visibility,+ExactMatch) 18 , find_predicate_definitions/10 19 , find_primary_definition_visible_in/9 20 , find_definition_contained_in/9 21 , find_definition_contained_in/10 22 , find_completion/14 23 , find_entity_definition/6 24 , find_module_reference/9 25 , loaded_file/1 26 , loaded_by/4 27 ]). 28 29:- use_module( prolog_connector_pl(split_file_path), 30 [ split_file_path/5 % (File,Folder,FileName,BaseName,Extension) 31 ] ). 32:- use_module( 'xref/pdt_xref', 33 [ find_reference_to/9 % ... 34 ] ). 35:- use_module( properties, 36 [ properties_for_predicate/4 37 ] ). 38%:- use_module( pdt_prolog_library(utils4modules_visibility), 39% [ module_of_file/2 % (File,FileModule) 40% , defined_in_module/3 % (Module,Name,Arity), 41% , declared_in_file/4 % (Module,Name,Arity,Location) 42% , defined_in_files/4 % (Module,Name,Arity,Locations) 43% ] ). 44:- use_module(pdt_prolog_library(utils4modules_visibility)). 45:- use_module(pdt_manual_entry). 46:- use_module(library(charsio)). 47:- use_module(library(lists)). 48:- use_module(library(prolog_clause)). 49:- use_module(library(prolog_source), [ 50 read_source_term_at_location/3 51]). 52:- use_module(pdt_prolog_library(compatibility), [ 53 pdt_source_file/2 54]). 55:- use_module('callgraph/pdt_call_graph', [ 56 ensure_call_graph_generated/0, 57 pdt_walk_code/1 58]). 59 60:- op(600, xfy, ::). % Logtalk message sending operator 61 62%%% find_predicate_reference(Term, ExactMatch, Root, EnclFile, LineInEnclFile, RefModule, RefName, RefArity, RefFile, Position, PropertyList) 63%find_predicate_reference(Term0, ExactMatch, Root, EnclFile, _LineInEnclFile, RefModule, RefName, RefArity, RefFile, Position, PropertyList) :- 64% ( nonvar(EnclFile), 65% \+ split_file_path(EnclFile, _, _, _, lgt), 66% Term0 = predicate(M, S0, F, S1, A), 67% var(M) 68% -> once(module_of_file(EnclFile, FileModule)), 69% ( nonvar(F), 70% nonvar(A), 71% functor(H, F, A), 72% predicate_property(FileModule:H, imported_from(ImportedModule)) 73% -> Term = predicate(ImportedModule, S0, F, S1, A) 74% ; Term = predicate(FileModule, S0, F, S1, A) 75% ) 76% ; Term = Term0 77% ), 78% find_reference_to(Term, ExactMatch, Root, RefModule, RefName, RefArity, RefFile, Position, PropertyList).
81find_predicate_reference(Term, ExactMatch, Root, RefModule, RefName, RefArity, RefFile, Position, PropertyList) :- 82 current_predicate(logtalk_load/1), 83 logtalk_adapter::find_reference_to(Term, ExactMatch, Root, RefModule, RefName, RefArity, RefFile, Line, PropertyList), 84 ( var(RefName), 85 read_term_position_at_location(RefFile, Line, user, Position) 86 -> true 87 ; Position = Line 88 ). 89find_predicate_reference(Term, ExactMatch, Root, RefModule, RefName, RefArity, RefFile, Position, PropertyList) :- 90 find_reference_to(Term, ExactMatch, Root, RefModule, RefName, RefArity, RefFile, Position, PropertyList).
93update_predicate_reference_search_term_to_context(Term, EnclFile, _LineInEnclFile, NewModule, NewTerm) :- 94 ( nonvar(EnclFile), 95 \+ split_file_path(EnclFile, _, _, _, lgt), 96 Term = predicate(M, S0, F, S1, A), 97 var(M) 98 -> once(module_of_file(EnclFile, FileModule)), 99 ( nonvar(F), 100 nonvar(A), 101 functor(H, F, A), 102 predicate_property(FileModule:H, imported_from(ImportedModule)) 103 -> NewModule = ImportedModule 104 ; NewModule = FileModule 105 ), 106 NewTerm = predicate(NewModule, S0, F, S1, A) 107 ; NewTerm = Term 108 ). 109 110 /*********************************************************************** 111 * Find Definitions and Declarations and categorize them by visibility * 112 * --------------------------------------------------------------------* 113 * for "Find All Declarations" (Ctrl+G) action * 114 ***********************************************************************/
118find_predicate_definitions(Term, ExactMatch, Root, DefiningModule, Functor, Arity, DeclOrDef, File, Location, PropertyList) :- 119 Term = predicate(DefiningModule, _, SearchFunctor, Separator, Arity0), 120 ( Separator == (//), 121 nonvar(Arity0) 122 -> Arity is Arity0 + 2 123 ; Arity = Arity0 124 ), 125 ( ExactMatch == true 126 -> Functor = SearchFunctor, 127 declared_in_module(DefiningModule, Functor, Arity, DefiningModule) 128 ; declared_in_module(DefiningModule, Functor, Arity, DefiningModule), 129 once(sub_atom(Functor,_,_,_,SearchFunctor)) 130 ), 131 find_decl_or_def_2(Functor,Arity,Sources), % Unique, grouped sources (--> setof) 132 member(DeclOrDef-DefiningModule-Locations,Sources), 133 member(File-Lines,Locations), 134 ( nonvar(Root) 135 -> sub_atom(File, 0, _, _, Root) 136 ; true 137 ), 138 member(location(Line, Ref),Lines), 139 properties_for_predicate(DefiningModule,Functor,Arity,PropertyList0), 140 ( head_position_of_clause(Ref, Position) 141 -> Location = Position, 142 PropertyList = [line(Line)|PropertyList0] 143 ; Location = Line, 144 PropertyList = PropertyList0 145 ). 146 147find_predicate_definitions(Term, ExactMatch, Root, DefiningModule, Functor, Arity, DeclOrDef, File,Line, PropertyList) :- 148 current_predicate(logtalk_load/1), 149 logtalk_adapter::find_predicate_definitions(Term, ExactMatch, Root, DefiningModule, Functor, Arity, DeclOrDef, File,Line, PropertyList).
154find_categorized_predicate_definitions(Term, EnclFile, SelectionLine, Functor, Arity, DeclOrDef, DefiningEntity, FullPath, Line, Properties, Visibility):- 155 Term \= _:_, 156 split_file_path(EnclFile, _Directory,_FileName,_,lgt), 157 !, 158 logtalk_adapter::find_categorized_predicate_definitions(Term, EnclFile, SelectionLine, Functor, Arity, DeclOrDef, DefiningEntity, FullPath, Line, Properties, Visibility). 159 160find_categorized_predicate_definitions(Term, EnclFile, _SelectionLine, Functor, Arity, DeclOrDef, DefiningModule, File, Location, PropertyList, Visibility):- 161 referenced_entity(EnclFile, ReferencedModule), 162 Term = predicate(_, _, Functor, _, Arity), 163 find_decl_or_def(ReferencedModule,Functor,Arity,Sources), % Unique, grouped sources (--> setof) 164 member(DeclOrDef-Visibility-DefiningModule-Locations,Sources), 165 member(File-Lines,Locations), 166 member(location(Line, Ref),Lines), 167 properties_for_predicate(DefiningModule,Functor,Arity,PropertyList0), 168 ( head_position_of_clause(Ref, Position) 169 -> Location = Position, 170 PropertyList = [line(Line)|PropertyList0] 171 ; Location = Line, 172 PropertyList = PropertyList0 173 ). 174 175head_position_of_clause(Ref, Position) :- 176 catch(clause_info(Ref, _, TermPosition, _),_,fail), 177 ( clause_property(Ref, fact) 178 -> % fact 179 TermPosition = HeadPosition 180 ; % clause with body 181 TermPosition = term_position(_, _, _, _, [HeadPosition|_]) 182 ), 183 ( HeadPosition = Start-End 184 -> % no arguments 185 true 186 ; % at least one argument 187 HeadPosition = term_position(Start, End, _, _, _) 188 ), 189 format(atom(Position), '~w-~w', [Start, End]). 190 191find_decl_or_def_2(Name,Arity,Declarations) :- 192 setof( declaration-DeclModule-Location, Name^Arity^ 193 ( declared_but_undefined(DeclModule,Name,Arity), 194 declared_in_file(DeclModule,Name,Arity,Location) 195 ), 196 Declarations). 197 198find_decl_or_def_2(Name,Arity,Definitions) :- 199 setof( definition-DefiningModule-Locations, Name^Arity^ % Locations is list of File-Lines terms 200 ( defined_in_module(DefiningModule,Name,Arity), 201 defined_in_files(DefiningModule,Name,Arity,Locations) 202% results_context_category_label(defined, Visibility, VisibilityText) 203 ), 204 Definitions 205 ). 206 207referenced_entity(EnclFile, ReferencedModule) :- 208 ( atom(ReferencedModule) 209 -> true % Explicit entity reference ReferencedModule:Term (or ReferencedModule::Term 210 ; module_of_file(EnclFile,ReferencedModule) % Implicit module reference 211 ). 212 213search_term_to_predicate_indicator(_:Functor/(-1), Functor/_Arity) :- !. 214search_term_to_predicate_indicator(Functor/(-1), Functor/_Arity) :- !. 215search_term_to_predicate_indicator(_:Functor/Arity, Functor/Arity) :- !. 216search_term_to_predicate_indicator(Functor/Arity, Functor/Arity) :- !. 217search_term_to_predicate_indicator(_:Term, Functor/Arity) :- !, functor(Term, Functor, Arity). 218search_term_to_predicate_indicator(Term, Functor/Arity) :- functor(Term, Functor, Arity).
223find_decl_or_def(Module,Name,Arity,Sources) :- 224 ( var(Module) 225 ; var(Name) 226 ), 227 throw( input_argument_free(find_decl_or_def(Module,Name,Arity,Sources)) ). 228 229%find_decl_or_def(CallingModule,Name,Arity,['Missing declarations'-DeclModule-[File-[Line]]]) :- 230% referenced_but_undeclared(CallingModule,Name,Arity), 231% DeclModule = 'none', 232% File = 'none', 233% Line = 0. 234find_decl_or_def(CallingModule,Name,Arity,[declaration-none-none-[none-[none]]]) :- 235 referenced_but_undeclared(CallingModule,Name,Arity). 236 237find_decl_or_def(ContextModule,Name,Arity,Declarations) :- 238 setof( declaration-Visibility-DeclModule-Location, ContextModule^Name^Arity^ 239 ( declared_but_undefined(DeclModule,Name,Arity), 240 visibility(Visibility, ContextModule,Name,Arity,DeclModule), 241 declared_in_file(DeclModule,Name,Arity,Location) 242% results_context_category_label(declared, Visibility, VisibilityText) 243 ), 244 Declarations). 245 246find_decl_or_def(ContextModule,Name,Arity,Definitions) :- 247 setof( definition-Visibility-DefiningModule-Locations, ContextModule^Name^Arity^ % Locations is list of File-Lines terms 248 ( defined_in_module(DefiningModule,Name,Arity), 249 visibility(Visibility, ContextModule,Name,Arity,DefiningModule), 250 defined_in_files(DefiningModule,Name,Arity,Locations) 251% results_context_category_label(defined, Visibility, VisibilityText) 252 ), 253 Definitions 254 ). 255 256:- multifile(results_category_label/2). 257 258 259:- multifile(results_context_category_label/3). 260%results_context_category_label(declared, local, 'Local declaration' ) :- !. 261%results_context_category_label(declared, supermodule,'Imported declaration' ) :- !. 262%results_context_category_label(declared, submodule, 'Submodule declaration') :- !. 263%results_context_category_label(declared, invisible, 'Locally invisible declaration') :- !. 264% 265%results_context_category_label(defined, local, 'Local definitions' ) :- !. 266%results_context_category_label(defined, supermodule,'Imported definitions' ) :- !. 267%results_context_category_label(defined, submodule, 'Submodule definitions') :- !. 268%results_context_category_label(defined, invisible, 'Locally invisible definitions') :- !. 269 270 271% These clauses must stay in this order since they determine 272% the order of elements in the result of find_decl_or_def 273% and hence the order of elements in the search result view 274% (which is the INVERSE of the order of elements that we 275% compute here). 276 277 278visibility(super, ContextModule,Name,Arity,DeclModule) :- 279 ( module_imports_predicate_from(ContextModule, Name, Arity, DeclModule, overridden) 280 ; module_imports_predicate_from(ContextModule, Name, Arity, DeclModule, imported) 281 ), 282 !. 283% declared_in_module(ContextModule,Name,Arity,DeclModule), 284% ContextModule \== DeclModule. 285 286 287visibility(local, ContextModule,Name,Arity,DeclModule) :- 288 declared_in_module(ContextModule,Name,Arity,DeclModule), 289 ContextModule == DeclModule, 290 !. 291 292visibility(sub, ContextModule,Name,Arity,DeclModule) :- 293 ( module_imports_predicate_from(DeclModule, Name, Arity, ContextModule, overridden) 294 ; module_imports_predicate_from(DeclModule, Name, Arity, ContextModule, imported) 295 ), 296 !. 297% declared_in_module(DeclModule,Name,Arity,DeclModule), 298% % DeclModule is a submodule of ContextModule 299% declared_in_module(DeclModule,_,_,ContextModule), % submodule 300% ContextModule \== DeclModule. 301visibility(invisible, ContextModule,Name,Arity,DeclModule) :- 302 % Take care to generate all values befor using negation. 303 % Otherwise the clause will not be able to generate values. 304 % Negation DOES NOT generate values for unbound variables! 305 306 % There is some DeclaringModule 307 declared_in_module(DeclModule,Name,Arity,DeclModule), 308 ContextModule \== DeclModule, 309 \+ module_imports_predicate_from(DeclModule, Name, Arity, ContextModule, overridden), 310 \+ module_imports_predicate_from(DeclModule, Name, Arity, ContextModule, imported), 311 \+ module_imports_predicate_from(ContextModule, Name, Arity, DeclModule, overridden), 312 \+ module_imports_predicate_from(ContextModule, Name, Arity, DeclModule, imported). 313% \+ declared_in_module(ContextModule,Name,Arity,DeclModule), 314% \+ declared_in_module(DeclModule,_,_,ContextModule). 315 316 /*********************************************************************** 317 * Find Primary Definition * 318 * --------------------------------------------------------------------* 319 * for "Open Primary Declaration" (F3) action * 320 ***********************************************************************/
Used for the open declaration action in pdt/src/org/cs3/pdt/internal/actions/FindPredicateActionDelegate.java
ResultKind is one of: single, multifile, foreign, dynamic
334find_primary_definition_visible_in(File, Line, OffsetStart, OffsetEnd, TermString, TargetKind, TargetFile, TargetLine, TargetLabel) :- 335 retrieve_term_from_atom(File, TermString, Term), 336 nonvar(Term), 337 find_primary_definition_visible_in_(File, Line, OffsetStart, OffsetEnd, Term, TargetKind, TargetFile, TargetLine, TargetLabel). 338 339retrieve_term_from_atom(File, TermString, Term) :- 340 ( module_property(Module, file(File)) 341 -> atom_concat(TermString, '.', TermStringWithDot), 342 open_chars_stream(TermStringWithDot, Stream), 343 read_term(Stream, Term, [module(Module)]) 344 ; atom_to_term(TermString, Term, _) 345 ). 346 347% Logtalk file 348find_primary_definition_visible_in_(File, Line, _OffsetStart, _OffsetEnd, Term, single, TargetFile, TargetLine, _TargetLabel) :- 349 split_file_path(File, _Directory, _FileName, _, lgt), 350 !, 351 current_predicate(logtalk_load/1), 352 logtalk_adapter::find_primary_definition_visible_in(File, Line, Term, _Functor, _Arity, TargetFile, TargetLine), 353 !. 354 355% Logtalk message in non-Logtalk file 356find_primary_definition_visible_in_(_File, _Line, _OffsetStart, _OffsetEnd, Term, single, TargetFile, TargetLine, _TargetLabel) :- 357 Term = Obj::Call, 358 !, 359 current_predicate(logtalk_load/1), 360 nonvar(Obj), 361 nonvar(Call), 362 functor(Call, Name, Arity), 363 ( object_property(Obj, defines(Name/Arity, Properties)) 364 ; object_property(Obj, declares(Name/Arity, Properties)) 365 ), 366 memberchk(line_count(TargetLine), Properties), 367 object_property(Obj, file(FileName, Directory)), 368 atom_concat(Directory, FileName, TargetFile), 369 !. 370 371% file specification/loading directive 372find_primary_definition_visible_in_(File, _Line, _OffsetStart, _OffsetEnd, Term, single, TargetFile, TargetLine, _TargetLabel) :- 373 find_file(File, Term, TargetFile, TargetLine), 374 !. 375 376% metacall in a transparent predicate 377find_primary_definition_visible_in_(File, Line, OffsetStart, OffsetEnd, Term, transparent, TargetFile, TargetLine, TargetLabel) :- 378 '$clause_from_source'(File, File, Line, ClauseRef), 379 % '$clause_from_source'(File, Line, ClauseRef), 380 clause_property(ClauseRef, predicate(SrcModule:SrcName/SrcArity)), 381 functor(SrcHead, SrcName, SrcArity), 382 predicate_property(SrcModule:SrcHead, transparent), 383 \+ predicate_property(SrcModule:SrcHead, meta_predicate(_)), 384 ( Term = _:_ 385 -> RefTerm = Term 386 ; RefTerm = _:Term 387 ), 388 retractall(alternative(_, _, _, _, _)), 389 pdt_walk_code([clauses([ClauseRef]), trace_reference(RefTerm), reiterate(false), on_trace(pdt_search:assert_alternative(OffsetStart, OffsetEnd))]), 390 findall(a(Module, Name, Arity, File2, Line2), retract(alternative(Module, Name, Arity, File2, Line2)), Alternatives), 391 Alternatives \== [], 392 !, 393 member(a(RefModule, RefName, RefArity, TargetFile, TargetLine), Alternatives), 394 format(atom(TargetLabel), '~w:~w/~w', [RefModule, RefName, RefArity]). 395 396% any other term 397find_primary_definition_visible_in_(File, _Line, _OffsetStart, _OffsetEnd, Term, TargetKind, TargetFile, TargetLine, TargetLabel) :- 398 extract_name_arity(Term, Module, _Head, Name, Arity), 399 find_definition_visible_in(File, Module, Name, Arity, _DefiningModule, Locations), 400 ( Locations = [_,_|_] 401 -> TargetKind = (multifile) 402 ; Locations = [Location], 403 ( Location = (dynamic)-_ -> 404 TargetKind = (dynamic) 405 ; Location = foreign-_ -> 406 TargetKind = foreign 407 ; TargetKind = single 408 ) 409 ), 410 !, 411 member(TargetFile-[location(TargetLine, _)|_], Locations), 412 format(atom(TargetLabel), '~w:~w', [TargetFile, TargetLine]). 413 414:- if(current_prolog_flag(dialect, swi)). 415find_primary_definition_visible_in_(File, _Line, _OffsetStart, _OffsetEnd, Term, dwim, TargetFile, TargetLine, TargetLabel) :- 416 extract_name_arity(Term, Module, Head, _Name, _Arity), 417 ( var(Module) 418 -> once(module_of_file(File,FileModule)), 419 dwim_predicate(FileModule:Head, RefModule:RefHead) 420 ; dwim_predicate(Module:Head, RefModule:RefHead) 421 ), 422 functor(RefHead, RefName, RefArity), 423 ( predicate_property(RefModule:RefHead, file(TargetFile)), 424 predicate_property(RefModule:RefHead, line_count(TargetLine)) 425 -> true 426 ; TargetFile = foreign, 427 TargetLine = -1 428 ), 429 format(atom(TargetLabel), '~w:~w/~w', [RefModule, RefName, RefArity]). 430:- endif. 431 432% If Term is a loading directive, find the related file, 433% eventually interpreting a FileSPec that contains an alias 434find_file(EnclFile,Term,File,Line) :- 435 extract_file_spec(Term,FileSpec), 436 catch( absolute_file_name(FileSpec,[relative_to(EnclFile), solutions(all),extensions(['.pl', '.lgt', '.ct', '.ctc'])], File), 437 _, 438 fail 439 ), 440 access_file(File, read), 441 !, 442 Line=1. 443 444% Work regardelessly whether the user selected the entire consult/use_module 445% statement or just the file spec. Does NOT work if he only selected a file 446% name within an alias but not the complete alias. 447extract_file_spec(consult(FileSpec),FileSpec) :- !. 448extract_file_spec(use_module(FileSpec),FileSpec) :- !. 449extract_file_spec(use_module(FileSpec,_),FileSpec) :- !. 450extract_file_spec(reexport(FileSpec),FileSpec) :- !. 451extract_file_spec(reexport(FileSpec,_),FileSpec) :- !. 452extract_file_spec(ensure_loaded(FileSpec),FileSpec) :- !. 453extract_file_spec(Term,Term). 454 455:- dynamic(alternative/5). 456assert_alternative(GivenStart, GivenEnd, Module0:Goal, _Caller, clause_term_position(_Ref, TermPosition), metacall(_, _)) :- 457 ( TermPosition = term_position(Start, End, _, _, _) 458 ; TermPosition = Start-End 459 ), 460 GivenStart =< Start, 461 End =< GivenEnd, 462 functor(Goal, Name, Arity), 463 declared_in_module(Module0, Name, Arity, Module), 464 predicate_property(Module:Goal, file(File)), 465 predicate_property(Module:Goal, line_count(Line)), 466 !, 467 assertz(alternative(Module, Name, Arity, File, Line)). 468assert_alternative(_, _, _, _, _, _). 469 470extract_name_arity(Term,Module,Head,Name,Arity) :- 471 % Special treatment of Name/Arity terms: 472 ( Term = Module:Name/Arity 473 -> true 474 ; ( Term = Name/Arity 475 -> true 476 ; ( Term = Module:Term2 477 -> functor(Term2, Name, Arity) 478 ; functor(Term,Name,Arity) 479 ) 480 ) 481 ), 482 % Create most general head 483 functor(Head,Name,Arity). 484 485 486find_definition_visible_in(EnclFile,ReferencedModule,Name,Arity,DefiningModule,Locations) :- 487 module_of_file(EnclFile,FileModule), 488 ( atom(ReferencedModule) 489 -> true % Explicit module reference 490 ; ReferencedModule = FileModule % Implicit module reference 491 ), 492 declared_in_module(ReferencedModule,Name,Arity,DeclaringModule), 493 defined_in_files(DeclaringModule,Name,Arity,Locations0), 494 ( Locations0 == [] 495 -> declared_in_file(DefiningModule, Name, Arity, Locations) 496 ; Locations0 = Locations 497 ). 498 499 500 /*********************************************************************** 501 * Find Definitions in File * 502 * --------------------------------------------------------------------* 503 * for Outline * 504 ***********************************************************************/ 505 506% TODO: This is meanwhile subsumed by other predicates. Integrate!
526% Called from PDTOutlineQuery.java 527 528find_definition_contained_in(File, Entity, EntityLine, EntityKind, Functor, Arity, SearchCategory, Line, PropertyList) :- 529 find_definition_contained_in(File, [multifile(true), all_clauses(true), first_arg_size_limit(102400)], Entity, EntityLine, EntityKind, Functor, Arity, SearchCategory, Line, PropertyList). 530 531find_definition_contained_in(File, Options, Entity, EntityLine, EntityKind, Functor, Arity, SearchCategory, Line, PropertyList) :- 532 split_file_path(File, _Directory,_FileName,_,lgt), 533 !, 534 current_predicate(logtalk_load/1), 535 logtalk_adapter::find_definition_contained_in(File, Options, Entity, EntityLine, EntityKind, Functor, Arity, SearchCategory, Line, PropertyList). 536 537find_definition_contained_in(ContextFile, Options, DefiningModule, ModuleLine, module, Functor, Arity, SearchCategory, Line, PropertyList) :- 538 SearchCategory = definition, 539 540% module_of_file(ContextFile, ContextModule), 541 % Backtrack over all predicates defined in File 542 % including multifile contributions to other modules: 543 ( pdt_source_file(DefiningModule:Head, ContextFile) 544 ; source_file_property(ContextFile, included_in(ParentFile, _)), 545 pdt_source_file(DefiningModule:Head, ParentFile) 546 ), 547 ( module_property(DefiningModule, line_count(ModuleLine)) 548 -> true 549 ; ModuleLine = 1 550 ), 551 552 % Predicate properties: 553 functor(Head, Functor, Arity), 554 \+ find_blacklist(Functor,Arity,DefiningModule), 555 properties_for_predicate(DefiningModule,Functor, Arity, PropertyList0), 556 557 % In the case of a multifile predicate, we want to find all clauses for this 558 % predicate, even when they occur in other files 559 %defined_in_file(DefiningModule, Functor, Arity, Ref, _, DefiningFile, Line), 560 find_definition_in_file(Options, ContextFile, DefiningModule, Functor, Arity, Ref, DefiningFile, Line), 561 ( nonvar(ParentFile) 562 -> DefiningFile \== ParentFile 563 ; true 564 ), 565 ( DefiningFile == ContextFile 566 -> ( module_of_file(ContextFile, DefiningModule)%DefiningModule == ContextModule 567 -> % local definition 568 PropertyList1 = [local(DefiningModule)|PropertyList0] 569 ; % contribution of ContextModule for DefiningModule 570 PropertyList1 = [for(DefiningModule), defining_file(DefiningFile) | PropertyList0] 571 ) 572 ; ( module_of_file(ContextFile, DefiningModule)%DefiningModule == ContextModule 573 -> % contribution from DefiningFile to ContextModule, ContextFile 574 PropertyList1 = [from(DefiningModule), defining_file(DefiningFile) | PropertyList0] 575 ; % other file to itself 576 PropertyList1 = [remote(DefiningModule), defining_file(DefiningFile) | PropertyList0] 577 ) 578 ), 579 ( first_argument_of_clause(Ref, Options, FirstArg) 580 -> PropertyList = [FirstArg|PropertyList1] 581 ; PropertyList = PropertyList1 582 ). 583 584find_definition_in_file(Options, ContextFile, Module, Name, Arity, Ref, File, Line) :- 585 once(member(multifile(IsMultifile), Options)), 586 once(member(all_clauses(IsAllClauses), Options)), 587 find_definition_in_file(IsAllClauses, IsMultifile, ContextFile, Module, Name, Arity, Ref, File, Line). 588 589find_definition_in_file(true, IsMultifile, ContextFile, Module, Name, Arity, Ref, File, Line) :- 590 !, 591 ( IsMultifile == true 592 -> true 593 ; ContextFile = File 594 ), 595 defined_in_file(Module, Name, Arity, Ref, _, File, Line). 596find_definition_in_file(_/*false*/, IsMultifile, ContextFile, Module, Name, Arity, Ref, File, Line) :- 597 functor(Head, Name, Arity), 598 ( predicate_property(Module:Head, multifile) 599 -> ( IsMultifile == true 600 -> true 601 ; ContextFile = File 602 ), 603 find_lines(Module:Head, File, Line, Ref) 604 ; ContextFile = File, 605 predicate_property(Module:Head, line_count(Line)), 606 nth_clause(Module:Head, _, Ref), 607 clause_property(Ref, line_count(Line)), 608 ! 609 ). 610 611:- dynamic(file_line/3). 612find_lines(Head, File, Line, Ref) :- 613 predicate_property(Head, number_of_clauses(N)), 614 N > 1000, 615 !, 616 findall(F, (source_file(F), pdt_source_file(Head, F)), Files), 617 Line = 1, 618 Ref = [], 619 member(File, Files). 620find_lines(Head, File, Line, Ref) :- 621 with_mutex(find_lines, ( 622 retractall(file_line(_, _, _)), 623 walk_clauses(Head, 1), 624 findall(F-L-R, file_line(F, L, R), Locations) 625 )), 626 member(File-Line-Ref, Locations). 627walk_clauses(Head, N) :- 628 nth_clause(Head, N, Ref), 629 !, 630 ( clause_property(Ref, file(File)), 631 clause_property(Ref, line_count(Line)) 632 -> ( file_line(File, L, _) 633 -> ( Line < L 634 -> retract(file_line(File, L, _)), 635 assertz(file_line(File, Line, Ref)) 636 ; true 637 ) 638 ; assertz(file_line(File, Line, Ref)) 639 ) 640 ; true 641 ), 642 succ(N, N2), 643 walk_clauses(Head, N2). 644walk_clauses(_, _). 645 646first_argument_of_clause(Ref, Options, first_argument(Arg)) :- 647 catch(clause(_:, _, Ref), _, fail), 648 compound(Head), 649 arg(1, Head, FirstArg), 650 ( var(FirstArg) 651 -> clause_property(Ref, file(File)), 652 ( memberchk(first_arg_size_limit(Limit), Options) 653 -> true 654 ; Limit = 102400 655 ), 656 size_file(File, Size), 657 Size =< Limit, 658 clause_info(Ref, _, _, Varnames), 659 arg(1, Varnames, FirstVarName), 660 Arg = FirstVarName 661 ; functor(FirstArg, F, N), 662 ( N == 0 663 -> Arg = F 664 ; format(atom(Arg), '~w/~w', [F, N]) 665 ) 666 ). 667 668% TODO: Reconcile the above with utils4modules_visibility.pl::module_of_file/2
675find_blacklist('$load_context_module',2,_). 676find_blacklist('$load_context_module',3,_). 677find_blacklist('$mode',2,_). 678find_blacklist('$pldoc',4,_). 679 680 681 682 683 684 /*********************************************** 685 * FIND VISIBLE PREDICATE (FOR AUTOCOMPLETION) * 686 ***********************************************/
690find_completion(Prefix, EnclosingFile, LineInFile, Kind, Entity, Name, Arity, Visibility, IsBuiltin, IsDeprecated, ArgNames, DocKind, Doc, NeedsQuotes) :- 691 var(Prefix), 692 !, 693 throw(prefix_not_bound(find_completion(Prefix, EnclosingFile, LineInFile, Kind, Entity, Name, Arity, Visibility, IsBuiltin, IsDeprecated, ArgNames, DocKind, Doc, NeedsQuotes))). 694 695find_completion(Prefix, EnclosingFile, LineInFile, Kind, Entity, Name, Arity, Visibility, IsBuiltin, IsDeprecated, ArgNames, DocKind, Doc, NeedsQuotes) :- 696 nonvar(EnclosingFile), 697 !, 698 ( split_file_path(EnclosingFile, _, _, _, lgt) 699 -> current_predicate(logtalk_load/1), 700 IsDeprecated = false, 701 logtalk_adapter::find_completion(Prefix, EnclosingFile, LineInFile, Kind, Entity, Name, Arity, Visibility, IsBuiltin, ArgNames, DocKind, Doc) 702 ; find_completion_(Prefix, EnclosingFile, LineInFile, Kind, Entity, Name, Arity, Visibility, IsBuiltin, IsDeprecated, ArgNames, DocKind, Doc) 703 ), 704 needs_quotes(Name, NeedsQuotes). 705 706find_completion(Prefix, EnclosingFile, LineInFile, Kind, Entity, Name, Arity, Visibility, IsBuiltin, IsDeprecated, ArgNames, DocKind, Doc, NeedsQuotes) :- 707 ( find_completion_(Prefix, EnclosingFile, LineInFile, Kind, Entity, Name, Arity, Visibility, IsBuiltin, IsDeprecated, ArgNames, DocKind, Doc) 708 ; current_predicate(logtalk_load/1), 709 IsDeprecated = false, 710 logtalk_adapter::find_completion(Prefix, EnclosingFile, LineInFile, Kind, Entity, Name, Arity, Visibility, IsBuiltin, ArgNames, DocKind, Doc) 711 ), 712 needs_quotes(Name, NeedsQuotes). 713 714needs_quotes(Value, NeedsQuotes) :- 715 ( atom(Value) 716 -> with_output_to(atom(A), writeq(Value)), 717 ( atom_length(Value, VL), 718 atom_length(A, AL), 719 AL > VL 720 -> NeedsQuotes = true 721 ; NeedsQuotes = false 722 ) 723 ; NeedsQuotes = false 724 ). 725 726:- discontiguous(find_completion_/13). 727 728find_completion_(SpecifiedModule:PredicatePrefix, _EnclosingFile, _LineInFile, predicate, Module, Name, Arity, Visibility, IsBuiltin, IsDeprecated, ArgNames, DocKind, Doc) :- 729 !, 730 ( PredicatePrefix \== '' 731 -> setof( 732 Module-Name-Arity, 733 SpecifiedModule^( 734 declared_in_module(SpecifiedModule, Name, Arity, Module), 735 is_case_insensitive_prefix_of(PredicatePrefix, Name) 736 ), 737 Predicates 738 ) 739 ; nonvar(SpecifiedModule), 740 setof( 741 SpecifiedModule-Name-Arity, 742 SpecifiedModule^(declared_in_module(SpecifiedModule, Name, Arity, SpecifiedModule)), 743 Predicates 744 ) 745 ), 746 member(Module-Name-Arity, Predicates), 747 predicate_information(Module, Name, Arity, IsBuiltin, IsDeprecated, Visibility, ArgNames, DocKind, Doc). 748 749find_completion_(PredicatePrefix, EnclosingFile, _LineInFile, predicate, Module, Name, Arity, Visibility, IsBuiltin, IsDeprecated, ArgNames, DocKind, Doc) :- 750 atomic(PredicatePrefix), 751 nonvar(EnclosingFile), 752 setof( 753 Module-Name-Arity, 754 EnclosingFile^FileModule^IncludeLine^File^( 755 ( File = EnclosingFile 756 ; source_file_property(EnclosingFile, included_in(File, IncludeLine)) 757 ), 758 module_of_file(File, FileModule), 759 declared_in_module(FileModule, Name, Arity, Module), 760 is_case_insensitive_prefix_of(PredicatePrefix, Name) 761 ), 762 Predicates 763 ), 764 member(Module-Name-Arity, Predicates), 765 predicate_information(Module, Name, Arity, IsBuiltin, IsDeprecated, Visibility, ArgNames, DocKind, Doc). 766 767find_completion_(PredicatePrefix, EnclosingFile, _LineInFile, predicate, Module, Name, Arity, Visibility, IsBuiltin, IsDeprecated, ArgNames, DocKind, Doc) :- 768 atomic(PredicatePrefix), 769 var(EnclosingFile), 770 setof(Module-Name-Arity, ( 771 declared_in_module(user, Name, Arity, Module), 772 is_case_insensitive_prefix_of(PredicatePrefix, Name) 773 ), Predicates), 774 member(Module-Name-Arity, Predicates), 775 predicate_information(Module, Name, Arity, IsBuiltin, IsDeprecated, Visibility, ArgNames, DocKind, Doc). 776 777predicate_information(Module, Name, Arity, IsBuiltin, IsDeprecated, Visibility, ArgNames, DocKind, Doc) :- 778 functor(Head, Name, Arity), 779 ( predicate_property(Module:Head, built_in) 780 -> IsBuiltin = true 781 ; IsBuiltin = false 782 ), 783 ( ( Module == user 784 ; predicate_property(Module:Head, exported) 785 ) 786 -> Visibility = (public) 787 ; Visibility = protected 788 ), 789 ( predicate_completion_documentation_hook(Module, Name, Arity, ArgNames, DocKind, Doc) 790 -> true 791 ; predicate_manual_entry(Module, Name, Arity, Content, IsDeprecated), 792 ( Content == nodoc 793 -> DocKind = nodoc 794 ; DocKind = html, 795 Doc = Content, 796 ( Arity == 0 797 -> ArgNames = [] 798 ; ignore(predicate_arg_list(Content, ArgNames)) 799 ) 800 ) 801 ), 802 ( var(IsDeprecated) 803 -> IsDeprecated = false 804 ; true 805 ). 806 807:- multifile(predicate_completion_documentation_hook/6). 808 809predicate_arg_list(Comment, ArgList) :- 810 sub_atom(Comment, End, _, _, '</var>'), 811 sub_atom(Comment, BeforeBegin, BeforeBeginLength, _, '"arglist">'), 812 !, 813 Begin is BeforeBegin + BeforeBeginLength, 814 Length is End - Begin, 815 sub_atom(Comment, Begin, Length, _, Args), 816 format(atom(ArgsWithDot), '~w.', [Args]), 817 open_chars_stream(ArgsWithDot, Stream), 818 call_cleanup(read_term(Stream, Term, [variable_names(Vars), module(pldoc_modes)]), close(Stream)), 819 args_from_mode_term(Term, ArgList, Vars). 820 821args_from_mode_term(Arg, [ArgName], Vars) :- 822 var(Arg), 823 !, 824 var_to_arg(Arg, ArgName, Vars). 825 826args_from_mode_term((Arg, Args), [ArgName|ArgNames], Vars) :- 827 !, 828 var_to_arg(Arg, ArgName, Vars), 829 args_from_mode_term(Args, ArgNames, Vars). 830 831args_from_mode_term(Arg, [ArgName], Vars) :- 832 var_to_arg(Arg, ArgName, Vars). 833 834var_to_arg(Arg, ArgName, Vars) :- 835 ( var(Arg) 836 -> Arg = Var 837 ; Arg =.. [_Mode|Other], 838 ( Other = [Var:_] 839 ; Other = [Var] 840 ) 841 ), 842 member(ArgName=V, Vars), 843 V == Var, 844 !. 845 846find_completion_(ModulePrefix, _EnclosingFile, _LineInFile, module, _, Name, _, _, _, _, _, _, _) :- 847 atomic(ModulePrefix), 848 current_module(Name), 849 is_case_insensitive_prefix_of(ModulePrefix,Name). 850 851:- if(current_prolog_flag(dialect, swi)). 852find_completion_(AtomPrefix, _EnclosingFile, _LineInFile, atom, _, Atom, _, _, _, _, _, _, _) :- 853 atomic(AtomPrefix), 854 garbage_collect_atoms, 855 '$atom_completions'(AtomPrefix, Atoms), 856 member(Atom,Atoms), 857 '$atom_references'(Atom, ReferenceCount), 858 ReferenceCount > 0, 859% Atom \= AtomPrefix, 860 \+ current_predicate(Atom/_Arity). 861:- endif. 862 863is_case_insensitive_prefix_of(Prefix, Name) :- 864 downcase_atom(Prefix, PrefixDowncase), 865 downcase_atom(Name, NameDowncase), 866 atom_concat(PrefixDowncase, _, NameDowncase).
870find_entity_definition(SearchString, ExactMatch, Root, File, Line, Entity) :- 871 current_predicate(logtalk_load/1), 872 logtalk_adapter::find_entity_definition(SearchString, ExactMatch, Root, File, Line, Entity). 873 874find_entity_definition(SearchString, ExactMatch, Root, File, Line, Entity) :- 875 find_module_definition(SearchString, ExactMatch, Root, File, Line, Entity). 876 877 878find_module_definition(SearchModule, ExactMatch, Root, File, Line, Module) :- 879 current_module(Module), 880 ( ExactMatch == true 881 -> SearchModule = Module 882 ; once(sub_atom(Module, _, _, _, SearchModule)) 883 ), 884 module_property(Module, file(File)), 885 ( nonvar(Root) 886 -> sub_atom(File, 0, _, _, Root) 887 ; true 888 ), 889 module_property(Module, line_count(Line)).
894find_module_reference(Module, ExactMatch, Root, File, Location, LoadingModule, _, _, [line(Line), label(Label)]) :- 895 find_use_module(Module, ExactMatch, _, LoadingModule, File, Line, OptionList), 896 ( nonvar(Root) 897 -> sub_atom(File, 0, _, _, Root) 898 ; true 899 ), 900 format(atom(Label), ':- load_files(~w, ~w).', [Module, OptionList]), 901 ( read_term_position_at_location(File, Line, LoadingModule, Location) 902 -> true 903 ; Location = Line 904 ). 905 906find_module_reference(Module, ExactMatch, Root, File, Line, ReferencingModule, RefName, RefArity, PropertyList) :- 907 search_module_name(Module, ExactMatch, SearchModule), 908 find_reference_to(predicate(SearchModule, _, _, _, _), ExactMatch, Root, ReferencingModule, RefName, RefArity, File, Line, PropertyList). 909 910find_module_reference(Module, ExactMatch, Root, File, Location, ReferencingModule, RefName, RefArity, PropertyList) :- 911 current_predicate(logtalk_load/1), 912 logtalk_adapter::find_entity_reference(Module, ExactMatch, Root, File, Line, ReferencingModule, RefName, RefArity, PropertyList), 913 ( var(RefName), 914 read_term_position_at_location(File, Line, user, Location) 915 -> true 916 ; Location = Line 917 ). 918 919read_term_position_at_location(File, Line, Module, Location) :- 920 catch(open(File, read, In), _, fail), 921 set_stream(In, newline(detect)), 922 call_cleanup( 923 read_source_term_at_location( 924 In, 925 _Clause, 926 [ line(Line), 927 module(Module), 928 subterm_positions(TermPos) 929 ] 930 ), 931 close(In) 932 ), 933 TermPos = term_position(Start, End, _, _, _), 934 format(atom(Location), '~w-~w', [Start, End]), 935 !. 936 937search_module_name(Module, true, Module) :- !. 938search_module_name(ModulePart, false, Module) :- 939 current_module(Module), 940 once(sub_atom(Module, _, _, _, ModulePart)).
944/* For Load File Dependency Graph: */ 945loaded_by(LoadedFile, LoadingFile, Line, Directive) :- 946 nonvar(LoadedFile), 947 ( split_file_path(LoadedFile, _, _, _, lgt) 948 ; split_file_path(LoadedFile, _, _, _, logtalk) 949 ), 950 % Logtalk source file 951 !, 952 logtalk_adapter::loaded_by(LoadedFile, LoadingFile, Line, Directive). 953 954loaded_by(LoadedFile, LoadingFile, Line, Directive) :- 955 source_file_property(LoadedFile, load_context(_LoadingModule, LoadingFile:Line, _OptionList)), 956 % If the loaded file is a module conclude that the 957 % loading directive should have been 'use_module'. 958 % Otherwise, treat it as a 'consult': 959 ( module_property(_Module, file(LoadedFile)) 960 -> Directive = use_module 961 ; Directive = consult 962 ). 963 964find_use_module(ModuleOrPart, ExactMatch, ModuleFile, LoadingModule, File, Line, OptionList) :- 965 ( ExactMatch == true 966 -> ModuleOrPart = Module 967 ; current_module(Module), 968 once(sub_atom(Module, _, _, _, ModuleOrPart)) 969 ), 970 module_property(Module, file(ModuleFile)), 971 source_file_property(ModuleFile, load_context(LoadingModule, File:Line, OptionList)). 972% member(if(not_loaded), OptionList), 973% member(must_be_module(true), OptionList). 974 975module_imports_predicate_from(Module, Name, Arity, SuperModule, Case) :- 976 has_super_module(Module, SuperModule), 977 visible_in_module(Module, Name, Arity), 978 979 ( defined_in_module(Module, Name, Arity) 980 -> ( module_property(SuperModule, exports(ExportList)), 981 member(Name/Arity, ExportList) 982 -> Case = overridden 983 ; Case = local 984 ) 985 ; functor(Head, Name, Arity), 986 ( predicate_property(Module:Head, imported_from(SuperModule)) 987 -> Case = imported 988 ; Case = not_imported 989 ) 990 ). 991 992has_super_module(Module, SuperModule) :- 993 module_property(SuperModule, file(SuperModuleFile)), 994 source_file_property(SuperModuleFile, load_context(Module, _, _OptionList)). 995 996 997loaded_file(FullPath) :- 998 ( ( split_file_path(FullPath, Directory, Basename, _, lgt) 999 ; split_file_path(FullPath, Directory, Basename, _, logtalk) 1000 ) -> 1001 % Logtalk source file 1002 current_predicate(logtalk_load/1), 1003 % assume that Logtalk is loaded 1004 ( current_logtalk_flag(version, version(3, _, _)) -> 1005 logtalk::loaded_file(FullPath) 1006 ; logtalk::loaded_file(Basename, Directory) 1007 ) 1008 ; % assume Prolog source file 1009 source_file(FullPath) 1010 )