Home | History | Annotate | Download | only in Scripts
      1 #!/usr/bin/perl -w
      2 
      3 # Copyright (C) 2008 Apple Inc.  All rights reserved.
      4 #
      5 # Redistribution and use in source and binary forms, with or without
      6 # modification, are permitted provided that the following conditions
      7 # are met:
      8 #
      9 # 1.  Redistributions of source code must retain the above copyright
     10 #     notice, this list of conditions and the following disclaimer. 
     11 # 2.  Redistributions in binary form must reproduce the above copyright
     12 #     notice, this list of conditions and the following disclaimer in the
     13 #     documentation and/or other materials provided with the distribution. 
     14 # 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     15 #     its contributors may be used to endorse or promote products derived
     16 #     from this software without specific prior written permission. 
     17 #
     18 # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     19 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21 # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     22 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     23 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     24 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     25 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 #
     30 # This script attempts to find instances of a problem where the signatures
     31 # of virtual methods fail to match because one is defined 'const', and another
     32 # is not. For example:
     33 #       virtual void Base::doStuff() const;
     34 #       virtual void Derived::doStuff();
     35 #
     36 # The lack of 'const' on the derived class gives it a different signature, and
     37 # it will therefore not be called when doStuff() is called on a derived object
     38 # via a base class pointer.
     39 #
     40 # Limitations of this script:
     41 # * It only works on things in the WebCore namespace
     42 # * Not all templatized methods may be found correctly
     43 # * It doesn't know anything about inheritance, or if methods are actually virtual
     44 # * It has lots of false positives (should add a whitelist for known-good signatures,
     45 #    and specific methods)
     46 # * It's rather slow
     47 #
     48 # Added by Simon Fraser <simon.fraser (at] apple.com>
     49 #
     50 # Run the script like this:
     51 #  WebKitTools/Scripts/detect-mismatched-virtual-const WebKitBuild/Debug/WebCore.framework/WebCore
     52 #
     53 # Output consists of a series of warnings like this:
     54 #
     55 # Both const and non-const versions of bgColor():
     56 #     HTMLDocument::bgColor()
     57 #     HTMLBodyElement::bgColor() const
     58 #     HTMLTableElement::bgColor() const
     59 #     HTMLTableRowElement::bgColor() const
     60 #     HTMLTableCellElement::bgColor() const
     61 #
     62 
     63 use strict;
     64 no warnings qw /syntax/;
     65 
     66 
     67 my $file = $ARGV[0];
     68 
     69 print "Looking for unmatched const methods in $file\n";
     70 
     71 if (!open NM, "(nm '$file' | c++filt | sed 's/^/STDOUT:/') 2>&1 |") {
     72     die "Could not open $file\n";
     73 }
     74 
     75 my $nestedParens;
     76    $nestedParens = qr /
     77                       [(]
     78                       [^()]*
     79                         (?:
     80                           (??{ $nestedParens })
     81                           [^()]*
     82                         )*
     83                       [)]/x;
     84 
     85 my $nestedAngleBrackets;
     86    $nestedAngleBrackets = qr /
     87                       [<]
     88                       [^<>]*
     89                         (?:
     90                           (??{ $nestedAngleBrackets })
     91                           [^<>]*
     92                         )*
     93                       [>]/x;
     94 
     95 my $bal;
     96    $bal = qr /([^:]+
     97               (??{ $nestedAngleBrackets })?
     98               (??{ $nestedParens }))
     99               ([^()]*)$/x;
    100 
    101 my %signature_map = ();
    102 
    103 while (<NM>) {
    104   my $line = $_;
    105   chomp($line);
    106   if ($line =~ m/ [tT] WebCore::(.+)$/) {
    107     my $method = $1;
    108     
    109     if ($method =~ /$bal/) {
    110       my $signature = $1;
    111       my $const = $2 eq " const";
    112       
    113       my $class = substr($method, 0, length($method) - length($signature) - ($const ? 6 : 0));
    114 
    115 #      print "line: $line\nclass: $class\nmethod: $method\nsignature: $signature\nconst: $const\n\n";
    116 
    117       my %method_info = (
    118           'class' => $class,
    119           'const' => $const,
    120           'method' => $method,
    121       );
    122       
    123       push @{$signature_map{$signature}}, \%method_info;
    124     } else {
    125       print "unmatched line $method\n\n"
    126     }
    127   }
    128 }
    129 close NM;
    130 
    131 my $sig;
    132 for $sig (keys %signature_map) {
    133   #print "\n$sig\n";
    134 
    135   my @entries = @{$signature_map{$sig}};
    136 #  print "$#entries\n";
    137   
    138   my $num_const = 0;
    139   my $num_not_const = 0;
    140   my $i;
    141   for $i (0 .. $#entries) {
    142     my $entry = @entries[$i];
    143 
    144     my $class = $entry->{'class'};
    145     my $const = $entry->{'const'};
    146     
    147     if ($const) {
    148       $num_const++;
    149     } else {
    150       $num_not_const++;
    151     }
    152   }
    153 
    154   if ($#entries > 1 && $num_const > 0 && $num_not_const > 0) {
    155     print "Both const and non-const versions of $sig:\n";
    156 
    157     for $i (0 .. $#entries) {
    158       my $entry = @entries[$i];
    159       my $method = $entry->{'method'};
    160       print "\t$method\n";
    161     }
    162 
    163   }
    164 }
    165 
    166 
    167 
    168