OSDN Git Service

Version 5.91
[vbslib/main.git] / GPL_bin_fullset / NaturalDocs / Modules / NaturalDocs / ClassHierarchy.pm
1 ###############################################################################
2 #
3 #   Package: NaturalDocs::ClassHierarchy
4 #
5 ###############################################################################
6 #
7 #   A package that handles all the gory details of managing the class hierarchy.  It handles the hierarchy itself, which files define
8 #   them, rebuilding the files that are affected by changes, and loading and saving them to a file.
9 #
10 #   Usage and Dependencies:
11 #
12 #       - <NaturalDocs::Settings> and <NaturalDocs::Project> must be initialized before use.
13 #
14 #       - <NaturalDocs::SymbolTable> must be initialized before <Load()> is called.  It must reflect the state as of the last time
15 #          Natural Docs was run.
16 #
17 #       - <Load()> must be called to initialize the package.  At this point, the <Information Functions> will return the state as
18 #         of the last time Natural Docs was run.  You are free to resolve <NaturalDocs::SymbolTable()> afterwards.
19 #
20 #       - <Purge()> must be called, and then <NaturalDocs::Parser->ParseForInformation()> must be called on all files that
21 #         have changed so it can fully resolve the hierarchy via the <Modification Functions()>.  Afterwards the
22 #         <Information Functions> will reflect the current state of the code.
23 #
24 #       - <Save()> must be called to commit any changes to the symbol table back to disk.
25 #
26 ###############################################################################
27
28 # This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
29 # Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
30 # Refer to License.txt for the complete details
31
32
33 use strict;
34 use integer;
35
36 use NaturalDocs::ClassHierarchy::Class;
37 use NaturalDocs::ClassHierarchy::File;
38
39 package NaturalDocs::ClassHierarchy;
40
41 use Encode qw(encode_utf8 decode_utf8);
42
43
44 ###############################################################################
45 # Group: Variables
46
47 #
48 #   handle: CLASS_HIERARCHY_FILEHANDLE
49 #   The file handle used with <ClassHierarchy.nd>.
50 #
51
52 #
53 #   hash: classes
54 #
55 #   A hash of all the classes.  The keys are the class <SymbolStrings> and the values are <NaturalDocs::ClassHierarchy::Classes>.
56 #
57 my %classes;
58
59 #
60 #   hash: files
61 #
62 #   A hash of the hierarchy information referenced by file.  The keys are the <FileNames>, and the values are
63 #   <NaturalDocs::ClassHierarchy::File>s.
64 #
65 my %files;
66
67 #
68 #   hash: parentReferences
69 #
70 #   A hash of all the parent reference strings and what they resolve to.  The keys are the <ReferenceStrings> and the values are
71 #   the class <SymbolStrings> that they resolve to.
72 #
73 my %parentReferences;
74
75 #
76 #   object: watchedFile
77 #
78 #   A <NaturalDocs::ClassHierarchy::File> object of the file being watched for changes.  This is compared to the version in <files>
79 #   to see if anything was changed since the last parse.
80 #
81 my $watchedFile;
82
83 #
84 #   string: watchedFileName
85 #
86 #   The <FileName> of the watched file, if any.  If there is no watched file, this will be undef.
87 #
88 my $watchedFileName;
89
90 #
91 #   bool: dontRebuildFiles
92 #
93 #   A bool to set if you don't want changes in the hierarchy to cause files to be rebuilt.
94 #
95 my $dontRebuildFiles;
96
97
98
99 ###############################################################################
100 # Group: Files
101
102
103 #
104 #   File: ClassHierarchy.nd
105 #
106 #   Stores the class hierarchy on disk.
107 #
108 #   Format:
109 #
110 #       > [BINARY_FORMAT]
111 #       > [VersionInt: app version]
112 #
113 #       The standard <BINARY_FORMAT> and <VersionInt> header.
114 #
115 #       > [SymbolString: class or undef to end]
116 #
117 #       Next we begin a class segment with its <SymbolString>.  These continue until the end of the file.  Only defined classes are
118 #       included.
119 #
120 #       > [UInt32: number of files]
121 #       > [UString16: file] [UString16: file] ...
122 #
123 #       Next there is the number of files that define that class.  It's a UInt32, which seems like overkill, but I could imagine every
124 #       file in a huge C++ project being under the same namespace, and thus contributing its own definition.  It's theoretically
125 #       possible.
126 #
127 #       Following the number is that many file names.  You must remember the index of each file, as they will be important later.
128 #       Indexes start at one because zero has a special meaning.
129 #
130 #       > [UInt8: number of parents]
131 #       > ( [ReferenceString (no type): parent]
132 #       >   [UInt32: file index] [UInt32: file index] ... [UInt32: 0] ) ...
133 #
134 #       Next there is the number of parents defined for this class.  For each one, we define a parent segment, which consists of
135 #       its <ReferenceString>, and then a zero-terminated string of indexes of the files that define that parent as part of that class.
136 #       The indexes start at one, and are into the list of files we saw previously.
137 #
138 #       Note that we do store class segments for classes without parents, but not for undefined classes.
139 #
140 #       This concludes a class segment.  These segments continue until an undef <SymbolString>.
141 #
142 #   See Also:
143 #
144 #       <File Format Conventions>
145 #
146 #   Revisions:
147 #
148 #               1.52:
149 #
150 #                       - Changed AString16s to UString16s.
151 #
152 #       1.22:
153 #
154 #           - Classes and parents switched from AString16s to <SymbolStrings> and <ReferenceStrings>.
155 #           - A ending undef <SymbolString> was added to the end.  Previously it stopped when the file ran out.
156 #
157 #       1.2:
158 #
159 #           - This file was introduced in 1.2.
160 #
161
162
163 ###############################################################################
164 # Group: File Functions
165
166
167 #
168 #   Function: Load
169 #
170 #   Loads the class hierarchy from disk.
171 #
172 sub Load
173     {
174     my ($self) = @_;
175
176     $dontRebuildFiles = 1;
177
178     my $fileIsOkay;
179     my $fileName = NaturalDocs::Project->DataFile('ClassHierarchy.nd');
180
181     if (!NaturalDocs::Settings->RebuildData() && open(CLASS_HIERARCHY_FILEHANDLE, '<' . $fileName))
182         {
183         # See if it's binary.
184         binmode(CLASS_HIERARCHY_FILEHANDLE);
185
186         my $firstChar;
187         read(CLASS_HIERARCHY_FILEHANDLE, $firstChar, 1);
188
189         if ($firstChar != ::BINARY_FORMAT())
190             {
191             close(CLASS_HIERARCHY_FILEHANDLE);
192             }
193         else
194             {
195             my $version = NaturalDocs::Version->FromBinaryFile(\*CLASS_HIERARCHY_FILEHANDLE);
196
197             # Last file format change was 1.52
198
199             if (NaturalDocs::Version->CheckFileFormat( $version, NaturalDocs::Version->FromString('1.52') ))
200                 {  $fileIsOkay = 1;  }
201             else
202                 {  close(CLASS_HIERARCHY_FILEHANDLE);  };
203             };
204         };
205
206
207     if (!$fileIsOkay)
208         {
209         NaturalDocs::Project->ReparseEverything();
210         }
211     else
212         {
213         my $raw;
214
215         for (;;)
216             {
217             # [SymbolString: class or undef to end]
218
219             my $class = NaturalDocs::SymbolString->FromBinaryFile(\*CLASS_HIERARCHY_FILEHANDLE);
220
221             if (!defined $class)
222                 {  last;  };
223
224             # [UInt32: number of files]
225
226             read(CLASS_HIERARCHY_FILEHANDLE, $raw, 4);
227             my $numberOfFiles = unpack('N', $raw);
228
229             my @files;
230
231             while ($numberOfFiles)
232                 {
233                 # [UString16: file]
234
235                 read(CLASS_HIERARCHY_FILEHANDLE, $raw, 2);
236                 my $fileLength = unpack('n', $raw);
237
238                 my $file;
239                 read(CLASS_HIERARCHY_FILEHANDLE, $file, $fileLength);
240                 $file = decode_utf8($file);
241
242                 push @files, $file;
243                 $self->AddClass($file, $class, NaturalDocs::Languages->LanguageOf($file)->Name());
244
245                 $numberOfFiles--;
246                 };
247
248             # [UInt8: number of parents]
249
250             read(CLASS_HIERARCHY_FILEHANDLE, $raw, 1);
251             my $numberOfParents = unpack('C', $raw);
252
253             while ($numberOfParents)
254                 {
255                 # [ReferenceString (no type): parent]
256
257                 my $parent = NaturalDocs::ReferenceString->FromBinaryFile(\*CLASS_HIERARCHY_FILEHANDLE,
258                                                                                                          ::BINARYREF_NOTYPE(),
259                                                                                                          ::REFERENCE_CH_PARENT());
260
261                 for (;;)
262                     {
263                     # [UInt32: file index or 0]
264
265                     read(CLASS_HIERARCHY_FILEHANDLE, $raw, 4);
266                     my $fileIndex = unpack('N', $raw);
267
268                     if ($fileIndex == 0)
269                         {  last;  }
270
271                     $self->AddParentReference( $files[$fileIndex - 1], $class, $parent );
272                     };
273
274                 $numberOfParents--;
275                 };
276             };
277
278         close(CLASS_HIERARCHY_FILEHANDLE);
279         };
280
281     $dontRebuildFiles = undef;
282     };
283
284
285 #
286 #   Function: Save
287 #
288 #   Saves the class hierarchy to disk.
289 #
290 sub Save
291     {
292     my ($self) = @_;
293
294     open (CLASS_HIERARCHY_FILEHANDLE, '>' . NaturalDocs::Project->DataFile('ClassHierarchy.nd'))
295         or die "Couldn't save " . NaturalDocs::Project->DataFile('ClassHierarchy.nd') . ".\n";
296
297     binmode(CLASS_HIERARCHY_FILEHANDLE);
298
299     print CLASS_HIERARCHY_FILEHANDLE '' . ::BINARY_FORMAT();
300     NaturalDocs::Version->ToBinaryFile(\*CLASS_HIERARCHY_FILEHANDLE, NaturalDocs::Settings->AppVersion());
301
302     while (my ($class, $classObject) = each %classes)
303         {
304         if ($classObject->IsDefined())
305             {
306             # [SymbolString: class or undef to end]
307
308             NaturalDocs::SymbolString->ToBinaryFile(\*CLASS_HIERARCHY_FILEHANDLE, $class);
309
310             # [UInt32: number of files]
311
312             my @definitions = $classObject->Definitions();
313             my %definitionIndexes;
314
315             print CLASS_HIERARCHY_FILEHANDLE pack('N', scalar @definitions);
316
317             for (my $i = 0; $i < scalar @definitions; $i++)
318                 {
319                 # [UString16: file]
320                 my $uDefinition = encode_utf8($definitions[$i]);
321                 print CLASS_HIERARCHY_FILEHANDLE pack('na*', length($uDefinition), $uDefinition);
322                 $definitionIndexes{$definitions[$i]} = $i + 1;
323                 };
324
325             # [UInt8: number of parents]
326
327             my @parents = $classObject->ParentReferences();
328             print CLASS_HIERARCHY_FILEHANDLE pack('C', scalar @parents);
329
330             foreach my $parent (@parents)
331                 {
332                 # [ReferenceString (no type): parent]
333
334                 NaturalDocs::ReferenceString->ToBinaryFile(\*CLASS_HIERARCHY_FILEHANDLE, $parent, ::BINARYREF_NOTYPE());
335
336                 # [UInt32: file index]
337
338                 my @parentDefinitions = $classObject->ParentReferenceDefinitions($parent);
339
340                 foreach my $parentDefinition (@parentDefinitions)
341                     {
342                     print CLASS_HIERARCHY_FILEHANDLE pack('N', $definitionIndexes{$parentDefinition});
343                     };
344
345                 # [UInt32: 0]
346                 print CLASS_HIERARCHY_FILEHANDLE pack('N', 0);
347                 };
348             };
349         };
350
351     # [SymbolString: class or undef to end]
352
353     NaturalDocs::SymbolString->ToBinaryFile(\*CLASS_HIERARCHY_FILEHANDLE, undef);
354
355     close(CLASS_HIERARCHY_FILEHANDLE);
356     };
357
358
359 #
360 #   Function: Purge
361 #
362 #   Purges the hierarchy of files that no longer have Natural Docs content.
363 #
364 sub Purge
365     {
366     my ($self) = @_;
367
368     my $filesToPurge = NaturalDocs::Project->FilesToPurge();
369
370     foreach my $file (keys %$filesToPurge)
371         {
372         $self->DeleteFile($file);
373         };
374     };
375
376
377
378 ###############################################################################
379 # Group: Interface Functions
380
381
382 #
383 #   Function: OnInterpretationChange
384 #
385 #   Called by <NaturalDocs::SymbolTable> whenever a class hierarchy reference's intepretation changes, meaning it switched
386 #   from one symbol to another.
387 #
388 #       reference - The <ReferenceString> whose current interpretation changed.
389 #
390 sub OnInterpretationChange #(reference)
391     {
392     my ($self, $reference) = @_;
393
394     if (NaturalDocs::ReferenceString->TypeOf($reference) == ::REFERENCE_CH_PARENT())
395         {
396         # The approach here is simply to completely delete the reference and readd it.  This is less than optimal efficiency, since it's
397         # being removed and added from %files too, even though that isn't required.  However, the simpler code is worth it
398         # considering this will only happen when a parent reference becomes defined or undefined, or on the rare languages (like C#)
399         # that allow relative parent references.
400
401         my $oldTargetSymbol = $parentReferences{$reference};
402         my $oldTargetObject = $classes{$oldTargetSymbol};
403
404         my @classesWithReferenceParent = $oldTargetObject->Children();
405
406         # Each entry is an arrayref of file names.  Indexes are the same as classesWithReferenceParent's.
407         my @filesDefiningReferenceParent;
408
409         foreach my $classWithReferenceParent (@classesWithReferenceParent)
410             {
411             my $fileList = [ $classes{$classWithReferenceParent}->ParentReferenceDefinitions($reference) ];
412             push @filesDefiningReferenceParent, $fileList;
413
414             foreach my $fileDefiningReferenceParent (@$fileList)
415                 {
416                 $self->DeleteParentReference($fileDefiningReferenceParent, $classWithReferenceParent, $reference);
417                 };
418             };
419
420
421         # This will force the reference to be reinterpreted on the next add.
422
423         delete $parentReferences{$reference};
424
425
426         # Now we can just readd it.
427
428         for (my $i = 0; $i < scalar @classesWithReferenceParent; $i++)
429             {
430             foreach my $file (@{$filesDefiningReferenceParent[$i]})
431                 {
432                 $self->AddParentReference($file, $classesWithReferenceParent[$i], $reference);
433                 };
434             };
435         };
436
437     # The only way for a REFERENCE_CH_CLASS reference to change is if the symbol is deleted.  That will be handled by
438     # <AnalyzeChanges()>, so we don't need to do anything here.
439     };
440
441
442 #
443 #   Function: OnTargetSymbolChange
444 #
445 #   Called by <NaturalDocs::SymbolTable> whenever a class hierarchy reference's target symbol changes, but the reference
446 #   still resolves to the same symbol.
447 #
448 #   Parameters:
449 #
450 #       reference - The <ReferenceString> that was affected by the change.
451 #
452 sub OnTargetSymbolChange #(reference)
453     {
454     my ($self, $reference) = @_;
455
456     my $type = NaturalDocs::ReferenceString->TypeOf($reference);
457     my $class;
458
459     if ($type == ::REFERENCE_CH_PARENT())
460         {  $class = $parentReferences{$reference};  }
461     else # ($type == ::REFERENCE_CH_CLASS())
462         {
463         # Class references are global absolute, so we can just yank the symbol.
464         (undef, $class, undef, undef, undef, undef) = NaturalDocs::ReferenceString->InformationOf($reference);
465         };
466
467     $self->RebuildFilesFor($class, 1, 0, 1);
468     };
469
470
471
472 ###############################################################################
473 # Group: Modification Functions
474
475
476 #
477 #   Function: AddClass
478 #
479 #   Adds a class to the hierarchy.
480 #
481 #   Parameters:
482 #
483 #       file - The <FileName> the class was defined in.
484 #       class - The class <SymbolString>.
485 #       languageName - The name of the language this applies to.
486 #
487 #   Note:
488 #
489 #       The file parameter must be defined when using this function externally.  It may be undef for internal use only.
490 #
491 sub AddClass #(file, class, languageName)
492     {
493     my ($self, $file, $class, $languageName) = @_;
494
495     if (!exists $classes{$class})
496         {
497         $classes{$class} = NaturalDocs::ClassHierarchy::Class->New();
498         NaturalDocs::SymbolTable->AddReference($self->ClassReferenceOf($class, $languageName), $file)
499         };
500
501     if (defined $file)
502         {
503         # If this was the first definition for this class...
504         if ($classes{$class}->AddDefinition($file))
505             {  $self->RebuildFilesFor($class, 1, 1, 1);  };
506
507         if (!exists $files{$file})
508             {  $files{$file} = NaturalDocs::ClassHierarchy::File->New();  };
509
510         $files{$file}->AddClass($class);
511
512         if (defined $watchedFileName)
513             {  $watchedFile->AddClass($class);  };
514         };
515     };
516
517
518 #
519 #   Function: AddParentReference
520 #
521 #   Adds a class-parent relationship to the hierarchy.  The classes will be created if they don't already exist.
522 #
523 #   Parameters:
524 #
525 #       file - The <FileName> the reference was defined in.
526 #       class - The class <SymbolString>.
527 #       symbol - The parent class <SymbolString>.
528 #       scope - The package <SymbolString> that the reference appeared in.
529 #       using - An arrayref of package <SymbolStrings> that the reference has access to via "using" statements.
530 #       resolvingFlags - Any <Resolving Flags> to be used when resolving the reference.
531 #
532 #   Alternate Parameters:
533 #
534 #       file - The <FileName> the reference was defined in.
535 #       class - The class <SymbolString>.
536 #       reference - The parent <ReferenceString>.
537 #
538 sub AddParentReference #(file, class, symbol, scope, using, resolvingFlags) or (file, class, reference)
539     {
540     my ($self, $file, $class, $symbol, $parentReference);
541
542     if (scalar @_ == 7)
543         {
544         my ($scope, $using, $resolvingFlags);
545         ($self, $file, $class, $symbol, $scope, $using, $resolvingFlags) = @_;
546
547         $parentReference = NaturalDocs::ReferenceString->MakeFrom(::REFERENCE_CH_PARENT(), $symbol,
548                                                                                                     NaturalDocs::Languages->LanguageOf($file)->Name(),
549                                                                                                     $scope, $using, $resolvingFlags);
550         }
551     else
552         {
553         ($self, $file, $class, $parentReference) = @_;
554         $symbol = (NaturalDocs::ReferenceString->InformationOf($parentReference))[1];
555         };
556
557
558     # In case it doesn't already exist.
559     $self->AddClass($file, $class);
560
561     my $parent;
562     if (exists $parentReferences{$parentReference})
563         {
564         $parent = $parentReferences{$parentReference};
565         }
566     else
567         {
568         NaturalDocs::SymbolTable->AddReference($parentReference, $file);
569         my $parentTarget = NaturalDocs::SymbolTable->References($parentReference);
570
571         if (defined $parentTarget)
572             {  $parent = $parentTarget->Symbol();  }
573         else
574             {  $parent = $symbol;  };
575
576         # In case it doesn't already exist.
577         $self->AddClass(undef, $parent);
578
579         $parentReferences{$parentReference} = $parent;
580         };
581
582
583     # If this defined a new parent...
584     if ($classes{$class}->AddParentReference($parentReference, $file, \%parentReferences))
585         {
586         $classes{$parent}->AddChild($class);
587
588         $self->RebuildFilesFor($class, 0, 1, 0);
589         $self->RebuildFilesFor($parent, 0, 1, 0);
590         };
591
592     $files{$file}->AddParentReference($class, $parentReference);
593
594     if (defined $watchedFileName)
595         {  $watchedFile->AddParentReference($class, $parentReference);  };
596     };
597
598
599 #
600 #   Function: WatchFileForChanges
601 #
602 #   Watches a file for changes, which can then be applied by <AnalyzeChanges()>.  Definitions are not deleted via a DeleteClass()
603 #   function.  Instead, a file is watched for changes, reparsed, and then a comparison is made to look for definitions that
604 #   disappeared and any other relevant changes.
605 #
606 #   Parameters:
607 #
608 #       file - The <FileName> to watch.
609 #
610 sub WatchFileForChanges #(file)
611     {
612     my ($self, $file) = @_;
613
614     $watchedFile = NaturalDocs::ClassHierarchy::File->New();
615     $watchedFileName = $file;
616     };
617
618
619 #
620 #   Function: AnalyzeChanges
621 #
622 #   Checks the watched file for any changes that occured since the last time is was parsed, and updates the hierarchy as
623 #   necessary.  Also sends any files that are affected to <NaturalDocs::Project->RebuildFile()>.
624 #
625 sub AnalyzeChanges
626     {
627     my ($self) = @_;
628
629     # If the file didn't have any classes before, and it still doesn't, it wont be in %files.
630     if (exists $files{$watchedFileName})
631         {
632         my @originalClasses = $files{$watchedFileName}->Classes();
633
634         foreach my $originalClass (@originalClasses)
635             {
636             # If the class isn't there the second time around...
637             if (!$watchedFile->HasClass($originalClass))
638                 {  $self->DeleteClass($watchedFileName, $originalClass);  }
639
640             else
641                 {
642                 my @originalParents = $files{$watchedFileName}->ParentReferencesOf($originalClass);
643
644                 foreach my $originalParent (@originalParents)
645                     {
646                     # If the parent reference wasn't there the second time around...
647                     if (!$watchedFile->HasParentReference($originalClass, $originalParent))
648                         {  $self->DeleteParentReference($watchedFileName, $originalClass, $originalParent);  };
649                     };
650                 };
651             };
652         };
653
654
655     $watchedFile = undef;
656     $watchedFileName = undef;
657     };
658
659
660
661 ###############################################################################
662 # Group: Information Functions
663
664
665 #
666 #   Function: ParentsOf
667 #   Returns a <SymbolString> array of the passed class' parents, or an empty array if none.  Note that not all of them may be
668 #   defined.
669 #
670 sub ParentsOf #(class)
671     {
672     my ($self, $class) = @_;
673
674     if (exists $classes{$class})
675         {  return $classes{$class}->Parents();  }
676     else
677         {  return ( );  };
678     };
679
680 #
681 #   Function: ChildrenOf
682 #   Returns a <SymbolString> array of the passed class' children, or an empty array if none.  Note that not all of them may be
683 #   defined.
684 #
685 sub ChildrenOf #(class)
686     {
687     my ($self, $class) = @_;
688
689     if (exists $classes{$class})
690         {  return $classes{$class}->Children();  }
691     else
692         {  return ( );  };
693     };
694
695
696
697 ###############################################################################
698 # Group: Support Functions
699
700
701 #
702 #   Function: DeleteFile
703 #
704 #   Deletes a file and everything defined in it.
705 #
706 #   Parameters:
707 #
708 #       file - The <FileName>.
709 #
710 sub DeleteFile #(file)
711     {
712     my ($self, $file) = @_;
713
714     if (!exists $files{$file})
715         {  return;  };
716
717     my @classes = $files{$file}->Classes();
718     foreach my $class (@classes)
719         {
720         $self->DeleteClass($file, $class);
721         };
722
723     delete $files{$file};
724     };
725
726 #
727 #   Function: DeleteClass
728 #
729 #   Deletes a class definition from a file.  Will also delete any parent references from this class and file.  Will rebuild any file
730 #   affected unless <dontRebuildFiles> is set.
731 #
732 #   Parameters:
733 #
734 #       file - The <FileName> that defines the class.
735 #       class - The class <SymbolString>.
736 #
737 sub DeleteClass #(file, class)
738     {
739     my ($self, $file, $class) = @_;
740
741     my @parents = $files{$file}->ParentReferencesOf($class);
742     foreach my $parent (@parents)
743         {
744         $self->DeleteParentReference($file, $class, $parent);
745         };
746
747     $files{$file}->DeleteClass($class);
748
749     # If we're deleting the last definition of this class.
750     if ($classes{$class}->DeleteDefinition($file))
751         {
752         if (!$classes{$class}->HasChildren())
753             {
754             delete $classes{$class};
755
756             if (!$dontRebuildFiles)
757                 {  NaturalDocs::Project->RebuildFile($file);  };
758             }
759         else
760             {  $self->RebuildFilesFor($class, 0, 1, 1);  };
761
762         };
763     };
764
765
766 #
767 #   Function: DeleteParentReference
768 #
769 #   Deletes a class' parent reference and returns whether it resulted in the loss of a parent class.  Will rebuild any file affected
770 #   unless <dontRebuildFiles> is set.
771 #
772 #   Parameters:
773 #
774 #       file - The <FileName> that defines the reference.
775 #       class - The class <SymbolString>.
776 #       reference - The parent <ReferenceString>.
777 #
778 #   Returns:
779 #
780 #       If the class lost a parent as a result of this, it will return its <SymbolString>.  It will return undef otherwise.
781 #
782 sub DeleteParentReference #(file, class, reference)
783     {
784     my ($self, $file, $class, $reference) = @_;
785
786     if (!exists $classes{$class})
787         {  return;  };
788
789     $files{$file}->DeleteParentReference($class, $reference);
790
791     my $deletedParent = $classes{$class}->DeleteParentReference($reference, $file, \%parentReferences);
792
793     if (defined $deletedParent)
794         {
795         my $deletedParentObject = $classes{$deletedParent};
796
797         $deletedParentObject->DeleteChild($class);
798
799         $self->RebuildFilesFor($deletedParent, 0, 1, 0);
800         $self->RebuildFilesFor($class, 0, 1, 0);
801
802         if (!$deletedParentObject->HasChildren() && !$deletedParentObject->IsDefined())
803             {
804             delete $classes{$deletedParent};
805             NaturalDocs::SymbolTable->DeleteReference(
806                 $self->ClassReferenceOf($class, NaturalDocs::Languages->LanguageOf($file)->Name()) );
807             };
808
809         return $deletedParent;
810         };
811
812     return undef;
813     };
814
815
816 #
817 #   Function: ClassReferenceOf
818 #
819 #   Returns the <REFERENCE_CH_CLASS> <ReferenceString> of the passed class <SymbolString>.
820 #
821 sub ClassReferenceOf #(class, languageName)
822     {
823     my ($self, $class, $languageName) = @_;
824
825     return NaturalDocs::ReferenceString->MakeFrom(::REFERENCE_CH_CLASS(), $class, $languageName, undef, undef,
826                                                                             ::RESOLVE_ABSOLUTE() | ::RESOLVE_NOPLURAL());
827     };
828
829
830 #
831 #   Function: RebuildFilesFor
832 #
833 #   Calls <NaturalDocs::Project->RebuildFile()> for every file defining the passed class, its parents, and/or its children.
834 #   Returns without doing anything if <dontRebuildFiles> is set.
835 #
836 #   Parameters:
837 #
838 #       class - The class <SymbolString>.
839 #       rebuildParents - Whether to rebuild the class' parents.
840 #       rebuildSelf - Whether to rebuild the class.
841 #       rebuildChildren - Whether to rebuild the class' children.
842 #
843 sub RebuildFilesFor #(class, rebuildParents, rebuildSelf, rebuildChildren)
844     {
845     my ($self, $class, $rebuildParents, $rebuildSelf, $rebuildChildren) = @_;
846
847     if ($dontRebuildFiles)
848         {  return;  };
849
850     my @classesToBuild;
851
852     if ($rebuildParents)
853         {  @classesToBuild = $classes{$class}->Parents();  };
854     if ($rebuildSelf)
855         {  push @classesToBuild, $class;  };
856     if ($rebuildChildren)
857         {  push @classesToBuild, $classes{$class}->Children();  };
858
859     foreach my $classToBuild (@classesToBuild)
860         {
861         my @definitions = $classes{$classToBuild}->Definitions();
862
863         foreach my $definition (@definitions)
864             {  NaturalDocs::Project->RebuildFile($definition);  };
865         };
866     };
867
868
869 1;