1/***************************************************************************** 2 * This file is part of the Prolog Development Tool (PDT) 3 * 4 * Author: G�nter Kniesel 5 * WWW: http://sewiki.iai.uni-bonn.de/research/pdt/start 6 * Mail: pdt@lists.iai.uni-bonn.de 7 * Copyright (C): 2013, CS Dept. III, University of Bonn 8 * 9 * All rights reserved. This program is made available under the terms 10 * of the Eclipse Public License v1.0 which accompanies this distribution, 11 * and is available at http://www.eclipse.org/legal/epl-v10.html 12 * 13 ****************************************************************************/ 14 15:- module( pdt_search, 16 [ find_reference_to/12 % (+Functor,+Arity,?DefFile,?DefModule,?RefModule,?RefName,?RefArity,?RefFile,?RefLine,?Nth,?Kind) 17 , find_definitions_categorized/12 % (+EnclFile,+SelectionLine, +Term, -Functor, -Arity, -This, -DeclOrDef, -DefiningEntity, -FullPath, -Line, -Properties,-Visibility) 18 , find_primary_definition_visible_in/6 % (EnclFile,TermString,ReferencedModule,MainFile,FirstLine,MultifileResult) 19 , find_definition_contained_in/8 20 , find_pred/8 21 ]). 22 23:- use_module( split_file_path, 24 [ split_file_path/4 % (File,Folder,FileName,BaseName,Extension) 25 ] ). 26:- use_module( pdt_xref, 27 [ find_reference_to/12 % ... 28 ] ). 29:- use_module( properties, 30 [ properties_for_predicate/4 31 ] ). 32:- use_module( pdt_prolog_library(utils4modules), 33 [ module_of_file/2 % (File,FileModule) 34 , defined_in/4 % (SubModule,Name,Arity,DeclModule), 35 , defined_in_module/3 % (Module,Name,Arity), 36 , declared_in_file/4 % (Module,Name,Arity,Location) 37 , defined_in_files/4 % (Module,Name,Arity,Locations) 38 ] ). 39 40 41% TODO: Why this import? 42:- user:consult(pdt_runtime_builder_analyzer('meta_pred_toplevel.pl')). 43 44 45:- op(600, xfy, ::). % Logtalk message sending operator 46 47 /*********************************************************************** 48 * Find Definitions and Declarations and categorize them by visibility * 49 * --------------------------------------------------------------------* 50 * for "Find All Declarations" (Ctrl+G) action * 51 ***********************************************************************/ 52 53 54% find_definitions_categorized(+ReferencingFile,+-ReferencingLine,+ReferencingTerm,-Name,-Arity, 55% ???ReferencingModule, -DefiningModule, -DeclOrDef, -Visibility, -File,-Line) 56% ^^^^^^^^^^^^^^ TODO: moved to this place (two arguments forward) 57% Logtalk 58find_definitions_categorized(EnclFile,SelectionLine, Term, Functor, Arity, This, DeclOrDef, DefiningEntity, FullPath, Line, Properties, Visibility):- 59 Term \= _:_, 60 split_file_path(EnclFile, _Directory,_FileName,_,lgt), 61 !, 62 logtalk_adapter::find_definitions_categorized(EnclFile,SelectionLine, Term, Functor, Arity, This, DeclOrDef, DefiningEntity, FullPath, Line, Properties, Visibility). 63 64find_definitions_categorized(EnclFile,_SelectionLine,Term,Functor,Arity, ReferencingModule, DeclOrDef, DefiningModule, File,Line, PropertyList, Visibility):- 65 search_term_to_predicate_indicator(Term, Functor/Arity), 66 module_of_file(EnclFile,FileModule), 67 ( atom(ReferencingModule) 68 -> true % Explicit entity reference ReferencedModule:Term (or ReferencedModule::Term 69 ; ReferencingModule = FileModule % Implicit module reference 70 ), 71 find_definition(ReferencingModule,Functor,Arity,Sources), 72 member(DeclOrDef-Visibility-DefiningModule-Location,Sources), 73 member(File-Lines,Location), 74 member(Line,Lines), 75 properties_for_predicate(ReferencingModule,Functor,Arity,PropertyList). 76 77search_term_to_predicate_indicator(_:Term, Functor/Arity) :- !, functor(Term, Functor, Arity). 78search_term_to_predicate_indicator( Term, Functor/Arity) :- functor(Term, Functor, Arity).
83find_definition(ReferencingModule,Name,Arity,Sources) :- 84 var(Name), 85 throw( input_argument_free(find_definition(ReferencingModule,Name,Arity,Sources)) ). 86 87find_definition(Name,Arity,ReferencingModule,Module,Visibility,File,LineNr,N,Case) :- 88% ( pdt_option(search, restrict_arity(true)) 89% -> 90% ), 91% ( pdt_option( search, restrict_module(true) 92% -> 93% ), 94 defined_in(Module,Name,Arity), 95 visibility(Module,Name,Arity,ReferencingModule,Visibility), 96 location(Module,Name,Arity,File,LineNr,N,Case). 97% locations_by_file(Module,Name,Arity,File,Lines). 98% 99%locations_by_file(Module,Name,Arity,File,Line) :- 100% setof( LineNr-N-Case, 101% Module^Name^Arity^ location(Module,Name,Arity,File,LineNr,N,Case), 102% Lines 103% ), 104% member(Line,Lines) 105% .
128location(Module,Name,Arity, File,Line,N,clause) :- % Clause 129 clause_location(Module,Name,Arity,File,Line,N). 130 131location(Module,Name,Arity,File,Line,N,declaration) :- % Declaration 132 \+ clause_location(Module,Name,Arity,_,_,_), 133 module_property(Module, file(File)), 134 !, 135 Line=1, 136 N=0. 137 138location(Module,Name,Arity,File,Line,N,Prop) :- % No source code 139 \+ clause_location(Module,Name,Arity,_,_,_), 140 functor(Head,Name,Arity), 141 ( (Prop = foreign, predicate_property(Module:Head,Prop)) 142 ; (Prop = (dynamic), predicate_property(Module:Head,Prop)) 143 ), 144 !, 145 File=none, 146 Line=0, 147 N=0.
157clause_location(Module,Name,Arity,N,File,Line) :- 158 functor(Head,Name,Arity), 159 nth_clause(Module:Head,N,Ref), 160 clause_property(Ref, file(File)), 161 clause_property(Ref, line_count(Line)). 162 163 164 165imports_pred_from(Sub,Head,Super) :- 166 predicate_property(Sub:Head, imported_from(Super)).
172visibility(ContextModule,Name,Arity,DeclModule, supermodule) :- 173 defined_in(ContextModule,Name,Arity,DeclModule), 174 ContextModule \== DeclModule. 175 176visibility(ContextModule,Name,Arity,DeclModule, local) :- 177 defined_in(ContextModule,Name,Arity,DeclModule), 178 ContextModule == DeclModule. 179 180visibility(ContextModule,Name,Arity,DeclModule, submodule) :- 181 defined_in(DeclModule,Name,Arity,DeclModule), 182 % DeclModule is a submodule of ContextModule 183 defined_in(DeclModule,_,_,ContextModule), % submodule 184 ContextModule \== DeclModule. 185visibility(ContextModule,Name,Arity,DeclModule, invisible) :- 186 % There is some DeclaringModule 187 defined_in(DeclModule,Name,Arity,DeclModule), 188 DeclModule \== ContextModule, 189 % ... but the ContextModule neither is imported to it 190 % nor imports from it: 191 functor(Head,Name,Arity), 192 \+ imports_pred_from(DeclModule,Head,ContextModule), 193 \+ imports_pred_from(ContextModule,Head,DeclModule). 194 195 196 197 198 /*********************************************************************** 199 * Find Primary Definition * 200 * --------------------------------------------------------------------* 201 * for "Open Primary Declaration" (F3) action * 202 ***********************************************************************/
Used for the open declaration action (F3) in pdt/src/org/cs3/pdt/internal/actions/FindPredicateActionDelegate.java
215find_primary_definition_visible_in(EnclFile,TermString,ReferencedModule,MainFile,FirstLine,MultifileResult) :- 216 split_file_path(EnclFile, _Directory,_FileName,_,lgt), 217 !, 218 logtalk_adapter::find_primary_definition_visible_in(EnclFile,TermString,ReferencedModule,MainFile,FirstLine,MultifileResult). 219 220 221% The second argument is just an atom contianing the string representation of the term: 222find_primary_definition_visible_in(EnclFile,TermString,ReferencedModule,MainFile,FirstLine,MultifileResult) :- 223 retrieve_term_from_atom(EnclFile, TermString, Term), 224 extract_name_arity(Term,Head,Name,Arity), 225 find_primary_definition_visible_in__(EnclFile,Head,Name,Arity,ReferencedModule,MainFile,FirstLine,MultifileResult). 226 227retrieve_term_from_atom(EnclFile, TermString, Term) :- 228 ( module_property(Module, file(EnclFile)) 229 -> atom_concat(TermString, '.', TermStringWithDot), 230 open_chars_stream(TermStringWithDot, Stream), 231 read_term(Stream, Term, [module(Module)]) 232 ; atom_to_term(TermString, Term, _) 233 ). 234 235extract_name_arity(Term,Head,Name,Arity) :- 236 ( var(Term) 237 -> throw( 'Cannot display the definition of a variable. Please select a predicate name.' ) 238 ; true 239 ), 240 % Special treatment of Name/Arity terms: 241 ( Term = Name/Arity 242 -> true 243 ; ( Term = _Module:Term2 244 -> functor(Term2, Name, Arity) 245 ; functor(Term,Name,Arity) 246 ) 247 ), 248 % Create most general head 249 functor(Head,Name,Arity). 250 251% Now the second argument is a real term that is 252% a) a file loading directive: 253find_primary_definition_visible_in__(_,Term,_,_,_,File,Line,no):- 254 find_file(Term,File,Line). 255 256% b) a literal (call or clause head): 257find_primary_definition_visible_in__(EnclFile,Term,Name,Arity,ReferencedModule,MainFile,FirstLine,MultifileResult) :- 258 find_definition_visible_in(EnclFile,Term,Name,Arity,ReferencedModule,DefiningModule,Locations), 259 ( Locations = [_,_|_] 260 -> MultifileResult = yes 261 ; MultifileResult = no 262 ), 263 primary_location(Locations,DefiningModule,MainFile,FirstLine). 264 265 266% If Term is a loading directive, find the related file, 267% eventually interpreting a FileSPec that contains an alias 268find_file(Term,File,Line) :- 269 extract_file_spec(Term,FileSpec), 270 catch( absolute_file_name(FileSpec,[solutions(all),extensions(['.pl', '.lgt', '.ct', '.ctc'])], File), 271 _, 272 fail 273 ), 274 access_file(File, read), 275 !, 276 Line=1. 277 278% Work regardelessly whether the user selected the entire consult/use_module 279% statement or just the file spec. Does NOT work if he only selected a file 280% name within an alias but not the complete alias. 281extract_file_spec(consult(FileSpec),FileSpec) :- !. 282extract_file_spec(use_module(FileSpec),FileSpec) :- !. 283extract_file_spec(ensure_loaded(FileSpec),FileSpec) :- !. 284extract_file_spec(Term,Term). 285 286find_definition_visible_in(EnclFile,_Term,Name,Arity,ReferencedModule,DefiningModule,Locations) :- 287 module_of_file(EnclFile,FileModule), 288 ( atom(ReferencedModule) 289 -> true % Explicit module reference 290 ; ReferencedModule = FileModule % Implicit module reference 291 ), 292 ( defined_in_module(ReferencedModule,Name,Arity,DefiningModule) 293 -> defined_in_files(DefiningModule,Name,Arity,Locations) 294 ; ( defined_in(ReferencedModule,Name,Arity,DeclaringModule), 295 defined_in_files(DeclaringModule,Name,Arity,Locations) 296 ) 297 ). 298 299primary_location(Locations,DefiningModule,File,FirstLine) :- 300 member(File-Lines,Locations), 301 module_of_file(File,DefiningModule), 302 !, 303 Lines = [FirstLine|_]. 304primary_location(Locations,_,File,FirstLine) :- 305 findall( NrOfClauses-File-FirstLine, 306 ( member(File-Lines,Locations), 307 length(Lines,NrOfClauses), 308 Lines=[FirstLine|_] 309 ), 310 All 311 ), 312 sort(All, Sorted), 313 Sorted = [ NrOfClauses-File-FirstLine |_ ]. 314 315 316 /*********************************************************************** 317 * Find Definitions in File * 318 * --------------------------------------------------------------------* 319 * for Outline * 320 ***********************************************************************/ 321 322% TODO: This is meanwhile subsumed by other predicates. Integrate!
Called from PDTOutlineQuery.java
332find_definition_contained_in(File, Entity, EntityKind, Functor, Arity, SearchCategory, Line, PropertyList) :- 333 split_file_path(File, _Directory,_FileName,_,lgt), 334 !, 335 logtalk_adapter::find_definition_contained_in(File, Entity, EntityKind, Functor, Arity, SearchCategory, Line, PropertyList). 336 337find_definition_contained_in(File, Module, module, Functor, Arity, SearchCategory, Line, PropertyList) :- 338 % Backtrack over all predicates defined in File: 339 source_file(ModuleCandidate:Head, File), 340 % strip_module(ModuleHead,ModuleCandidate,Head), 341 ( module_property(ModuleCandidate, file(File)) 342 -> Module = ModuleCandidate 343 ; Module = user 344 ), 345 functor(Head, Functor, Arity), 346 properties_for_predicate(ModuleCandidate,Functor, Arity, PropertyList0), 347 % In the case of a multifile predicate, we want to find all clauses for this 348 % predicate, even when they occur in other files 349 ( member(multifile, PropertyList0) 350 -> ( defined_in_file(ModuleCandidate, Functor, Arity, _, DeclFile, Line), 351 ( DeclFile \= File 352 -> ( module_property(MultiModule, file(DeclFile)), 353 append([for(MultiModule), defining_file(DeclFile)], PropertyList0, PropertyList), 354 SearchCategory = multifile 355 ) 356 ; ( PropertyList = PropertyList0, 357 SearchCategory = definition 358 ) 359 ) 360 ) 361 ; ( PropertyList = PropertyList0, 362 SearchCategory = definition, 363 % The following backtracks over each clause of each predicate. 364 % Do this at the end, after the things that are deterministic: 365 ( defined_in_file(ModuleCandidate, Functor, Arity, _, File, _) 366 -> Module2 = ModuleCandidate 367 ; Module2 = Module 368 ), 369 defined_in_file(Module2, Functor, Arity, _, File, Line) 370 ) 371 ), 372 \+find_blacklist(Functor,Arity,Module). 373 374 375% The following clause searches for clauses inside the given file, which contribute to multifile 376% predicates, defined in foreign modules. 377find_definition_contained_in(File, Module, module, Functor, Arity, multifile, Line, PropertyList):- 378 module_property(FileModule, file(File)), 379 declared_in_module(Module,Head), 380 Module \= FileModule, 381 predicate_property(Module:Head, multifile), 382 nth_clause(Module:Head,_,Ref), 383 clause_property(Ref,file(File)), 384 clause_property(Ref,line_count(Line)), 385 functor(Head, Functor, Arity), 386 properties_for_predicate(Module, Functor, Arity, PropertyList0), 387 append([from(Module)], PropertyList0, PropertyList), 388 \+find_blacklist(Functor,Arity,Module).
396find_blacklist('$load_context_module',2,_). 397find_blacklist('$mode',2,_). 398find_blacklist('$pldoc',4,_). 399 400 401 402 403 404 /*********************************************** 405 * FIND VISIBLE PREDICATE (FOR AUTOCOMPLETION) * 406 ***********************************************/
Used by the PLEditor content assist.
The meaning of Arity is overloaded: -2: atom, -1 : module, >= 0 : predicate
For performance reasons an empty prefix with an unspecified module will only bind predicates if EnclFile is specified.
<EnclFile> specifies the file in which this query is triggered <Prefix> specifies the prefix of the predicate <Module> specifies the module associated to the file.
423find_pred(EnclFile,Prefix,Module,Name,Arity,Exported,Builtin,Help) :- 424 split_file_path(EnclFile, _Directory,_FileName,_,lgt), 425 !, 426 logtalk_adapter::find_pred(EnclFile,Prefix,Module,Name,Arity,Exported,Builtin,Help). 427 428 429find_pred(EnclFile,Prefix,Module,Name,Arity,Exported,Builtin,Help) :- 430 \+ atom(EnclFile), 431 throw( first_argument_free_in_call_to(find_pred(EnclFile,Prefix,Module,Name,Arity,Exported,Builtin,Help))). 432 433find_pred(EnclFile,Prefix,Module,Name,Arity,Exported,Builtin,Help) :- 434 setof( 435 (Name,Arity), 436 Prefix^Module^ 437 ( my_module_of_file(EnclFile,Module), 438 find_pred_(Prefix,Module,Name,Arity,true) 439 ), 440 All 441 ), 442 member((Name,Arity),All), 443 444 % no enclosing module specified in the code via modulename:.. 445 get_declaring_module(EnclFile,Module,Name,Arity), 446 functor(Term,Name,Arity), 447 ( predicate_property(Module:Term,exported)-> 448 Exported=true 449 ; Exported=false 450 ), 451 ( predicate_property(Module:Term,built_in)-> 452 Builtin=true 453 ; Builtin=false 454 ), 455 predicate_manual_entry(Module,Name,Arity,Help). 456 457find_pred_(Prefix,Module,Name,Arity,true) :- 458 ( var(Module)-> 459 Prefix \== '' 460 ; true 461 ), % performance tweak: 462 current_predicate(Module:Name/Arity), 463 atom_concat(Prefix,_,Name), 464 % rule out used built-ins, like =../2, in case the enclosing module is given (in this case the prefix might be empty): 465 ( nonvar(Module) -> 466 ( functor(Term,Name,Arity), 467 (Prefix \== ''; \+ predicate_property(Term, built_in)) ) 468 ; true 469 ). 470 471 472get_declaring_module(EnclFile,Module,Name,Arity) :- 473 var(Module), 474 my_module_of_file(EnclFile,ContainingModule), 475 current_predicate(ContainingModule:Name/Arity), 476 functor(Head,Name,Arity), 477 ( predicate_property(ContainingModule:Head,imported_from(Module)) 478 ; Module = ContainingModule 479 ), 480 !. 481 482get_declaring_module(_EnclFile,Module,_Name,_Arity) :- 483 nonvar(Module), 484 !.
489find_pred_for_editor_completion(EnclFile,Prefix,Module,Name,Arity,Exported,Builtin,Help,Kind) :- 490 \+ atom(EnclFile), 491 throw( first_argument_free_in_call_to(find_pred_for_editor_completion(EnclFile,Prefix,Module,Name,Arity,Exported,Builtin,Help,Kind))). 492 493find_pred_for_editor_completion(EnclFile,Prefix,Module,Name,Arity,Exported,Builtin,Help,predicate) :- 494 find_pred(EnclFile,Prefix,Module,Name,Arity,Exported,Builtin,Help). 495 496find_pred_for_editor_completion(_EnclFile,Prefix,EnclModule,Name,-1,true,false,'nodoc', module) :- 497 var(EnclModule), 498 current_module(Name), 499 atom_concat(Prefix,_,Name). 500 501% TODO: Improvement Idea: use "string" Prefix instead 502% of atom to avoid Prefix to be added to the set of atoms 503find_pred_for_editor_completion(_EnclFile,Prefix,'',Atom,-1,fail,true,'nodoc', atom) :- 504 '$atom_completions'(Prefix, Atoms), 505 member(Atom,Atoms), 506 Atom \= Prefix, 507 garbage_collect_atoms, 508 \+ current_predicate(Atom/_Arity). 509 510my_module_of_file(_File, Module) :- 511 atom(Module), 512 current_module(Module), 513 !. 514 515my_module_of_file(File,Module):- 516 module_property(Module2,file(File)), 517 ( Module = Module2 518 ; Module = user 519 ). 520 521my_module_of_file(File,Module):- 522 atom(File), 523 \+ module_property(Module,file(File)), 524 ( Module=user 525 ; Module=system 526 )