Index: trunk/tools/japicc/japi-compliance-checker.pl
===================================================================
--- trunk/tools/japicc/japi-compliance-checker.pl	(revision 11682)
+++ trunk/tools/japicc/japi-compliance-checker.pl	(revision 12872)
@@ -1,5 +1,5 @@
 #!/usr/bin/perl
 ###########################################################################
-# Java API Compliance Checker (JAPICC) 2.1
+# Java API Compliance Checker (JAPICC) 2.3
 # A tool for checking backward compatibility of a Java library API
 #
@@ -43,7 +43,7 @@
 use Data::Dumper;
 
-my $TOOL_VERSION = "2.1";
-my $API_DUMP_VERSION = "2.1";
-my $API_DUMP_VERSION_MIN = "2.0";
+my $TOOL_VERSION = "2.3";
+my $API_DUMP_VERSION = "2.2";
+my $API_DUMP_VERSION_MIN = "2.2";
 
 # Internal modules
@@ -110,4 +110,5 @@
   "skip-internal-types=s" => \$In::Opt{"SkipInternalTypes"},
   "dump|dump-api=s" => \$In::Opt{"DumpAPI"},
+  "check-packages=s" => \$In::Opt{"CheckPackages"},
   "classes-list=s" => \$In::Opt{"ClassListPath"},
   "annotations-list=s" => \$In::Opt{"AnnotationsListPath"},
@@ -291,14 +292,21 @@
   
   -skip-internal-packages PATTERN
-      Do not check packages matched by the pattern.
+      Do not check packages matched by the regular expression.
   
   -skip-internal-types PATTERN
-      Do not check types (classes and interfaces) matched by the pattern.
+      Do not check types (classes and interfaces) matched by the regular
+      expression. It's matched against full qualified type names (e.g.
+      'org.xyz.Name<T>'). It has to match any part of type name.
   
   -dump|-dump-api PATH
       Dump library API to gzipped TXT format file. You can transfer it
       anywhere and pass instead of the descriptor. Also it may be used
-      for debugging the tool.
-      
+      for debugging the tool. PATH is the path to the Java archive or
+      XML descriptor of the library.
+  
+  -check-packages PATTERN
+      Check packages matched by the regular expression. Other packages
+      will not be checked.
+  
   -classes-list PATH
       This option allows to specify a file with a list
@@ -441,4 +449,6 @@
 #Aliases
 my (%MethodInfo, %TypeInfo, %TName_Tid) = ();
+
+my %TName_Tid_Generic = ();
 
 #Separate checked and unchecked exceptions
@@ -522,4 +532,5 @@
 my %LibArchives;
 my %Class_Methods;
+my %Class_Methods_Generic;
 my %Class_AbstractMethods;
 my %Class_Fields;
@@ -530,4 +541,5 @@
 my %CheckedMethods;
 my %MethodUsed;
+my %OldMethodSignature;
 
 #Merging
@@ -537,4 +549,5 @@
 my %CompatRules;
 my %IncompleteRules;
+my %UnknownRules;
 
 #Report
