Changeset 13595 in josm for trunk/tools/japicc/japi-compliance-checker.pl
- Timestamp:
- 2018-04-02T23:20:00+02:00 (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/tools/japicc/japi-compliance-checker.pl
r12872 r13595 1 1 #!/usr/bin/perl 2 ######################################################################### ##3 # Java API Compliance Checker (JAPICC) 2. 32 ######################################################################### 3 # Java API Compliance Checker (JAPICC) 2.4 4 4 # A tool for checking backward compatibility of a Java library API 5 5 # 6 6 # Written by Andrey Ponomarenko 7 7 # 8 # Copyright (C) 2011-201 7Andrey Ponomarenko's ABI Laboratory8 # Copyright (C) 2011-2018 Andrey Ponomarenko's ABI Laboratory 9 9 # 10 10 # PLATFORMS … … 15 15 # ============ 16 16 # Linux, FreeBSD, Mac OS X 17 # - JDK or OpenJDK - development files (javap, javac )17 # - JDK or OpenJDK - development files (javap, javac, jar, jmod) 18 18 # - Perl 5 (5.8 or newer) 19 19 # 20 20 # MS Windows 21 # - JDK or OpenJDK (javap, javac )21 # - JDK or OpenJDK (javap, javac, jar, jmod) 22 22 # - Active Perl 5 (5.8 or newer) 23 23 # 24 # This program is free software: you can redistribute it and/or modify 25 # it under the terms of the GNU General Public License or the GNU Lesser 26 # General Public License as published by the Free Software Foundation. 24 # This library is free software; you can redistribute it and/or 25 # modify it under the terms of the GNU Lesser General Public 26 # License as published by the Free Software Foundation; either 27 # version 2.1 of the License, or (at your option) any later version. 27 28 # 28 # This programis distributed in the hope that it will be useful,29 # This library is distributed in the hope that it will be useful, 29 30 # but WITHOUT ANY WARRANTY; without even the implied warranty of 30 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 # GNUGeneral Public License for more details.31 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 32 # Lesser General Public License for more details. 32 33 # 33 # You should have received a copy of the GNU General Public License 34 # and the GNU Lesser General Public License along with this program. 35 # If not, see <http://www.gnu.org/licenses/>. 36 ########################################################################### 34 # You should have received a copy of the GNU Lesser General Public 35 # License along with this library; if not, write to the Free Software 36 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 37 # MA 02110-1301 USA. 38 ######################################################################### 37 39 use Getopt::Long; 38 40 Getopt::Long::Configure ("posix_default", "no_ignore_case", "permute"); … … 43 45 use Data::Dumper; 44 46 45 my $TOOL_VERSION = "2. 3";46 my $API_DUMP_VERSION = "2. 2";47 my $TOOL_VERSION = "2.4"; 48 my $API_DUMP_VERSION = "2.4"; 47 49 my $API_DUMP_VERSION_MIN = "2.2"; 48 50 … … 78 80 my $ShortUsage = "Java API Compliance Checker (JAPICC) $TOOL_VERSION 79 81 A tool for checking backward compatibility of a Java library API 80 Copyright (C) 201 7Andrey Ponomarenko's ABI Laboratory81 License: GNU LGPL or GNU GPL82 Copyright (C) 2018 Andrey Ponomarenko's ABI Laboratory 83 License: LGPLv2.1+ 82 84 83 85 Usage: $CmdName [options] 84 Example: $CmdName OLD.jar NEW.jar 86 Example: 87 $CmdName OLD.jar NEW.jar 88 $CmdName OLD.jmod NEW.jmod 85 89 86 90 More info: $CmdName --help"; … … 110 114 "skip-internal-types=s" => \$In::Opt{"SkipInternalTypes"}, 111 115 "dump|dump-api=s" => \$In::Opt{"DumpAPI"}, 116 "check-annotations!" => \$In::Opt{"CheckAnnotations"}, 112 117 "check-packages=s" => \$In::Opt{"CheckPackages"}, 113 118 "classes-list=s" => \$In::Opt{"ClassListPath"}, … … 117 122 "skip-classes=s" => \$In::Opt{"SkipClassesList"}, 118 123 "skip-packages=s" => \$In::Opt{"SkipPackagesList"}, 124 "non-impl=s" => \$In::Opt{"NonImplClassesList"}, 125 "non-impl-all!" => \$In::Opt{"NonImplAll"}, 119 126 "short" => \$In::Opt{"ShortMode"}, 120 127 "dump-path=s" => \$In::Opt{"OutputDumpPath"}, … … 189 196 190 197 This tool is free software: you can redistribute it and/or modify it 191 under the terms of the GNU LGPL or GNU GPL.198 under the terms of the GNU LGPL. 192 199 193 200 USAGE: 194 201 $CmdName [options] 195 202 196 EXAMPLE 1:203 EXAMPLE (1): 197 204 $CmdName OLD.jar NEW.jar 198 205 199 EXAMPLE 2: 206 EXAMPLE (2): 207 $CmdName OLD.jmod NEW.jmod 208 209 EXAMPLE (3): 200 210 $CmdName -lib NAME -old OLD.xml -new NEW.xml 201 211 OLD.xml and NEW.xml are XML-descriptors: … … 206 216 207 217 <archives> 208 /path1/to/JAR(s) /209 /path2/to/JAR(s) /218 /path1/to/JAR(s) OR JMOD(s)/ 219 /path2/to/JAR(s) OR JMOD(s)/ 210 220 ... 211 221 </archives> … … 229 239 It may be one of the following: 230 240 231 1. Java archive (*.jar )241 1. Java archive (*.jar or *.jmod) 232 242 2. XML-descriptor (VERSION.xml file): 233 243 … … 237 247 238 248 <archives> 239 /path1/to/JAR(s) /240 /path2/to/JAR(s) /249 /path1/to/JAR(s) OR JMOD(s)/ 250 /path2/to/JAR(s) OR JMOD(s)/ 241 251 ... 242 252 </archives> … … 246 256 3. API dump generated by -dump option 247 257 248 If you are using *.jar as a descriptor then you should249 specify version numbers with -v1 and -v2 options too.250 If version numbers are not specified then the tool will251 t ry to detect them automatically.258 If you are using *.jar or *.jmod as a descriptor then 259 you should specify version numbers with -v1 and -v2 260 options too. If version numbers are not specified then 261 the tool will try to detect them automatically. 252 262 253 263 -new|-d2 PATH … … 304 314 for debugging the tool. PATH is the path to the Java archive or 305 315 XML descriptor of the library. 316 317 -check-annotations 318 Check for changes in annotations like in any other interfaces. 306 319 307 320 -check-packages PATTERN … … 325 338 326 339 -skip-classes PATH 327 This option allows to specify a file with a list 328 of classes that should not be checked. 329 340 List of classes that should not be checked. 341 330 342 -skip-packages PATH 331 This option allows to specify a file with a list 332 of packages that should not be checked. 333 343 List of packages that should not be checked. 344 345 -non-impl PATH 346 List of interfaces that should not be implemented by users. 347 348 -non-impl-all 349 All interfaces should not be implemented by users. 350 334 351 -short 335 352 Do not list added/removed methods. … … 805 822 } 806 823 } 824 825 if(defined $Class1->{"Annotation"}) 826 { 827 my %AnnParam = (); 828 foreach my $VN (1, 2) 829 { 830 foreach my $Method (keys(%{$Class_Methods{$VN}{$ClassName}})) 831 { 832 my $MInfo = $MethodInfo{$VN}{$Method}; 833 $AnnParam{$VN}{$MInfo->{"ShortName"}} = {"Default"=>$MInfo->{"Default"}, "Return"=>getTypeName($MInfo->{"Return"}, $VN)}; 834 } 835 } 836 foreach my $AParam (sort keys(%{$AnnParam{1}})) 837 { 838 my $R1 = $AnnParam{1}{$AParam}{"Return"}; 839 my $D1 = $AnnParam{1}{$AParam}{"Default"}; 840 841 if(defined $AnnParam{2}{$AParam}) 842 { 843 my $R2 = $AnnParam{2}{$AParam}{"Return"}; 844 my $D2 = $AnnParam{2}{$AParam}{"Default"}; 845 846 if($R1 ne $R2) 847 { 848 if($R1 eq "java.lang.String" and $R2 eq "java.lang.String[]") 849 { 850 %{$CompatProblems{".client_method"}{"Annotation_Element_Changed_Type_Safe"}{$AParam}} = ( 851 "Type_Name"=>$ClassName, 852 "Old_Value"=>$R1, 853 "New_Value"=>$R2, 854 "Target"=>$AParam); 855 } 856 else 857 { 858 %{$CompatProblems{".client_method"}{"Annotation_Element_Changed_Type"}{$AParam}} = ( 859 "Type_Name"=>$ClassName, 860 "Old_Value"=>$R1, 861 "New_Value"=>$R2, 862 "Target"=>$AParam); 863 } 864 } 865 866 if(defined $D1 and not defined $D2) 867 { 868 %{$CompatProblems{".client_method"}{"Annotation_Element_Removed_Default_Value"}{$AParam}} = ( 869 "Type_Name"=>$ClassName, 870 "Old_Value"=>$D1, 871 "Target"=>$AParam); 872 } 873 elsif(not defined $D1 and defined $D2) 874 { 875 %{$CompatProblems{".client_method"}{"Annotation_Element_Added_Default_Value"}{$AParam}} = ( 876 "Type_Name"=>$ClassName, 877 "New_Value"=>$D2, 878 "Target"=>$AParam); 879 } 880 elsif($D1 ne $D2) 881 { 882 %{$CompatProblems{".client_method"}{"Annotation_Element_Changed_Default_Value"}{$AParam}} = ( 883 "Type_Name"=>$ClassName, 884 "Old_Value"=>$D1, 885 "New_Value"=>$D2, 886 "Target"=>$AParam); 887 } 888 } 889 else 890 { 891 if(defined $D1) 892 { 893 %{$CompatProblems{".client_method"}{"Removed_Annotation_Default_Element"}{$AParam}} = ( 894 "Type_Name"=>$ClassName, 895 "Elem_Type"=>$R1, 896 "Old_Value"=>$D1, 897 "Target"=>$AParam); 898 } 899 else 900 { 901 %{$CompatProblems{".client_method"}{"Removed_Annotation_NonDefault_Element"}{$AParam}} = ( 902 "Type_Name"=>$ClassName, 903 "Elem_Type"=>$R1, 904 "Target"=>$AParam); 905 } 906 } 907 } 908 909 foreach my $AParam (sort keys(%{$AnnParam{2}})) 910 { 911 if(not defined $AnnParam{1}{$AParam}) 912 { 913 my $R2 = $AnnParam{2}{$AParam}{"Return"}; 914 915 if(defined $AnnParam{2}{$AParam}{"Default"}) 916 { 917 my $D2 = $AnnParam{2}{$AParam}{"Default"}; 918 %{$CompatProblems{".client_method"}{"Added_Annotation_Default_Element"}{$AParam}} = ( 919 "Type_Name"=>$ClassName, 920 "Elem_Type"=>$R2, 921 "New_Value"=>$D2, 922 "Target"=>$AParam); 923 } 924 else 925 { 926 %{$CompatProblems{".client_method"}{"Added_Annotation_NonDefault_Element"}{$AParam}} = ( 927 "Type_Name"=>$ClassName, 928 "Elem_Type"=>$R2, 929 "Target"=>$AParam); 930 } 931 } 932 } 933 } 807 934 } 808 935 else … … 1051 1178 else 1052 1179 { 1053 if(my @InvokedBy = sort keys(%{$MethodUsed{2}{$AddedMethod}})) 1180 if(nonImplClass(\%Type1)) 1181 { 1182 %{$SubProblems{"NonImpl_Interface_Added_Abstract_Method"}{getSFormat($AddedMethod)}} = ( 1183 "Type_Name"=>$Type1{"Name"}, 1184 "Type_Type"=>$Type1{"Type"}, 1185 "Target"=>$AddedMethod); 1186 } 1187 elsif(my @InvokedBy = sort keys(%{$MethodUsed{2}{$AddedMethod}})) 1054 1188 { 1055 1189 %{$SubProblems{"Interface_Added_Abstract_Method_Invoked_By_Others"}{getSFormat($AddedMethod)}} = ( … … 1754 1888 1755 1889 my $ClassId1 = $MethodInfo{1}{$Method}{"Class"}; 1756 my $Class1_Name = getTypeName($ClassId1, 1); 1757 my $Class1_Type = getTypeType($ClassId1, 1); 1890 my $Class1 = getType($ClassId1, 1); 1891 1892 if(not defined $In::Opt{"CheckAnnotations"} and $Class1->{"Annotation"}) { 1893 next; 1894 } 1895 1896 my $Class1_Name = $Class1->{"Name"}; 1897 my $Class1_Type = $Class1->{"Type"}; 1758 1898 1759 1899 $CheckedTypes{$Class1_Name} = 1; … … 2520 2660 foreach my $Method (sort keys(%CompatProblems)) 2521 2661 { 2522 foreach my $Kind ( keys(%{$CompatProblems{$Method}}))2662 foreach my $Kind (sort keys(%{$CompatProblems{$Method}})) 2523 2663 { 2524 2664 if(not defined $CompatRules{"Binary"}{$Kind} and not defined $CompatRules{"Source"}{$Kind}) … … 2527 2667 { # only one warning 2528 2668 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")"); 2529 $UnknownRules{$Level}{$Kind} =1;2669 $UnknownRules{$Level}{$Kind} = 1; 2530 2670 } 2531 2671 } … … 2694 2834 $Checked_Archives_Link = "<a href='#Checked_Archives' style='color:Blue;'>".keys(%{$LibArchives{1}})."</a>" if(keys(%{$LibArchives{1}})>0); 2695 2835 2696 $TestResults .= "<tr><th>Total J ARs</th><td>$Checked_Archives_Link</td></tr>\n";2836 $TestResults .= "<tr><th>Total Java Modules</th><td>$Checked_Archives_Link</td></tr>\n"; 2697 2837 $TestResults .= "<tr><th>Total Methods / Classes</th><td>".keys(%CheckedMethods)." / ".keys(%CheckedTypes)."</td></tr>\n"; 2698 2838 … … 3363 3503 { 3364 3504 my ($Name, $Html, $LVer) = @_; 3365 my $TType = $TypeInfo{$LVer}{$TName_Tid{$LVer}{$Name}}{"Type"}; 3505 my $TInfo = $TypeInfo{$LVer}{$TName_Tid{$LVer}{$Name}}; 3506 my $TType = $TInfo->{"Type"}; 3507 3508 if($TInfo->{"Annotation"}) { 3509 $TType = '@'.$TType; 3510 } 3511 3366 3512 if($Html) { 3367 3513 $Name = "<span class='ttype'>".$TType."</span> ".specChars($Name); … … 3894 4040 $Head .= "<head>\n"; 3895 4041 $Head .= "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n"; 4042 $Head .= "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n"; 3896 4043 $Head .= "<meta name=\"keywords\" content=\"$Keywords\" />\n"; 3897 4044 $Head .= "<meta name=\"description\" content=\"$Description\" />\n"; … … 3973 4120 3974 4121 my $Class = getType($MethodInfo{2}{$Method}{"Class"}, 2); 4122 4123 if(not defined $In::Opt{"CheckAnnotations"} and $Class->{"Annotation"}) { 4124 next; 4125 } 3975 4126 3976 4127 $CheckedTypes{$Class->{"Name"}} = 1; … … 4048 4199 my $Class = getType($MethodInfo{1}{$Method}{"Class"}, 1); 4049 4200 4201 if(not defined $In::Opt{"CheckAnnotations"} and $Class->{"Annotation"}) { 4202 next; 4203 } 4204 4050 4205 $CheckedTypes{$Class->{"Name"}} = 1; 4051 4206 $CheckedMethods{$Method} = 1; … … 4079 4234 } 4080 4235 4081 sub getArchivePaths($$)4082 {4083 my ($Dest, $LVer) = @_;4084 if(-f $Dest) {4085 return ($Dest);4086 }4087 elsif(-d $Dest)4088 {4089 $Dest=~s/[\/\\]+\Z//g;4090 next if(not $Dest);4091 4092 my @Archives = ();4093 foreach my $Path (cmdFind($Dest, "", "*\\.jar"))4094 {4095 next if(ignorePath($Path, $Dest));4096 push(@Archives, realpath_F($Path));4097 }4098 return @Archives;4099 }4100 return ();4101 }4102 4103 4236 sub isCyclical($$) { 4104 4237 return (grep {$_ eq $_[1]} @{$_[0]}); … … 4206 4339 } 4207 4340 4208 if($Path!~/\. jar\Z/i) {4341 if($Path!~/\.(jar|jmod)\Z/i) { 4209 4342 return; 4210 4343 } … … 4212 4345 my $Ver = undef; 4213 4346 4214 if(not defined $Ver) { 4215 $Ver = getManifestVersion(getAbsPath($Path)); 4347 if($Path=~/\.jar\Z/i) 4348 { 4349 if(not defined $Ver) { 4350 $Ver = getManifestVersion(getAbsPath($Path)); 4351 } 4216 4352 } 4217 4353 … … 4875 5011 if(defined $In::Opt{"ShowVersion"}) 4876 5012 { 4877 printMsg("INFO", "Java API Compliance Checker (JAPICC) $TOOL_VERSION\nCopyright (C) 201 7 Andrey Ponomarenko's ABI Laboratory\nLicense: LGPL or GPL<http://www.gnu.org/licenses/>\nThis program is free software: you can redistribute it and/or modify it.\n\nWritten by Andrey Ponomarenko.");5013 printMsg("INFO", "Java API Compliance Checker (JAPICC) $TOOL_VERSION\nCopyright (C) 2018 Andrey Ponomarenko's ABI Laboratory\nLicense: LGPLv2.1+ <http://www.gnu.org/licenses/>\nThis program is free software: you can redistribute it and/or modify it.\n\nWritten by Andrey Ponomarenko."); 4878 5014 exit(0); 4879 5015 } … … 4911 5047 if($In::Opt{"DumpAPI"}) 4912 5048 { 4913 if($In::Opt{"DumpAPI"}=~/\. jar\Z/)5049 if($In::Opt{"DumpAPI"}=~/\.(jar|jmod)\Z/) 4914 5050 { # short usage 4915 5051 my ($Name, $Version) = getPkgVersion(getFilename($In::Opt{"DumpAPI"})); … … 4925 5061 else 4926 5062 { 4927 if($In::Desc{1}{"Path"}=~/\. jar\Z/ and $In::Desc{2}{"Path"}=~/\.jar\Z/)5063 if($In::Desc{1}{"Path"}=~/\.(jar|jmod)\Z/ and $In::Desc{2}{"Path"}=~/\.(jar|jmod)\Z/) 4928 5064 { # short usage 4929 5065 my ($Name1, $Version1) = getPkgVersion(getFilename($In::Desc{1}{"Path"})); … … 4999 5135 } 5000 5136 } 5137 if(my $NonImplClassesList = $In::Opt{"NonImplClassesList"}) 5138 { 5139 if(not -f $NonImplClassesList) { 5140 exitStatus("Access_Error", "can't access file \'$NonImplClassesList\'"); 5141 } 5142 foreach my $Class (split(/\n/, readFile($NonImplClassesList))) 5143 { 5144 $Class=~s/\//./g; 5145 $In::Opt{"NonImplClasses"}{$Class} = 1; 5146 } 5147 } 5001 5148 if(my $SkipPackagesList = $In::Opt{"SkipPackagesList"}) 5002 5149 {
Note:
See TracChangeset
for help on using the changeset viewer.