source: josm/trunk/tools/japicc/japi-compliance-checker.pl @ 11198

Last change on this file since 11198 was 10845, checked in by Don-vip, 7 years ago

see #13232 - use JAPICC to generate a compatibility report between optimized jar and normal one

File size: 310.9 KB
Line 
1#!/usr/bin/perl
2###########################################################################
3# Java API Compliance Checker (JAPICC) 1.8
4# A tool for checking backward compatibility of a Java library API
5#
6# Written by Andrey Ponomarenko
7#
8# Copyright (C) 2011 Institute for System Programming, RAS
9# Copyright (C) 2011-2016 Andrey Ponomarenko's ABI Laboratory
10#
11# PLATFORMS
12# =========
13#  Linux, FreeBSD, Mac OS X, MS Windows
14#
15# REQUIREMENTS
16# ============
17#  Linux, FreeBSD, Mac OS X
18#    - JDK or OpenJDK - development files (javap, javac)
19#    - Perl 5 (5.8 or newer)
20#
21#  MS Windows
22#    - JDK or OpenJDK (javap, javac)
23#    - Active Perl 5 (5.8 or newer)
24#
25# This program is free software: you can redistribute it and/or modify
26# it under the terms of the GNU General Public License or the GNU Lesser
27# General Public License as published by the Free Software Foundation.
28#
29# This program is distributed in the hope that it will be useful,
30# but WITHOUT ANY WARRANTY; without even the implied warranty of
31# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32# GNU General Public License for more details.
33#
34# You should have received a copy of the GNU General Public License
35# and the GNU Lesser General Public License along with this program.
36# If not, see <http://www.gnu.org/licenses/>.
37###########################################################################
38use Getopt::Long;
39Getopt::Long::Configure ("posix_default", "no_ignore_case", "permute");
40use File::Path qw(mkpath rmtree);
41use File::Temp qw(tempdir);
42use File::Copy qw(copy);
43use File::Spec::Functions qw(abs2rel);
44use Cwd qw(abs_path cwd);
45use Data::Dumper;
46use Digest::MD5 qw(md5_hex);
47use Config;
48
49my $TOOL_VERSION = "1.8";
50my $API_DUMP_VERSION = "2.0";
51my $API_DUMP_MAJOR = majorVersion($API_DUMP_VERSION);
52
53my ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, $CheckSeparately,
54$TestSystem, $DumpAPI, $ClassListPath, $ClientPath, $StrictCompat,
55$DumpVersion, $BinaryOnly, $TargetTitle, %TargetVersion, $SourceOnly,
56$ShortMode, $KeepInternal, $OutputReportPath, $BinaryReportPath,
57$SourceReportPath, $Debug, $Quick, $SortDump, $SkipDeprecated, $SkipClassesList,
58$ShowAccess, $AffectLimit, $JdkPath, $SkipInternalPackages, $HideTemplates,
59$HidePackages, $ShowPackages, $Minimal, $AnnotationsListPath,
60$SkipPackagesList, $OutputDumpPath, $AllAffected, $Compact,
61$SkipAnnotationsListPath, $ExternCss, $ExternJs, $SkipInternalTypes,
62$AddedAnnotations, $RemovedAnnotations, $CountMethods, %DepDump, $OldStyle);
63
64my $CmdName = get_filename($0);
65my $OSgroup = get_OSgroup();
66my $ORIG_DIR = cwd();
67my $TMP_DIR = tempdir(CLEANUP=>1);
68my $ARG_MAX = get_ARG_MAX();
69my $REPRODUCIBLE = 1;
70my $MD5_LEN = 8;
71
72my %OS_Archive = (
73    "windows"=>"zip",
74    "default"=>"tar.gz"
75);
76
77my %ERROR_CODE = (
78    # Compatible verdict
79    "Compatible"=>0,
80    "Success"=>0,
81    # Incompatible verdict
82    "Incompatible"=>1,
83    # Undifferentiated error code
84    "Error"=>2,
85    # System command is not found
86    "Not_Found"=>3,
87    # Cannot access input files
88    "Access_Error"=>4,
89    # Invalid input API dump
90    "Invalid_Dump"=>7,
91    # Incompatible version of API dump
92    "Dump_Version"=>8,
93    # Cannot find a module
94    "Module_Error"=>9
95);
96
97my %HomePage = (
98    "Dev"=>"https://github.com/lvc/japi-compliance-checker",
99    "Wiki"=>"http://ispras.linuxbase.org/index.php/Java_API_Compliance_Checker"
100);
101
102my $ShortUsage = "Java API Compliance Checker (JAPICC) $TOOL_VERSION
103A tool for checking backward compatibility of a Java library API
104Copyright (C) 2016 Andrey Ponomarenko's ABI Laboratory
105License: GNU LGPL or GNU GPL
106
107Usage: $CmdName [options]
108Example: $CmdName OLD.jar NEW.jar
109
110More info: $CmdName --help";
111
112if($#ARGV==-1)
113{
114    printMsg("INFO", $ShortUsage);
115    exit(0);
116}
117
118GetOptions("h|help!" => \$Help,
119  "v|version!" => \$ShowVersion,
120  "dumpversion!" => \$DumpVersion,
121# general options
122  "l|lib|library=s" => \$TargetLibraryName,
123  "d1|old|o=s" => \$Descriptor{1}{"Path"},
124  "d2|new|n=s" => \$Descriptor{2}{"Path"},
125# extra options
126  "client|app=s" => \$ClientPath,
127  "binary|bin!" => \$BinaryOnly,
128  "source|src!" => \$SourceOnly,
129  "v1|version1|vnum=s" => \$TargetVersion{1},
130  "v2|version2=s" => \$TargetVersion{2},
131  "s|strict!" => \$StrictCompat,
132  "keep-internal!" => \$KeepInternal,
133  "skip-internal-packages|skip-internal=s" => \$SkipInternalPackages,
134  "skip-internal-types=s" => \$SkipInternalTypes,
135  "dump|dump-api=s" => \$DumpAPI,
136  "classes-list=s" => \$ClassListPath,
137  "annotations-list=s" => \$AnnotationsListPath,
138  "skip-annotations-list=s" => \$SkipAnnotationsListPath,
139  "skip-deprecated!" => \$SkipDeprecated,
140  "skip-classes=s" => \$SkipClassesList,
141  "skip-packages=s" => \$SkipPackagesList,
142  "short" => \$ShortMode,
143  "dump-path=s" => \$OutputDumpPath,
144  "report-path=s" => \$OutputReportPath,
145  "bin-report-path=s" => \$BinaryReportPath,
146  "src-report-path=s" => \$SourceReportPath,
147  "quick!" => \$Quick,
148  "sort!" => \$SortDump,
149  "show-access!" => \$ShowAccess,
150  "limit-affected=s" => \$AffectLimit,
151  "hide-templates!" => \$HideTemplates,
152  "show-packages!" => \$ShowPackages,
153  "compact!" => \$Compact,
154  "added-annotations!" => \$AddedAnnotations,
155  "removed-annotations!" => \$RemovedAnnotations,
156  "count-methods=s" => \$CountMethods,
157  "dep1=s" => \$DepDump{1},
158  "dep2=s" => \$DepDump{2},
159  "old-style!" => \$OldStyle,
160# other options
161  "test!" => \$TestSystem,
162  "debug!" => \$Debug,
163  "title=s" => \$TargetTitle,
164  "jdk-path=s" => \$JdkPath,
165  "external-css=s" => \$ExternCss,
166  "external-js=s" => \$ExternJs,
167# deprecated
168  "minimal!" => \$Minimal,
169  "hide-packages!" => \$HidePackages,
170# private
171  "all-affected!" => \$AllAffected
172) or ERR_MESSAGE();
173
174if(@ARGV)
175{ 
176    if($#ARGV==1)
177    { # japi-compliance-checker OLD.jar NEW.jar
178        $Descriptor{1}{"Path"} = $ARGV[0];
179        $Descriptor{2}{"Path"} = $ARGV[1];
180    }
181    else {
182        ERR_MESSAGE();
183    }
184}
185
186sub ERR_MESSAGE()
187{
188    printMsg("INFO", "\n".$ShortUsage);
189    exit($ERROR_CODE{"Error"});
190}
191
192my $AR_EXT = getAR_EXT($OSgroup);
193
194my $HelpMessage="
195NAME:
196  Java API Compliance Checker ($CmdName)
197  Check backward compatibility of a Java library API
198
199DESCRIPTION:
200  Java API Compliance Checker (JAPICC) is a tool for checking backward
201  binary/source compatibility of a Java library API. The tool checks classes
202  declarations of old and new versions and analyzes changes that may break
203  compatibility: removed class members, added abstract methods, etc. Breakage
204  of the binary compatibility may result in crashing or incorrect behavior of
205  existing clients built with an old version of a library if they run with a
206  new one. Breakage of the source compatibility may result in recompilation
207  errors with a new library version.
208
209  JAPICC is intended for library developers and operating system maintainers
210  who are interested in ensuring backward compatibility (i.e. allow old clients
211  to run or to be recompiled with a new version of a library).
212
213  This tool is free software: you can redistribute it and/or modify it
214  under the terms of the GNU LGPL or GNU GPL.
215
216USAGE:
217  $CmdName [options]
218
219EXAMPLE:
220  $CmdName OLD.jar NEW.jar
221    OR
222  $CmdName -lib NAME -old OLD.xml -new NEW.xml
223  OLD.xml and NEW.xml are XML-descriptors:
224
225    <version>
226        1.0
227    </version>
228   
229    <archives>
230        /path1/to/JAR(s)/
231        /path2/to/JAR(s)/
232        ...
233    </archives>
234
235INFORMATION OPTIONS:
236  -h|-help
237      Print this help.
238
239  -v|-version
240      Print version information.
241
242  -dumpversion
243      Print the tool version ($TOOL_VERSION) and don't do anything else.
244
245GENERAL OPTIONS:
246  -l|-lib|-library NAME
247      Library name (without version).
248
249  -d1|-old|-o PATH
250      Descriptor of 1st (old) library version.
251      It may be one of the following:
252     
253         1. Java ARchive (*.jar)
254         2. XML-descriptor (VERSION.xml file):
255
256              <version>
257                  1.0
258              </version>
259             
260              <archives>
261                  /path1/to/JAR(s)/
262                  /path2/to/JAR(s)/
263                   ...
264              </archives>
265
266                 ...
267         
268         3. API dump generated by -dump option
269
270      If you are using 1, 4-6 descriptor types then you should
271      specify version numbers with -v1 and -v2 options too.
272
273      If you are using *.jar as a descriptor then the tool will try to
274      get implementation version from MANIFEST.MF file.
275
276  -d2|-new|-n PATH
277      Descriptor of 2nd (new) library version.
278
279EXTRA OPTIONS:
280  -client|-app PATH
281      This option allows to specify the client Java ARchive that should be
282      checked for portability to the new library version.
283     
284  -binary|-bin
285      Show \"Binary\" compatibility problems only.
286      Generate report to \"bin_compat_report.html\".
287     
288  -source|-src
289      Show \"Source\" compatibility problems only.
290      Generate report to \"src_compat_report.html\".
291     
292  -v1|-version1 NUM
293      Specify 1st API version outside the descriptor. This option is needed
294      if you have prefered an alternative descriptor type (see -d1 option).
295     
296      In general case you should specify it in the XML descriptor:
297          <version>
298              VERSION
299          </version>
300
301  -v2|-version2 NUM
302      Specify 2nd library version outside the descriptor.
303
304  -vnum NUM
305      Specify the library version in the generated API dump.
306
307  -s|-strict
308      Treat all API compatibility warnings as problems.
309
310  -keep-internal
311      Do not skip checking of these packages:
312        *impl*
313        *internal*
314        *examples*
315 
316  -skip-internal-packages PATTERN
317      Do not check packages matched by the pattern.
318 
319  -skip-internal-types PATTERN
320      Do not check types (classes and interfaces) matched by the pattern.
321 
322  -dump|-dump-api PATH
323      Dump library API to gzipped TXT format file. You can transfer it
324      anywhere and pass instead of the descriptor. Also it may be used
325      for debugging the tool. Compatible dump versions: $API_DUMP_MAJOR.0<=V<=$API_DUMP_VERSION
326     
327  -classes-list PATH
328      This option allows to specify a file with a list
329      of classes that should be checked, other classes will not be checked.
330 
331  -annotations-list PATH
332      Specifies a file with a list of annotations. The tool will check only
333      classes annotated by the annotations from the list. Other classes
334      will not be checked.
335 
336  -skip-annotations-list PATH
337      Skip checking of classes annotated by the annotations in the list.
338     
339  -skip-deprecated
340      Skip analysis of deprecated methods and classes.
341     
342  -skip-classes PATH
343      This option allows to specify a file with a list
344      of classes that should not be checked.
345     
346  -skip-packages PATH
347      This option allows to specify a file with a list
348      of packages that should not be checked.
349     
350  -short
351      Do not list added/removed methods.
352 
353  -dump-path PATH
354      Specify a *.api.$AR_EXT or *.api file path where to generate an API dump.
355      Default:
356          abi_dumps/LIB_NAME/LIB_NAME_VERSION.api.$AR_EXT
357
358  -report-path PATH
359      Path to compatibility report.
360      Default:
361          compat_reports/LIB_NAME/V1_to_V2/compat_report.html
362
363  -bin-report-path PATH
364      Path to \"Binary\" compatibility report.
365      Default:
366          compat_reports/LIB_NAME/V1_to_V2/bin_compat_report.html
367
368  -src-report-path PATH
369      Path to \"Source\" compatibility report.
370      Default:
371          compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
372
373  -quick
374      Quick analysis.
375      Disabled:
376        - analysis of method parameter names
377        - analysis of class field values
378        - analysis of usage of added abstract methods
379        - distinction of deprecated methods and classes
380
381  -sort
382      Enable sorting of data in API dumps.
383     
384  -show-access
385      Show access level of non-public methods listed in the report.
386     
387  -hide-templates
388      Hide template parameters in the report.
389 
390  -hide-packages
391  -minimal
392      Do nothing.
393 
394  -show-packages
395      Show package names in the report.
396     
397  -limit-affected LIMIT
398      The maximum number of affected methods listed under the description
399      of the changed type in the report.
400 
401  -compact
402      Try to simplify formatting and reduce size of the report (for a big
403      set of changes).
404 
405  -added-annotations
406      Apply filters by annotations only to new version of the library.
407 
408  -removed-annotations
409      Apply filters by annotations only to old version of the library.
410 
411  -count-methods PATH
412      Count total public methods in the API dump.
413 
414  -dep1 PATH
415  -dep2 PATH
416      Path to the API dump of the required dependency archive. It will
417      be used to resolve overwritten methods and more.
418 
419  -old-style
420      Generate old-style report.
421
422OTHER OPTIONS:
423  -test
424      Run internal tests. Create two incompatible versions of a sample library
425      and run the tool to check them for compatibility. This option allows to
426      check if the tool works correctly in the current environment.
427
428  -debug
429      Debugging mode. Print debug info on the screen. Save intermediate
430      analysis stages in the debug directory:
431          debug/LIB_NAME/VER/
432
433      Also consider using -dump option for debugging the tool.
434
435  -title NAME
436      Change library name in the report title to NAME. By default
437      will be displayed a name specified by -l option.
438
439  -jdk-path PATH
440      Path to the JDK install tree (e.g. /usr/lib/jvm/java-7-openjdk-amd64).
441
442  -external-css PATH
443      Generate CSS styles file to PATH. This helps to save space when
444      generating thousands of reports.
445
446  -external-js PATH
447      Generate JS script file to PATH.
448
449REPORT:
450    Compatibility report will be generated to:
451        compat_reports/LIB_NAME/V1_to_V2/compat_report.html
452
453EXIT CODES:
454    0 - Compatible. The tool has run without any errors.
455    non-zero - Incompatible or the tool has run with errors.
456
457MORE INFORMATION:
458    ".$HomePage{"Wiki"}."
459    ".$HomePage{"Dev"}."\n\n";
460
461sub HELP_MESSAGE()
462{ # -help
463    printMsg("INFO", $HelpMessage."\n");
464}
465
466my %TypeProblems_Kind=(
467    "Binary"=>{
468        "NonAbstract_Class_Added_Abstract_Method"=>"High",
469        "Abstract_Class_Added_Abstract_Method"=>"Safe",
470        "Abstract_Class_Added_Abstract_Method_Invoked_By_Others"=>"Medium",
471        "Class_Removed_Abstract_Method"=>"High",
472        "Interface_Added_Abstract_Method"=>"Safe",
473        "Interface_Added_Abstract_Method_Invoked_By_Others"=>"Medium",
474        "Interface_Removed_Abstract_Method"=>"High",
475        "Removed_Class"=>"High",
476        "Removed_Interface"=>"High",
477        "Class_Method_Became_Abstract"=>"High",
478        "Class_Method_Became_NonAbstract"=>"Low",
479        "Interface_Method_Became_NonDefault"=>"High",
480        "Interface_Method_Became_Default"=>"Safe",
481        "Added_Super_Class"=>"Low",
482        "Abstract_Class_Added_Super_Abstract_Class"=>"Safe",
483        "Abstract_Class_Added_Super_Abstract_Class_Invoked_By_Others"=>"Medium",
484        "Removed_Super_Class"=>"Medium",
485        "Changed_Super_Class"=>"Medium",
486        "Abstract_Class_Added_Super_Interface"=>"Safe",
487        "Abstract_Class_Added_Super_Interface_Invoked_By_Others"=>"Medium",
488        "Abstract_Class_Added_Super_Interface_With_Implemented_Methods"=>"Safe",
489        "Class_Removed_Super_Interface"=>"High",
490        "Interface_Added_Super_Interface"=>"Safe",
491        "Interface_Added_Super_Interface_Used_By_Others"=>"Medium",
492        "Interface_Added_Super_Constant_Interface"=>"Low",
493        "Interface_Added_Super_Interface_With_Implemented_Methods"=>"Safe",
494        "Interface_Removed_Super_Interface"=>"High",
495        "Interface_Removed_Super_Constant_Interface"=>"Safe",
496        "Class_Became_Interface"=>"High",
497        "Interface_Became_Class"=>"High",
498        "Class_Became_Final"=>"High",
499        "Class_Became_Abstract"=>"High",
500        "Class_Added_Field"=>"Safe",
501        "Interface_Added_Field"=>"Safe",
502        "Removed_NonConstant_Field"=>"High",
503        "Removed_Constant_Field"=>"Low",
504        "Renamed_Field"=>"High",
505        "Renamed_Constant_Field"=>"Low",
506        "Changed_Field_Type"=>"High",
507        "Changed_Field_Access"=>"High",
508        "Changed_Final_Field_Value"=>"Medium",
509        "Changed_Final_Version_Field_Value"=>"Low",
510        "Field_Became_Final"=>"Medium",
511        "Field_Became_NonFinal"=>"Low",
512        "NonConstant_Field_Became_Static"=>"High",
513        "NonConstant_Field_Became_NonStatic"=>"High",
514        "Class_Overridden_Method"=>"Low",
515        "Class_Method_Moved_Up_Hierarchy"=>"Low"
516    },
517    "Source"=>{
518        "NonAbstract_Class_Added_Abstract_Method"=>"High",
519        "Abstract_Class_Added_Abstract_Method"=>"High",
520        "Abstract_Class_Added_Abstract_Method_Invoked_By_Others"=>"High",
521        "Interface_Added_Abstract_Method"=>"High",
522        "Interface_Added_Abstract_Method_Invoked_By_Others"=>"High",
523        "Class_Removed_Abstract_Method"=>"High",
524        "Interface_Removed_Abstract_Method"=>"High",
525        "Removed_Class"=>"High",
526        "Removed_Interface"=>"High",
527        "Class_Method_Became_Abstract"=>"High",
528        "Class_Method_Became_NonAbstract"=>"Safe",
529        "Interface_Method_Became_NonDefault"=>"High",
530        "Interface_Method_Became_Default"=>"Safe",
531        "Added_Super_Class"=>"Low",
532        "Abstract_Class_Added_Super_Abstract_Class"=>"High",
533        "Abstract_Class_Added_Super_Abstract_Class_Invoked_By_Others"=>"High",
534        "Removed_Super_Class"=>"Medium",
535        "Changed_Super_Class"=>"Medium",
536        "Abstract_Class_Added_Super_Interface"=>"High",
537        "Abstract_Class_Added_Super_Interface_Invoked_By_Others"=>"High",
538        "Abstract_Class_Added_Super_Interface_With_Implemented_Methods"=>"Safe",
539        "Class_Removed_Super_Interface"=>"High",
540        "Interface_Added_Super_Interface"=>"High",
541        "Interface_Added_Super_Interface_Used_By_Others"=>"High",
542        "Interface_Added_Super_Constant_Interface"=>"Low",
543        "Interface_Added_Super_Interface_With_Implemented_Methods"=>"Safe",
544        "Interface_Removed_Super_Interface"=>"High",
545        "Interface_Removed_Super_Constant_Interface"=>"High",
546        "Class_Became_Interface"=>"High",
547        "Interface_Became_Class"=>"High",
548        "Class_Became_Final"=>"High",
549        "Class_Became_Abstract"=>"High",
550        "Class_Added_Field"=>"Safe",
551        "Interface_Added_Field"=>"Safe",
552        "Removed_NonConstant_Field"=>"High",
553        "Removed_Constant_Field"=>"High",
554        "Renamed_Field"=>"High",
555        "Renamed_Constant_Field"=>"High",
556        "Changed_Field_Type"=>"High",
557        "Changed_Field_Access"=>"High",
558        "Field_Became_Final"=>"Medium",
559        "Constant_Field_Became_NonStatic"=>"High",
560        "NonConstant_Field_Became_NonStatic"=>"High",
561        "Removed_Annotation"=>"High"
562    }
563);
564
565my %MethodProblems_Kind=(
566    "Binary"=>{
567        "Added_Method"=>"Safe",
568        "Removed_Method"=>"High",
569        "Method_Became_Static"=>"High",
570        "Method_Became_NonStatic"=>"High",
571        "NonStatic_Method_Became_Final"=>"Medium",
572        "Changed_Method_Access"=>"High",
573        "Method_Became_Synchronized"=>"Low",
574        "Method_Became_NonSynchronized"=>"Low",
575        "Method_Became_Abstract"=>"High",
576        "Method_Became_NonAbstract"=>"Low",
577        "Method_Became_NonDefault"=>"High",
578        "Method_Became_Default"=>"Safe",
579        "NonAbstract_Method_Added_Checked_Exception"=>"Low",
580        "NonAbstract_Method_Removed_Checked_Exception"=>"Low",
581        "Added_Unchecked_Exception"=>"Low",
582        "Removed_Unchecked_Exception"=>"Low",
583        "Variable_Arity_To_Array"=>"Low",# not implemented yet
584        "Changed_Method_Return_From_Void"=>"High"
585    },
586    "Source"=>{
587        "Added_Method"=>"Safe",
588        "Removed_Method"=>"High",
589        "Method_Became_Static"=>"Low",
590        "Method_Became_NonStatic"=>"High",
591        "Static_Method_Became_Final"=>"Medium",
592        "NonStatic_Method_Became_Final"=>"Medium",
593        "Changed_Method_Access"=>"High",
594        "Method_Became_Abstract"=>"High",
595        "Method_Became_NonAbstract"=>"Safe",
596        "Method_Became_NonDefault"=>"High",
597        "Method_Became_Default"=>"Safe",
598        "Abstract_Method_Added_Checked_Exception"=>"Medium",
599        "NonAbstract_Method_Added_Checked_Exception"=>"Medium",
600        "Abstract_Method_Removed_Checked_Exception"=>"Medium",
601        "NonAbstract_Method_Removed_Checked_Exception"=>"Medium"
602    }
603);
604
605my %KnownRuntimeExceptions= map {$_=>1} (
606# To separate checked- and unchecked- exceptions
607    "java.lang.AnnotationTypeMismatchException",
608    "java.lang.ArithmeticException",
609    "java.lang.ArrayStoreException",
610    "java.lang.BufferOverflowException",
611    "java.lang.BufferUnderflowException",
612    "java.lang.CannotRedoException",
613    "java.lang.CannotUndoException",
614    "java.lang.ClassCastException",
615    "java.lang.CMMException",
616    "java.lang.ConcurrentModificationException",
617    "java.lang.DataBindingException",
618    "java.lang.DOMException",
619    "java.lang.EmptyStackException",
620    "java.lang.EnumConstantNotPresentException",
621    "java.lang.EventException",
622    "java.lang.IllegalArgumentException",
623    "java.lang.IllegalMonitorStateException",
624    "java.lang.IllegalPathStateException",
625    "java.lang.IllegalStateException",
626    "java.lang.ImagingOpException",
627    "java.lang.IncompleteAnnotationException",
628    "java.lang.IndexOutOfBoundsException",
629    "java.lang.JMRuntimeException",
630    "java.lang.LSException",
631    "java.lang.MalformedParameterizedTypeException",
632    "java.lang.MirroredTypeException",
633    "java.lang.MirroredTypesException",
634    "java.lang.MissingResourceException",
635    "java.lang.NegativeArraySizeException",
636    "java.lang.NoSuchElementException",
637    "java.lang.NoSuchMechanismException",
638    "java.lang.NullPointerException",
639    "java.lang.ProfileDataException",
640    "java.lang.ProviderException",
641    "java.lang.RasterFormatException",
642    "java.lang.RejectedExecutionException",
643    "java.lang.SecurityException",
644    "java.lang.SystemException",
645    "java.lang.TypeConstraintException",
646    "java.lang.TypeNotPresentException",
647    "java.lang.UndeclaredThrowableException",
648    "java.lang.UnknownAnnotationValueException",
649    "java.lang.UnknownElementException",
650    "java.lang.UnknownEntityException",
651    "java.lang.UnknownTypeException",
652    "java.lang.UnmodifiableSetException",
653    "java.lang.UnsupportedOperationException",
654    "java.lang.WebServiceException",
655    "java.lang.WrongMethodTypeException"
656);
657
658my %Slash_Type=(
659    "default"=>"/",
660    "windows"=>"\\"
661);
662
663my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
664
665my %OS_AddPath=(
666# this data needed if tool can't detect it automatically
667"macos"=>{
668    "bin"=>{"/Developer/usr/bin"=>1}},
669"beos"=>{
670    "bin"=>{"/boot/common/bin"=>1,"/boot/system/bin"=>1,"/boot/develop/abi"=>1}}
671);
672
673#Global variables
674my %RESULT;
675my $ExtractCounter = 0;
676my %Cache;
677my $TOP_REF = "<a class='top_ref' href='#Top'>to the top</a>";
678my %DEBUG_PATH;
679
680#Types
681my %TypeInfo;
682my $TYPE_ID = 0;
683my %CheckedTypes;
684my %TName_Tid;
685my %Class_Constructed;
686
687#Classes
688my %ClassList_User;
689my %UsedMethods_Client;
690my %UsedFields_Client;
691my %UsedClasses_Client;
692my %LibArchives;
693my %Class_Methods;
694my %Class_AbstractMethods;
695my %Class_Fields;
696my %MethodUsed;
697my %ClassMethod_AddedUsed;
698# my %FieldUsed;
699
700#java.lang.Object
701my %JavaObjectMethod = (
702   
703    "java/lang/Object.clone:()Ljava/lang/Object;" => 1,
704    "java/lang/Object.equals:(Ljava/lang/Object;)Z" => 1,
705    "java/lang/Object.finalize:()V" => 1,
706    "java/lang/Object.getClass:()Ljava/lang/Class;" => 1,
707    "java/lang/Object.hashCode:()I" => 1,
708    "java/lang/Object.notify:()V" => 1,
709    "java/lang/Object.notifyAll:()V" => 1,
710    "java/lang/Object.toString:()Ljava/lang/String;" => 1,
711    "java/lang/Object.wait:()V" => 1,
712    "java/lang/Object.wait:(J)V" => 1,
713    "java/lang/Object.wait:(JI)V" => 1
714);
715
716#Annotations
717my %AnnotationList_User;
718my %SkipAnnotationList_User;
719
720#Methods
721my %CheckedMethods;
722my %tr_name;
723
724#Merging
725my %MethodInfo;
726my $Version;
727my %AddedMethod_Abstract;
728my %RemovedMethod_Abstract;
729my %ChangedReturnFromVoid;
730my %SkipClasses;
731my %SkipPackages;
732my %KeepPackages;
733my %SkippedPackage;
734
735#Report
736my %TypeChanges;
737
738#Recursion locks
739my @RecurSymlink;
740my @RecurTypes;
741
742#System
743my %SystemPaths;
744my %DefaultBinPaths;
745
746#Problem descriptions
747my %CompatProblems;
748my %TotalAffected;
749
750#Speedup
751my %TypeProblemsIndex;
752
753#Rerort
754my $ContentID = 1;
755my $ContentSpanStart = "<span class=\"section\" onclick=\"sC(this, 'CONTENT_ID')\">\n";
756my $ContentSpanStart_Affected = "<span class=\"sect_aff\" onclick=\"sC(this, 'CONTENT_ID')\">\n";
757my $ContentSpanEnd = "</span>\n";
758my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
759my $ContentDivEnd = "</div>\n";
760my $Content_Counter = 0;
761
762#Modes
763my $JoinReport = 1;
764my $DoubleReport = 0;
765
766sub get_CmdPath($)
767{
768    my $Name = $_[0];
769    return "" if(not $Name);
770    if(defined $Cache{"get_CmdPath"}{$Name}) {
771        return $Cache{"get_CmdPath"}{$Name};
772    }
773    my $Path = search_Cmd($Name);
774    if(not $Path and $OSgroup eq "windows")
775    { # search for *.exe file
776        $Path=search_Cmd($Name.".exe");
777    }
778    if (not $Path) {
779        $Path=search_Cmd_Path($Name);
780    }
781    if($Path=~/\s/) {
782        $Path = "\"".$Path."\"";
783    }
784    return ($Cache{"get_CmdPath"}{$Name} = $Path);
785}
786
787sub search_Cmd($)
788{
789    my $Name = $_[0];
790    return "" if(not $Name);
791    if(defined $Cache{"search_Cmd"}{$Name}) {
792        return $Cache{"search_Cmd"}{$Name};
793    }
794    if(defined $JdkPath)
795    {
796        if(-x $JdkPath."/".$Name) {
797            return ($Cache{"search_Cmd"}{$Name} = $JdkPath."/".$Name);
798        }
799       
800        if(-x $JdkPath."/bin/".$Name) {
801            return ($Cache{"search_Cmd"}{$Name} = $JdkPath."/bin/".$Name);
802        }
803    }
804    if(my $DefaultPath = get_CmdPath_Default($Name)) {
805        return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
806    }
807    return ($Cache{"search_Cmd"}{$Name} = "");
808}
809
810sub search_Cmd_Path($)
811{
812    my $Name = $_[0];
813    return "" if(not $Name);
814   
815    if(defined $Cache{"search_Cmd_Path"}{$Name}) {
816        return $Cache{"search_Cmd_Path"}{$Name};
817    }
818   
819    if(defined $SystemPaths{"bin"})
820    {
821        foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
822        {
823            if(-f $Path."/".$Name or -f $Path."/".$Name.".exe") {
824                return ($Cache{"search_Cmd_Path"}{$Name} = joinPath($Path,$Name));
825            }
826        }
827    }
828
829    return ($Cache{"search_Cmd_Path"}{$Name} = "");
830}
831
832sub get_CmdPath_Default($)
833{ # search in PATH
834    return "" if(not $_[0]);
835    if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) {
836        return $Cache{"get_CmdPath_Default"}{$_[0]};
837    }
838    return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0]));
839}
840
841sub get_CmdPath_Default_I($)
842{ # search in PATH
843    my $Name = $_[0];
844    if($Name=~/find/)
845    { # special case: search for "find" utility
846        if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) {
847            return "find";
848        }
849    }
850    if(get_version($Name)) {
851        return $Name;
852    }
853    if($OSgroup eq "windows")
854    {
855        if(`$Name /? 2>\"$TMP_DIR/null\"`) {
856            return $Name;
857        }
858    }
859    if($Name!~/which/)
860    {
861        if(my $WhichCmd = get_CmdPath("which"))
862        {
863            if(`$WhichCmd $Name 2>\"$TMP_DIR/null\"`) {
864                return $Name;
865            }
866        }
867    }
868    foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
869    {
870        if(-f $Path."/".$Name) {
871            return joinPath($Path,$Name);
872        }
873    }
874    return "";
875}
876
877sub showPos($)
878{
879    my $Number = $_[0];
880    if(not $Number) {
881        $Number = 1;
882    }
883    else {
884        $Number = int($Number)+1;
885    }
886    if($Number>3) {
887        return $Number."th";
888    }
889    elsif($Number==1) {
890        return "1st";
891    }
892    elsif($Number==2) {
893        return "2nd";
894    }
895    elsif($Number==3) {
896        return "3rd";
897    }
898    else {
899        return $Number;
900    }
901}
902
903sub getAR_EXT($)
904{
905    my $Target = $_[0];
906    if(my $Ext = $OS_Archive{$Target}) {
907        return $Ext;
908    }
909    return $OS_Archive{"default"};
910}
911
912sub readDescriptor($$)
913{
914    my ($LibVersion, $Content) = @_;
915    return if(not $LibVersion);
916    my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
917    if(not $Content) {
918        exitStatus("Error", "$DName is empty");
919    }
920    if($Content!~/\</) {
921        exitStatus("Error", "descriptor should be one of the following:\n  Java ARchive, XML descriptor, gzipped API dump or directory with Java ARchives.");
922    }
923    $Content=~s/\/\*(.|\n)+?\*\///g;
924    $Content=~s/<\!--(.|\n)+?-->//g;
925    $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
926    $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion} if($TargetVersion{$LibVersion});
927    if($Descriptor{$LibVersion}{"Version"} eq "") {
928        exitStatus("Error", "version in the $DName is not specified (<version> section)");
929    }
930   
931    my $DArchives = parseTag(\$Content, "archives");
932    if(not $DArchives){
933        exitStatus("Error", "Java ARchives in the $DName are not specified (<archive> section)");
934    }
935    else
936    {# append the descriptor Java ARchives list
937        if($Descriptor{$LibVersion}{"Archives"}) {
938            $Descriptor{$LibVersion}{"Archives"} .= "\n".$DArchives;
939        }
940        else {
941            $Descriptor{$LibVersion}{"Archives"} = $DArchives;
942        }
943        foreach my $Path (split(/\s*\n\s*/, $DArchives))
944        {
945            if(not -e $Path) {
946                exitStatus("Access_Error", "can't access \'$Path\'");
947            }
948        }
949    }
950    foreach my $Package (split(/\s*\n\s*/, parseTag(\$Content, "skip_packages"))) {
951        $SkipPackages{$LibVersion}{$Package} = 1;
952    }
953    foreach my $Package (split(/\s*\n\s*/, parseTag(\$Content, "packages"))) {
954        $KeepPackages{$LibVersion}{$Package} = 1;
955    }
956}
957
958sub parseTag($$)
959{
960    my ($CodeRef, $Tag) = @_;
961    return "" if(not $CodeRef or not ${$CodeRef} or not $Tag);
962    if(${$CodeRef}=~s/\<\Q$Tag\E\>((.|\n)+?)\<\/\Q$Tag\E\>//)
963    {
964        my $Content = $1;
965        $Content=~s/(\A\s+|\s+\Z)//g;
966        return $Content;
967    }
968    else {
969        return "";
970    }
971}
972
973sub ignore_path($$)
974{
975    my ($Path, $Prefix) = @_;
976    return 1 if(not $Path or not -e $Path
977    or not $Prefix or not -e $Prefix);
978    return 1 if($Path=~/\~\Z/);# skipping system backup files
979    # skipping hidden .svn, .git, .bzr, .hg and CVS directories
980    return 1 if(cut_path_prefix($Path, $Prefix)=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/);
981    return 0;
982}
983
984sub cut_path_prefix($$)
985{
986    my ($Path, $Prefix) = @_;
987    $Prefix=~s/[\/\\]+\Z//;
988    $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
989    return $Path;
990}
991
992sub get_filename($)
993{ # much faster than basename() from File::Basename module
994    if(defined $Cache{"get_filename"}{$_[0]}) {
995        return $Cache{"get_filename"}{$_[0]};
996    }
997    if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
998        return ($Cache{"get_filename"}{$_[0]}=$1);
999    }
1000    return ($Cache{"get_filename"}{$_[0]}="");
1001}
1002
1003sub get_dirname($)
1004{ # much faster than dirname() from File::Basename module
1005    if(defined $Cache{"get_dirname"}{$_[0]}) {
1006        return $Cache{"get_dirname"}{$_[0]};
1007    }
1008    if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
1009        return ($Cache{"get_dirname"}{$_[0]}=$1);
1010    }
1011    return ($Cache{"get_dirname"}{$_[0]}="");
1012}
1013
1014sub separate_path($) {
1015    return (get_dirname($_[0]), get_filename($_[0]));
1016}
1017
1018sub joinPath($$)
1019{
1020    return join($SLASH, @_);
1021}
1022
1023sub get_abs_path($)
1024{ # abs_path() should NOT be called for absolute inputs
1025  # because it can change them
1026    my $Path = $_[0];
1027    if(not is_abs($Path)) {
1028        $Path = abs_path($Path);
1029    }
1030    return $Path;
1031}
1032
1033sub is_abs($) {
1034    return ($_[0]=~/\A(\/|\w+:[\/\\])/);
1035}
1036
1037sub cmd_find($$$$)
1038{
1039    my ($Path, $Type, $Name, $MaxDepth) = @_;
1040    return () if(not $Path or not -e $Path);
1041    if($OSgroup eq "windows")
1042    {
1043        my $DirCmd = get_CmdPath("dir");
1044        if(not $DirCmd) {
1045            exitStatus("Not_Found", "can't find \"dir\" command");
1046        }
1047        $Path=~s/[\\]+\Z//;
1048        $Path = get_abs_path($Path);
1049        my $Cmd = $DirCmd." \"$Path\" /B /O";
1050        if($MaxDepth!=1) {
1051            $Cmd .= " /S";
1052        }
1053        if($Type eq "d") {
1054            $Cmd .= " /AD";
1055        }
1056        my @Files = ();
1057        if($Name)
1058        { # FIXME: how to search file names in MS shell?
1059            $Name=~s/\*/.*/g if($Name!~/\]/);
1060            foreach my $File (split(/\n/, `$Cmd`))
1061            {
1062                if($File=~/$Name\Z/i) {
1063                    push(@Files, $File);   
1064                }
1065            }
1066        }
1067        else {
1068            @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
1069        }
1070        my @AbsPaths = ();
1071        foreach my $File (@Files)
1072        {
1073            if(not is_abs($File)) {
1074                $File = joinPath($Path, $File);
1075            }
1076            if($Type eq "f" and not -f $File)
1077            { # skip dirs
1078                next;
1079            }
1080            push(@AbsPaths, $File);
1081        }
1082        if($Type eq "d") {
1083            push(@AbsPaths, $Path);
1084        }
1085        return @AbsPaths;
1086    }
1087    else
1088    {
1089        my $FindCmd = get_CmdPath("find");
1090        if(not $FindCmd) {
1091            exitStatus("Not_Found", "can't find a \"find\" command");
1092        }
1093        $Path = get_abs_path($Path);
1094        if(-d $Path and -l $Path
1095        and $Path!~/\/\Z/)
1096        { # for directories that are symlinks
1097            $Path.="/";
1098        }
1099        my $Cmd = $FindCmd." \"$Path\"";
1100        if($MaxDepth) {
1101            $Cmd .= " -maxdepth $MaxDepth";
1102        }
1103        if($Type) {
1104            $Cmd .= " -type $Type";
1105        }
1106        if($Name)
1107        {
1108            if($Name=~/\]/) {
1109                $Cmd .= " -regex \"$Name\"";
1110            }
1111            else {
1112                $Cmd .= " -name \"$Name\"";
1113            }
1114        }
1115        return split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
1116    }
1117}
1118
1119sub path_format($$)
1120{ # forward slash to pass into MinGW GCC
1121    my ($Path, $Fmt) = @_;
1122    if($Fmt eq "windows")
1123    {
1124        $Path=~s/\//\\/g;
1125        $Path=lc($Path);
1126    }
1127    else {
1128        $Path=~s/\\/\//g;
1129    }
1130    return $Path;
1131}
1132
1133sub unpackDump($)
1134{
1135    my $Path = $_[0];
1136    return "" if(not $Path or not -e $Path);
1137   
1138    if(isDumpFile($Path)) {
1139        return $Path;
1140    }
1141   
1142    $Path = get_abs_path($Path);
1143    $Path = path_format($Path, $OSgroup);
1144    my ($Dir, $FileName) = separate_path($Path);
1145    my $UnpackDir = $TMP_DIR."/unpack";
1146    if(-d $UnpackDir) {
1147        rmtree($UnpackDir);
1148    }
1149    mkpath($UnpackDir);
1150    if($FileName=~s/\Q.zip\E\Z//g)
1151    { # *.zip
1152        my $UnzipCmd = get_CmdPath("unzip");
1153        if(not $UnzipCmd) {
1154            exitStatus("Not_Found", "can't find \"unzip\" command");
1155        }
1156        chdir($UnpackDir);
1157        system("$UnzipCmd \"$Path\" >contents.txt");
1158        if($?) {
1159            exitStatus("Error", "can't extract \'$Path\'");
1160        }
1161        chdir($ORIG_DIR);
1162        my @Contents = ();
1163        foreach (split("\n", readFile("$UnpackDir/contents.txt")))
1164        {
1165            if(/inflating:\s*([^\s]+)/) {
1166                push(@Contents, $1);
1167            }
1168        }
1169        if(not @Contents) {
1170            exitStatus("Error", "can't extract \'$Path\'");
1171        }
1172        return joinPath($UnpackDir, $Contents[0]);
1173    }
1174    elsif($FileName=~s/\Q.tar.gz\E\Z//g)
1175    { # *.tar.gz
1176        if($OSgroup eq "windows")
1177        { # -xvzf option is not implemented in tar.exe (2003)
1178          # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
1179            my $TarCmd = get_CmdPath("tar");
1180            if(not $TarCmd) {
1181                exitStatus("Not_Found", "can't find \"tar\" command");
1182            }
1183            my $GzipCmd = get_CmdPath("gzip");
1184            if(not $GzipCmd) {
1185                exitStatus("Not_Found", "can't find \"gzip\" command");
1186            }
1187            chdir($UnpackDir);
1188            qx/$GzipCmd -k -d -f "$Path"/; # keep input files (-k)
1189            if($?) {
1190                exitStatus("Error", "can't extract \'$Path\'");
1191            }
1192            my @Contents = qx/$TarCmd -xvf "$Dir\\$FileName.tar"/;
1193            if($? or not @Contents) {
1194                exitStatus("Error", "can't extract \'$Path\'");
1195            }
1196            chdir($ORIG_DIR);
1197            unlink($Dir."/".$FileName.".tar");
1198            chomp $Contents[0];
1199            return joinPath($UnpackDir, $Contents[0]);
1200        }
1201        else
1202        { # Linux, Unix, OS X
1203            my $TarCmd = get_CmdPath("tar");
1204            if(not $TarCmd) {
1205                exitStatus("Not_Found", "can't find \"tar\" command");
1206            }
1207            chdir($UnpackDir);
1208            my @Contents = qx/$TarCmd -xvzf "$Path" 2>&1/;
1209            if($? or not @Contents) {
1210                exitStatus("Error", "can't extract \'$Path\'");
1211            }
1212            chdir($ORIG_DIR);
1213            $Contents[0]=~s/^x //; # OS X
1214            chomp $Contents[0];
1215            return joinPath($UnpackDir, $Contents[0]);
1216        }
1217    }
1218}
1219
1220sub mergeClasses()
1221{
1222    my %ReportedRemoved = undef;
1223   
1224    foreach my $ClassName (keys(%{$Class_Methods{1}}))
1225    {
1226        next if(not $ClassName);
1227        my $Type1_Id = $TName_Tid{1}{$ClassName};
1228        my %Type1 = get_Type($Type1_Id, 1);
1229       
1230        if($Type1{"Type"}!~/class|interface/) {
1231            next;
1232        }
1233       
1234        if(defined $Type1{"Access"}
1235        and $Type1{"Access"}=~/private/) {
1236            next;
1237        }
1238       
1239        if(not classFilter(\%Type1, 1, 0)) {
1240            next;
1241        }
1242       
1243        my $Type2_Id = $TName_Tid{2}{$ClassName};
1244        if(not $Type2_Id)
1245        { # classes and interfaces with public methods
1246            foreach my $Method (keys(%{$Class_Methods{1}{$ClassName}}))
1247            {
1248                if(not methodFilter($Method, 1)) {
1249                    next;
1250                }
1251               
1252                $CheckedTypes{$ClassName} = 1;
1253                $CheckedMethods{$Method} = 1;
1254               
1255                if($Type1{"Type"} eq "class")
1256                {
1257                    %{$CompatProblems{$Method}{"Removed_Class"}{"this"}} = (
1258                        "Type_Name"=>$ClassName,
1259                        "Target"=>$ClassName  );
1260                }
1261                else
1262                {
1263                    %{$CompatProblems{$Method}{"Removed_Interface"}{"this"}} = (
1264                        "Type_Name"=>$ClassName,
1265                        "Target"=>$ClassName  );
1266                }
1267               
1268                $ReportedRemoved{$ClassName} = 1;
1269            }
1270        }
1271    }
1272   
1273    foreach my $Class_Id (keys(%{$TypeInfo{1}}))
1274    {
1275        my %Class1 = get_Type($Class_Id, 1);
1276       
1277        if($Class1{"Type"}!~/class|interface/) {
1278            next;
1279        }
1280       
1281        if(defined $Class1{"Access"}
1282        and $Class1{"Access"}=~/private/) {
1283            next;
1284        }
1285       
1286        if(not classFilter(\%Class1, 1, 1)) {
1287            next;
1288        }
1289       
1290        my $ClassName = $Class1{"Name"};
1291       
1292        if(my $Class2_Id = $TName_Tid{2}{$ClassName})
1293        { # classes and interfaces with public static fields
1294            if(not defined $Class_Methods{1}{$ClassName})
1295            {
1296                my %Class2 = get_Type($Class2_Id, 2);
1297               
1298                foreach my $Field (keys(%{$Class1{"Fields"}}))
1299                {
1300                    my $FieldInfo = $Class1{"Fields"}{$Field};
1301                   
1302                    my $FAccess = $FieldInfo->{"Access"};
1303                    if($FAccess=~/private/) {
1304                        next;
1305                    }
1306                   
1307                    if($FieldInfo->{"Static"})
1308                    {
1309                        $CheckedTypes{$ClassName} = 1;
1310                       
1311                        if(not defined $Class2{"Fields"}{$Field})
1312                        {
1313                            %{$CompatProblems{".client_method"}{"Removed_NonConstant_Field"}{$Field}}=(
1314                                "Target"=>$Field,
1315                                "Type_Name"=>$ClassName,
1316                                "Type_Type"=>$Class1{"Type"},
1317                                "Field_Type"=>get_TypeName($FieldInfo->{"Type"}, 1)  );
1318                        }
1319                    }
1320                }
1321            }
1322        }
1323        else
1324        { # removed
1325            if(defined $Class1{"Annotation"})
1326            {
1327                %{$CompatProblems{".client_method"}{"Removed_Annotation"}{"this"}} = (
1328                    "Type_Name"=>$ClassName,
1329                    "Target"=>$ClassName  );
1330            }
1331           
1332            if(not defined $Class_Methods{1}{$ClassName})
1333            {
1334                # classes and interfaces with public static fields
1335                if(not defined $ReportedRemoved{$ClassName})
1336                {
1337                    foreach my $Field (keys(%{$Class1{"Fields"}}))
1338                    {
1339                        my $FieldInfo = $Class1{"Fields"}{$Field};
1340                       
1341                        my $FAccess = $FieldInfo->{"Access"};
1342                        if($FAccess=~/private/) {
1343                            next;
1344                        }
1345                       
1346                        if($FieldInfo->{"Static"})
1347                        {
1348                            $CheckedTypes{$ClassName} = 1;
1349                           
1350                            if($Class1{"Type"} eq "class")
1351                            {
1352                                %{$CompatProblems{".client_method"}{"Removed_Class"}{"this"}} = (
1353                                    "Type_Name"=>$ClassName,
1354                                    "Target"=>$ClassName  );
1355                            }
1356                            else
1357                            {
1358                                %{$CompatProblems{".client_method"}{"Removed_Interface"}{"this"}} = (
1359                                    "Type_Name"=>$ClassName,
1360                                    "Target"=>$ClassName  );
1361                            }
1362                        }
1363                    }
1364                }
1365            }
1366        }
1367    }
1368}
1369
1370sub findFieldPair($$)
1371{
1372    my ($Field_Pos, $Pair_Type) = @_;
1373    foreach my $Pair_Name (sort keys(%{$Pair_Type->{"Fields"}}))
1374    {
1375        if(defined $Pair_Type->{"Fields"}{$Pair_Name})
1376        {
1377            if($Pair_Type->{"Fields"}{$Pair_Name}{"Pos"} eq $Field_Pos) {
1378                return $Pair_Name;
1379            }
1380        }
1381    }
1382    return "lost";
1383}
1384
1385my %Severity_Val=(
1386    "High"=>3,
1387    "Medium"=>2,
1388    "Low"=>1,
1389    "Safe"=>-1
1390);
1391
1392sub isRecurType($$)
1393{
1394    foreach (@RecurTypes)
1395    {
1396        if($_->{"Tid1"} eq $_[0]
1397        and $_->{"Tid2"} eq $_[1])
1398        {
1399            return 1;
1400        }
1401    }
1402    return 0;
1403}
1404
1405sub pushType($$)
1406{
1407    my %TypeDescriptor=(
1408        "Tid1"  => $_[0],
1409        "Tid2"  => $_[1]  );
1410    push(@RecurTypes, \%TypeDescriptor);
1411}
1412
1413sub get_SFormat($)
1414{
1415    my $Name = $_[0];
1416    $Name=~s/\./\//g;
1417    return $Name;
1418}
1419
1420sub get_PFormat($)
1421{
1422    my $Name = $_[0];
1423    $Name=~s/\//./g;
1424    return $Name;
1425}
1426
1427sub get_ConstantValue($$)
1428{
1429    my ($Value, $ValueType) = @_;
1430    return "" if(not $Value);
1431    if($Value eq "\@EMPTY_STRING\@") {
1432        return "\"\"";
1433    }
1434    elsif($ValueType eq "java.lang.String") {
1435        return "\"".$Value."\"";
1436    }
1437    else {
1438        return $Value;
1439    }
1440}
1441
1442sub getInvoked($)
1443{
1444    my $TName = $_[0];
1445   
1446    if(my @Invoked = sort keys(%{$ClassMethod_AddedUsed{$TName}}))
1447    {
1448        my $MFirst = $Invoked[0];
1449        my $MSignature = unmangle($MFirst);
1450        $MSignature=~s/\A.+\.(\w+\()/$1/g; # short name
1451        my $InvokedBy = $ClassMethod_AddedUsed{$TName}{$MFirst};
1452        return ($MSignature, $InvokedBy);
1453    }
1454   
1455    return ();
1456}
1457
1458sub mergeTypes($$)
1459{
1460    my ($Type1_Id, $Type2_Id) = @_;
1461    return {} if(not $Type1_Id or not $Type2_Id);
1462   
1463    if(defined $Cache{"mergeTypes"}{$Type1_Id}{$Type2_Id})
1464    { # already merged
1465        return $Cache{"mergeTypes"}{$Type1_Id}{$Type2_Id};
1466    }
1467   
1468    my %Type1 = get_Type($Type1_Id, 1);
1469    my %Type2 = get_Type($Type2_Id, 2);
1470    if(isRecurType($Type1_Id, $Type2_Id))
1471    { # do not follow to recursive declarations
1472        return {};
1473    }
1474    return {} if(not $Type1{"Name"} or not $Type2{"Name"});
1475    return {} if(not $Type1{"Archive"} or not $Type2{"Archive"});
1476    return {} if($Type1{"Name"} ne $Type2{"Name"});
1477   
1478    if(not classFilter(\%Type1, 1, 0)) {
1479        return {};
1480    }
1481   
1482    $CheckedTypes{$Type1{"Name"}} = 1;
1483   
1484    my %SubProblems = ();
1485   
1486    if($Type1{"BaseType"} and $Type2{"BaseType"})
1487    { # check base type (arrays)
1488        return mergeTypes($Type1{"BaseType"}, $Type2{"BaseType"});
1489    }
1490   
1491    if($Type2{"Type"}!~/(class|interface)/) {
1492        return {};
1493    }
1494   
1495    if($Type1{"Type"} eq "class" and not $Class_Constructed{1}{$Type1_Id})
1496    { # class cannot be constructed or inherited by clients
1497        return {};
1498    }
1499   
1500    if($Type1{"Type"} eq "class"
1501    and $Type2{"Type"} eq "interface")
1502    {
1503        %{$SubProblems{"Class_Became_Interface"}{""}}=(
1504            "Type_Name"=>$Type1{"Name"}  );
1505       
1506        return ($Cache{"mergeTypes"}{$Type1_Id}{$Type2_Id} = \%SubProblems);
1507    }
1508    if($Type1{"Type"} eq "interface"
1509    and $Type2{"Type"} eq "class")
1510    {
1511        %{$SubProblems{"Interface_Became_Class"}{""}}=(
1512            "Type_Name"=>$Type1{"Name"}  );
1513       
1514        return ($Cache{"mergeTypes"}{$Type1_Id}{$Type2_Id} = \%SubProblems);
1515    }
1516    if(not $Type1{"Final"}
1517    and $Type2{"Final"})
1518    {
1519        %{$SubProblems{"Class_Became_Final"}{""}}=(
1520            "Type_Name"=>$Type1{"Name"},
1521            "Target"=>$Type1{"Name"}  );
1522    }
1523    if(not $Type1{"Abstract"}
1524    and $Type2{"Abstract"})
1525    {
1526        %{$SubProblems{"Class_Became_Abstract"}{""}}=(
1527            "Type_Name"=>$Type1{"Name"}  );
1528    }
1529   
1530    pushType($Type1_Id, $Type2_Id);
1531   
1532    foreach my $AddedMethod (keys(%{$AddedMethod_Abstract{$Type1{"Name"}}}))
1533    {
1534        if($Type1{"Type"} eq "class")
1535        {
1536            if($Type1{"Abstract"})
1537            {
1538                if(my @InvokedBy = sort keys(%{$MethodUsed{2}{$AddedMethod}}))
1539                {
1540                    %{$SubProblems{"Abstract_Class_Added_Abstract_Method_Invoked_By_Others"}{get_SFormat($AddedMethod)}} = (
1541                        "Type_Name"=>$Type1{"Name"},
1542                        "Type_Type"=>$Type1{"Type"},
1543                        "Target"=>$AddedMethod,
1544                        "InvokedBy"=>$InvokedBy[0]  );
1545                }
1546                else
1547                {
1548                    %{$SubProblems{"Abstract_Class_Added_Abstract_Method"}{get_SFormat($AddedMethod)}} = (
1549                        "Type_Name"=>$Type1{"Name"},
1550                        "Type_Type"=>$Type1{"Type"},
1551                        "Target"=>$AddedMethod  );
1552                }
1553            }
1554            else
1555            {
1556                %{$SubProblems{"NonAbstract_Class_Added_Abstract_Method"}{get_SFormat($AddedMethod)}} = (
1557                    "Type_Name"=>$Type1{"Name"},
1558                    "Type_Type"=>$Type1{"Type"},
1559                    "Target"=>$AddedMethod  );
1560            }
1561        }
1562        else
1563        {
1564            if(my @InvokedBy = sort keys(%{$MethodUsed{2}{$AddedMethod}}))
1565            {
1566                %{$SubProblems{"Interface_Added_Abstract_Method_Invoked_By_Others"}{get_SFormat($AddedMethod)}} = (
1567                    "Type_Name"=>$Type1{"Name"},
1568                    "Type_Type"=>$Type1{"Type"},
1569                    "Target"=>$AddedMethod,
1570                    "InvokedBy"=>$InvokedBy[0]  );
1571            }
1572            else
1573            {
1574                %{$SubProblems{"Interface_Added_Abstract_Method"}{get_SFormat($AddedMethod)}} = (
1575                    "Type_Name"=>$Type1{"Name"},
1576                    "Type_Type"=>$Type1{"Type"},
1577                    "Target"=>$AddedMethod  );
1578            }
1579        }
1580    }
1581    foreach my $RemovedMethod (keys(%{$RemovedMethod_Abstract{$Type1{"Name"}}}))
1582    {
1583        if($Type1{"Type"} eq "class")
1584        {
1585            %{$SubProblems{"Class_Removed_Abstract_Method"}{get_SFormat($RemovedMethod)}} = (
1586                "Type_Name"=>$Type1{"Name"},
1587                "Type_Type"=>$Type1{"Type"},
1588                "Target"=>$RemovedMethod  );
1589        }
1590        else
1591        {
1592            %{$SubProblems{"Interface_Removed_Abstract_Method"}{get_SFormat($RemovedMethod)}} = (
1593                "Type_Name"=>$Type1{"Name"},
1594                "Type_Type"=>$Type1{"Type"},
1595                "Target"=>$RemovedMethod  );
1596        }
1597    }
1598    if($Type1{"Type"} eq "class"
1599    and $Type2{"Type"} eq "class")
1600    {
1601        my %SuperClass1 = get_Type($Type1{"SuperClass"}, 1);
1602        my %SuperClass2 = get_Type($Type2{"SuperClass"}, 2);
1603        if($SuperClass2{"Name"} ne $SuperClass1{"Name"})
1604        {
1605            if($SuperClass1{"Name"} eq "java.lang.Object"
1606            or not $SuperClass1{"Name"})
1607            {
1608              # Java 6: java.lang.Object
1609              # Java 7: none
1610                if($SuperClass2{"Name"} ne "java.lang.Object")
1611                {
1612                    if($SuperClass2{"Abstract"}
1613                    and $Type1{"Abstract"} and $Type2{"Abstract"}
1614                    and keys(%{$Class_AbstractMethods{2}{$SuperClass2{"Name"}}}))
1615                    {
1616                        if(my ($Invoked, $InvokedBy) = getInvoked($Type1{"Name"}))
1617                        {
1618                            %{$SubProblems{"Abstract_Class_Added_Super_Abstract_Class_Invoked_By_Others"}{""}} = (
1619                                "Type_Name"=>$Type1{"Name"},
1620                                "Target"=>$SuperClass2{"Name"},
1621                                "Invoked"=>$Invoked,
1622                                "InvokedBy"=>$InvokedBy  );
1623                        }
1624                        else
1625                        {
1626                            %{$SubProblems{"Abstract_Class_Added_Super_Abstract_Class"}{""}} = (
1627                                "Type_Name"=>$Type1{"Name"},
1628                                "Target"=>$SuperClass2{"Name"}  );
1629                        }
1630                    }
1631                    else
1632                    {
1633                        %{$SubProblems{"Added_Super_Class"}{""}} = (
1634                            "Type_Name"=>$Type1{"Name"},
1635                            "Target"=>$SuperClass2{"Name"}  );
1636                    }
1637                }
1638            }
1639            elsif($SuperClass2{"Name"} eq "java.lang.Object"
1640            or not $SuperClass2{"Name"})
1641            {
1642              # Java 6: java.lang.Object
1643              # Java 7: none
1644                if($SuperClass1{"Name"} ne "java.lang.Object")
1645                {
1646                    %{$SubProblems{"Removed_Super_Class"}{""}} = (
1647                        "Type_Name"=>$Type1{"Name"},
1648                        "Target"=>$SuperClass1{"Name"}  );
1649                }
1650            }
1651            else
1652            {
1653                %{$SubProblems{"Changed_Super_Class"}{""}} = (
1654                    "Type_Name"=>$Type1{"Name"},
1655                    "Target"=>$SuperClass1{"Name"},
1656                    "Old_Value"=>$SuperClass1{"Name"},
1657                    "New_Value"=>$SuperClass2{"Name"}  );
1658            }
1659        }
1660    }
1661    my %SuperInterfaces_Old = map {get_TypeName($_, 1) => 1} keys(%{$Type1{"SuperInterface"}});
1662    my %SuperInterfaces_New = map {get_TypeName($_, 2) => 1} keys(%{$Type2{"SuperInterface"}});
1663    foreach my $SuperInterface (keys(%SuperInterfaces_New))
1664    {
1665        if(not $SuperInterfaces_Old{$SuperInterface})
1666        {
1667            my $HaveMethods = keys(%{$Class_AbstractMethods{2}{$SuperInterface}});
1668            my $HaveFields = keys(%{$Class_Fields{2}{$SuperInterface}});
1669           
1670            if($Type1{"Type"} eq "interface")
1671            {
1672                if($HaveMethods
1673                or $SuperInterface=~/\Ajava\./)
1674                {
1675                    if($HaveMethods and checkDefaultImpl(2, $SuperInterface, $Type2{"Name"}))
1676                    {
1677                        %{$SubProblems{"Interface_Added_Super_Interface_With_Implemented_Methods"}{get_SFormat($SuperInterface)}} = (
1678                            "Type_Name"=>$Type1{"Name"},
1679                            "Target"=>$SuperInterface  );
1680                    }
1681                    else
1682                    {
1683                        if(my ($Invoked, $InvokedBy) = getInvoked($Type1{"Name"}))
1684                        {
1685                            %{$SubProblems{"Interface_Added_Super_Interface_Used_By_Others"}{get_SFormat($SuperInterface)}} = (
1686                                "Type_Name"=>$Type1{"Name"},
1687                                "Target"=>$SuperInterface,
1688                                "Invoked"=>$Invoked,
1689                                "InvokedBy"=>$InvokedBy  );
1690                        }
1691                        else
1692                        {
1693                            %{$SubProblems{"Interface_Added_Super_Interface"}{get_SFormat($SuperInterface)}} = (
1694                                "Type_Name"=>$Type1{"Name"},
1695                                "Target"=>$SuperInterface  );
1696                        }
1697                    }
1698                }
1699                elsif($HaveFields)
1700                {
1701                    %{$SubProblems{"Interface_Added_Super_Constant_Interface"}{get_SFormat($SuperInterface)}} = (
1702                        "Type_Name"=>$Type2{"Name"},
1703                        "Target"=>$SuperInterface  );
1704                }
1705                else
1706                {
1707                    # empty interface
1708                }
1709            }
1710            else
1711            {
1712                if($Type1{"Abstract"} and $Type2{"Abstract"})
1713                {
1714                    if($HaveMethods and checkDefaultImpl(2, $SuperInterface, $Type2{"Name"}))
1715                    {
1716                        %{$SubProblems{"Abstract_Class_Added_Super_Interface_With_Implemented_Methods"}{get_SFormat($SuperInterface)}} = (
1717                            "Type_Name"=>$Type1{"Name"},
1718                            "Target"=>$SuperInterface  );
1719                    }
1720                    else
1721                    {
1722                        if(my ($Invoked, $InvokedBy) = getInvoked($Type1{"Name"}))
1723                        {
1724                            %{$SubProblems{"Abstract_Class_Added_Super_Interface_Invoked_By_Others"}{get_SFormat($SuperInterface)}} = (
1725                                "Type_Name"=>$Type1{"Name"},
1726                                "Target"=>$SuperInterface,
1727                                "Invoked"=>$Invoked,
1728                                "InvokedBy"=>$InvokedBy  );
1729                        }
1730                        else
1731                        {
1732                            %{$SubProblems{"Abstract_Class_Added_Super_Interface"}{get_SFormat($SuperInterface)}} = (
1733                                "Type_Name"=>$Type1{"Name"},
1734                                "Target"=>$SuperInterface  );
1735                        }
1736                    }
1737                }
1738            }
1739        }
1740    }
1741    foreach my $SuperInterface (keys(%SuperInterfaces_Old))
1742    {
1743        if(not $SuperInterfaces_New{$SuperInterface})
1744        {
1745            my $HaveMethods = keys(%{$Class_AbstractMethods{1}{$SuperInterface}});
1746            my $HaveFields = keys(%{$Class_Fields{1}{$SuperInterface}});
1747           
1748            if($Type1{"Type"} eq "interface")
1749            {
1750                if($HaveMethods
1751                or $SuperInterface=~/\Ajava\./)
1752                {
1753                    %{$SubProblems{"Interface_Removed_Super_Interface"}{get_SFormat($SuperInterface)}} = (
1754                        "Type_Name"=>$Type1{"Name"},
1755                        "Type_Type"=>"interface",
1756                        "Target"=>$SuperInterface  );
1757                }
1758                elsif($HaveFields)
1759                {
1760                    %{$SubProblems{"Interface_Removed_Super_Constant_Interface"}{get_SFormat($SuperInterface)}} = (
1761                        "Type_Name"=>$Type1{"Name"},
1762                        "Target"=>$SuperInterface  );
1763                }
1764                else {
1765                    # empty interface
1766                }
1767            }
1768            else
1769            {
1770                %{$SubProblems{"Class_Removed_Super_Interface"}{get_SFormat($SuperInterface)}} = (
1771                    "Type_Name"=>$Type1{"Name"},
1772                    "Type_Type"=>"class",
1773                    "Target"=>$SuperInterface  );
1774            }
1775        }
1776    }
1777   
1778    foreach my $Field_Name (sort keys(%{$Type1{"Fields"}}))
1779    {# check older fields
1780        my $Access1 = $Type1{"Fields"}{$Field_Name}{"Access"};
1781        if($Access1=~/private/) {
1782            next;
1783        }
1784       
1785        my $Field_Pos1 = $Type1{"Fields"}{$Field_Name}{"Pos"};
1786        my $FieldType1_Id = $Type1{"Fields"}{$Field_Name}{"Type"};
1787        my %FieldType1 = get_Type($FieldType1_Id, 1);
1788       
1789        if(not $Type2{"Fields"}{$Field_Name})
1790        {# removed fields
1791            my $StraightPair_Name = findFieldPair($Field_Pos1, \%Type2);
1792            if($StraightPair_Name ne "lost" and not $Type1{"Fields"}{$StraightPair_Name}
1793            and $FieldType1{"Name"} eq get_TypeName($Type2{"Fields"}{$StraightPair_Name}{"Type"}, 2))
1794            {
1795                if(my $Constant = get_ConstantValue($Type1{"Fields"}{$Field_Name}{"Value"}, $FieldType1{"Name"}))
1796                {
1797                    %{$SubProblems{"Renamed_Constant_Field"}{$Field_Name}}=(
1798                        "Target"=>$Field_Name,
1799                        "Type_Name"=>$Type1{"Name"},
1800                        "Old_Value"=>$Field_Name,
1801                        "New_Value"=>$StraightPair_Name,
1802                        "Field_Type"=>$FieldType1{"Name"},
1803                        "Field_Value"=>$Constant  );
1804                }
1805                else
1806                {
1807                    %{$SubProblems{"Renamed_Field"}{$Field_Name}}=(
1808                        "Target"=>$Field_Name,
1809                        "Type_Name"=>$Type1{"Name"},
1810                        "Old_Value"=>$Field_Name,
1811                        "New_Value"=>$StraightPair_Name,
1812                        "Field_Type"=>$FieldType1{"Name"}  );
1813                }
1814            }
1815            else
1816            {
1817                if(my $Constant = get_ConstantValue($Type1{"Fields"}{$Field_Name}{"Value"}, $FieldType1{"Name"}))
1818                { # has a compile-time constant value
1819                    %{$SubProblems{"Removed_Constant_Field"}{$Field_Name}}=(
1820                        "Target"=>$Field_Name,
1821                        "Type_Name"=>$Type1{"Name"},
1822                        "Field_Value"=>$Constant,
1823                        "Field_Type"=>$FieldType1{"Name"},
1824                        "Type_Type"=>$Type1{"Type"}  );
1825                }
1826                else
1827                {
1828                    %{$SubProblems{"Removed_NonConstant_Field"}{$Field_Name}}=(
1829                        "Target"=>$Field_Name,
1830                        "Type_Name"=>$Type1{"Name"},
1831                        "Type_Type"=>$Type1{"Type"},
1832                        "Field_Type"=>$FieldType1{"Name"}  );
1833                }
1834            }
1835            next;
1836        }
1837        my $FieldType2_Id = $Type2{"Fields"}{$Field_Name}{"Type"};
1838        my %FieldType2 = get_Type($FieldType2_Id, 2);
1839       
1840        if(not $Type1{"Fields"}{$Field_Name}{"Static"}
1841        and $Type2{"Fields"}{$Field_Name}{"Static"})
1842        {
1843            if(not $Type1{"Fields"}{$Field_Name}{"Value"})
1844            {
1845                %{$SubProblems{"NonConstant_Field_Became_Static"}{$Field_Name}}=(
1846                    "Target"=>$Field_Name,
1847                    "Field_Type"=>$FieldType1{"Name"},
1848                    "Type_Name"=>$Type1{"Name"}  );
1849            }
1850        }
1851        elsif($Type1{"Fields"}{$Field_Name}{"Static"}
1852        and not $Type2{"Fields"}{$Field_Name}{"Static"})
1853        {
1854            if($Type1{"Fields"}{$Field_Name}{"Value"})
1855            {
1856                %{$SubProblems{"Constant_Field_Became_NonStatic"}{$Field_Name}}=(
1857                    "Target"=>$Field_Name,
1858                    "Field_Type"=>$FieldType1{"Name"},
1859                    "Type_Name"=>$Type1{"Name"}  );
1860            }
1861            else
1862            {
1863                %{$SubProblems{"NonConstant_Field_Became_NonStatic"}{$Field_Name}}=(
1864                    "Target"=>$Field_Name,
1865                    "Field_Type"=>$FieldType1{"Name"},
1866                    "Type_Name"=>$Type1{"Name"}  );
1867            }
1868        }
1869        if(not $Type1{"Fields"}{$Field_Name}{"Final"}
1870        and $Type2{"Fields"}{$Field_Name}{"Final"})
1871        {
1872            %{$SubProblems{"Field_Became_Final"}{$Field_Name}}=(
1873                "Target"=>$Field_Name,
1874                "Field_Type"=>$FieldType1{"Name"},
1875                "Type_Name"=>$Type1{"Name"}  );
1876        }
1877        elsif($Type1{"Fields"}{$Field_Name}{"Final"}
1878        and not $Type2{"Fields"}{$Field_Name}{"Final"})
1879        {
1880            %{$SubProblems{"Field_Became_NonFinal"}{$Field_Name}}=(
1881                "Target"=>$Field_Name,
1882                "Field_Type"=>$FieldType1{"Name"},
1883                "Type_Name"=>$Type1{"Name"}  );
1884        }
1885        my $Access2 = $Type2{"Fields"}{$Field_Name}{"Access"};
1886        if($Access1 eq "public" and $Access2=~/protected|private/
1887        or $Access1 eq "protected" and $Access2=~/private/)
1888        {
1889            %{$SubProblems{"Changed_Field_Access"}{$Field_Name}}=(
1890                "Target"=>$Field_Name,
1891                "Type_Name"=>$Type1{"Name"},
1892                "Old_Value"=>$Access1,
1893                "New_Value"=>$Access2  );
1894        }
1895       
1896        my $Value1 = get_ConstantValue($Type1{"Fields"}{$Field_Name}{"Value"}, $FieldType1{"Name"});
1897        my $Value2 = get_ConstantValue($Type2{"Fields"}{$Field_Name}{"Value"}, $FieldType2{"Name"});
1898       
1899        if($Value1 ne $Value2)
1900        {
1901            if($Value1 and $Value2)
1902            {
1903                if($Type1{"Fields"}{$Field_Name}{"Final"}
1904                and $Type2{"Fields"}{$Field_Name}{"Final"})
1905                {
1906                    if($Field_Name=~/(\A|_)(VERSION|VERNUM|BUILDNUMBER|BUILD)(_|\Z)/i)
1907                    {
1908                        %{$SubProblems{"Changed_Final_Version_Field_Value"}{$Field_Name}}=(
1909                            "Target"=>$Field_Name,
1910                            "Field_Type"=>$FieldType1{"Name"},
1911                            "Type_Name"=>$Type1{"Name"},
1912                            "Old_Value"=>$Value1,
1913                            "New_Value"=>$Value2  );
1914                    }
1915                    else
1916                    {
1917                        %{$SubProblems{"Changed_Final_Field_Value"}{$Field_Name}}=(
1918                            "Target"=>$Field_Name,
1919                            "Field_Type"=>$FieldType1{"Name"},
1920                            "Type_Name"=>$Type1{"Name"},
1921                            "Old_Value"=>$Value1,
1922                            "New_Value"=>$Value2  );
1923                    }
1924                }
1925            }
1926        }
1927       
1928        my %Sub_SubChanges = detectTypeChange($FieldType1_Id, $FieldType2_Id, "Field");
1929        foreach my $Sub_SubProblemType (keys(%Sub_SubChanges))
1930        {
1931            %{$SubProblems{$Sub_SubProblemType}{$Field_Name}}=(
1932                "Target"=>$Field_Name,
1933                "Type_Name"=>$Type1{"Name"});
1934           
1935            foreach my $Attr (keys(%{$Sub_SubChanges{$Sub_SubProblemType}}))
1936            {
1937                $SubProblems{$Sub_SubProblemType}{$Field_Name}{$Attr} = $Sub_SubChanges{$Sub_SubProblemType}{$Attr};
1938            }
1939        }
1940       
1941        if($FieldType1_Id and $FieldType2_Id)
1942        { # check field type change
1943            my $Sub_SubProblems = mergeTypes($FieldType1_Id, $FieldType2_Id);
1944            my %DupProblems = ();
1945           
1946            foreach my $Sub_SubProblemType (sort keys(%{$Sub_SubProblems}))
1947            {
1948                foreach my $Sub_SubLocation (sort {length($a)<=>length($b)} sort keys(%{$Sub_SubProblems->{$Sub_SubProblemType}}))
1949                {
1950                    if(not defined $AllAffected)
1951                    {
1952                        if(defined $DupProblems{$Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}}) {
1953                            next;
1954                        }
1955                    }
1956                   
1957                    my $NewLocation = ($Sub_SubLocation)?$Field_Name.".".$Sub_SubLocation:$Field_Name;
1958                    $SubProblems{$Sub_SubProblemType}{$NewLocation} = $Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation};
1959                   
1960                    if(not defined $AllAffected)
1961                    {
1962                        $DupProblems{$Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}} = 1;
1963                    }
1964                }
1965            }
1966            %DupProblems = ();
1967        }
1968    }
1969   
1970    foreach my $Field_Name (sort keys(%{$Type2{"Fields"}}))
1971    { # check added fields
1972        if($Type2{"Fields"}{$Field_Name}{"Access"}=~/private/) {
1973            next;
1974        }
1975        my $FieldPos2 = $Type2{"Fields"}{$Field_Name}{"Pos"};
1976        my $FieldType2_Id = $Type2{"Fields"}{$Field_Name}{"Type"};
1977        my %FieldType2 = get_Type($FieldType2_Id, 2);
1978       
1979        if(not $Type1{"Fields"}{$Field_Name})
1980        {# added fields
1981            my $StraightPair_Name = findFieldPair($FieldPos2, \%Type1);
1982            if($StraightPair_Name ne "lost" and not $Type2{"Fields"}{$StraightPair_Name}
1983            and get_TypeName($Type1{"Fields"}{$StraightPair_Name}{"Type"}, 1) eq $FieldType2{"Name"})
1984            {
1985                # Already reported as "Renamed_Field" or "Renamed_Constant_Field"
1986            }
1987            else
1988            {
1989                if($Type1{"Type"} eq "interface")
1990                {
1991                    %{$SubProblems{"Interface_Added_Field"}{$Field_Name}}=(
1992                        "Target"=>$Field_Name,
1993                        "Type_Name"=>$Type1{"Name"}  );
1994                }
1995                else
1996                {
1997                    %{$SubProblems{"Class_Added_Field"}{$Field_Name}}=(
1998                        "Target"=>$Field_Name,
1999                        "Type_Name"=>$Type1{"Name"}  );
2000                }
2001            }
2002        }
2003    }
2004   
2005    pop(@RecurTypes);
2006    return ($Cache{"mergeTypes"}{$Type1_Id}{$Type2_Id} = \%SubProblems);
2007}
2008
2009sub checkDefaultImpl($$$)
2010{ # Check if all abstract methods of the super class have
2011  # default implementations in the class
2012    my ($LibVersion, $SuperClassName, $ClassName) = @_;
2013   
2014    foreach my $Method (keys(%{$Class_AbstractMethods{$LibVersion}{$SuperClassName}}))
2015    {
2016        if(my $Overridden = findMethod_Class($Method, $ClassName, $LibVersion))
2017        {
2018            if($MethodInfo{$LibVersion}{$Overridden}{"Abstract"}) {
2019                return 0;
2020            }
2021        }
2022        else {
2023            return 0;
2024        }
2025    }
2026   
2027    return 1;
2028}
2029
2030sub unmangle($)
2031{
2032    my $Name = $_[0];
2033    $Name=~s!/!.!g;
2034    $Name=~s!:\(!(!g;
2035    $Name=~s!\).+\Z!)!g;
2036    if($Name=~/\A(.+)\((.+)\)/)
2037    {
2038        my ($ShortName, $MangledParams) = ($1, $2);
2039        my @UnmangledParams = ();
2040        my ($IsArray, $Shift, $Pos, $CurParam) = (0, 0, 0, "");
2041        while($Pos<length($MangledParams))
2042        {
2043            my $Symbol = substr($MangledParams, $Pos, 1);
2044            if($Symbol eq "[")
2045            { # array
2046                $IsArray = 1;
2047                $Pos+=1;
2048            }
2049            elsif($Symbol eq "L")
2050            { # class
2051                if(substr($MangledParams, $Pos+1)=~/\A(.+?);/) {
2052                    $CurParam = $1;
2053                    $Shift = length($CurParam)+2;
2054                }
2055                if($IsArray) {
2056                    $CurParam .= "[]";
2057                }
2058                $Pos+=$Shift;
2059                push(@UnmangledParams, $CurParam);
2060                ($IsArray, $Shift, $CurParam) = (0, 0, "")
2061            }
2062            else
2063            {
2064                if($Symbol eq "C") {
2065                    $CurParam = "char";
2066                }
2067                elsif($Symbol eq "B") {
2068                    $CurParam = "byte";
2069                }
2070                elsif($Symbol eq "S") {
2071                    $CurParam = "short";
2072                }
2073                elsif($Symbol eq "S") {
2074                    $CurParam = "short";
2075                }
2076                elsif($Symbol eq "I") {
2077                    $CurParam = "int";
2078                }
2079                elsif($Symbol eq "F") {
2080                    $CurParam = "float";
2081                }
2082                elsif($Symbol eq "J") {
2083                    $CurParam = "long";
2084                }
2085                elsif($Symbol eq "D") {
2086                    $CurParam = "double";
2087                }
2088                else {
2089                    printMsg("INFO", "WARNING: unmangling error");
2090                }
2091                if($IsArray) {
2092                    $CurParam .= "[]";
2093                }
2094                $Pos+=1;
2095                push(@UnmangledParams, $CurParam);
2096                ($IsArray, $Shift, $CurParam) = (0, 0, "")
2097            }
2098        }
2099        return $ShortName."(".join(", ", @UnmangledParams).")";
2100    }
2101    else {
2102        return $Name;
2103    }
2104}
2105
2106sub get_TypeName($$)
2107{
2108    my ($TypeId, $LibVersion) = @_;
2109    return $TypeInfo{$LibVersion}{$TypeId}{"Name"};
2110}
2111
2112sub get_ShortName($$)
2113{
2114    my ($TypeId, $LibVersion) = @_;
2115    my $TypeName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
2116    $TypeName=~s/\A.*\.//g;
2117    return $TypeName;
2118}
2119
2120sub get_TypeType($$)
2121{
2122    my ($TypeId, $LibVersion) = @_;
2123    return $TypeInfo{$LibVersion}{$TypeId}{"Type"};
2124}
2125
2126sub get_TypeHeader($$)
2127{
2128    my ($TypeId, $LibVersion) = @_;
2129    return $TypeInfo{$LibVersion}{$TypeId}{"Header"};
2130}
2131
2132sub get_BaseType($$)
2133{
2134    my ($TypeId, $LibVersion) = @_;
2135    return "" if(not $TypeId);
2136    if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) {
2137        return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}};
2138    }
2139    return "" if(not $TypeInfo{$LibVersion}{$TypeId});
2140    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
2141    return %Type if(not $Type{"BaseType"});
2142    %Type = get_BaseType($Type{"BaseType"}, $LibVersion);
2143    $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
2144    return %Type;
2145}
2146
2147sub get_OneStep_BaseType($$)
2148{
2149    my ($TypeId, $LibVersion) = @_;
2150    return "" if(not $TypeId);
2151    return "" if(not $TypeInfo{$LibVersion}{$TypeId});
2152    my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
2153    return %Type if(not $Type{"BaseType"});
2154    return get_Type($Type{"BaseType"}, $LibVersion);
2155}
2156
2157sub get_Type($$)
2158{
2159    my ($TypeId, $LibVersion) = @_;
2160    return "" if(not $TypeId);
2161    return "" if(not $TypeInfo{$LibVersion}{$TypeId});
2162    return %{$TypeInfo{$LibVersion}{$TypeId}};
2163}
2164
2165sub classFilter($$$)
2166{
2167    my ($Class, $LibVersion, $ClassContext) = @_;
2168   
2169    if(defined $Class->{"Dep"}) {
2170        return 0;
2171    }
2172   
2173    my $CName = $Class->{"Name"};
2174    my $Package = $Class->{"Package"};
2175   
2176    if(defined $ClassListPath
2177    and not defined $ClassList_User{$CName})
2178    { # user defined classes
2179        return 0;
2180    }
2181   
2182    if(defined $SkipClassesList
2183    and defined $SkipClasses{$CName})
2184    { # user defined classes
2185        return 0;
2186    }
2187   
2188    if(skipPackage($Package, $LibVersion))
2189    { # internal packages
2190        return 0;
2191    }
2192   
2193    if(skipType($CName))
2194    { # internal types
2195        return 0;
2196    }
2197   
2198    if($ClassContext)
2199    {
2200        my @Ann = ();
2201       
2202        if(defined $Class->{"Annotations"}) {
2203            @Ann = keys(%{$Class->{"Annotations"}});
2204        }
2205       
2206        if(not annotationFilter(\@Ann, $LibVersion)) {
2207            return 0;
2208        }
2209       
2210        if($ClientPath)
2211        {
2212            if(not defined $UsedClasses_Client{$CName}) {
2213                return 0;
2214            }
2215        }
2216    }
2217   
2218    return 1;
2219}
2220
2221sub annotationFilter($$)
2222{
2223    my ($Ann, $LibVersion) = @_;
2224   
2225    if(not defined $CountMethods)
2226    {
2227        if(defined $AddedAnnotations and $LibVersion==1) {
2228            return 1;
2229        }
2230       
2231        if(defined $RemovedAnnotations and $LibVersion==2) {
2232            return 1;
2233        }
2234    }
2235   
2236    if($SkipAnnotationsListPath)
2237    {
2238        foreach my $Aid (@{$Ann})
2239        {
2240            my $AName = $TypeInfo{$LibVersion}{$Aid}{"Name"};
2241           
2242            if(defined $SkipAnnotationList_User{$AName}) {
2243                return 0;
2244            }
2245        }
2246    }
2247   
2248    if($AnnotationsListPath)
2249    {
2250        my $Annotated = 0;
2251       
2252        foreach my $Aid (@{$Ann})
2253        {
2254            my $AName = $TypeInfo{$LibVersion}{$Aid}{"Name"};
2255           
2256            if(defined $AnnotationList_User{$AName})
2257            {
2258                $Annotated = 1;
2259                last;
2260            }
2261        }
2262       
2263        if(not $Annotated) {
2264            return 0;
2265        }
2266    }
2267   
2268    return 1;
2269}
2270
2271sub methodFilter($$)
2272{
2273    my ($Method, $LibVersion) = @_;
2274   
2275    if(defined $MethodInfo{$LibVersion}{$Method}{"Dep"}) {
2276        return 0;
2277    }
2278   
2279    if($MethodInfo{$LibVersion}{$Method}{"Access"}=~/private/)
2280    { # non-public
2281        return 0;
2282    }
2283   
2284    my $ClassId = $MethodInfo{$LibVersion}{$Method}{"Class"};
2285    my %Class = get_Type($ClassId, $LibVersion);
2286   
2287    if($Class{"Access"}=~/private/)
2288    { # skip private classes
2289        return 0;
2290    }
2291   
2292    my $Package = $MethodInfo{$LibVersion}{$Method}{"Package"};
2293   
2294    my @Ann = ();
2295   
2296    if(defined $Class{"Annotations"}) {
2297        @Ann = (@Ann, keys(%{$Class{"Annotations"}}));
2298    }
2299   
2300    if(defined $MethodInfo{$LibVersion}{$Method}{"Annotations"}) {
2301        @Ann = (@Ann, keys(%{$MethodInfo{$LibVersion}{$Method}{"Annotations"}}));
2302    }
2303   
2304    if(not annotationFilter(\@Ann, $LibVersion)) {
2305        return 0;
2306    }
2307   
2308    if($ClientPath)
2309    { # user defined application
2310        if(not defined $UsedMethods_Client{$Method}
2311        and not defined $UsedClasses_Client{$Class{"Name"}}) {
2312            return 0;
2313        }
2314    }
2315   
2316    if(skipPackage($Package, $LibVersion))
2317    { # internal packages
2318        return 0;
2319    }
2320   
2321    if(not classFilter(\%Class, $LibVersion, 0)) {
2322        return 0;
2323    }
2324   
2325    if(defined $SkipDeprecated)
2326    {
2327        if($Class{"Deprecated"})
2328        { # deprecated class
2329            return 0;
2330        }
2331        if($MethodInfo{$LibVersion}{$Method}{"Deprecated"})
2332        { # deprecated method
2333            return 0;
2334        }
2335    }
2336   
2337    return 1;
2338}
2339
2340sub skipType($)
2341{
2342    my $TName = $_[0];
2343   
2344    if(defined $SkipInternalTypes)
2345    {
2346        if($TName=~/($SkipInternalTypes)/) {
2347            return 1;
2348        }
2349    }
2350   
2351    return 0;
2352}
2353
2354sub skipPackage($$)
2355{
2356    my ($Package, $LibVersion) = @_;
2357    return 0 if(not $Package);
2358   
2359    if(defined $SkipInternalPackages)
2360    {
2361        if($Package=~/($SkipInternalPackages)/) {
2362            return 1;
2363        }
2364    }
2365   
2366    if(defined $SkipPackages{$LibVersion})
2367    {
2368        foreach my $SkipPackage (keys(%{$SkipPackages{$LibVersion}}))
2369        {
2370            if($Package=~/\A\Q$SkipPackage\E(\.|\Z)/)
2371            { # user skipped packages
2372                return 1;
2373            }
2374        }
2375    }
2376   
2377    if(not defined $KeepInternal)
2378    {
2379        my $Note = (not keys %SkippedPackage)?" (use --keep-internal option to check them)":"";
2380       
2381        if($Package=~/(\A|\.)(internal|impl|examples)(\.|\Z)/)
2382        { # internal packages
2383            if(not $SkippedPackage{$LibVersion}{$2})
2384            {
2385                $SkippedPackage{$LibVersion}{$2} = 1;
2386                printMsg("WARNING", "skip \"$2\" packages".$Note);
2387            }
2388            return 1;
2389        }
2390    }
2391   
2392    if(defined $KeepPackages{$LibVersion}
2393    and my @Keeped = keys(%{$KeepPackages{$LibVersion}}))
2394    {
2395        my $UserKeeped = 0;
2396        foreach my $KeepPackage (@Keeped)
2397        {
2398            if($Package=~/\A\Q$KeepPackage\E(\.|\Z)/)
2399            { # user keeped packages
2400                $UserKeeped = 1;
2401                last;
2402            }
2403        }
2404        if(not $UserKeeped) {
2405            return 1;
2406        }
2407    }
2408   
2409    return 0;
2410}
2411
2412sub get_MSuffix($)
2413{
2414    my $Method = $_[0];
2415    if($Method=~/(\(.*\))/) {
2416        return $1;
2417    }
2418    return "";
2419}
2420
2421sub get_MShort($)
2422{
2423    my $Method = $_[0];
2424    if($Method=~/([^\.]+)\:\(/) {
2425        return $1;
2426    }
2427    return "";
2428}
2429
2430sub findMethod($$$$)
2431{
2432    my ($Method, $MethodVersion, $ClassName, $ClassVersion) = @_;
2433    my $ClassId = $TName_Tid{$ClassVersion}{$ClassName};
2434   
2435    if($ClassId)
2436    {
2437        my @Search = ();
2438        if(get_TypeType($ClassId, $ClassVersion) eq "class")
2439        {
2440            if(my $SuperClassId = $TypeInfo{$ClassVersion}{$ClassId}{"SuperClass"}) {
2441                push(@Search, $SuperClassId);
2442            }
2443        }
2444       
2445        if(not defined $MethodInfo{$MethodVersion}{$Method}
2446        or $MethodInfo{$MethodVersion}{$Method}{"Abstract"})
2447        {
2448            if(my @SuperInterfaces = sort keys(%{$TypeInfo{$ClassVersion}{$ClassId}{"SuperInterface"}})) {
2449                push(@Search, @SuperInterfaces);
2450            }
2451        }
2452       
2453        foreach my $SuperId (@Search)
2454        {
2455            if($SuperId eq $ClassId) {
2456                next;
2457            }
2458           
2459            my $SuperName = get_TypeName($SuperId, $ClassVersion);
2460           
2461            if(my $MethodInClass = findMethod_Class($Method, $SuperName, $ClassVersion)) {
2462                return $MethodInClass;
2463            }
2464            elsif(my $MethodInSuperClasses = findMethod($Method, $MethodVersion, $SuperName, $ClassVersion)) {
2465                return $MethodInSuperClasses;
2466            }
2467        }
2468    }
2469   
2470    my $TargetSuffix = get_MSuffix($Method);
2471    my $TargetShortName = get_MShort($Method);
2472   
2473    # search in java.lang.Object
2474    foreach my $C (keys(%JavaObjectMethod))
2475    {
2476        if($TargetSuffix eq get_MSuffix($C))
2477        {
2478            if($TargetShortName eq get_MShort($C)) {
2479                return $C;
2480            }
2481        }
2482    }
2483   
2484    return undef;
2485}
2486
2487sub findMethod_Class($$$)
2488{
2489    my ($Method, $ClassName, $ClassVersion) = @_;
2490    my $TargetSuffix = get_MSuffix($Method);
2491    my $TargetShortName = get_MShort($Method);
2492   
2493    if(not defined $Class_Methods{$ClassVersion}{$ClassName}) {
2494        return undef;
2495    }
2496   
2497    foreach my $Candidate (sort keys(%{$Class_Methods{$ClassVersion}{$ClassName}}))
2498    { # search for method with the same parameters suffix
2499        next if($MethodInfo{$ClassVersion}{$Candidate}{"Constructor"});
2500        if($TargetSuffix eq get_MSuffix($Candidate))
2501        {
2502            if($TargetShortName eq get_MShort($Candidate)) {
2503                return $Candidate;
2504            }
2505        }
2506    }
2507   
2508    return undef;
2509}
2510
2511sub prepareMethods($)
2512{
2513    my $LibVersion = $_[0];
2514    foreach my $Method (keys(%{$MethodInfo{$LibVersion}}))
2515    {
2516        if($MethodInfo{$LibVersion}{$Method}{"Access"}!~/private/)
2517        {
2518            if($MethodInfo{$LibVersion}{$Method}{"Constructor"}) {
2519                registerUsage($MethodInfo{$LibVersion}{$Method}{"Class"}, $LibVersion);
2520            }
2521            else {
2522                registerUsage($MethodInfo{$LibVersion}{$Method}{"Return"}, $LibVersion);
2523            }
2524        }
2525    }
2526}
2527
2528sub mergeMethods()
2529{
2530    foreach my $Method (sort keys(%{$MethodInfo{1}}))
2531    { # compare methods
2532        next if(not defined $MethodInfo{2}{$Method});
2533       
2534        if(not $MethodInfo{1}{$Method}{"Archive"}
2535        or not $MethodInfo{2}{$Method}{"Archive"}) {
2536            next;
2537        }
2538       
2539        if(not methodFilter($Method, 1)) {
2540            next;
2541        }
2542       
2543        my $ClassId1 = $MethodInfo{1}{$Method}{"Class"};
2544        my %Class1 = get_Type($ClassId1, 1);
2545       
2546        $CheckedTypes{$Class1{"Name"}} = 1;
2547        $CheckedMethods{$Method} = 1;
2548       
2549        my %Class2 = get_Type($MethodInfo{2}{$Method}{"Class"}, 2);
2550        if(not $MethodInfo{1}{$Method}{"Static"}
2551        and $Class1{"Type"} eq "class" and not $Class_Constructed{1}{$ClassId1})
2552        { # class cannot be constructed or inherited by clients
2553          # non-static method cannot be called
2554            next;
2555        }
2556        # checking attributes
2557        if(not $MethodInfo{1}{$Method}{"Static"}
2558        and $MethodInfo{2}{$Method}{"Static"}) {
2559            %{$CompatProblems{$Method}{"Method_Became_Static"}{""}} = ();
2560        }
2561        elsif($MethodInfo{1}{$Method}{"Static"}
2562        and not $MethodInfo{2}{$Method}{"Static"}) {
2563            %{$CompatProblems{$Method}{"Method_Became_NonStatic"}{""}} = ();
2564        }
2565        if(not $MethodInfo{1}{$Method}{"Synchronized"}
2566        and $MethodInfo{2}{$Method}{"Synchronized"}) {
2567            %{$CompatProblems{$Method}{"Method_Became_Synchronized"}{""}} = ();
2568        }
2569        elsif($MethodInfo{1}{$Method}{"Synchronized"}
2570        and not $MethodInfo{2}{$Method}{"Synchronized"}) {
2571            %{$CompatProblems{$Method}{"Method_Became_NonSynchronized"}{""}} = ();
2572        }
2573        if(not $MethodInfo{1}{$Method}{"Final"}
2574        and $MethodInfo{2}{$Method}{"Final"})
2575        {
2576            if($MethodInfo{1}{$Method}{"Static"}) {
2577                %{$CompatProblems{$Method}{"Static_Method_Became_Final"}{""}} = ();
2578            }
2579            else {
2580                %{$CompatProblems{$Method}{"NonStatic_Method_Became_Final"}{""}} = ();
2581            }
2582        }
2583        my $Access1 = $MethodInfo{1}{$Method}{"Access"};
2584        my $Access2 = $MethodInfo{2}{$Method}{"Access"};
2585        if($Access1 eq "public" and $Access2=~/protected|private/
2586        or $Access1 eq "protected" and $Access2=~/private/)
2587        {
2588            %{$CompatProblems{$Method}{"Changed_Method_Access"}{""}} = (
2589                "Old_Value"=>$Access1,
2590                "New_Value"=>$Access2  );
2591        }
2592        if($Class1{"Type"} eq "class"
2593        and $Class2{"Type"} eq "class")
2594        {
2595            if(not $MethodInfo{1}{$Method}{"Abstract"}
2596            and $MethodInfo{2}{$Method}{"Abstract"})
2597            {
2598                %{$CompatProblems{$Method}{"Method_Became_Abstract"}{""}} = ();
2599                %{$CompatProblems{$Method}{"Class_Method_Became_Abstract"}{"this.".get_SFormat($Method)}} = (
2600                    "Type_Name"=>$Class1{"Name"},
2601                    "Target"=>$Method  );
2602            }
2603            elsif($MethodInfo{1}{$Method}{"Abstract"}
2604            and not $MethodInfo{2}{$Method}{"Abstract"})
2605            {
2606                %{$CompatProblems{$Method}{"Method_Became_NonAbstract"}{""}} = ();
2607                %{$CompatProblems{$Method}{"Class_Method_Became_NonAbstract"}{"this.".get_SFormat($Method)}} = (
2608                    "Type_Name"=>$Class1{"Name"},
2609                    "Target"=>$Method  );
2610            }
2611        }
2612        elsif($Class1{"Type"} eq "interface"
2613        and $Class2{"Type"} eq "interface")
2614        {
2615            if(not $MethodInfo{1}{$Method}{"Abstract"}
2616            and $MethodInfo{2}{$Method}{"Abstract"})
2617            {
2618                %{$CompatProblems{$Method}{"Method_Became_NonDefault"}{""}} = ();
2619                %{$CompatProblems{$Method}{"Interface_Method_Became_NonDefault"}{"this.".get_SFormat($Method)}} = (
2620                    "Type_Name"=>$Class1{"Name"},
2621                    "Target"=>$Method  );
2622            }
2623            elsif($MethodInfo{1}{$Method}{"Abstract"}
2624            and not $MethodInfo{2}{$Method}{"Abstract"})
2625            {
2626                %{$CompatProblems{$Method}{"Method_Became_Default"}{""}} = ();
2627                %{$CompatProblems{$Method}{"Interface_Method_Became_Default"}{"this.".get_SFormat($Method)}} = (
2628                    "Type_Name"=>$Class1{"Name"},
2629                    "Target"=>$Method  );
2630            }
2631        }
2632       
2633        my %Exceptions_Old = map {get_TypeName($_, 1) => $_} keys(%{$MethodInfo{1}{$Method}{"Exceptions"}});
2634        my %Exceptions_New = map {get_TypeName($_, 2) => $_} keys(%{$MethodInfo{2}{$Method}{"Exceptions"}});
2635        foreach my $Exception (keys(%Exceptions_Old))
2636        {
2637            if(not $Exceptions_New{$Exception})
2638            {
2639                my %ExceptionType = get_Type($Exceptions_Old{$Exception}, 1);
2640                my $SuperClass = $ExceptionType{"SuperClass"};
2641                if($KnownRuntimeExceptions{$Exception}
2642                or defined $SuperClass and get_TypeName($SuperClass, 1) eq "java.lang.RuntimeException")
2643                {
2644                    if(not $MethodInfo{1}{$Method}{"Abstract"}
2645                    and not $MethodInfo{2}{$Method}{"Abstract"})
2646                    {
2647                        %{$CompatProblems{$Method}{"Removed_Unchecked_Exception"}{"this.".get_SFormat($Exception)}} = (
2648                            "Type_Name"=>$Class1{"Name"},
2649                            "Target"=>$Exception  );
2650                    }
2651                }
2652                else
2653                {
2654                    if($MethodInfo{1}{$Method}{"Abstract"}
2655                    and $MethodInfo{2}{$Method}{"Abstract"})
2656                    {
2657                        %{$CompatProblems{$Method}{"Abstract_Method_Removed_Checked_Exception"}{"this.".get_SFormat($Exception)}} = (
2658                            "Type_Name"=>$Class1{"Name"},
2659                            "Target"=>$Exception  );
2660                    }
2661                    else
2662                    {
2663                        %{$CompatProblems{$Method}{"NonAbstract_Method_Removed_Checked_Exception"}{"this.".get_SFormat($Exception)}} = (
2664                            "Type_Name"=>$Class1{"Name"},
2665                            "Target"=>$Exception  );
2666                    }
2667                }
2668            }
2669        }
2670        foreach my $Exception (keys(%Exceptions_New))
2671        {
2672            if(not $Exceptions_Old{$Exception})
2673            {
2674                my %ExceptionType = get_Type($Exceptions_New{$Exception}, 2);
2675                my $SuperClass = $ExceptionType{"SuperClass"};
2676                if($KnownRuntimeExceptions{$Exception}
2677                or defined $SuperClass and get_TypeName($SuperClass, 2) eq "java.lang.RuntimeException")
2678                {
2679                    if(not $MethodInfo{1}{$Method}{"Abstract"}
2680                    and not $MethodInfo{2}{$Method}{"Abstract"})
2681                    {
2682                        %{$CompatProblems{$Method}{"Added_Unchecked_Exception"}{"this.".get_SFormat($Exception)}} = (
2683                            "Type_Name"=>$Class1{"Name"},
2684                            "Target"=>$Exception  );
2685                    }
2686                }
2687                else
2688                {
2689                    if($MethodInfo{1}{$Method}{"Abstract"}
2690                    and $MethodInfo{2}{$Method}{"Abstract"})
2691                    {
2692                        %{$CompatProblems{$Method}{"Abstract_Method_Added_Checked_Exception"}{"this.".get_SFormat($Exception)}} = (
2693                            "Type_Name"=>$Class1{"Name"},
2694                            "Target"=>$Exception  );
2695                    }
2696                    else
2697                    {
2698                        %{$CompatProblems{$Method}{"NonAbstract_Method_Added_Checked_Exception"}{"this.".get_SFormat($Exception)}} = (
2699                            "Type_Name"=>$Class1{"Name"},
2700                            "Target"=>$Exception  );
2701                    }
2702                }
2703            }
2704        }
2705       
2706        if(defined $MethodInfo{1}{$Method}{"Param"})
2707        {
2708            foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$MethodInfo{1}{$Method}{"Param"}}))
2709            { # checking parameters
2710                mergeParameters($Method, $ParamPos, $ParamPos);
2711            }
2712        }
2713       
2714        # check object type
2715        my $ObjectType1_Id = $MethodInfo{1}{$Method}{"Class"};
2716        my $ObjectType2_Id = $MethodInfo{2}{$Method}{"Class"};
2717        if($ObjectType1_Id and $ObjectType2_Id)
2718        {
2719            my $SubProblems = mergeTypes($ObjectType1_Id, $ObjectType2_Id);
2720            foreach my $SubProblemType (keys(%{$SubProblems}))
2721            {
2722                foreach my $SubLocation (keys(%{$SubProblems->{$SubProblemType}}))
2723                {
2724                    my $NewLocation = ($SubLocation)?"this.".$SubLocation:"this";
2725                    $CompatProblems{$Method}{$SubProblemType}{$NewLocation} = $SubProblems->{$SubProblemType}{$SubLocation};
2726                }
2727            }
2728        }
2729        # check return type
2730        my $ReturnType1_Id = $MethodInfo{1}{$Method}{"Return"};
2731        my $ReturnType2_Id = $MethodInfo{2}{$Method}{"Return"};
2732        if($ReturnType1_Id and $ReturnType2_Id)
2733        {
2734            my $SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id);
2735            foreach my $SubProblemType (keys(%{$SubProblems}))
2736            {
2737                foreach my $SubLocation (keys(%{$SubProblems->{$SubProblemType}}))
2738                {
2739                    my $NewLocation = ($SubLocation)?"retval.".$SubLocation:"retval";
2740                    $CompatProblems{$Method}{$SubProblemType}{$NewLocation} = $SubProblems->{$SubProblemType}{$SubLocation};
2741                }
2742            }
2743        }
2744    }
2745}
2746
2747sub mergeParameters($$$)
2748{
2749    my ($Method, $ParamPos1, $ParamPos2) = @_;
2750    if(not $Method or not defined $MethodInfo{1}{$Method}{"Param"}
2751    or not defined $MethodInfo{2}{$Method}{"Param"}) {
2752        return;
2753    }
2754   
2755    my $ParamType1_Id = $MethodInfo{1}{$Method}{"Param"}{$ParamPos1}{"Type"};
2756    my $ParamType2_Id = $MethodInfo{2}{$Method}{"Param"}{$ParamPos2}{"Type"};
2757   
2758    if(not $ParamType1_Id or not $ParamType2_Id) {
2759        return;
2760    }
2761   
2762    my $Parameter_Name = $MethodInfo{1}{$Method}{"Param"}{$ParamPos1}{"Name"};
2763    my $Parameter_Location = ($Parameter_Name)?$Parameter_Name:showPos($ParamPos1)." Parameter";
2764   
2765    # checking type declaration changes
2766    my $SubProblems = mergeTypes($ParamType1_Id, $ParamType2_Id);
2767    foreach my $SubProblemType (keys(%{$SubProblems}))
2768    {
2769        foreach my $SubLocation (keys(%{$SubProblems->{$SubProblemType}}))
2770        {
2771            my $NewLocation = ($SubLocation)?$Parameter_Location.".".$SubLocation:$Parameter_Location;
2772            $CompatProblems{$Method}{$SubProblemType}{$NewLocation} = $SubProblems->{$SubProblemType}{$SubLocation};
2773        }
2774    }
2775}
2776
2777sub detectTypeChange($$$)
2778{
2779    my ($Type1_Id, $Type2_Id, $Prefix) = @_;
2780    my %LocalProblems = ();
2781    my %Type1 = get_Type($Type1_Id, 1);
2782    my %Type2 = get_Type($Type2_Id, 2);
2783    my %Type1_Base = ($Type1{"Type"} eq "array")?get_OneStep_BaseType($Type1_Id, 1):get_BaseType($Type1_Id, 1);
2784    my %Type2_Base = ($Type2{"Type"} eq "array")?get_OneStep_BaseType($Type2_Id, 2):get_BaseType($Type2_Id, 2);
2785    return () if(not $Type1{"Name"} or not $Type2{"Name"});
2786    return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
2787    if($Type1_Base{"Name"} ne $Type2_Base{"Name"} and $Type1{"Name"} eq $Type2{"Name"})
2788    {# base type change
2789        %{$LocalProblems{"Changed_".$Prefix."_BaseType"}}=(
2790            "Old_Value"=>$Type1_Base{"Name"},
2791            "New_Value"=>$Type2_Base{"Name"} );
2792    }
2793    elsif($Type1{"Name"} ne $Type2{"Name"})
2794    {# type change
2795        %{$LocalProblems{"Changed_".$Prefix."_Type"}}=(
2796            "Old_Value"=>$Type1{"Name"},
2797            "New_Value"=>$Type2{"Name"} );
2798    }
2799    return %LocalProblems;
2800}
2801
2802sub htmlSpecChars($)
2803{
2804    my $Str = $_[0];
2805    if(not defined $Str
2806    or $Str eq "") {
2807        return "";
2808    }
2809    $Str=~s/\&([^#]|\Z)/&amp;$1/g;
2810    $Str=~s/</&lt;/g;
2811    $Str=~s/\-\>/&#45;&gt;/g; # &minus;
2812    $Str=~s/>/&gt;/g;
2813    $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
2814    $Str=~s/ /&#160;/g; # &nbsp;
2815    $Str=~s/\@ALONE_SP\@/ /g;
2816    $Str=~s/\n/<br\/>/g;
2817    $Str=~s/\"/&quot;/g;
2818    $Str=~s/\'/&#39;/g;
2819    return $Str;
2820}
2821
2822sub black_Name($$)
2823{
2824    my ($M, $V) = @_;
2825    return "<span class='iname_b'>".highLight_Signature($M, $V)."</span>";
2826}
2827
2828sub black_Name_S($)
2829{
2830    my $Name = $_[0];
2831    $Name=~s!\A(\w+)!<span class='iname_b'>$1</span>&#160;!g;
2832    return $Name;
2833}
2834
2835sub highLight_Signature($$)
2836{
2837    my ($M, $V) = @_;
2838    return get_Signature($M, $V, "Class|HTML|Italic");
2839}
2840
2841sub highLight_Signature_Italic_Color($$)
2842{
2843    my ($M, $V) = @_;
2844    return get_Signature($M, $V, "Full|HTML|Italic|Color");
2845}
2846
2847sub get_Signature($$$)
2848{
2849    my ($Method, $LibVersion, $Kind) = @_;
2850    if(defined $Cache{"get_Signature"}{$LibVersion}{$Method}{$Kind}) {
2851        return $Cache{"get_Signature"}{$LibVersion}{$Method}{$Kind};
2852    }
2853   
2854    # settings
2855    my ($Full, $Html, $Simple, $Italic, $Color,
2856    $ShowParams, $ShowClass, $ShowAttr, $Target) = (0, 0, 0, 0, 0, 0, 0, 0, undef);
2857   
2858    if($Kind=~/Full/) {
2859        $Full = 1;
2860    }
2861    if($Kind=~/HTML/) {
2862        $Html = 1;
2863    }
2864    if($Kind=~/Simple/) {
2865        $Simple = 1;
2866    }
2867    if($Kind=~/Italic/) {
2868        $Italic = 1;
2869    }
2870    if($Kind=~/Color/) {
2871        $Color = 1;
2872    }
2873    if($Kind=~/Target=(\d+)/) {
2874        $Target = $1;
2875    }
2876    if($Kind=~/Param/) {
2877        $ShowParams = 1;
2878    }
2879    if($Kind=~/Class/) {
2880        $ShowClass = 1;
2881    }
2882    if($Kind=~/Attr/) {
2883        $ShowAttr = 1;
2884    }
2885   
2886    if(not defined $MethodInfo{$LibVersion}{$Method}{"ShortName"})
2887    { # from java.lang.Object
2888        if($Html or $Simple) {
2889            return htmlSpecChars($Method);
2890        }
2891        else
2892        {
2893            return $Method;
2894        }
2895    }
2896   
2897    my $Signature = $MethodInfo{$LibVersion}{$Method}{"ShortName"};
2898    if($Full or $ShowClass)
2899    {
2900        my $Class = get_TypeName($MethodInfo{$LibVersion}{$Method}{"Class"}, $LibVersion);
2901       
2902        if($HideTemplates) {
2903            $Class=~s/<.*>//g;
2904        }
2905       
2906        if($Html) {
2907            $Class = htmlSpecChars($Class);
2908        }
2909       
2910        $Signature = $Class.".".$Signature;
2911    }
2912    my @Params = ();
2913   
2914    if(defined $MethodInfo{$LibVersion}{$Method}{"Param"})
2915    {
2916        foreach my $PPos (sort {int($a)<=>int($b)}
2917        keys(%{$MethodInfo{$LibVersion}{$Method}{"Param"}}))
2918        {
2919            my $PTid = $MethodInfo{$LibVersion}{$Method}{"Param"}{$PPos}{"Type"};
2920            if(my $PTName = get_TypeName($PTid, $LibVersion))
2921            {
2922                if($HideTemplates) {
2923                    $PTName=~s/<.*>//g;
2924                }
2925               
2926                if(not $ShowPackages) {
2927                    $PTName=~s/(\A|\<\s*|\,\s*)[a-z0-9\.]+\./$1/g;
2928                }
2929               
2930                if($Html) {
2931                    $PTName = htmlSpecChars($PTName);
2932                }
2933               
2934                if($Full or $ShowParams)
2935                {
2936                    my $PName = $MethodInfo{$LibVersion}{$Method}{"Param"}{$PPos}{"Name"};
2937                   
2938                    if($Simple) {
2939                        $PName = "<i>$PName</i>";
2940                    }
2941                    elsif($Html)
2942                    {
2943                        my $Style = "param";
2944                       
2945                        if(defined $Target
2946                        and $Target==$PPos) {
2947                            $PName = "<span class='focus_p'>$PName</span>";
2948                        }
2949                        elsif($Color) {
2950                            $PName = "<span class='color_p'>$PName</span>";
2951                        }
2952                        else {
2953                            $PName = "<i>$PName</i>";
2954                        }
2955                    }
2956                   
2957                    push(@Params, $PTName." ".$PName);
2958                }
2959                else {
2960                    push(@Params, $PTName);
2961                }
2962            }
2963        }
2964    }
2965   
2966    if($Simple) {
2967        $Signature = "<b>".$Signature."</b>";
2968    }
2969   
2970    if($Html and not $Simple)
2971    {
2972        $Signature .= "&#160;";
2973        $Signature .= "<span class='sym_p'>";
2974        if(@Params)
2975        {
2976            foreach my $Pos (0 .. $#Params)
2977            {
2978                my $Name = "";
2979               
2980                if($Pos==0) {
2981                    $Name .= "(&#160;";
2982                }
2983               
2984                $Name .= $Params[$Pos];
2985               
2986                $Name = "<span>".$Name."</span>";
2987               
2988                if($Pos==$#Params) {
2989                    $Name .= "&#160;)";
2990                }
2991                else {
2992                    $Name .= ", ";
2993                }
2994               
2995                $Signature .= $Name;
2996            }
2997        }
2998        else {
2999            $Signature .= "(&#160;)";
3000        }
3001        $Signature .= "</span>";
3002    }
3003    else
3004    {
3005        if(@Params) {
3006            $Signature .= " ( ".join(", ", @Params)." )";
3007        }
3008        else {
3009            $Signature .= " ( )";
3010        }
3011    }
3012   
3013    if($Full or $ShowAttr)
3014    {
3015        if($MethodInfo{$LibVersion}{$Method}{"Static"}) {
3016            $Signature .= " [static]";
3017        }
3018        elsif($MethodInfo{$LibVersion}{$Method}{"Abstract"}) {
3019            $Signature .= " [abstract]";
3020        }
3021    }
3022   
3023    if($Full)
3024    {
3025        if($ShowAccess)
3026        {
3027            if(my $Access = $MethodInfo{$LibVersion}{$Method}{"Access"})
3028            {
3029                if($Access ne "public") {
3030                    $Signature .= " [".$Access."]";
3031                }
3032            }
3033        }
3034       
3035        if(my $ReturnId = $MethodInfo{$LibVersion}{$Method}{"Return"})
3036        {
3037            my $RName = get_TypeName($ReturnId, $LibVersion);
3038           
3039            if($HideTemplates) {
3040                $RName=~s/<.*>//g;
3041            }
3042           
3043            if(not $ShowPackages) {
3044                $RName=~s/(\A|\<\s*|\,\s*)[a-z0-9\.]+\./$1/g;
3045            }
3046           
3047            if($Simple) {
3048                $Signature .= " <b>:</b> ".htmlSpecChars($RName);
3049            }
3050            elsif($Html) {
3051                $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($RName)."</span>";
3052            }
3053            else {
3054                $Signature .= " : ".$RName;
3055            }
3056        }
3057       
3058        if(not $SkipDeprecated)
3059        {
3060            if($MethodInfo{$LibVersion}{$Method}{"Deprecated"}) {
3061                $Signature .= " *DEPRECATED*";
3062            }
3063        }
3064    }
3065   
3066    $Signature=~s/java\.lang\.//g;
3067   
3068    if($Html)
3069    {
3070        if(not $SkipDeprecated) {
3071            $Signature=~s!(\*deprecated\*)!<span class='deprecated'>$1</span>!ig;
3072        }
3073       
3074        $Signature=~s!(\[static\]|\[abstract\]|\[public\]|\[private\]|\[protected\])!<span class='attr'>$1</span>!g;
3075    }
3076   
3077    if($Simple) {
3078        $Signature=~s/\[\]/\[ \]/g;
3079    }
3080    elsif($Html)
3081    {
3082        $Signature=~s!\[\]![&#160;]!g;
3083        $Signature=~s!operator=!operator&#160;=!g;
3084    }
3085   
3086    return ($Cache{"get_Signature"}{$LibVersion}{$Method}{$Kind} = $Signature);
3087}
3088
3089sub checkJavaCompiler($)
3090{ # check javac: compile simple program
3091    my $Cmd = $_[0];
3092   
3093    if(not $Cmd) {
3094        return;
3095    }
3096   
3097    writeFile($TMP_DIR."/test_javac/Simple.java",
3098    "public class Simple {
3099        public Integer f;
3100        public void method(Integer p) { };
3101    }");
3102    chdir($TMP_DIR."/test_javac");
3103    system("$Cmd Simple.java 2>errors.txt");
3104    chdir($ORIG_DIR);
3105    if($?)
3106    {
3107        my $Msg = "something is going wrong with the Java compiler (javac):\n";
3108        my $Err = readFile($TMP_DIR."/test_javac/errors.txt");
3109        $Msg .= $Err;
3110        if($Err=~/elf\/start\.S/ and $Err=~/undefined\s+reference\s+to/)
3111        { # /usr/lib/gcc/i586-suse-linux/4.5/../../../crt1.o: In function _start:
3112          # /usr/src/packages/BUILD/glibc-2.11.3/csu/../sysdeps/i386/elf/start.S:115: undefined reference to main
3113            $Msg .= "\nDid you install a JDK-devel package?";
3114        }
3115        exitStatus("Error", $Msg);
3116    }
3117}
3118
3119sub runTests($$$$)
3120{
3121    my ($TestsPath, $PackageName, $Path_v1, $Path_v2) = @_;
3122    # compile with old version of package
3123    my $JavacCmd = get_CmdPath("javac");
3124    if(not $JavacCmd) {
3125        exitStatus("Not_Found", "can't find \"javac\" compiler");
3126    }
3127    my $JavaCmd = get_CmdPath("java");
3128    if(not $JavaCmd) {
3129        exitStatus("Not_Found", "can't find \"java\" command");
3130    }
3131    mkpath($TestsPath."/$PackageName/");
3132    foreach my $ClassPath (cmd_find($Path_v1,"","*\.class",""))
3133    {# create a compile-time package copy
3134        copy($ClassPath, $TestsPath."/$PackageName/");
3135    }
3136    chdir($TestsPath);
3137    system($JavacCmd." -g *.java");
3138    chdir($ORIG_DIR);
3139    foreach my $TestSrc (cmd_find($TestsPath,"","*\.java",""))
3140    { # remove test source
3141        unlink($TestSrc);
3142    }
3143   
3144    my $PkgPath = $TestsPath."/".$PackageName;
3145    if(-d $PkgPath) {
3146        rmtree($PkgPath);
3147    }
3148    mkpath($PkgPath);
3149    foreach my $ClassPath (cmd_find($Path_v2,"","*\.class",""))
3150    {# create a run-time package copy
3151        copy($ClassPath, $PkgPath."/");
3152    }
3153    my $TEST_REPORT = "";
3154    foreach my $TestPath (cmd_find($TestsPath,"","*\.class",1))
3155    {# run tests
3156        my $Name = get_filename($TestPath);
3157        $Name=~s/\.class\Z//g;
3158        chdir($TestsPath);
3159        system($JavaCmd." $Name >result.txt 2>&1");
3160        chdir($ORIG_DIR);
3161        my $Result = readFile($TestsPath."/result.txt");
3162        unlink($TestsPath."/result.txt");
3163        $TEST_REPORT .= "TEST CASE: $Name\n";
3164        if($Result) {
3165            $TEST_REPORT .= "RESULT: FAILED\n";
3166            $TEST_REPORT .= "OUTPUT:\n$Result\n";
3167        }
3168        else {
3169            $TEST_REPORT .= "RESULT: SUCCESS\n";
3170        }
3171        $TEST_REPORT .= "\n";
3172    }
3173    writeFile("$TestsPath/Journal.txt", $TEST_REPORT);
3174   
3175    if(-d $PkgPath) {
3176        rmtree($PkgPath);
3177    }
3178}
3179
3180sub compileJavaLib($$$)
3181{
3182    my ($LibName, $BuildRoot1, $BuildRoot2) = @_;
3183    my $JavacCmd = get_CmdPath("javac");
3184    if(not $JavacCmd) {
3185        exitStatus("Not_Found", "can't find \"javac\" compiler");
3186    }
3187    checkJavaCompiler($JavacCmd);
3188    my $JarCmd = get_CmdPath("jar");
3189    if(not $JarCmd) {
3190        exitStatus("Not_Found", "can't find \"jar\" command");
3191    }
3192    writeFile("$BuildRoot1/MANIFEST.MF", "Implementation-Version: 1.0\n");
3193    # space before value, new line
3194    writeFile("$BuildRoot2/MANIFEST.MF", "Implementation-Version: 2.0\n");
3195    my (%SrcDir1, %SrcDir2) = ();
3196    foreach my $Path (cmd_find($BuildRoot1,"f","*.java","")) {
3197        $SrcDir1{get_dirname($Path)} = 1;
3198    }
3199    foreach my $Path (cmd_find($BuildRoot2,"f","*.java","")) {
3200        $SrcDir2{get_dirname($Path)} = 1;
3201    }
3202    # build classes v.1
3203    foreach my $Dir (keys(%SrcDir1))
3204    {
3205        chdir($Dir);
3206        system("$JavacCmd -g *.java");
3207        chdir($ORIG_DIR);
3208        if($?) {
3209            exitStatus("Error", "can't compile classes v.1");
3210        }
3211    }
3212    # create java archive v.1
3213    chdir($BuildRoot1);
3214    system("$JarCmd -cmf MANIFEST.MF $LibName.jar TestPackage");
3215    chdir($ORIG_DIR);
3216   
3217    # build classes v.2
3218    foreach my $Dir (keys(%SrcDir2))
3219    {
3220        chdir($Dir);
3221        system("$JavacCmd -g *.java");
3222        chdir($ORIG_DIR);
3223        if($?) {
3224            exitStatus("Error", "can't compile classes v.2");
3225        }
3226    }
3227    # create java archive v.2
3228    chdir($BuildRoot2);
3229    system("$JarCmd -cmf MANIFEST.MF $LibName.jar TestPackage");
3230    chdir($ORIG_DIR);
3231   
3232    foreach my $SrcPath (cmd_find($BuildRoot1,"","*\.java","")) {
3233        unlink($SrcPath);
3234    }
3235    foreach my $SrcPath (cmd_find($BuildRoot2,"","*\.java","")) {
3236        unlink($SrcPath);
3237    }
3238    return 1;
3239}
3240
3241sub readLineNum($$)
3242{
3243    my ($Path, $Num) = @_;
3244    return "" if(not $Path or not -f $Path);
3245    open (FILE, $Path);
3246    foreach (1 ... $Num) {
3247        <FILE>;
3248    }
3249    my $Line = <FILE>;
3250    close(FILE);
3251    return $Line;
3252}
3253
3254sub readAttributes($$)
3255{
3256    my ($Path, $Num) = @_;
3257    return () if(not $Path or not -f $Path);
3258    my %Attributes = ();
3259    if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
3260    {
3261        foreach my $AttrVal (split(/;/, $1))
3262        {
3263            if($AttrVal=~/(.+):(.+)/)
3264            {
3265                my ($Name, $Value) = ($1, $2);
3266                $Attributes{$Name} = $Value;
3267            }
3268        }
3269    }
3270    return \%Attributes;
3271}
3272
3273sub runChecker($$$)
3274{
3275    my ($LibName, $Path1, $Path2) = @_;
3276    writeFile("$LibName/v1.xml", "
3277        <version>
3278            1.0
3279        </version>
3280        <archives>
3281            ".get_abs_path($Path1)."
3282        </archives>");
3283    writeFile("$LibName/v2.xml", "
3284        <version>
3285            2.0
3286        </version>
3287        <archives>
3288            ".get_abs_path($Path2)."
3289        </archives>");
3290    my $Cmd = "perl $0 -l $LibName $LibName/v1.xml $LibName/v2.xml";
3291    if($Quick) {
3292        $Cmd .= " -quick";
3293    }
3294    if(defined $SkipDeprecated) {
3295        $Cmd .= " -skip-deprecated";
3296    }
3297    if(defined $OldStyle) {
3298        $Cmd .= " -old-style";
3299    }
3300    writeFile($TMP_DIR."/skip-annotations.list", "TestPackage.Beta");
3301    $Cmd .= " -skip-annotations-list ".$TMP_DIR."/skip-annotations.list";
3302    if($Debug)
3303    {
3304        $Cmd .= " -debug";
3305        printMsg("INFO", "running $Cmd");
3306    }
3307    system($Cmd);
3308    my $Report = "compat_reports/$LibName/1.0_to_2.0/compat_report.html";
3309    # Binary
3310    my $BReport = readAttributes($Report, 0);
3311    my $NProblems = $BReport->{"type_problems_high"}+$BReport->{"type_problems_medium"};
3312    $NProblems += $BReport->{"method_problems_high"}+$BReport->{"method_problems_medium"};
3313    $NProblems += $BReport->{"removed"};
3314    # Source
3315    my $SReport = readAttributes($Report, 1);
3316    $NProblems += $SReport->{"type_problems_high"}+$SReport->{"type_problems_medium"};
3317    $NProblems += $SReport->{"method_problems_high"}+$SReport->{"method_problems_medium"};
3318    $NProblems += $SReport->{"removed"};
3319    if($NProblems>=100) {
3320        printMsg("INFO", "test result: SUCCESS ($NProblems breaks found)\n");
3321    }
3322    else {
3323        printMsg("ERROR", "test result: FAILED ($NProblems breaks found)\n");
3324    }
3325}
3326
3327sub writeFile($$)
3328{
3329    my ($Path, $Content) = @_;
3330    return if(not $Path);
3331    if(my $Dir = get_dirname($Path)) {
3332        mkpath($Dir);
3333    }
3334    open (FILE, ">".$Path) || die ("can't open file \'$Path\': $!\n");
3335    print FILE $Content;
3336    close(FILE);
3337}
3338
3339sub readFile($)
3340{
3341    my $Path = $_[0];
3342    return "" if(not $Path or not -f $Path);
3343    open (FILE, $Path);
3344    my $Content = join("", <FILE>);
3345    close(FILE);
3346    $Content=~s/\r//g;
3347    return $Content;
3348}
3349
3350sub appendFile($$)
3351{
3352    my ($Path, $Content) = @_;
3353    return if(not $Path);
3354    if(my $Dir = get_dirname($Path)) {
3355        mkpath($Dir);
3356    }
3357    open(FILE, ">>".$Path) || die ("can't open file \'$Path\': $!\n");
3358    print FILE $Content;
3359    close(FILE);
3360}
3361
3362sub get_Report_Header($)
3363{
3364    my $Level = $_[0];
3365    my $Report_Header = "<h1>";
3366    if($Level eq "Source") {
3367        $Report_Header .= "Source compatibility";
3368    }
3369    elsif($Level eq "Binary") {
3370        $Report_Header .= "Binary compatibility";
3371    }
3372    else {
3373        $Report_Header .= "API compatibility";
3374    }
3375    $Report_Header .= " report for the <span style='color:Blue;'>$TargetTitle</span> library between <span style='color:Red;'>".$Descriptor{1}{"Version"}."</span> and <span style='color:Red;'>".$Descriptor{2}{"Version"}."</span> versions";
3376    if($ClientPath) {
3377        $Report_Header .= " (concerning portability of the client: <span style='color:Blue;'>".get_filename($ClientPath)."</span>)";
3378    }
3379    $Report_Header .= "</h1>\n";
3380    return $Report_Header;
3381}
3382
3383sub get_SourceInfo()
3384{
3385    my $CheckedArchives = "<a name='Checked_Archives'></a>";
3386    if($OldStyle) {
3387        $CheckedArchives .= "<h2>Java ARchives (".keys(%{$LibArchives{1}}).")</h2>";
3388    }
3389    else {
3390        $CheckedArchives .= "<h2>Java ARchives <span class='gray'>&nbsp;".keys(%{$LibArchives{1}})."&nbsp;</span></h2>";
3391    }
3392    $CheckedArchives .= "\n<hr/><div class='jar_list'>\n";
3393    foreach my $ArchivePath (sort {lc($a) cmp lc($b)}  keys(%{$LibArchives{1}})) {
3394        $CheckedArchives .= get_filename($ArchivePath)."<br/>\n";
3395    }
3396    $CheckedArchives .= "</div><br/>$TOP_REF<br/>\n";
3397    return $CheckedArchives;
3398}
3399
3400sub get_TypeProblems_Count($$)
3401{
3402    my ($TargetSeverity, $Level) = @_;
3403    my $Type_Problems_Count = 0;
3404   
3405    foreach my $Type_Name (sort keys(%{$TypeChanges{$Level}}))
3406    {
3407        my %Kinds_Target = ();
3408        foreach my $Kind (sort keys(%{$TypeChanges{$Level}{$Type_Name}}))
3409        {
3410            if($TypeProblems_Kind{$Level}{$Kind} ne $TargetSeverity) {
3411                next;
3412            }
3413            foreach my $Location (sort keys(%{$TypeChanges{$Level}{$Type_Name}{$Kind}}))
3414            {
3415                my $Target = $TypeChanges{$Level}{$Type_Name}{$Kind}{$Location}{"Target"};
3416               
3417                if($Kinds_Target{$Kind}{$Target}) {
3418                    next;
3419                }
3420               
3421                $Kinds_Target{$Kind}{$Target} = 1;
3422                $Type_Problems_Count += 1;
3423            }
3424        }
3425    }
3426   
3427    return $Type_Problems_Count;
3428}
3429
3430sub show_number($)
3431{
3432    if($_[0])
3433    {
3434        my $Num = cut_off_number($_[0], 2, 0);
3435        if($Num eq "0")
3436        {
3437            foreach my $P (3 .. 7)
3438            {
3439                $Num = cut_off_number($_[0], $P, 1);
3440                if($Num ne "0") {
3441                    last;
3442                }
3443            }
3444        }
3445        if($Num eq "0") {
3446            $Num = $_[0];
3447        }
3448        return $Num;
3449    }
3450    return $_[0];
3451}
3452
3453sub cut_off_number($$$)
3454{
3455    my ($num, $digs_to_cut, $z) = @_;
3456    if($num!~/\./)
3457    {
3458        $num .= ".";
3459        foreach (1 .. $digs_to_cut-1) {
3460            $num .= "0";
3461        }
3462    }
3463    elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
3464    {
3465        foreach (1 .. $digs_to_cut - 1 - length($1)) {
3466            $num .= "0";
3467        }
3468    }
3469    elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
3470      $num=sprintf("%.".($digs_to_cut-1)."f", $num);
3471    }
3472    $num=~s/\.[0]+\Z//g;
3473    if($z) {
3474        $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
3475    }
3476    return $num;
3477}
3478
3479sub get_Summary($)
3480{
3481    my $Level = $_[0];
3482    my ($Added, $Removed, $M_Problems_High, $M_Problems_Medium, $M_Problems_Low,
3483    $T_Problems_High, $T_Problems_Medium, $T_Problems_Low, $M_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0);
3484   
3485    %{$RESULT{$Level}} = (
3486        "Problems"=>0,
3487        "Warnings"=>0,
3488        "Affected"=>0 );
3489   
3490    foreach my $Method (sort keys(%CompatProblems))
3491    {
3492        foreach my $Kind (sort keys(%{$CompatProblems{$Method}}))
3493        {
3494            if(my $Severity = $MethodProblems_Kind{$Level}{$Kind})
3495            {
3496                foreach my $Location (sort keys(%{$CompatProblems{$Method}{$Kind}}))
3497                {
3498                    if($Kind eq "Added_Method")
3499                    {
3500                        if($Level eq "Source")
3501                        {
3502                            if($ChangedReturnFromVoid{$Method}) {
3503                                next;
3504                            }
3505                        }
3506                        $Added+=1;
3507                    }
3508                    elsif($Kind eq "Removed_Method")
3509                    {
3510                        if($Level eq "Source")
3511                        {
3512                            if($ChangedReturnFromVoid{$Method}) {
3513                                next;
3514                            }
3515                        }
3516                        $Removed+=1;
3517                        $TotalAffected{$Level}{$Method} = $Severity;
3518                    }
3519                    else
3520                    {
3521                        if($Severity eq "Safe") {
3522                            $M_Other += 1;
3523                        }
3524                        elsif($Severity eq "High") {
3525                            $M_Problems_High+=1;
3526                        }
3527                        elsif($Severity eq "Medium") {
3528                            $M_Problems_Medium+=1;
3529                        }
3530                        elsif($Severity eq "Low") {
3531                            $M_Problems_Low+=1;
3532                        }
3533                        if(($Severity ne "Low" or $StrictCompat)
3534                        and $Severity ne "Safe") {
3535                            $TotalAffected{$Level}{$Method} = $Severity;
3536                        }
3537                    }
3538                }
3539            }
3540        }
3541    }
3542   
3543    my %MethodTypeIndex = ();
3544   
3545    foreach my $Method (sort keys(%CompatProblems))
3546    {
3547        my @Kinds = sort keys(%{$CompatProblems{$Method}});
3548        foreach my $Kind (@Kinds)
3549        {
3550            if(my $Severity = $TypeProblems_Kind{$Level}{$Kind})
3551            {
3552                my @Locs = sort {length($a)<=>length($b)} sort keys(%{$CompatProblems{$Method}{$Kind}});
3553                foreach my $Location (@Locs)
3554                {
3555                    my $Type_Name = $CompatProblems{$Method}{$Kind}{$Location}{"Type_Name"};
3556                    my $Target = $CompatProblems{$Method}{$Kind}{$Location}{"Target"};
3557                   
3558                    if(defined $MethodTypeIndex{$Method}{$Type_Name}{$Kind}{$Target})
3559                    { # one location for one type and target
3560                        next;
3561                    }
3562                    $MethodTypeIndex{$Method}{$Type_Name}{$Kind}{$Target} = 1;
3563                    $TypeChanges{$Level}{$Type_Name}{$Kind}{$Location} = $CompatProblems{$Method}{$Kind}{$Location};
3564                   
3565                    if(($Severity ne "Low" or $StrictCompat)
3566                    and $Severity ne "Safe")
3567                    {
3568                        if(my $Sev = $TotalAffected{$Level}{$Method})
3569                        {
3570                            if($Severity_Val{$Severity}>$Severity_Val{$Sev}) {
3571                                $TotalAffected{$Level}{$Method} = $Severity;
3572                            }
3573                        }
3574                        else {
3575                            $TotalAffected{$Level}{$Method} = $Severity;
3576                        }
3577                    }
3578                }
3579            }
3580        }
3581    }
3582   
3583    %MethodTypeIndex = (); # clear memory
3584   
3585   
3586    $T_Problems_High = get_TypeProblems_Count("High", $Level);
3587    $T_Problems_Medium = get_TypeProblems_Count("Medium", $Level);
3588    $T_Problems_Low = get_TypeProblems_Count("Low", $Level);
3589    $T_Other = get_TypeProblems_Count("Safe", $Level);
3590   
3591    my $SCount = keys(%CheckedMethods)-$Added;
3592    if($SCount)
3593    {
3594        my %Weight = (
3595            "High" => 100,
3596            "Medium" => 50,
3597            "Low" => 25
3598        );
3599        foreach (keys(%{$TotalAffected{$Level}})) {
3600            $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
3601        }
3602        $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
3603    }
3604    else {
3605        $RESULT{$Level}{"Affected"} = 0;
3606    }
3607    $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
3608    if($RESULT{$Level}{"Affected"}>=100) {
3609        $RESULT{$Level}{"Affected"} = 100;
3610    }
3611   
3612    my ($TestInfo, $TestResults, $Problem_Summary) = ();
3613   
3614    # test info
3615    $TestInfo .= "<h2>Test Info</h2><hr/>\n";
3616    $TestInfo .= "<table class='summary'>\n";
3617    $TestInfo .= "<tr><th>Library Name</th><td>$TargetTitle</td></tr>\n";
3618    $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}."</td></tr>\n";
3619    $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}."</td></tr>\n";
3620   
3621    if($JoinReport)
3622    {
3623        if($Level eq "Binary") {
3624            $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
3625        }
3626        if($Level eq "Source") {
3627            $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
3628        }
3629    }
3630    $TestInfo .= "</table>\n";
3631   
3632    # test results
3633    $TestResults .= "<h2>Test Results</h2><hr/>";
3634    $TestResults .= "<table class='summary'>";
3635   
3636    my $Checked_Archives_Link = "0";
3637    $Checked_Archives_Link = "<a href='#Checked_Archives' style='color:Blue;'>".keys(%{$LibArchives{1}})."</a>" if(keys(%{$LibArchives{1}})>0);
3638   
3639    $TestResults .= "<tr><th>Total JARs</th><td>$Checked_Archives_Link</td></tr>\n";
3640    $TestResults .= "<tr><th>Total Methods / Classes</th><td>".keys(%CheckedMethods)." / ".keys(%CheckedTypes)."</td></tr>\n";
3641   
3642    $RESULT{$Level}{"Problems"} += $Removed+$M_Problems_High+$T_Problems_High+$T_Problems_Medium+$M_Problems_Medium;
3643    if($StrictCompat) {
3644        $RESULT{$Level}{"Problems"}+=$T_Problems_Low+$M_Problems_Low;
3645    }
3646    else {
3647        $RESULT{$Level}{"Warnings"}+=$T_Problems_Low+$M_Problems_Low;
3648    }
3649   
3650    my $META_DATA = "kind:".lc($Level).";";
3651    $META_DATA .= $RESULT{$Level}{"Problems"}?"verdict:incompatible;":"verdict:compatible;";
3652    $TestResults .= "<tr><th>Compatibility</th>\n";
3653   
3654    my $BC_Rate = show_number(100 - $RESULT{$Level}{"Affected"});
3655   
3656    if($RESULT{$Level}{"Problems"})
3657    {
3658        my $Cl = "incompatible";
3659        if($BC_Rate>=90) {
3660            $Cl = "warning";
3661        }
3662        elsif($BC_Rate>=80) {
3663            $Cl = "almost_compatible";
3664        }
3665       
3666        $TestResults .= "<td class=\'$Cl\'>".$BC_Rate."%</td>\n";
3667    }
3668    else
3669    {
3670        $TestResults .= "<td class=\'compatible\'>100%</td>\n";
3671    }
3672   
3673    $TestResults .= "</tr>\n";
3674    $TestResults .= "</table>\n";
3675   
3676    $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
3677   
3678    # Problem Summary
3679    $Problem_Summary .= "<h2>Problem Summary</h2><hr/>";
3680    $Problem_Summary .= "<table class='summary'>";
3681    $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
3682   
3683    my $Added_Link = "0";
3684    if($Added>0)
3685    {
3686        if($ShortMode) {
3687            $Added_Link = $Added;
3688        }
3689        else
3690        {
3691            if($JoinReport) {
3692                $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
3693            }
3694            else {
3695                $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
3696            }
3697        }
3698    }
3699    $META_DATA .= "added:$Added;";
3700    $Problem_Summary .= "<tr><th>Added Methods</th><td>-</td><td".getStyle("M", "Added", $Added).">$Added_Link</td></tr>";
3701   
3702    my $Removed_Link = "0";
3703    if($Removed>0)
3704    {
3705        if($ShortMode) {
3706            $Removed_Link = $Removed;
3707        }
3708        else
3709        {
3710            if($JoinReport) {
3711                $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
3712            }
3713            else {
3714                $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
3715            }
3716        }
3717    }
3718    $META_DATA .= "removed:$Removed;";
3719    $Problem_Summary .= "<tr><th>Removed Methods</th>";
3720    $Problem_Summary .= "<td>High</td><td".getStyle("M", "Removed", $Removed).">$Removed_Link</td></tr>";
3721   
3722    my $TH_Link = "0";
3723    $TH_Link = "<a href='#".get_Anchor("Type", $Level, "High")."' style='color:Blue;'>$T_Problems_High</a>" if($T_Problems_High>0);
3724    $META_DATA .= "type_problems_high:$T_Problems_High;";
3725    $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
3726    $Problem_Summary .= "<td>High</td><td".getStyle("T", "High", $T_Problems_High).">$TH_Link</td></tr>";
3727   
3728    my $TM_Link = "0";
3729    $TM_Link = "<a href='#".get_Anchor("Type", $Level, "Medium")."' style='color:Blue;'>$T_Problems_Medium</a>" if($T_Problems_Medium>0);
3730    $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
3731    $Problem_Summary .= "<tr><td>Medium</td><td".getStyle("T", "Medium", $T_Problems_Medium).">$TM_Link</td></tr>";
3732   
3733    my $TL_Link = "0";
3734    $TL_Link = "<a href='#".get_Anchor("Type", $Level, "Low")."' style='color:Blue;'>$T_Problems_Low</a>" if($T_Problems_Low>0);
3735    $META_DATA .= "type_problems_low:$T_Problems_Low;";
3736    $Problem_Summary .= "<tr><td>Low</td><td".getStyle("T", "Low", $T_Problems_Low).">$TL_Link</td></tr>";
3737   
3738    my $MH_Link = "0";
3739    $MH_Link = "<a href='#".get_Anchor("Method", $Level, "High")."' style='color:Blue;'>$M_Problems_High</a>" if($M_Problems_High>0);
3740    $META_DATA .= "method_problems_high:$M_Problems_High;";
3741    $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Methods</th>";
3742    $Problem_Summary .= "<td>High</td><td".getStyle("M", "High", $M_Problems_High).">$MH_Link</td></tr>";
3743   
3744    my $MM_Link = "0";
3745    $MM_Link = "<a href='#".get_Anchor("Method", $Level, "Medium")."' style='color:Blue;'>$M_Problems_Medium</a>" if($M_Problems_Medium>0);
3746    $META_DATA .= "method_problems_medium:$M_Problems_Medium;";
3747    $Problem_Summary .= "<tr><td>Medium</td><td".getStyle("M", "Medium", $M_Problems_Medium).">$MM_Link</td></tr>";
3748   
3749    my $ML_Link = "0";
3750    $ML_Link = "<a href='#".get_Anchor("Method", $Level, "Low")."' style='color:Blue;'>$M_Problems_Low</a>" if($M_Problems_Low>0);
3751    $META_DATA .= "method_problems_low:$M_Problems_Low;";
3752    $Problem_Summary .= "<tr><td>Low</td><td".getStyle("M", "Low", $M_Problems_Low).">$ML_Link</td></tr>";
3753   
3754    # Safe Changes
3755    if($T_Other)
3756    {
3757        my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
3758        $Problem_Summary .= "<tr><th>Other Changes<br/>in Data Types</th><td>-</td><td".getStyle("T", "Safe", $T_Other).">$TS_Link</td></tr>\n";
3759    }
3760   
3761    if($M_Other)
3762    {
3763        my $MS_Link = "<a href='#".get_Anchor("Method", $Level, "Safe")."' style='color:Blue;'>$M_Other</a>";
3764        $Problem_Summary .= "<tr><th>Other Changes<br/>in Methods</th><td>-</td><td".getStyle("M", "Safe", $M_Other).">$MS_Link</td></tr>\n";
3765    }
3766    $META_DATA .= "checked_methods:".keys(%CheckedMethods).";";
3767    $META_DATA .= "checked_types:".keys(%CheckedTypes).";";
3768    $META_DATA .= "tool_version:$TOOL_VERSION";
3769    $Problem_Summary .= "</table>\n";
3770    return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
3771}
3772
3773sub getStyle($$$)
3774{
3775    my ($Subj, $Act, $Num) = @_;
3776    my %Style = (
3777        "Added"=>"new",
3778        "Removed"=>"failed",
3779        "Safe"=>"passed",
3780        "Low"=>"warning",
3781        "Medium"=>"failed",
3782        "High"=>"failed"
3783    );
3784   
3785    if($Num>0) {
3786        return " class='".$Style{$Act}."'";
3787    }
3788   
3789    return "";
3790}
3791
3792sub get_Anchor($$$)
3793{
3794    my ($Kind, $Level, $Severity) = @_;
3795    if($JoinReport)
3796    {
3797        if($Severity eq "Safe") {
3798            return "Other_".$Level."_Changes_In_".$Kind."s";
3799        }
3800        else {
3801            return $Kind."_".$Level."_Problems_".$Severity;
3802        }
3803    }
3804    else
3805    {
3806        if($Severity eq "Safe") {
3807            return "Other_Changes_In_".$Kind."s";
3808        }
3809        else {
3810            return $Kind."_Problems_".$Severity;
3811        }
3812    }
3813}
3814
3815sub get_Report_Added($)
3816{
3817    if($ShortMode) {
3818        return "";
3819    }
3820   
3821    my $Level = $_[0];
3822    my ($ADDED_METHODS, %MethodAddedInArchiveClass);
3823    foreach my $Method (sort keys(%CompatProblems))
3824    {
3825        foreach my $Kind (sort keys(%{$CompatProblems{$Method}}))
3826        {
3827            if($Kind eq "Added_Method")
3828            {
3829                my $ArchiveName = $MethodInfo{2}{$Method}{"Archive"};
3830                my $ClassName = get_ShortName($MethodInfo{2}{$Method}{"Class"}, 2);
3831                if($Level eq "Source")
3832                {
3833                    if($ChangedReturnFromVoid{$Method}) {
3834                        next;
3835                    }
3836                }
3837                $MethodAddedInArchiveClass{$ArchiveName}{$ClassName}{$Method} = 1;
3838            }
3839        }
3840    }
3841    my $Added_Number = 0;
3842    foreach my $ArchiveName (sort {lc($a) cmp lc($b)} keys(%MethodAddedInArchiveClass))
3843    {
3844        foreach my $ClassName (sort {lc($a) cmp lc($b)} keys(%{$MethodAddedInArchiveClass{$ArchiveName}}))
3845        {
3846            my %NameSpace_Method = ();
3847            foreach my $Method (keys(%{$MethodAddedInArchiveClass{$ArchiveName}{$ClassName}})) {
3848                $NameSpace_Method{$MethodInfo{2}{$Method}{"Package"}}{$Method} = 1;
3849            }
3850           
3851            my $ShowClass = $ClassName;
3852            $ShowClass=~s/<.*>//g;
3853           
3854            foreach my $NameSpace (sort keys(%NameSpace_Method))
3855            {
3856                $ADDED_METHODS .= "<span class='jar'>$ArchiveName</span>, <span class='cname'>".htmlSpecChars($ShowClass).".class</span><br/>\n";
3857               
3858                if($NameSpace) {
3859                    $ADDED_METHODS .= "<span class='pkg_t'>package</span> <span class='pkg'>$NameSpace</span><br/>\n";
3860                }
3861               
3862                if($Compact) {
3863                    $ADDED_METHODS .= "<div class='symbols'>";
3864                }
3865               
3866                my @SortedMethods = sort {lc($MethodInfo{2}{$a}{"Signature"}) cmp lc($MethodInfo{2}{$b}{"Signature"})} keys(%{$NameSpace_Method{$NameSpace}});
3867                foreach my $Method (@SortedMethods)
3868                {
3869                    $Added_Number += 1;
3870                   
3871                    my $Signature = undef;
3872                   
3873                    if($Compact) {
3874                        $Signature = get_Signature($Method, 2, "Full|HTML|Simple");
3875                    }
3876                    else {
3877                        $Signature = highLight_Signature_Italic_Color($Method, 2);
3878                    }
3879                   
3880                    if($NameSpace) {
3881                        $Signature=~s/(\W|\A)\Q$NameSpace\E\.(\w)/$1$2/g;
3882                    }
3883                   
3884                    if($Compact) {
3885                        $ADDED_METHODS .= "&nbsp;".$Signature."<br/>\n";
3886                    }
3887                    else {
3888                        $ADDED_METHODS .= insertIDs($ContentSpanStart.$Signature.$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mngl'>[mangled: <b>".htmlSpecChars($Method)."</b>]</span><br/><br/>".$ContentDivEnd."\n");
3889                    }
3890                }
3891               
3892                if($Compact) {
3893                    $ADDED_METHODS .= "</div>";
3894                }
3895               
3896                $ADDED_METHODS .= "<br/>\n";
3897            }
3898           
3899        }
3900    }
3901    if($ADDED_METHODS)
3902    {
3903        my $Anchor = "<a name='Added'></a>";
3904        if($JoinReport) {
3905            $Anchor = "<a name='".$Level."_Added'></a>";
3906        }
3907        if($OldStyle) {
3908            $ADDED_METHODS = "<h2>Added Methods ($Added_Number)</h2><hr/>\n".$ADDED_METHODS;
3909        }
3910        else {
3911            $ADDED_METHODS = "<h2>Added Methods <span".getStyle("M", "Added", $Added_Number).">&nbsp;$Added_Number&nbsp;</span></h2><hr/>\n".$ADDED_METHODS;
3912        }
3913        $ADDED_METHODS = $Anchor.$ADDED_METHODS.$TOP_REF."<br/>\n";
3914    }
3915    return $ADDED_METHODS;
3916}
3917
3918sub get_Report_Removed($)
3919{
3920    if($ShortMode) {
3921        return "";
3922    }
3923   
3924    my $Level = $_[0];
3925    my ($REMOVED_METHODS, %MethodRemovedFromArchiveClass);
3926    foreach my $Method (sort keys(%CompatProblems))
3927    {
3928        foreach my $Kind (sort keys(%{$CompatProblems{$Method}}))
3929        {
3930            if($Kind eq "Removed_Method")
3931            {
3932                if($Level eq "Source")
3933                {
3934                    if($ChangedReturnFromVoid{$Method}) {
3935                        next;
3936                    }
3937                }
3938                my $ArchiveName = $MethodInfo{1}{$Method}{"Archive"};
3939                my $ClassName = get_ShortName($MethodInfo{1}{$Method}{"Class"}, 1);
3940                $MethodRemovedFromArchiveClass{$ArchiveName}{$ClassName}{$Method} = 1;
3941            }
3942        }
3943    }
3944    my $Removed_Number = 0;
3945    foreach my $ArchiveName (sort {lc($a) cmp lc($b)} keys(%MethodRemovedFromArchiveClass))
3946    {
3947        foreach my $ClassName (sort {lc($a) cmp lc($b)} keys(%{$MethodRemovedFromArchiveClass{$ArchiveName}}))
3948        {
3949            my %NameSpace_Method = ();
3950            foreach my $Method (keys(%{$MethodRemovedFromArchiveClass{$ArchiveName}{$ClassName}}))
3951            {
3952                $NameSpace_Method{$MethodInfo{1}{$Method}{"Package"}}{$Method} = 1;
3953            }
3954           
3955            my $ShowClass = $ClassName;
3956            $ShowClass=~s/<.*>//g;
3957           
3958            foreach my $NameSpace (sort keys(%NameSpace_Method))
3959            {
3960                $REMOVED_METHODS .= "<span class='jar'>$ArchiveName</span>, <span class='cname'>".htmlSpecChars($ShowClass).".class</span><br/>\n";
3961               
3962                if($NameSpace) {
3963                    $REMOVED_METHODS .= "<span class='pkg_t'>package</span> <span class='pkg'>$NameSpace</span><br/>\n";
3964                }
3965               
3966                if($Compact) {
3967                    $REMOVED_METHODS .= "<div class='symbols'>";
3968                }
3969               
3970                my @SortedMethods = sort {lc($MethodInfo{1}{$a}{"Signature"}) cmp lc($MethodInfo{1}{$b}{"Signature"})} keys(%{$NameSpace_Method{$NameSpace}});
3971                foreach my $Method (@SortedMethods)
3972                {
3973                    $Removed_Number += 1;
3974                   
3975                    my $Signature = undef;
3976                   
3977                    if($Compact) {
3978                        $Signature = get_Signature($Method, 1, "Full|HTML|Simple");
3979                    }
3980                    else {
3981                        $Signature = highLight_Signature_Italic_Color($Method, 1);
3982                    }
3983                   
3984                    if($NameSpace) {
3985                        $Signature=~s/(\W|\A)\Q$NameSpace\E\.(\w)/$1$2/g;
3986                    }
3987                   
3988                    if($Compact) {
3989                        $REMOVED_METHODS .= "&nbsp;".$Signature."<br/>\n";
3990                    }
3991                    else {
3992                        $REMOVED_METHODS .= insertIDs($ContentSpanStart.$Signature.$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mngl'>[mangled: <b>".htmlSpecChars($Method)."</b>]</span><br/><br/>".$ContentDivEnd."\n");
3993                    }
3994                }
3995               
3996                if($Compact) {
3997                    $REMOVED_METHODS .= "</div>";
3998                }
3999               
4000                $REMOVED_METHODS .= "<br/>\n";
4001            }
4002        }
4003    }
4004    if($REMOVED_METHODS)
4005    {
4006        my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
4007        if($JoinReport) {
4008            $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
4009        }
4010        if($OldStyle) {
4011            $REMOVED_METHODS = "<h2>Removed Methods ($Removed_Number)</h2><hr/>\n".$REMOVED_METHODS;
4012        }
4013        else {
4014            $REMOVED_METHODS = "<h2>Removed Methods <span".getStyle("M", "Removed", $Removed_Number).">&nbsp;$Removed_Number&nbsp;</span></h2><hr/>\n".$REMOVED_METHODS;
4015        }
4016        $REMOVED_METHODS = $Anchor.$REMOVED_METHODS.$TOP_REF."<br/>\n";
4017    }
4018    return $REMOVED_METHODS;
4019}
4020
4021sub get_Report_MethodProblems($$)
4022{
4023    my ($TargetSeverity, $Level) = @_;
4024    my $METHOD_PROBLEMS = "";
4025    my (%ReportMap, %MethodChanges) = ();
4026   
4027    foreach my $Method (sort keys(%CompatProblems))
4028    {
4029        my $ArchiveName = $MethodInfo{1}{$Method}{"Archive"};
4030        my $ClassName = get_ShortName($MethodInfo{1}{$Method}{"Class"}, 1);
4031       
4032        foreach my $Kind (sort keys(%{$CompatProblems{$Method}}))
4033        {
4034            if($Kind eq "Added_Method"
4035            or $Kind eq "Removed_Method") {
4036                next;
4037            }
4038           
4039            if(my $Severity = $MethodProblems_Kind{$Level}{$Kind})
4040            {
4041                if($Severity ne $TargetSeverity) {
4042                    next;
4043                }
4044               
4045                $MethodChanges{$Method}{$Kind} = $CompatProblems{$Method}{$Kind};
4046                $ReportMap{$ArchiveName}{$ClassName}{$Method} = 1;
4047            }
4048        }
4049    }
4050    my $ProblemsNum = 0;
4051    foreach my $ArchiveName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
4052    {
4053        foreach my $ClassName (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$ArchiveName}}))
4054        {
4055            my %NameSpace_Method = ();
4056            foreach my $Method (keys(%{$ReportMap{$ArchiveName}{$ClassName}})) {
4057                $NameSpace_Method{$MethodInfo{1}{$Method}{"Package"}}{$Method} = 1;
4058            }
4059           
4060            my $ShowClass = $ClassName;
4061            $ShowClass=~s/<.*>//g;
4062           
4063            foreach my $NameSpace (sort keys(%NameSpace_Method))
4064            {
4065                $METHOD_PROBLEMS .= "<span class='jar'>$ArchiveName</span>, <span class='cname'>".htmlSpecChars($ShowClass).".class</span><br/>\n";
4066                if($NameSpace) {
4067                    $METHOD_PROBLEMS .= "<span class='pkg_t'>package</span> <span class='pkg'>$NameSpace</span><br/>\n";
4068                }
4069               
4070                my @SortedMethods = sort {lc($MethodInfo{1}{$a}{"Signature"}) cmp lc($MethodInfo{1}{$b}{"Signature"})} keys(%{$NameSpace_Method{$NameSpace}});
4071                foreach my $Method (@SortedMethods)
4072                {
4073                    my $ShortSignature = get_Signature($Method, 1, "Short");
4074                    my $ClassName_Full = get_TypeName($MethodInfo{1}{$Method}{"Class"}, 1);
4075                    my $METHOD_REPORT = "";
4076                    my $ProblemNum = 1;
4077                    foreach my $Kind (sort keys(%{$MethodChanges{$Method}}))
4078                    {
4079                        foreach my $Location (sort keys(%{$MethodChanges{$Method}{$Kind}}))
4080                        {
4081                            my %Problems = %{$MethodChanges{$Method}{$Kind}{$Location}};
4082                           
4083                            my $Target = $Problems{"Target"};
4084                           
4085                            my ($Change, $Effect) = ("", "");
4086                            my $Old_Value = htmlSpecChars($Problems{"Old_Value"});
4087                            my $New_Value = htmlSpecChars($Problems{"New_Value"});
4088                           
4089                            if($Kind eq "Method_Became_Static")
4090                            {
4091                                $Change = "Method became <b>static</b>.\n";
4092                                $Effect = "A client program may be interrupted by <b>NoSuchMethodError</b> exception.";
4093                            }
4094                            elsif($Kind eq "Method_Became_NonStatic")
4095                            {
4096                                $Change = "Method became <b>non-static</b>.\n";
4097                                if($Level eq "Binary") {
4098                                    $Effect = "A client program may be interrupted by <b>NoSuchMethodError</b> exception.";
4099                                }
4100                                else {
4101                                    $Effect = "Recompilation of a client program may be terminated with the message: non-static method ".htmlSpecChars($ShortSignature)." cannot be referenced from a static context.";
4102                                }
4103                            }
4104                            elsif($Kind eq "Changed_Method_Return_From_Void")
4105                            {
4106                                $Change = "Return value type has been changed from <b>void</b> to <b>".htmlSpecChars($New_Value)."</b>.\n";
4107                                $Effect = "This method has been removed because the return type is part of the method signature.";
4108                            }
4109                            elsif($Kind eq "Static_Method_Became_Final")
4110                            {# Source Only
4111                                $Change = "Method became <b>final</b>.\n";
4112                                $Effect = "Recompilation of a client program may be terminated with the message: ".htmlSpecChars($ShortSignature)." in client class C cannot override ".htmlSpecChars($ShortSignature)." in ".htmlSpecChars($ClassName_Full)."; overridden method is final.";
4113                            }
4114                            elsif($Kind eq "NonStatic_Method_Became_Final")
4115                            {
4116                                $Change = "Method became <b>final</b>.\n";
4117                                if($Level eq "Binary") {
4118                                    $Effect = "A client program trying to reimplement this method may be interrupted by <b>VerifyError</b> exception.";
4119                                }
4120                                else {
4121                                    $Effect = "Recompilation of a client program may be terminated with the message: ".htmlSpecChars($ShortSignature)." in client class C cannot override ".htmlSpecChars($ShortSignature)." in ".htmlSpecChars($ClassName_Full)."; overridden method is final.";
4122                                }
4123                            }
4124                            elsif($Kind eq "Method_Became_Abstract")
4125                            {
4126                                $Change = "Method became <b>abstract</b>.\n";
4127                                if($Level eq "Binary") {
4128                                    $Effect = "A client program trying to create an instance of the method's class may be interrupted by <b>InstantiationError</b> exception.";
4129                                }
4130                                else {
4131                                    $Effect = "Recompilation of a client program may be terminated with the message: A client class C is not abstract and does not override abstract method ".htmlSpecChars($ShortSignature)." in ".htmlSpecChars($ClassName_Full).".";
4132                                }
4133                            }
4134                            elsif($Kind eq "Method_Became_NonAbstract")
4135                            {
4136                                $Change = "Method became <b>non-abstract</b>.\n";
4137                                if($Level eq "Binary") {
4138                                    $Effect = "A client program may change behavior.";
4139                                }
4140                                else {
4141                                    $Effect = "No effect.";
4142                                }
4143                            }
4144                            elsif($Kind eq "Method_Became_Default")
4145                            {
4146                                $Change = "Method became <b>default</b>.\n";
4147                                if($Level eq "Binary") {
4148                                    $Effect = "No effect.";
4149                                }
4150                                else {
4151                                    $Effect = "No effect.";
4152                                }
4153                            }
4154                            elsif($Kind eq "Method_Became_NonDefault")
4155                            {
4156                                $Change = "Method became <b>non-default</b>.\n";
4157                                if($Level eq "Binary") {
4158                                    $Effect = "A client program trying to create an instance of a class may be interrupted by <b>AbstractMethodError</b> exception.";
4159                                }
4160                                else {
4161                                    $Effect = "Recompilation of a client program may be terminated with the message: A client class C is not abstract and does not override abstract method ".htmlSpecChars($ShortSignature)." in ".htmlSpecChars($ClassName_Full).".";
4162                                }
4163                            }
4164                            elsif($Kind eq "Method_Became_Synchronized")
4165                            {
4166                                $Change = "Method became <b>synchronized</b>.\n";
4167                                $Effect = "A multi-threaded client program may change behavior.";
4168                            }
4169                            elsif($Kind eq "Method_Became_NonSynchronized")
4170                            {
4171                                $Change = "Method became <b>non-synchronized</b>.\n";
4172                                $Effect = "A multi-threaded client program may change behavior.";
4173                            }
4174                            elsif($Kind eq "Changed_Method_Access")
4175                            {
4176                                $Change = "Access level has been changed from <span class='nowrap'><b>".htmlSpecChars($Old_Value)."</b></span> to <span class='nowrap'><b>".htmlSpecChars($New_Value)."</b></span>.";
4177                                if($Level eq "Binary") {
4178                                    $Effect = "A client program may be interrupted by <b>IllegalAccessError</b> exception.";
4179                                }
4180                                else {
4181                                    $Effect = "Recompilation of a client program may be terminated with the message: ".htmlSpecChars($ShortSignature)." has $New_Value access in ".htmlSpecChars($ClassName_Full).".";
4182                                }
4183                            }
4184                            elsif($Kind eq "Abstract_Method_Added_Checked_Exception")
4185                            {# Source Only
4186                                $Change = "Added <b>".htmlSpecChars($Target)."</b> exception thrown.\n";
4187                                $Effect = "Recompilation of a client program may be terminated with the message: unreported exception ".htmlSpecChars($Target)." must be caught or declared to be thrown.";
4188                            }
4189                            elsif($Kind eq "NonAbstract_Method_Added_Checked_Exception")
4190                            {
4191                                $Change = "Added <b>".htmlSpecChars($Target)."</b> exception thrown.\n";
4192                                if($Level eq "Binary") {
4193                                    $Effect = "A client program may be interrupted by added exception.";
4194                                }
4195                                else {
4196                                    $Effect = "Recompilation of a client program may be terminated with the message: unreported exception ".htmlSpecChars($Target)." must be caught or declared to be thrown.";
4197                                }
4198                            }
4199                            elsif($Kind eq "Abstract_Method_Removed_Checked_Exception")
4200                            {# Source Only
4201                                $Change = "Removed <b>".htmlSpecChars($Target)."</b> exception thrown.\n";
4202                                $Effect = "Recompilation of a client program may be terminated with the message: cannot override ".htmlSpecChars($ShortSignature)." in ".htmlSpecChars($ClassName_Full)."; overridden method does not throw ".htmlSpecChars($Target).".";
4203                            }
4204                            elsif($Kind eq "NonAbstract_Method_Removed_Checked_Exception")
4205                            {
4206                                $Change = "Removed <b>".htmlSpecChars($Target)."</b> exception thrown.\n";
4207                                if($Level eq "Binary") {
4208                                    $Effect = "A client program may change behavior because the removed exception will not be thrown any more and client will not catch and handle it.";
4209                                }
4210                                else {
4211                                    $Effect = "Recompilation of a client program may be terminated with the message: cannot override ".htmlSpecChars($ShortSignature)." in ".htmlSpecChars($ClassName_Full)."; overridden method does not throw ".htmlSpecChars($Target).".";
4212                                }
4213                            }
4214                            elsif($Kind eq "Added_Unchecked_Exception")
4215                            {# Binary Only
4216                                $Change = "Added <b>".htmlSpecChars($Target)."</b> exception thrown.\n";
4217                                $Effect = "A client program may be interrupted by added exception.";
4218                            }
4219                            elsif($Kind eq "Removed_Unchecked_Exception")
4220                            {# Binary Only
4221                                $Change = "Removed <b>".htmlSpecChars($Target)."</b> exception thrown.\n";
4222                                $Effect = "A client program may change behavior because the removed exception will not be thrown any more and client will not catch and handle it.";
4223                            }
4224                            if($Change)
4225                            {
4226                                $METHOD_REPORT .= "<tr><th>$ProblemNum</th><td>".$Change."</td><td>".$Effect."</td></tr>\n";
4227                                $ProblemNum += 1;
4228                                $ProblemsNum += 1;
4229                            }
4230                        }
4231                    }
4232                    $ProblemNum -= 1;
4233                    if($METHOD_REPORT)
4234                    {
4235                        my $ShowMethod = highLight_Signature_Italic_Color($Method, 1);
4236                        if($NameSpace)
4237                        {
4238                            $METHOD_REPORT = cut_Namespace($METHOD_REPORT, $NameSpace);
4239                            $ShowMethod = cut_Namespace($ShowMethod, $NameSpace);
4240                        }
4241                       
4242                        $METHOD_PROBLEMS .= $ContentSpanStart."<span class='ext'>[+]</span> ".$ShowMethod;
4243                        if($OldStyle) {
4244                            $METHOD_PROBLEMS .= " ($ProblemNum)";
4245                        }
4246                        else {
4247                            $METHOD_PROBLEMS .= " <span".getStyle("M", $TargetSeverity, $ProblemNum).">&nbsp;$ProblemNum&nbsp;</span>";
4248                        }
4249                        $METHOD_PROBLEMS .= $ContentSpanEnd."<br/>\n";
4250                        $METHOD_PROBLEMS .= $ContentDivStart;
4251                       
4252                        if(not $Compact) {
4253                            $METHOD_PROBLEMS .= "<span class='mngl'>&#160;&#160;&#160;[mangled: <b>".htmlSpecChars($Method)."</b>]</span><br/>\n";
4254                        }
4255                       
4256                        $METHOD_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$METHOD_REPORT</table><br/>$ContentDivEnd\n";
4257                       
4258                    }
4259                }
4260               
4261                $METHOD_PROBLEMS .= "<br/>";
4262            }
4263        }
4264    }
4265    if($METHOD_PROBLEMS)
4266    {
4267        $METHOD_PROBLEMS = insertIDs($METHOD_PROBLEMS);
4268       
4269        my $Title = "Problems with Methods, $TargetSeverity Severity";
4270        if($TargetSeverity eq "Safe")
4271        { # Safe Changes
4272            $Title = "Other Changes in Methods";
4273        }
4274        if($OldStyle) {
4275            $METHOD_PROBLEMS = "<h2>$Title ($ProblemsNum)</h2><hr/>\n".$METHOD_PROBLEMS;
4276        }
4277        else {
4278            $METHOD_PROBLEMS = "<h2>$Title <span".getStyle("M", $TargetSeverity, $ProblemsNum).">&nbsp;$ProblemsNum&nbsp;</span></h2><hr/>\n".$METHOD_PROBLEMS;
4279        }
4280        $METHOD_PROBLEMS = "<a name='".get_Anchor("Method", $Level, $TargetSeverity)."'></a>\n".$METHOD_PROBLEMS;
4281        $METHOD_PROBLEMS .= $TOP_REF."<br/>\n";
4282    }
4283    return $METHOD_PROBLEMS;
4284}
4285
4286sub get_Report_TypeProblems($$)
4287{
4288    my ($TargetSeverity, $Level) = @_;
4289    my $TYPE_PROBLEMS = "";
4290    my %ReportMap = ();
4291    my %TypeChanges_Sev = ();
4292   
4293    foreach my $TypeName (keys(%{$TypeChanges{$Level}}))
4294    {
4295        my $ArchiveName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Archive"};
4296       
4297        foreach my $Kind (keys(%{$TypeChanges{$Level}{$TypeName}}))
4298        {
4299            my $Severity = $TypeProblems_Kind{$Level}{$Kind};
4300           
4301            if($Severity ne $TargetSeverity) {
4302                next;
4303            }
4304           
4305            foreach my $Location (keys(%{$TypeChanges{$Level}{$TypeName}{$Kind}}))
4306            {
4307                $ReportMap{$ArchiveName}{$TypeName} = 1;
4308                $TypeChanges_Sev{$TypeName}{$Kind}{$Location} = $TypeChanges{$Level}{$TypeName}{$Kind}{$Location};
4309            }
4310        }
4311    }
4312   
4313    my $ProblemsNum = 0;
4314    foreach my $ArchiveName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
4315    {
4316        my ($HEADER_REPORT, %NameSpace_Type) = ();
4317        foreach my $TypeName (keys(%{$ReportMap{$ArchiveName}}))
4318        {
4319            $NameSpace_Type{$TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Package"}}{$TypeName} = 1;
4320        }
4321        foreach my $NameSpace (sort keys(%NameSpace_Type))
4322        {
4323            $TYPE_PROBLEMS .= "<span class='jar'>$ArchiveName</span><br/>\n";
4324            if($NameSpace) {
4325                $TYPE_PROBLEMS .= "<span class='pkg_t'>package</span> <span class='pkg'>".$NameSpace."</span><br/>\n";
4326            }
4327           
4328            my @SortedTypes = sort {lc($a) cmp lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
4329            foreach my $TypeName (@SortedTypes)
4330            {
4331                my $TypeId = $TName_Tid{1}{$TypeName};
4332                my $ProblemNum = 1;
4333                my $TYPE_REPORT = "";
4334                my (%Kinds_Locations, %Kinds_Target) = ();
4335                foreach my $Kind (sort keys(%{$TypeChanges_Sev{$TypeName}}))
4336                {
4337                    foreach my $Location (sort keys(%{$TypeChanges_Sev{$TypeName}{$Kind}}))
4338                    {
4339                        $Kinds_Locations{$Kind}{$Location} = 1;
4340                       
4341                        my $Target = $TypeChanges_Sev{$TypeName}{$Kind}{$Location}{"Target"};
4342                        if($Kinds_Target{$Kind}{$Target}) {
4343                            next;
4344                        }
4345                        $Kinds_Target{$Kind}{$Target} = 1;
4346                       
4347                        my ($Change, $Effect) = ("", "");
4348                        my %Problems = %{$TypeChanges_Sev{$TypeName}{$Kind}{$Location}};
4349                       
4350                        my $Old_Value = $Problems{"Old_Value"};
4351                        my $New_Value = $Problems{"New_Value"};
4352                        my $Field_Type = $Problems{"Field_Type"};
4353                        my $Field_Value = $Problems{"Field_Value"};
4354                        my $Type_Type = $Problems{"Type_Type"};
4355                       
4356                        if($Kind eq "NonAbstract_Class_Added_Abstract_Method")
4357                        {
4358                            $Change = "Abstract method ".black_Name($Target, 2)." has been added to this $Type_Type.";
4359                            if($Level eq "Binary") {
4360                                $Effect = "This class became <b>abstract</b> and a client program may be interrupted by <b>InstantiationError</b> exception.";
4361                            }
4362                            else {
4363                                $Effect = "Recompilation of a client program may be terminated with the message: a client class C is not abstract and does not override abstract method <b>".htmlSpecChars(get_Signature($Target, 2, "Short"))."</b> in <b>".htmlSpecChars(get_TypeName($MethodInfo{2}{$Target}{"Class"}, 2))."</b>.";
4364                            }
4365                        }
4366                        elsif($Kind eq "Abstract_Class_Added_Abstract_Method")
4367                        {
4368                            $Change = "Abstract method ".black_Name($Target, 2)." has been added to this $Type_Type.";
4369                            if($Level eq "Binary") {
4370                                $Effect = "No effect.";
4371                            }
4372                            else {
4373                                $Effect = "Recompilation of a client program may be terminated with the message: a client class C is not abstract and does not override abstract method <b>".htmlSpecChars(get_Signature($Target, 2, "Short"))."</b> in <b>".htmlSpecChars(get_TypeName($MethodInfo{2}{$Target}{"Class"}, 2))."</b>.";
4374                            }
4375                        }
4376                        elsif($Kind eq "Abstract_Class_Added_Abstract_Method_Invoked_By_Others")
4377                        {
4378                            $Change = "Abstract method ".black_Name($Target, 2)." has been added to this $Type_Type.";
4379                            if($Level eq "Binary") {
4380                                $Effect = "A client program may be interrupted by <b>AbstractMethodError</b> exception. Added abstract method is called in 2nd library version by the method ".black_Name($Problems{"InvokedBy"}, 1)." and may not be implemented by old clients.";
4381                            }
4382                            else {
4383                                $Effect = "Recompilation of a client program may be terminated with the message: a client class C is not abstract and does not override abstract method <b>".htmlSpecChars(get_Signature($Target, 2, "Short"))."</b> in <b>".htmlSpecChars(get_TypeName($MethodInfo{2}{$Target}{"Class"}, 2))."</b>.";
4384                            }
4385                        }
4386                        elsif($Kind eq "Class_Removed_Abstract_Method"
4387                        or $Kind eq "Interface_Removed_Abstract_Method")
4388                        {
4389                            $Change = "Abstract method ".black_Name($Target, 1)." has been removed from this $Type_Type.";
4390                            if($Level eq "Binary") {
4391                                $Effect = "A client program may be interrupted by <b>NoSuchMethodError</b> exception.";
4392                            }
4393                            else {
4394                                $Effect = "Recompilation of a client program may be terminated with the message: cannot find method <b>".htmlSpecChars(get_Signature($Target, 1, "Short"))."</b> in $Type_Type <b>".htmlSpecChars(get_TypeName($MethodInfo{1}{$Target}{"Class"}, 1))."</b>.";
4395                            }
4396                        }
4397                        elsif($Kind eq "Interface_Added_Abstract_Method")
4398                        {
4399                            $Change = "Abstract method ".black_Name($Target, 2)." has been added to this $Type_Type.";
4400                            if($Level eq "Binary") {
4401                                $Effect = "No effect.";
4402                            }
4403                            else {
4404                                $Effect = "Recompilation of a client program may be terminated with the message: a client class C is not abstract and does not override abstract method <b>".htmlSpecChars(get_Signature($Target, 2, "Short"))."</b> in <b>".htmlSpecChars(get_TypeName($MethodInfo{2}{$Target}{"Class"}, 2))."</b>.";
4405                            }
4406                        }
4407                        elsif($Kind eq "Interface_Added_Abstract_Method_Invoked_By_Others")
4408                        {
4409                            $Change = "Abstract method ".black_Name($Target, 2)." has been added to this $Type_Type.";
4410                            if($Level eq "Binary") {
4411                                $Effect = "A client program may be interrupted by <b>AbstractMethodError</b> exception. Added abstract method is called in 2nd library version by the method ".black_Name($Problems{"InvokedBy"}, 1)." and may not be implemented by old clients.";
4412                            }
4413                            else {
4414                                $Effect = "Recompilation of a client program may be terminated with the message: a client class C is not abstract and does not override abstract method <b>".htmlSpecChars(get_Signature($Target, 2, "Short"))."</b> in <b>".htmlSpecChars(get_TypeName($MethodInfo{2}{$Target}{"Class"}, 2))."</b>.";
4415                            }
4416                        }
4417                        elsif($Kind eq "Class_Method_Became_Abstract")
4418                        {
4419                            $Change = "Method ".black_Name($Target, 1)." became <b>abstract</b>.";
4420                            if($Level eq "Binary") {
4421                                $Effect = "A client program may be interrupted by <b>InstantiationError</b> exception.";
4422                            }
4423                            else {
4424                                $Effect = "Recompilation of a client program may be terminated with the message: a client class C is not abstract and does not override abstract method <b>".htmlSpecChars(get_Signature($Target, 1, "Short"))."</b> in <b>".htmlSpecChars(get_TypeName($MethodInfo{1}{$Target}{"Class"}, 1))."</b>.";
4425                            }
4426                        }
4427                        elsif($Kind eq "Class_Method_Became_NonAbstract")
4428                        {
4429                            $Change = "Abstract method ".black_Name($Target, 1)." became <b>non-abstract</b>.";
4430                            if($Level eq "Binary") {
4431                                $Effect = "Some methods in this class may change behavior.";
4432                            }
4433                            else {
4434                                $Effect = "No effect.";
4435                            }
4436                        }
4437                        elsif($Kind eq "Interface_Method_Became_NonDefault")
4438                        {
4439                            $Change = "Method ".black_Name($Target, 1)." became <b>non-default</b>.";
4440                            if($Level eq "Binary") {
4441                                $Effect = "A client program may be interrupted by <b>AbstractMethodError</b> exception.";
4442                            }
4443                            else {
4444                                $Effect = "Recompilation of a client program may be terminated with the message: a client class C is not abstract and does not override abstract method <b>".htmlSpecChars(get_Signature($Target, 1, "Short"))."</b> in <b>".htmlSpecChars(get_TypeName($MethodInfo{1}{$Target}{"Class"}, 1))."</b>.";
4445                            }
4446                        }
4447                        elsif($Kind eq "Interface_Method_Became_Default")
4448                        {
4449                            $Change = "Method ".black_Name($Target, 1)." became <b>default</b>.";
4450                            if($Level eq "Binary") {
4451                                $Effect = "No effect.";
4452                            }
4453                            else {
4454                                $Effect = "No effect.";
4455                            }
4456                        }
4457                        elsif($Kind eq "Class_Overridden_Method")
4458                        {
4459                            $Change = "Method ".black_Name($Old_Value, 2)." has been overridden by ".black_Name($New_Value, 2);
4460                            $Effect = "Method ".black_Name($New_Value, 2)." will be called instead of ".black_Name($Old_Value, 2)." in a client program.";
4461                        }
4462                        elsif($Kind eq "Class_Method_Moved_Up_Hierarchy")
4463                        {
4464                            $Change = "Method ".black_Name($Old_Value, 1)." has been moved up type hierarchy to ".black_Name($New_Value, 2);
4465                            $Effect = "Method ".black_Name($New_Value, 2)." will be called instead of ".black_Name($Old_Value, 1)." in a client program.";
4466                        }
4467                        elsif($Kind eq "Abstract_Class_Added_Super_Interface")
4468                        {
4469                            $Change = "Added super-interface <b>".htmlSpecChars($Target)."</b>.";
4470                            if($Level eq "Binary")
4471                            {
4472                                $Effect = "No effect.";
4473                            }
4474                            else {
4475                                $Effect = "Recompilation of a client program may be terminated with the message: a client class C is not abstract and does not override abstract method in <b>".htmlSpecChars($Target)."</b>.";
4476                            }
4477                        }
4478                        elsif($Kind eq "Abstract_Class_Added_Super_Interface_Invoked_By_Others")
4479                        {
4480                            $Change = "Added super-interface <b>".htmlSpecChars($Target)."</b>.";
4481                            if($Level eq "Binary") {
4482                                $Effect = "If abstract methods from an added super-interface must be implemented by client then it may be interrupted by <b>AbstractMethodError</b> exception.<br/><br/>Abstract method ".black_Name_S(htmlSpecChars($Problems{"Invoked"}))." from the added super-interface is called by the method ".black_Name($Problems{"InvokedBy"}, 2)." in 2nd library version and may not be implemented by old clients.";
4483                            }
4484                            else {
4485                                $Effect = "Recompilation of a client program may be terminated with the message: a client class C is not abstract and does not override abstract method in <b>".htmlSpecChars($Target)."</b>.";
4486                            }
4487                        }
4488                        elsif($Kind eq "Abstract_Class_Added_Super_Interface_With_Implemented_Methods")
4489                        {
4490                            $Change = "Added super-interface <b>".htmlSpecChars($Target)."</b>.";
4491                            $Effect = "No effect.";
4492                        }
4493                        elsif($Kind eq "Interface_Added_Super_Interface")
4494                        {
4495                            $Change = "Added super-interface <b>".htmlSpecChars($Target)."</b>.";
4496                            if($Level eq "Binary") {
4497                                $Effect = "No effect.";
4498                            }
4499                            else {
4500                                $Effect = "Recompilation of a client program may be terminated with the message: a client class C is not abstract and does not override abstract method in <b>".htmlSpecChars($Target)."</b>.";
4501                            }
4502                        }
4503                        elsif($Kind eq "Interface_Added_Super_Interface_Used_By_Others")
4504                        {
4505                            $Change = "Added super-interface <b>".htmlSpecChars($Target)."</b>.";
4506                            if($Level eq "Binary")
4507                            {
4508                                $Effect = "If abstract methods from an added super-interface must be implemented by client then it may be interrupted by <b>AbstractMethodError</b> exception.<br/><br/>Abstract method ".black_Name_S(htmlSpecChars($Problems{"Invoked"}))." from the added super-interface is called by the method ".black_Name($Problems{"InvokedBy"}, 2)." in 2nd library version and may not be implemented by old clients.";
4509                            }
4510                            else {
4511                                $Effect = "Recompilation of a client program may be terminated with the message: a client class C is not abstract and does not override abstract method in <b>".htmlSpecChars($Target)."</b>.";
4512                            }
4513                        }
4514                        elsif($Kind eq "Interface_Added_Super_Interface_With_Implemented_Methods")
4515                        {
4516                            $Change = "Added super-interface <b>".htmlSpecChars($Target)."</b>.";
4517                            if($Level eq "Binary") {
4518                                $Effect = "No effect.";
4519                            }
4520                            else {
4521                                $Effect = "No effect.";
4522                            }
4523                        }
4524                        elsif($Kind eq "Interface_Added_Super_Constant_Interface")
4525                        {
4526                            $Change = "Added super-interface <b>".htmlSpecChars($Target)."</b> containing constants only.";
4527                            if($Level eq "Binary") {
4528                                $Effect = "A static field from a super-interface of a client class may hide a field (with the same name) inherited from a super-class and cause <b>IncompatibleClassChangeError</b> exception.";
4529                            }
4530                            else {
4531                                $Effect = "A static field from a super-interface of a client class may hide a field (with the same name) inherited from a super-class. Recompilation of a client class may be terminated with the message: reference to variable is ambiguous.";
4532                            }
4533                        }
4534                        elsif($Kind eq "Interface_Removed_Super_Interface"
4535                        or $Kind eq "Class_Removed_Super_Interface")
4536                        {
4537                            $Change = "Removed super-interface <b>".htmlSpecChars($Target)."</b>.";
4538                            if($Level eq "Binary") {
4539                                $Effect = "A client program may be interrupted by <b>NoSuchMethodError</b> exception.";
4540                            }
4541                            else {
4542                                $Effect = "Recompilation of a client program may be terminated with the message: cannot find method in $Type_Type <b>".htmlSpecChars($TypeName)."</b>.";
4543                            }
4544                        }
4545                        elsif($Kind eq "Interface_Removed_Super_Constant_Interface")
4546                        {
4547                            $Change = "Removed super-interface <b>".htmlSpecChars($Target)."</b> containing constants only.";
4548                            if($Level eq "Binary") {
4549                                $Effect = "No effect.";
4550                            }
4551                            else {
4552                                $Effect = "Recompilation of a client program may be terminated with the message: cannot find variable in $Type_Type <b>".htmlSpecChars($TypeName)."</b>.";
4553                            }
4554                        }
4555                        elsif($Kind eq "Added_Super_Class")
4556                        {
4557                            $Change = "Added super-class <b>".htmlSpecChars($Target)."</b>.";
4558                            if($Level eq "Binary") {
4559                                $Effect = "A static field from a super-interface of a client class may hide a field (with the same name) inherited from new super-class and cause <b>IncompatibleClassChangeError</b> exception.";
4560                            }
4561                            else {
4562                                $Effect = "A static field from a super-interface of a client class may hide a field (with the same name) inherited from new super-class. Recompilation of a client class may be terminated with the message: reference to variable is ambiguous.";
4563                            }
4564                        }
4565                        elsif($Kind eq "Abstract_Class_Added_Super_Abstract_Class")
4566                        {
4567                            $Change = "Added abstract super-class <b>".htmlSpecChars($Target)."</b>.";
4568                            if($Level eq "Binary") {
4569                                $Effect = "No effect.";
4570                            }
4571                            else {
4572                                $Effect = "Recompilation of a client program may be terminated with the message: a client class C is not abstract and does not override abstract method in <b>".htmlSpecChars($Target)."</b>.";
4573                            }
4574                        }
4575                        elsif($Kind eq "Abstract_Class_Added_Super_Abstract_Class_Invoked_By_Others")
4576                        {
4577                            $Change = "Added abstract super-class <b>".htmlSpecChars($Target)."</b>.";
4578                            if($Level eq "Binary") {
4579                                $Effect = "If abstract methods from an added super-class must be implemented by client then it may be interrupted by <b>AbstractMethodError</b> exception.<br/><br/>Abstract method ".black_Name_S(htmlSpecChars($Problems{"Invoked"}))." from the added abstract super-class is called by the method ".black_Name($Problems{"InvokedBy"}, 2)." in 2nd library version and may not be implemented by old clients.";
4580                            }
4581                            else {
4582                                $Effect = "Recompilation of a client program may be terminated with the message: a client class C is not abstract and does not override abstract method in <b>".htmlSpecChars($Target)."</b>.";
4583                            }
4584                        }
4585                        elsif($Kind eq "Removed_Super_Class")
4586                        {
4587                            $Change = "Removed super-class <b>".htmlSpecChars($Target)."</b>.";
4588                            if($Level eq "Binary") {
4589                                $Effect = "Access of a client program to the fields or methods of the old super-class may be interrupted by <b>NoSuchFieldError</b> or <b>NoSuchMethodError</b> exceptions.";
4590                            }
4591                            else {
4592                                $Effect = "Recompilation of a client program may be terminated with the message: cannot find variable (or method) in <b>".htmlSpecChars($TypeName)."</b>.";
4593                            }
4594                        }
4595                        elsif($Kind eq "Changed_Super_Class")
4596                        {
4597                            $Change = "Superclass has been changed from <b>".htmlSpecChars($Old_Value)."</b> to <b>".htmlSpecChars($New_Value)."</b>.";
4598                            if($Level eq "Binary") {
4599                                $Effect = "1) Access of a client program to the fields or methods of the old super-class may be interrupted by <b>NoSuchFieldError</b> or <b>NoSuchMethodError</b> exceptions.<br/>2) A static field from a super-interface of a client class may hide a field (with the same name) inherited from new super-class and cause <b>IncompatibleClassChangeError</b> exception.";
4600                            }
4601                            else {
4602                                $Effect = "1) Recompilation of a client program may be terminated with the message: cannot find variable (or method) in <b>".htmlSpecChars($TypeName)."</b>.<br/>2) A static field from a super-interface of a client class may hide a field (with the same name) inherited from new super-class. Recompilation of a client class may be terminated with the message: reference to variable is ambiguous.";
4603                            }
4604                        }
4605                        elsif($Kind eq "Class_Added_Field")
4606                        {
4607                            $Change = "Field <b>$Target</b> has been added to this class.";
4608                            if($Level eq "Binary")
4609                            {
4610                                $Effect = "No effect.";
4611                                # $Effect .= "<br/><b>NOTE</b>: A static field from a super-interface of a client class may hide an added field (with the same name) inherited from the super-class of a client class and cause <b>IncompatibleClassChangeError</b> exception.";
4612                            }
4613                            else
4614                            {
4615                                $Effect = "No effect.";
4616                                # $Effect .= "<br/><b>NOTE</b>: A static field from a super-interface of a client class may hide an added field (with the same name) inherited from the super-class of a client class. Recompilation of a client class may be terminated with the message: reference to <b>$Target</b> is ambiguous.";
4617                            }
4618                        }
4619                        elsif($Kind eq "Interface_Added_Field")
4620                        {
4621                            $Change = "Field <b>$Target</b> has been added to this interface.";
4622                            if($Level eq "Binary") {
4623                                $Effect = "No effect.<br/><b>NOTE</b>: An added static field from a super-interface of a client class may hide a field (with the same name) inherited from the super-class of a client class and cause <b>IncompatibleClassChangeError</b> exception.";
4624                            }
4625                            else {
4626                                $Effect = "No effect.<br/><b>NOTE</b>: An added static field from a super-interface of a client class may hide a field (with the same name) inherited from the super-class of a client class. Recompilation of a client class may be terminated with the message: reference to <b>$Target</b> is ambiguous.";
4627                            }
4628                        }
4629                        elsif($Kind eq "Renamed_Field")
4630                        {
4631                            $Change = "Field <b>$Target</b> has been renamed to <b>".htmlSpecChars($New_Value)."</b>.";
4632                            if($Level eq "Binary") {
4633                                $Effect = "A client program may be interrupted by <b>NoSuchFieldError</b> exception.";
4634                            }
4635                            else {
4636                                $Effect = "Recompilation of a client program may be terminated with the message: cannot find variable <b>$Target</b> in <b>".htmlSpecChars($TypeName)."</b>.";
4637                            }
4638                        }
4639                        elsif($Kind eq "Renamed_Constant_Field")
4640                        {
4641                            if($Level eq "Binary") {
4642                                $Change = "Field <b>$Target</b> (".htmlSpecChars($Field_Type).") with the compile-time constant value <b>$Field_Value</b> has been renamed to <b>".htmlSpecChars($New_Value)."</b>.";
4643                                $Effect = "A client program may change behavior.";
4644                            }
4645                            else {
4646                                $Change = "Field <b>$Target</b> has been renamed to <b>".htmlSpecChars($New_Value)."</b>.";
4647                                $Effect = "Recompilation of a client program may be terminated with the message: cannot find variable <b>$Target</b> in <b>".htmlSpecChars($TypeName)."</b>.";
4648                            }
4649                        }
4650                        elsif($Kind eq "Removed_NonConstant_Field")
4651                        {
4652                            $Change = "Field <b>$Target</b> of type ".htmlSpecChars($Field_Type)." has been removed from this $Type_Type.";
4653                            if($Level eq "Binary") {
4654                                $Effect = "A client program may be interrupted by <b>NoSuchFieldError</b> exception.";
4655                            }
4656                            else {
4657                                $Effect = "Recompilation of a client program may be terminated with the message: cannot find variable <b>$Target</b> in <b>".htmlSpecChars($TypeName)."</b>.";
4658                            }
4659                        }
4660                        elsif($Kind eq "Removed_Constant_Field")
4661                        {
4662                            $Change = "Field <b>$Target</b> (".htmlSpecChars($Field_Type).") with the compile-time constant value <b>$Field_Value</b> has been removed from this $Type_Type.";
4663                            if($Level eq "Binary") {
4664                                $Effect = "A client program may change behavior.";
4665                            }
4666                            else {
4667                                $Effect = "Recompilation of a client program may be terminated with the message: cannot find variable <b>$Target</b> in <b>".htmlSpecChars($TypeName)."</b>.";
4668                            }
4669                        }
4670                        elsif($Kind eq "Changed_Field_Type")
4671                        {
4672                            $Change = "Type of field <b>$Target</b> has been changed from <span class='nowrap'><b>".htmlSpecChars($Old_Value)."</b></span> to <span class='nowrap'><b>".htmlSpecChars($New_Value)."</b></span>.";
4673                            if($Level eq "Binary") {
4674                                $Effect = "A client program may be interrupted by <b>NoSuchFieldError</b> exception.";
4675                            }
4676                            else {
4677                                $Effect = "Recompilation of a client program may be terminated with the message: incompatible types, found: <b>".htmlSpecChars($Old_Value)."</b>, required: <b>".htmlSpecChars($New_Value)."</b>.";
4678                            }
4679                        }
4680                        elsif($Kind eq "Changed_Field_Access")
4681                        {
4682                            $Change = "Access level of field <b>$Target</b> has been changed from <span class='nowrap'><b>$Old_Value</b></span> to <span class='nowrap'><b>$New_Value</b></span>.";
4683                            if($Level eq "Binary") {
4684                                $Effect = "A client program may be interrupted by <b>IllegalAccessError</b> exception.";
4685                            }
4686                            else
4687                            {
4688                                if($New_Value eq "package-private") {
4689                                    $Effect = "Recompilation of a client program may be terminated with the message: <b>$Target</b> is not public in <b>".htmlSpecChars($TypeName)."</b>; cannot be accessed from outside package.";
4690                                }
4691                                else {
4692                                    $Effect = "Recompilation of a client program may be terminated with the message: <b>$Target</b> has <b>$New_Value</b> access in <b>".htmlSpecChars($TypeName)."</b>.";
4693                                }
4694                            }
4695                        }
4696                        elsif($Kind eq "Changed_Final_Field_Value")
4697                        { # Binary Only
4698                            $Change = "Value of final field <b>$Target</b> (<b>$Field_Type</b>) has been changed from <span class='nowrap'><b>".htmlSpecChars($Old_Value)."</b></span> to <span class='nowrap'><b>".htmlSpecChars($New_Value)."</b></span>.";
4699                            $Effect = "Old value of the field will be inlined to the client code at compile-time and will be used instead of a new one.";
4700                        }
4701                        elsif($Kind eq "Changed_Final_Version_Field_Value")
4702                        { # Binary Only
4703                            $Change = "Value of final field <b>$Target</b> (<b>$Field_Type</b>) has been changed from <span class='nowrap'><b>".htmlSpecChars($Old_Value)."</b></span> to <span class='nowrap'><b>".htmlSpecChars($New_Value)."</b></span>.";
4704                            $Effect = "Old value of the field will be inlined to the client code at compile-time and will be used instead of a new one.";
4705                        }
4706                        elsif($Kind eq "Field_Became_Final")
4707                        {
4708                            $Change = "Field <b>$Target</b> became <b>final</b>.";
4709                            if($Level eq "Binary") {
4710                                $Effect = "A client program may be interrupted by <b>IllegalAccessError</b> exception when attempt to assign new values to the field.";
4711                            }
4712                            else {
4713                                $Effect = "Recompilation of a client program may be terminated with the message: cannot assign a value to final variable $Target.";
4714                            }
4715                        }
4716                        elsif($Kind eq "Field_Became_NonFinal")
4717                        { # Binary Only
4718                            $Change = "Field <b>$Target</b> became <b>non-final</b>.";
4719                            $Effect = "Old value of the field will be inlined to the client code at compile-time and will be used instead of a new one.";
4720                        }
4721                        elsif($Kind eq "NonConstant_Field_Became_Static")
4722                        { # Binary Only
4723                            $Change = "Non-final field <b>$Target</b> became <b>static</b>.";
4724                            $Effect = "A client program may be interrupted by <b>IncompatibleClassChangeError</b> exception.";
4725                        }
4726                        elsif($Kind eq "NonConstant_Field_Became_NonStatic")
4727                        {
4728                            if($Level eq "Binary") {
4729                                $Change = "Non-constant field <b>$Target</b> became <b>non-static</b>.";
4730                                $Effect = "A client program may be interrupted by <b>IncompatibleClassChangeError</b> exception.";
4731                            }
4732                            else {
4733                                $Change = "Field <b>$Target</b> became <b>non-static</b>.";
4734                                $Effect = "Recompilation of a client program may be terminated with the message: non-static variable <b>$Target</b> cannot be referenced from a static context.";
4735                            }
4736                        }
4737                        elsif($Kind eq "Constant_Field_Became_NonStatic")
4738                        { # Source Only
4739                            $Change = "Field <b>$Target</b> became <b>non-static</b>.";
4740                            $Effect = "Recompilation of a client program may be terminated with the message: non-static variable <b>$Target</b> cannot be referenced from a static context.";
4741                        }
4742                        elsif($Kind eq "Class_Became_Interface")
4743                        {
4744                            $Change = "This <b>class</b> became <b>interface</b>.";
4745                            if($Level eq "Binary") {
4746                                $Effect = "A client program may be interrupted by <b>IncompatibleClassChangeError</b> or <b>InstantiationError</b> exception dependent on the usage of this class.";
4747                            }
4748                            else {
4749                                $Effect = "Recompilation of a client program may be terminated with the message: <b>".htmlSpecChars($TypeName)."</b> is abstract; cannot be instantiated.";
4750                            }
4751                        }
4752                        elsif($Kind eq "Interface_Became_Class")
4753                        {
4754                            $Change = "This <b>interface</b> became <b>class</b>.";
4755                            if($Level eq "Binary") {
4756                                $Effect = "A client program may be interrupted by <b>IncompatibleClassChangeError</b> exception.";
4757                            }
4758                            else {
4759                                $Effect = "Recompilation of a client program may be terminated with the message: interface expected.";
4760                            }
4761                        }
4762                        elsif($Kind eq "Class_Became_Final")
4763                        {
4764                            $Change = "This class became <b>final</b>.";
4765                            if($Level eq "Binary") {
4766                                $Effect = "A client program may be interrupted by <b>VerifyError</b> exception.";
4767                            }
4768                            else {
4769                                $Effect = "Recompilation of a client program may be terminated with the message: cannot inherit from final <b>".htmlSpecChars($TypeName)."</b>.";
4770                            }
4771                        }
4772                        elsif($Kind eq "Class_Became_Abstract")
4773                        {
4774                            $Change = "This class became <b>abstract</b>.";
4775                            if($Level eq "Binary") {
4776                                $Effect = "A client program may be interrupted by <b>InstantiationError</b> exception.";
4777                            }
4778                            else {
4779                                $Effect = "Recompilation of a client program may be terminated with the message: <b>".htmlSpecChars($TypeName)."</b> is abstract; cannot be instantiated.";
4780                            }
4781                        }
4782                        elsif($Kind eq "Removed_Class")
4783                        {
4784                            $Change = "This class has been removed.";
4785                            if($Level eq "Binary") {
4786                                $Effect = "A client program may be interrupted by <b>NoClassDefFoundError</b> exception.";
4787                            }
4788                            else {
4789                                $Effect = "Recompilation of a client program may be terminated with the message: cannot find class <b>".htmlSpecChars($TypeName)."</b>.";
4790                            }
4791                        }
4792                        elsif($Kind eq "Removed_Interface")
4793                        {
4794                            $Change = "This interface has been removed.";
4795                            if($Level eq "Binary") {
4796                                $Effect = "A client program may be interrupted by <b>NoClassDefFoundError</b> exception.";
4797                            }
4798                            else {
4799                                $Effect = "Recompilation of a client program may be terminated with the message: cannot find class <b>".htmlSpecChars($TypeName)."</b>.";
4800                            }
4801                        }
4802                        elsif($Kind eq "Removed_Annotation")
4803                        {
4804                            $Change = "This annotation type has been removed.";
4805                            if($Level eq "Binary") {
4806                                $Effect = "No effect.";
4807                            }
4808                            else {
4809                                $Effect = "Recompilation of a client program may be terminated with the error message: cannot find symbol <b>\@".htmlSpecChars($TypeName)."</b>.";
4810                            }
4811                        }
4812                        if($Change)
4813                        {
4814                            $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td>".$Change."</td><td>".$Effect."</td></tr>\n";
4815                            $ProblemNum += 1;
4816                            $ProblemsNum += 1;
4817                            $Kinds_Locations{$Kind}{$Location} = 1;
4818                        }
4819                    }
4820                }
4821                $ProblemNum -= 1;
4822                if($TYPE_REPORT)
4823                {
4824                    my $Affected = "";
4825                    if(not defined $TypeInfo{1}{$TypeId}{"Annotation"}) {
4826                        $Affected = getAffectedMethods($Level, $TypeName, \%Kinds_Locations);
4827                    }
4828                   
4829                    my $ShowType = $TypeName;
4830                    if($NameSpace)
4831                    {
4832                        $TYPE_REPORT = cut_Namespace($TYPE_REPORT, $NameSpace);
4833                        $ShowType = cut_Namespace($ShowType, $NameSpace);
4834                        $Affected = cut_Namespace($Affected, $NameSpace);
4835                    }
4836                   
4837                    $TYPE_PROBLEMS .= $ContentSpanStart."<span class='ext'>[+]</span> ".htmlSpecChars($ShowType);
4838                    if($OldStyle) {
4839                        $TYPE_PROBLEMS .= " ($ProblemNum)";
4840                    }
4841                    else {
4842                        $TYPE_PROBLEMS .= " <span".getStyle("T", $TargetSeverity, $ProblemNum).">&nbsp;$ProblemNum&nbsp;</span>";
4843                    }
4844                    $TYPE_PROBLEMS .= $ContentSpanEnd."<br/>\n";
4845                    $TYPE_PROBLEMS .= $ContentDivStart."<table class='ptable'><tr>";
4846                    $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th><th>Effect</th>";
4847                    $TYPE_PROBLEMS .= "</tr>$TYPE_REPORT</table>".$Affected."<br/><br/>$ContentDivEnd\n";
4848                }
4849            }
4850           
4851            $TYPE_PROBLEMS .= "<br/>";
4852        }
4853    }
4854    if($TYPE_PROBLEMS)
4855    {
4856        $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
4857       
4858        my $Title = "Problems with Data Types, $TargetSeverity Severity";
4859        if($TargetSeverity eq "Safe")
4860        { # Safe Changes
4861            $Title = "Other Changes in Data Types";
4862        }
4863        if($OldStyle) {
4864            $TYPE_PROBLEMS = "<h2>$Title ($ProblemsNum)</h2><hr/>\n".$TYPE_PROBLEMS;
4865        }
4866        else {
4867            $TYPE_PROBLEMS = "<h2>$Title <span".getStyle("T", $TargetSeverity, $ProblemsNum).">&nbsp;$ProblemsNum&nbsp;</span></h2><hr/>\n".$TYPE_PROBLEMS;
4868        }
4869        $TYPE_PROBLEMS = "<a name='".get_Anchor("Type", $Level, $TargetSeverity)."'></a>\n".$TYPE_PROBLEMS;
4870        $TYPE_PROBLEMS .= $TOP_REF."<br/>\n";
4871    }
4872    return $TYPE_PROBLEMS;
4873}
4874
4875sub cut_Namespace($$)
4876{
4877    my ($N, $Ns) = @_;
4878    $N=~s/(\W|\A)\Q$Ns\E\.(\w)/$1$2/g;
4879    return $N;
4880}
4881
4882sub getAffectedMethods($$$)
4883{
4884    my ($Level, $Target_TypeName, $Kinds_Locations) = @_;
4885   
4886    my $LIMIT = 10;
4887    if(defined $AffectLimit) {
4888        $LIMIT = $AffectLimit;
4889    }
4890   
4891    my @Kinds = sort keys(%{$Kinds_Locations});
4892    my %KLocs = ();
4893    foreach my $Kind (@Kinds)
4894    {
4895        my @Locs = sort {$a=~/retval/ cmp $b=~/retval/} sort {length($a)<=>length($b)} sort keys(%{$Kinds_Locations->{$Kind}});
4896        $KLocs{$Kind} = \@Locs;
4897    }
4898   
4899    my %SymLocKind = ();
4900    foreach my $Method (sort keys(%{$TypeProblemsIndex{$Target_TypeName}}))
4901    {
4902        if($Method eq ".client_method") {
4903            next;
4904        }
4905       
4906        foreach my $Kind (@Kinds)
4907        {
4908            foreach my $Loc (@{$KLocs{$Kind}})
4909            {
4910                if(not defined $CompatProblems{$Method}{$Kind}{$Loc}) {
4911                    next;
4912                }
4913               
4914                my $Type_Name = $CompatProblems{$Method}{$Kind}{$Loc}{"Type_Name"};
4915                if($Type_Name ne $Target_TypeName) {
4916                    next;
4917                }
4918               
4919                $SymLocKind{$Method}{$Loc}{$Kind} = 1;
4920                last;
4921            }
4922        }
4923    }
4924   
4925    %KLocs = (); # clear
4926   
4927    if(not keys(%SymLocKind)) {
4928        return "";
4929    }
4930   
4931    my %SymSel = ();
4932    my $Num = 0;
4933    foreach my $Method (sort keys(%SymLocKind))
4934    {
4935        LOOP: foreach my $Loc (sort {$a=~/retval/ cmp $b=~/retval/} sort {length($a)<=>length($b)} sort keys(%{$SymLocKind{$Method}}))
4936        {
4937            foreach my $Kind (sort keys(%{$SymLocKind{$Method}{$Loc}}))
4938            {
4939                $SymSel{$Method}{"Loc"} = $Loc;
4940                $SymSel{$Method}{"Kind"} = $Kind;
4941                last LOOP;
4942            }
4943        }
4944       
4945        $Num += 1;
4946       
4947        if($Num>=$LIMIT) {
4948            last;
4949        }
4950    }
4951   
4952    my $Affected = "";
4953   
4954    foreach my $Method (sort {lc($a) cmp lc($b)} keys(%SymSel))
4955    {
4956        my $Kind = $SymSel{$Method}{"Kind"};
4957        my $Loc = $SymSel{$Method}{"Loc"};
4958       
4959        my $Desc = getAffectDesc($Method, $Kind, $Loc, $Level);
4960        my $PName = getParamName($Loc);
4961        my $Pos = getParamPos($PName, $Method, 1);
4962       
4963        $Affected .= "<span class='iname_a'>".get_Signature($Method, 1, "HTML|Italic|Param|Class|Target=".$Pos)."</span><br/>";
4964        $Affected .= "<div class='affect'>".$Desc."</div>\n";
4965    }
4966   
4967    if(keys(%SymLocKind)>$LIMIT) {
4968        $Affected .= " <b>...</b>\n<br/>\n"; # and others ...
4969    }
4970   
4971    $Affected = "<div class='affected'>".$Affected."</div>";
4972    if($Affected)
4973    {
4974        my $Num = keys(%SymLocKind);
4975        my $Per = show_number($Num*100/keys(%CheckedMethods));
4976        $Affected =  $ContentDivStart.$Affected.$ContentDivEnd;
4977        $Affected =  $ContentSpanStart_Affected."[+] affected methods: $Num ($Per\%)".$ContentSpanEnd.$Affected;
4978    }
4979   
4980    return ($Affected);
4981}
4982
4983sub getAffectDesc($$$$)
4984{
4985    my ($Method, $Kind, $Location, $Level) = @_;
4986    my %Affect = %{$CompatProblems{$Method}{$Kind}{$Location}};
4987    my $New_Value = $Affect{"New_Value"};
4988    my $Type_Name = $Affect{"Type_Name"};
4989    my @Sentence_Parts = ();
4990   
4991    $Location=~s/\.[^.]+?\Z//;
4992   
4993    my %TypeAttr = get_Type($MethodInfo{1}{$Method}{"Class"}, 1);
4994    my $Type_Type = $TypeAttr{"Type"};
4995   
4996    my $ABSTRACT_M = $MethodInfo{1}{$Method}{"Abstract"}?" abstract":"";
4997    my $ABSTRACT_C = $TypeAttr{"Abstract"}?" abstract":"";
4998    my $METHOD_TYPE = $MethodInfo{1}{$Method}{"Constructor"}?"constructor":"method";
4999   
5000    if($Kind eq "Class_Overridden_Method" or $Kind eq "Class_Method_Moved_Up_Hierarchy") {
5001        return "Method '".highLight_Signature($New_Value, 2)."' will be called instead of this method in a client program.";
5002    }
5003    elsif($TypeProblems_Kind{$Level}{$Kind})
5004    {
5005        my %MInfo = %{$MethodInfo{1}{$Method}};
5006       
5007        if($Location eq "this") {
5008            return "This$ABSTRACT_M $METHOD_TYPE is from \'".htmlSpecChars($Type_Name)."\'$ABSTRACT_C $Type_Type.";
5009        }
5010       
5011        my $TypeID = undef;
5012       
5013        if($Location=~/retval/)
5014        { # return value
5015            if($Location=~/\./) {
5016                push(@Sentence_Parts, "Field \'".htmlSpecChars($Location)."\' in return value");
5017            }
5018            else {
5019                push(@Sentence_Parts, "Return value");
5020            }
5021           
5022            $TypeID = $MInfo{"Return"};
5023        }
5024        elsif($Location=~/this/)
5025        { # "this" reference
5026            push(@Sentence_Parts, "Field \'".htmlSpecChars($Location)."\' in the object");
5027           
5028            $TypeID = $MInfo{"Class"};
5029        }
5030        else
5031        { # parameters
5032            my $PName = getParamName($Location);
5033            my $PPos = getParamPos($PName, $Method, 1);
5034           
5035            if($Location=~/\./) {
5036                push(@Sentence_Parts, "Field \'".htmlSpecChars($Location)."\' in ".showPos($PPos)." parameter");
5037            }
5038            else {
5039                push(@Sentence_Parts, showPos($PPos)." parameter");
5040            }
5041            if($PName) {
5042                push(@Sentence_Parts, "\'$PName\'");
5043            }
5044           
5045