@@ -623,5 +636,6 @@
     {
         next if(not $ClassName);
-        my $Type1 = getType($TName_Tid{1}{$ClassName}, 1);
+        my $Type1_Id = $TName_Tid{1}{$ClassName};
+        my $Type1 = getType($Type1_Id, 1);
         
         if($Type1->{"Type"}!~/class|interface/) {
@@ -634,10 +648,75 @@
         }
         
-        if(not classFilter($Type1, 1, 0)) {
+        if(not classFilter($Type1, 1, 1)) {
             next;
         }
         
-        my $Type2_Id = $TName_Tid{2}{$ClassName};
-        if(not $Type2_Id)
+        my $GenericName = getGeneric($ClassName);
+        my $Type2_Id = undef;
+        
+        if(defined $TName_Tid{2}{$ClassName}) {
+            $Type2_Id = $TName_Tid{2}{$ClassName};
+        }
+        elsif(defined $TName_Tid_Generic{2}{$GenericName}) {
+            $Type2_Id = $TName_Tid_Generic{2}{$GenericName};
+        }
+        
+        if($Type2_Id)
+        {
+            my $TName1 = $Type1->{"Name"};
+            my $TName2 = getTypeName($Type2_Id, 2);
+            
+            my $Generic1 = (index($TName1, "<")!=-1);
+            my $Generic2 = (index($TName2, "<")!=-1);
+            
+            if($Generic1 ne $Generic2)
+            { # removed generic parameters
+                foreach my $Method (keys(%{$Class_Methods{1}{$ClassName}}))
+                {
+                    if(not methodFilter($Method, 1)) {
+                        next;
+                    }
+                    
+                    $CheckedTypes{$ClassName} = 1;
+                    $CheckedMethods{$Method} = 1;
+                    
+                    if($Type1->{"Type"} eq "class")
+                    {
+                        if($Generic1)
+                        {
+                            %{$CompatProblems{$Method}{"Class_Became_Raw"}{"this"}} = (
+                                "Type_Name"=>$ClassName,
+                                "New_Value"=>$TName2,
+                                "Target"=>$ClassName);
+                        }
+                        else
+                        {
+                            %{$CompatProblems{$Method}{"Class_Became_Generic"}{"this"}} = (
+                                "Type_Name"=>$ClassName,
+                                "New_Value"=>$TName2,
+                                "Target"=>$ClassName);
+                        }
+                    }
+                    else
+                    {
+                        if($Generic1)
+                        {
+                            %{$CompatProblems{$Method}{"Interface_Became_Raw"}{"this"}} = (
+                                "Type_Name"=>$ClassName,
+                                "New_Value"=>$TName2,
+                                "Target"=>$ClassName);
+                        }
+                        else
+                        {
+                            %{$CompatProblems{$Method}{"Interface_Became_Generic"}{"this"}} = (
+                                "Type_Name"=>$ClassName,
+                                "New_Value"=>$TName2,
+                                "Target"=>$ClassName);
+                        }
+                    }
+                }
+            }
+        }
+        else
         { # classes and interfaces with public methods
             foreach my $Method (keys(%{$Class_Methods{1}{$ClassName}}))
@@ -686,6 +765,15 @@
         
         my $ClassName = $Class1->{"Name"};
-        
-        if(my $Class2_Id = $TName_Tid{2}{$ClassName})
+        my $GenericName = getGeneric($ClassName);
+        my $Class2_Id = undef;
+        
+        if(defined $TName_Tid{2}{$ClassName}) {
+            $Class2_Id = $TName_Tid{2}{$ClassName};
+        }
+        elsif(defined $TName_Tid_Generic{2}{$GenericName}) {
+            $Class2_Id = $TName_Tid_Generic{2}{$GenericName};
+        }
+        
+        if($Class2_Id)
         { # classes and interfaces with public static fields
             if(not defined $Class_Methods{1}{$ClassName})
@@ -869,7 +957,13 @@
     return {} if(not $Type1{"Name"} or not $Type2{"Name"});
     return {} if(not $Type1{"Archive"} or not $Type2{"Archive"});
-    return {} if($Type1{"Name"} ne $Type2{"Name"});
-    
-    if(not classFilter(\%Type1, 1, 0)) {
+    if($Type1{"Name"} ne $Type2{"Name"})
+    {
+        if(getGeneric($Type1{"Name"}) ne getGeneric($Type2{"Name"}))
+        { # compare type declarations if became generic or raw
+            return {};
+        }
+    }
+    
+    if(not classFilter(\%Type1, 1, 1)) {
         return {};
     }
@@ -925,5 +1019,5 @@
     pushType($Type1_Id, $Type2_Id);
     
-    foreach my $AddedMethod (keys(%{$AddedMethod_Abstract{$Type1{"Name"}}}))
+    foreach my $AddedMethod (keys(%{$AddedMethod_Abstract{$Type2{"Name"}}}))
     {
         if($Type1{"Type"} eq "class")
@@ -1000,51 +1094,49 @@
         my $SuperClassName2 = $SuperClass2->{"Name"};
         
+        # Java 6: java.lang.Object
+        # Java 7: none
+        if(not $SuperClassName1) {
+            $SuperClassName1 = "java.lang.Object";
+        }
+        
+        if(not $SuperClassName2) {
+            $SuperClassName2 = "java.lang.Object";
+        }
+        
         if($SuperClassName2 ne $SuperClassName1)
         {
-            if($SuperClassName1 eq "java.lang.Object"
-            or not $SuperClassName1)
-            {
-              # Java 6: java.lang.Object
-              # Java 7: none
-                if($SuperClassName2 ne "java.lang.Object")
+            if($SuperClassName1 eq "java.lang.Object")
+            {
+                if($SuperClass2->{"Abstract"}
+                and $Type1{"Abstract"} and $Type2{"Abstract"}
+                and keys(%{$Class_AbstractMethods{2}{$SuperClassName2}}))
                 {
-                    if($SuperClass2->{"Abstract"}
-                    and $Type1{"Abstract"} and $Type2{"Abstract"}
-                    and keys(%{$Class_AbstractMethods{2}{$SuperClassName2}}))
+                    if(my ($Invoked, $InvokedBy) = getInvoked($Type1{"Name"}))
                     {
-                        if(my ($Invoked, $InvokedBy) = getInvoked($Type1{"Name"}))
-                        {
-                            %{$SubProblems{"Abstract_Class_Added_Super_Abstract_Class_Invoked_By_Others"}{""}} = (
-                                "Type_Name"=>$Type1{"Name"},
-                                "Target"=>$SuperClassName2,
-                                "Invoked"=>$Invoked,
-                                "Invoked_By"=>$InvokedBy);
-                        }
-                        else
-                        {
-                            %{$SubProblems{"Abstract_Class_Added_Super_Abstract_Class"}{""}} = (
-                                "Type_Name"=>$Type1{"Name"},
-                                "Target"=>$SuperClassName2);
-                        }
+                        %{$SubProblems{"Abstract_Class_Added_Super_Abstract_Class_Invoked_By_Others"}{""}} = (
+                            "Type_Name"=>$Type1{"Name"},
+                            "Target"=>$SuperClassName2,
+                            "Invoked"=>$Invoked,
+                            "Invoked_By"=>$InvokedBy);
                     }
                     else
                     {
-                        %{$SubProblems{"Added_Super_Class"}{""}} = (
+                        %{$SubProblems{"Abstract_Class_Added_Super_Abstract_Class"}{""}} = (
                             "Type_Name"=>$Type1{"Name"},
                             "Target"=>$SuperClassName2);
                     }
                 }
-            }
-            elsif($SuperClassName2 eq "java.lang.Object"
-            or not $SuperClassName2)
-            {
-              # Java 6: java.lang.Object
-              # Java 7: none
-                if($SuperClassName1 ne "java.lang.Object")
+                else
                 {
-                    %{$SubProblems{"Removed_Super_Class"}{""}} = (
+                    %{$SubProblems{"Added_Super_Class"}{""}} = (
                         "Type_Name"=>$Type1{"Name"},
-                        "Target"=>$SuperClassName1);
-                }
+                        "Target"=>$SuperClassName2);
+                }
+            }
+            elsif($SuperClassName2 eq "java.lang.Object")
+            {
+                %{$SubProblems{"Removed_Super_Class"}{""}} = (
+                    "Type_Name"=>$Type1{"Name"},
+                    "Target"=>$SuperClassName1);
             }
             else
@@ -1337,5 +1429,5 @@
         }
         
-        my %Sub_SubChanges = detectTypeChange($FieldType1_Id, $FieldType2_Id, "Field");
+        my %Sub_SubChanges = detectTypeChange(\%Type1, \%Type2, $FieldType1_Id, $FieldType2_Id, "Field");
         foreach my $Sub_SubProblemType (keys(%Sub_SubChanges))
         {
@@ -1460,5 +1552,14 @@
 {
     my ($Method, $MethodVersion, $ClassName, $ClassVersion) = @_;
-    my $ClassId = $TName_Tid{$ClassVersion}{$ClassName};
+    
+    my $GenericName = getGeneric($ClassName);
+    my $ClassId = undef;
+    
+    if(defined $TName_Tid{$ClassVersion}{$ClassName}) {
+        $ClassId = $TName_Tid{$ClassVersion}{$ClassName};
+    }
+    elsif(defined $TName_Tid_Generic{$ClassVersion}{$GenericName}) {
+        $ClassId = $TName_Tid_Generic{$ClassVersion}{$GenericName};
+    }
     
     if($ClassId)
@@ -1517,14 +1618,25 @@
 {
     my ($Method, $ClassName, $ClassVersion) = @_;
+    
     my $TargetSuffix = getMSuffix($Method);
     my $TargetShortName = getMShort($Method);
-    
-    if(not defined $Class_Methods{$ClassVersion}{$ClassName}) {
+    my $GenericName = getGeneric($ClassName);
+    
+    my @Candidates = ();
+    
+    if(defined $Class_Methods{$ClassVersion}{$ClassName}) {
+        @Candidates = keys(%{$Class_Methods{$ClassVersion}{$ClassName}});
+    }
+    elsif(defined $Class_Methods_Generic{$ClassVersion}{$GenericName}) {
+        @Candidates = keys(%{$Class_Methods_Generic{$ClassVersion}{$GenericName}});
+    }
+    else {
         return undef;
     }
     
-    foreach my $Candidate (sort keys(%{$Class_Methods{$ClassVersion}{$ClassName}}))
+    foreach my $Candidate (sort @Candidates)
     { # search for method with the same parameters suffix
         next if($MethodInfo{$ClassVersion}{$Candidate}{"Constructor"});
+        
         if($TargetSuffix eq getMSuffix($Candidate))
         {
@@ -1538,4 +1650,11 @@
 }
 
+sub getBaseSignature($)
+{
+    my $Method = $_[0];
+    $Method=~s/\)(.+)\Z/\)/g;
+    return $Method;
+}
+
 sub prepareData($)
 {
@@ -1558,4 +1677,9 @@
         $TName_Tid{$LVer}{$TName} = $TypeId;
         
+        if(defined $TypeAttr->{"Archive"})
+        { # declaration
+            $TName_Tid_Generic{$LVer}{getGeneric($TName)} = $TypeId;
+        }
+        
         if(not $TypeAttr->{"Dep"})
         {
@@ -1590,4 +1714,6 @@
             my $CName = getTypeName($ClassId, $LVer);
             $Class_Methods{$LVer}{$CName}{$Method} = 1;
+            $Class_Methods_Generic{$LVer}{getGeneric($CName)}{$Method} = 1;
+            
             if($MAttr->{"Abstract"}) {
                 $Class_AbstractMethods{$LVer}{$CName}{$Method} = 1;
@@ -1603,4 +1729,9 @@
                 registerUsage($MAttr->{"Return"}, $LVer);
             }
+        }
+        
+        if($LVer==1 and not $MAttr->{"Constructor"}
+        and my $BaseSign = getBaseSignature($Method)) {
+            $OldMethodSignature{$BaseSign} = $Method;
         }
     }
@@ -1857,4 +1988,28 @@
     # checking type declaration changes
     my $SubProblems = mergeTypes($ParamType1_Id, $ParamType2_Id);
+    
+    my $Type1 = getType($ParamType1_Id, 1);
+    my $Type2 = getType($ParamType2_Id, 2);
+    
+    if($Type1->{"Name"} ne $Type2->{"Name"})
+    {
+        if(index($Type1->{"Name"}, "...")!=-1 and index($Type2->{"Name"}, "[]")!=-1)
+        {
+            %{$CompatProblems{$Method}{"Variable_Arity_To_Array"}{$Parameter_Name}} = (
+                "Type_Name"=>getTypeName($MethodInfo{1}{$Method}{"Class"}, 1),
+                "Param_Name"=>$Parameter_Name,
+                "Old_Value"=>$Type1->{"Name"},
+                "New_Value"=>$Type2->{"Name"});
+        }
+        elsif(index($Type1->{"Name"}, "[]")!=-1 and index($Type2->{"Name"}, "...")!=-1)
+        {
+            %{$CompatProblems{$Method}{"Array_To_Variable_Arity"}{$Parameter_Name}} = (
+                "Type_Name"=>getTypeName($MethodInfo{1}{$Method}{"Class"}, 1),
+                "Param_Name"=>$Parameter_Name,
+                "Old_Value"=>$Type1->{"Name"},
+                "New_Value"=>$Type2->{"Name"});
+        }
+    }
+    
     foreach my $SubProblemType (keys(%{$SubProblems}))
     {
@@ -1867,7 +2022,7 @@
 }
 
-sub detectTypeChange($$$)
-{
-    my ($Type1_Id, $Type2_Id, $Prefix) = @_;
+sub detectTypeChange($$$$$)
+{
+    my ($Ct1, $Ct2, $Type1_Id, $Type2_Id, $Prefix) = @_;
     my %LocalProblems = ();
     
@@ -1878,4 +2033,21 @@
     my $Type2_Name = $Type2->{"Name"};
     
+    my $Type1_Show = $Type1_Name;
+    my $Type2_Show = $Type2_Name;
+    
+    if(defined $Ct1->{"GenericParam"}
+    and defined $Ct1->{"GenericParam"}{$Type1_Name})
+    {
+        $Type1_Name = getTypeName($Ct1->{"GenericParam"}{$Type1_Name}, 1);
+        $Type1_Show .= " extends ".$Type1_Name;
+    }
+    
+    if(defined $Ct2->{"GenericParam"}
+    and defined $Ct2->{"GenericParam"}{$Type2_Name})
+    {
+        $Type2_Name = getTypeName($Ct2->{"GenericParam"}{$Type2_Name}, 2);
+        $Type2_Show .= " extends ".$Type2_Name;
+    }
+    
     my $Type1_Base = undef;
     my $Type2_Base = undef;
@@ -1897,4 +2069,5 @@
     return () if(not $Type1_Name or not $Type2_Name);
     return () if(not $Type1_Base->{"Name"} or not $Type2_Base->{"Name"});
+    
     if($Type1_Base->{"Name"} ne $Type2_Base->{"Name"} and $Type1_Name eq $Type2_Name)
     {# base type change
@@ -1906,6 +2079,6 @@
     {# type change
         %{$LocalProblems{"Changed_".$Prefix."_Type"}}=(
-            "Old_Value"=>$Type1_Name,
-            "New_Value"=>$Type2_Name);
+            "Old_Value"=>$Type1_Show,
+            "New_Value"=>$Type2_Show);
     }
     return %LocalProblems;
@@ -1953,5 +2126,6 @@
     # settings
     my ($Full, $Html, $Simple, $Italic, $Color,
-    $ShowParams, $ShowClass, $ShowAttr, $Desc, $Target) = (0, 0, 0, 0, 0, 0, 0, 0, 0, undef);
+    $ShowParams, $ShowClass, $ShowAttr, $Desc,
+    $ShowReturn, $Target) = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, undef);
     
     if($Kind=~/Full/) {
@@ -1985,8 +2159,11 @@
         $Desc = 1;
     }
+    if($Kind=~/Return/) {
+        $ShowReturn = 1;
+    }
     
     if(not defined $MethodInfo{$LVer}{$Method}{"ShortName"})
     { # from java.lang.Object
-        if($Html or $Simple) {
+        if($Html) {
             return specChars($Method);
         }
@@ -1996,5 +2173,14 @@
     }
     
-    my $Signature = $MethodInfo{$LVer}{$Method}{"ShortName"};
+    my $Signature = "";
+    
+    my $ShortName = $MethodInfo{$LVer}{$Method}{"ShortName"};
+    
+    if($Html) {
+        $ShortName = specChars($ShortName);
+    }
+    
+    $Signature .= $ShortName;
+    
     if($Full or $ShowClass)
     {
@@ -2138,5 +2324,8 @@
             }
         }
-        
+    }
+    
+    if($Full or $ShowReturn)
+    {
         if(my $ReturnId = $MethodInfo{$LVer}{$Method}{"Return"})
         {
@@ -2151,5 +2340,8 @@
             }
             
-            if($Simple) {
+            if($Desc) {
+                $Signature = "<b>".specChars($RName)."</b> ".$Signature;
+            }
+            elsif($Simple) {
                 $Signature .= " <b>:</b> ".specChars($RName);
             }
@@ -2161,5 +2353,8 @@
             }
         }
-        
+    }
+    
+    if($Full)
+    {
         if(not $In::Opt{"SkipDeprecated"})
         {
@@ -2321,4 +2516,20 @@
         "Warnings"=>0,
         "Affected"=>0);
+    
+    # check rules
+    foreach my $Method (sort keys(%CompatProblems))
+    {
+        foreach my $Kind (keys(%{$CompatProblems{$Method}}))
+        {
+            if(not defined $CompatRules{"Binary"}{$Kind} and not defined $CompatRules{"Source"}{$Kind})
+            { # unknown rule
+                if(not $UnknownRules{$Level}{$Kind})
+                { # only one warning
+                    printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
+                    $UnknownRules{$Level}{$Kind}=1;
+                }
+            }
+        }
+    }
     
     foreach my $Method (sort keys(%CompatProblems))
@@ -2614,5 +2825,9 @@
     $META_DATA .= "tool_version:$TOOL_VERSION";
     $Problem_Summary .= "</table>\n";
-    return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
+    
+    my $AnyChanged = ($Added or $Removed or $M_Problems_High or $M_Problems_Medium or $M_Problems_Low or
+    $T_Problems_High or $T_Problems_Medium or $T_Problems_Low or $M_Other or $T_Other);
+    
+    return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA, $AnyChanged);
 }
 
@@ -2710,5 +2925,5 @@
                 }
                 
-                my @SortedMethods = sort {lc($MethodInfo{2}{$a}{"Signature"}) cmp lc($MethodInfo{2}{$b}{"Signature"})} keys(%{$NameSpace_Method{$NameSpace}});
+                my @SortedMethods = sort {lc($MethodInfo{2}{$a}{"Signature"}) cmp lc($MethodInfo{2}{$b}{"Signature"})} sort keys(%{$NameSpace_Method{$NameSpace}});
                 foreach my $Method (@SortedMethods)
                 {
@@ -2814,5 +3029,5 @@
                 }
                 
-                my @SortedMethods = sort {lc($MethodInfo{1}{$a}{"Signature"}) cmp lc($MethodInfo{1}{$b}{"Signature"})} keys(%{$NameSpace_Method{$NameSpace}});
+                my @SortedMethods = sort {lc($MethodInfo{1}{$a}{"Signature"}) cmp lc($MethodInfo{1}{$b}{"Signature"})} sort keys(%{$NameSpace_Method{$NameSpace}});
                 foreach my $Method (@SortedMethods)
                 {
@@ -2929,7 +3144,7 @@
 }
 
-sub applyMacroses($$$$$)
-{
-    my ($Level, $Kind, $Content, $Problem, $AddAttr) = @_;
+sub applyMacroses($$$$$$)
+{
+    my ($Level, $Subj, $Kind, $Content, $Problem, $AddAttr) = @_;
     
     $Content = addMarkup($Content);
@@ -2977,4 +3192,8 @@
                     $Fmt = "HTML|Desc";
                 }
+            }
+            
+            if($Subj eq "Change") {
+                $Fmt .= "|Return";
             }
             
@@ -3062,5 +3281,5 @@
                 }
                 
-                my @SortedMethods = sort {lc($MethodInfo{1}{$a}{"Signature"}) cmp lc($MethodInfo{1}{$b}{"Signature"})} keys(%{$NameSpace_Method{$NameSpace}});
+                my @SortedMethods = sort {lc($MethodInfo{1}{$a}{"Signature"}) cmp lc($MethodInfo{1}{$b}{"Signature"})} sort keys(%{$NameSpace_Method{$NameSpace}});
                 foreach my $Method (@SortedMethods)
                 {
@@ -3078,7 +3297,7 @@
                             my $ProblemAttr = $MethodChanges{$Method}{$Kind}{$Loc};
                             
-                            if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemAttr, \%AddAttr))
+                            if(my $Change = applyMacroses($Level, "Change", $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemAttr, \%AddAttr))
                             {
-                                my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, $ProblemAttr, \%AddAttr);
+                                my $Effect = applyMacroses($Level, "Effect", $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, $ProblemAttr, \%AddAttr);
                                 $METHOD_REPORT .= "<tr>\n<th>$ProblemNum</th>\n<td>".$Change."</td>\n<td>".$Effect."</td>\n</tr>\n";
                                 $ProblemNum += 1;
@@ -3233,7 +3452,7 @@
                         my $ProblemAttr = $TypeChanges_Sev{$TypeName}{$Kind}{$Location};
                         
-                        if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemAttr, \%AddAttr))
+                        if(my $Change = applyMacroses($Level, "Change", $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemAttr, \%AddAttr))
                         {
-                            my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, $ProblemAttr, \%AddAttr);
+                            my $Effect = applyMacroses($Level, "Effect", $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, $ProblemAttr, \%AddAttr);
                             
                             $TYPE_REPORT .= "<tr>\n<th>$ProblemNum</th>\n<td>".$Change."</td>\n<td>".$Effect."</td>\n</tr>\n";
@@ -3587,8 +3806,8 @@
         my $Description = "Compatibility report for the ".$In::Opt{"TargetTitle"}." library between ".$In::Desc{1}{"Version"}." and ".$In::Desc{2}{"Version"}." versions";
         
-        my ($BSummary, $BMetaData) = getSummary("Binary");
-        my ($SSummary, $SMetaData) = getSummary("Source");
-        
-        my $Report = "<!-\- $BMetaData -\->\n<!-\- $SMetaData -\->\n".composeHTML_Head($Level, $Title, $Keywords, $Description, $CssStyles, $JScripts)."<body><a name='Source'></a><a name='Binary'></a><a name='Top'></a>";
+        my ($BSummary, $BMetaData, $BAnyChanged) = getSummary("Binary");
+        my ($SSummary, $SMetaData, $SAnyChanged) = getSummary("Source");
+        
+        my $Report = "<!-\- $BMetaData -\->\n<!-\- $SMetaData -\->\n".composeHTML_Head($Level, $Title, $Keywords, $Description, $CssStyles, $JScripts, ($BAnyChanged or $SAnyChanged))."<body><a name='Source'></a><a name='Binary'></a><a name='Top'></a>";
         
         $Report .= getReportHeader("Join");
@@ -3608,5 +3827,5 @@
     else
     {
-        my ($Summary, $MetaData) = getSummary($Level);
+        my ($Summary, $MetaData, $AnyChanged) = getSummary($Level);
         
         my $Title = $In::Opt{"TargetTitle"}.": ".$In::Desc{1}{"Version"}." to ".$In::Desc{2}{"Version"}." ".lc($Level)." compatibility report";
@@ -3614,5 +3833,5 @@
         my $Description = "$Level compatibility report for the ".$In::Opt{"TargetTitle"}." library between ".$In::Desc{1}{"Version"}." and ".$In::Desc{2}{"Version"}." versions";
         
-        my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Level, $Title, $Keywords, $Description, $CssStyles, $JScripts)."<body><a name='Top'></a>";
+        my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Level, $Title, $Keywords, $Description, $CssStyles, $JScripts, $AnyChanged)."<body><a name='Top'></a>";
         $Report .= getReportHeader($Level)."\n".$Summary."\n";
         $Report .= getReportAdded($Level).getReportRemoved($Level);
@@ -3667,7 +3886,7 @@
 }
 
