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

Last change on this file since 10845 was 10845, checked in by Don-vip, 8 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=~/\./) {