-sub composeHTML_Head($$$$$$)
-{
-    my ($Level, $Title, $Keywords, $Description, $Styles, $Scripts) = @_;
+sub composeHTML_Head($$$$$$$)
+{
+    my ($Level, $Title, $Keywords, $Description, $Styles, $Scripts, $AnyChanged) = @_;
     
     my $Head = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
@@ -3678,4 +3897,8 @@
     $Head .= "<meta name=\"description\" content=\"$Description\" />\n";
     
+    if(not $AnyChanged) {
+        $Head .= "<meta name=\"robots\" content=\"noindex\" />\n";
+    }
+    
     my $RPath = getReportPath($Level);
     
@@ -3749,18 +3972,18 @@
             }
             
-            my $ClassId = $MethodInfo{2}{$Method}{"Class"};
-            my $CName = getTypeName($ClassId, 2);
+            my $Class = getType($MethodInfo{2}{$Method}{"Class"}, 2);
             
-            $CheckedTypes{$CName} = 1;
+            $CheckedTypes{$Class->{"Name"}} = 1;
             $CheckedMethods{$Method} = 1;
             
             if(not $MethodInfo{2}{$Method}{"Constructor"}
-            and my $Overridden = findMethod($Method, 2, $CName, 2))
+            and my $Overridden = findMethod($Method, 2, $Class->{"Name"}, 2))
             {
                 if(defined $MethodInfo{1}{$Overridden}
-                and getTypeType($ClassId, 2) eq "class" and $TName_Tid{1}{$CName})
+                and $Class->{"Type"} eq "class"
+                and ($TName_Tid{1}{$Class->{"Name"}} or $TName_Tid_Generic{1}{getGeneric($Class->{"Name"})}))
                 { # class should exist in previous version
                     %{$CompatProblems{$Overridden}{"Class_Overridden_Method"}{"this.".getSFormat($Method)}}=(
-                        "Type_Name"=>$CName,
+                        "Type_Name"=>$Class->{"Name"},
                         "Target"=>$MethodInfo{2}{$Method}{"Signature"},
                         "Old_Value"=>$Overridden,
@@ -3769,21 +3992,40 @@
             }
             if($MethodInfo{2}{$Method}{"Abstract"}) {
-                $AddedMethod_Abstract{$CName}{$Method} = 1;
+                $AddedMethod_Abstract{$Class->{"Name"}}{$Method} = 1;
             }
             
-            %{$CompatProblems{$Method}{"Added_Method"}{""}}=();
+            if(not ($MethodInfo{2}{$Method}{"Access"} eq "protected" and $Class->{"Final"})) {
+                %{$CompatProblems{$Method}{"Added_Method"}{""}} = ();
+            }
             
             if(not $MethodInfo{2}{$Method}{"Constructor"})
             {
-                if(getTypeName($MethodInfo{2}{$Method}{"Return"}, 2) ne "void"
-                and my $VoidMethod = checkVoidMethod($Method))
+                my $VoidMethod = checkVoidMethod($Method);
+                my $ReturnType = getTypeName($MethodInfo{2}{$Method}{"Return"}, 2);
+                
+                if(defined $Class->{"GenericParam"}
+                and defined $Class->{"GenericParam"}{$ReturnType}) {
+                    $ReturnType = getTypeName($Class->{"GenericParam"}{$ReturnType}, 2);
+                }
+                
+                if(defined $MethodInfo{1}{$VoidMethod}
+                and $ReturnType ne "void")
+                { # return value type changed from void
+                    $ChangedReturnFromVoid{$VoidMethod} = 1;
+                    $ChangedReturnFromVoid{$Method} = 1;
+                    
+                    %{$CompatProblems{$VoidMethod}{"Changed_Method_Return_From_Void"}{""}}=(
+                        "New_Value"=>getTypeName($MethodInfo{2}{$Method}{"Return"}, 2)
+                    );
+                }
+                elsif(my $OldMethod = $OldMethodSignature{getBaseSignature($Method)})
                 {
-                    if(defined $MethodInfo{1}{$VoidMethod})
-                    { # return value type changed from "void" to 
-                        $ChangedReturnFromVoid{$VoidMethod} = 1;
-                        $ChangedReturnFromVoid{$Method} = 1;
+                    if($OldMethod ne $Method)
+                    {
+                        my $OldReturnType = getTypeName($MethodInfo{1}{$OldMethod}{"Return"}, 1);
                         
-                        %{$CompatProblems{$VoidMethod}{"Changed_Method_Return_From_Void"}{""}}=(
-                            "New_Value"=>getTypeName($MethodInfo{2}{$Method}{"Return"}, 2)
+                        %{$CompatProblems{$OldMethod}{"Changed_Method_Return"}{""}}=(
+                            "Old_Value"=>$OldReturnType,
+                            "New_Value"=>$ReturnType
                         );
                     }
@@ -3804,18 +4046,18 @@
             }
             
-            my $ClassId = $MethodInfo{1}{$Method}{"Class"};
-            my $CName = getTypeName($ClassId, 1);
+            my $Class = getType($MethodInfo{1}{$Method}{"Class"}, 1);
             
-            $CheckedTypes{$CName} = 1;
+            $CheckedTypes{$Class->{"Name"}} = 1;
             $CheckedMethods{$Method} = 1;
             
             if(not $MethodInfo{1}{$Method}{"Constructor"}
-            and my $MovedUp = findMethod($Method, 1, $CName, 2))
-            {
-                if(getTypeType($ClassId, 1) eq "class"
-                and not $MethodInfo{1}{$Method}{"Abstract"} and $TName_Tid{2}{$CName})
+            and my $MovedUp = findMethod($Method, 1, $Class->{"Name"}, 2))
+            {
+                if($Class->{"Type"} eq "class"
+                and not $MethodInfo{1}{$Method}{"Abstract"}
+                and ($TName_Tid{2}{$Class->{"Name"}} or $TName_Tid_Generic{2}{getGeneric($Class->{"Name"})}))
                 {# class should exist in newer version
                     %{$CompatProblems{$Method}{"Class_Method_Moved_Up_Hierarchy"}{"this.".getSFormat($MovedUp)}}=(
-                        "Type_Name"=>$CName,
+                        "Type_Name"=>$Class->{"Name"},
                         "Target"=>$MethodInfo{2}{$MovedUp}{"Signature"},
                         "Old_Value"=>$Method,
@@ -3826,7 +4068,10 @@
             {
                 if($MethodInfo{1}{$Method}{"Abstract"}) {
-                    $RemovedMethod_Abstract{$CName}{$Method} = 1;
-                }
-                %{$CompatProblems{$Method}{"Removed_Method"}{""}}=();
+                    $RemovedMethod_Abstract{$Class->{"Name"}}{$Method} = 1;
+                }
+                
+                if(not ($MethodInfo{1}{$Method}{"Access"} eq "protected" and $Class->{"Final"})) {
+                    %{$CompatProblems{$Method}{"Removed_Method"}{""}} = ();
+                }
             }
         }
@@ -3930,10 +4175,16 @@
         if(cmpVersions($APIVer, $API_DUMP_VERSION)>0)
         { # future formats
-            exitStatus("Dump_Version", "the versions of the API dump is newer than version of the tool");
-        }
-    }
-    
-    if(cmpVersions($APIVer, $API_DUMP_VERSION_MIN)<0) {
-        exitStatus("Dump_Version", "the version of the API dump is too old and unsupported anymore, please regenerate it");
+            exitStatus("Dump_Version", "version of the API dump is newer than version of the tool");
+        }
+        
+        if(cmpVersions($APIVer, $API_DUMP_VERSION)<0)
+        { # old formats
+            printMsg("WARNING", "version of the API dump is older than version of the tool");
+        }
+    }
+    
+    if(cmpVersions($APIVer, $API_DUMP_VERSION_MIN)<0)
+    { # obsolete formats
+        exitStatus("Dump_Version", "version of the API dump is too old and unsupported anymore, please regenerate it");
     }
     
@@ -4224,8 +4475,9 @@
         chdir($UnpackDir);
         system("$UnzipCmd \"$Path\" >contents.txt");
+        chdir($In::Opt{"OrigDir"});
         if($?) {
             exitStatus("Error", "can't extract \'$Path\'");
         }
-        chdir($In::Opt{"OrigDir"});
+        
         my @Contents = ();
         foreach (split("\n", readFile("$UnpackDir/contents.txt")))
@@ -4259,8 +4511,8 @@
             }
             my @Contents = qx/$TarCmd -xvf "$Dir\\$FileName.tar"/;
+            chdir($In::Opt{"OrigDir"});
             if($? or not @Contents) {
                 exitStatus("Error", "can't extract \'$Path\'");
             }
-            chdir($In::Opt{"OrigDir"});
             unlink($Dir."/".$FileName.".tar");
             chomp $Contents[0];
@@ -4275,8 +4527,8 @@
             chdir($UnpackDir);
             my @Contents = qx/$TarCmd -xvzf "$Path" 2>&1/;
+            chdir($In::Opt{"OrigDir"});
             if($? or not @Contents) {
                 exitStatus("Error", "can't extract \'$Path\'");
             }
-            chdir($In::Opt{"OrigDir"});
             $Contents[0]=~s/^x //; # OS X
             chomp $Contents[0];
@@ -4308,5 +4560,5 @@
         if($?)
         { # cannot allocate memory (or other problems with "zip")
-            unlink($Path);
+            chdir($In::Opt{"OrigDir"});
             exitStatus("Error", "can't pack the API dump: ".$!);
         }
@@ -4326,13 +4578,12 @@
         }
         my $Pkg = abs_path($To)."/".$Name.".tar.gz";
-        unlink($Pkg);
-        chdir($From);
-        system($TarCmd, "-czf", $Pkg, $Name);
+        if(-e $Pkg) {
+            unlink($Pkg);
+        }
+        system($TarCmd, "-C", $From, "-czf", $Pkg, $Name);
         if($?)
         { # cannot allocate memory (or other problems with "tar")
-            unlink($Path);
             exitStatus("Error", "can't pack the API dump: ".$!);
         }
-        chdir($In::Opt{"OrigDir"});
         unlink($Path);
         return $To."/".$Name.".tar.gz";
@@ -4768,4 +5019,6 @@
         {
             detectDefaultPaths("bin", undef);
+            loadModule("APIDump");
+            
             readArchive(0, $ClientPath)
         }
@@ -4785,5 +5038,6 @@
         
         my $Count = 0;
-        foreach my $Method (keys(%{$MethodInfo{1}})) {
+        foreach my $Method (keys(%{$MethodInfo{1}}))
+        {
             $Count += methodFilter($Method, 1);
         }
