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@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
63use strict;
64no warnings qw /syntax/;
65
66
67my $file = $ARGV[0];
68
69print "Looking for unmatched const methods in $file\n";
70
71if (!open NM, "(nm '$file' | c++filt | sed 's/^/STDOUT:/') 2>&1 |") {
72    die "Could not open $file\n";
73}
74
75my $nestedParens;
76   $nestedParens = qr /
77                      [(]
78                      [^()]*
79                        (?:
80                          (??{ $nestedParens })
81                          [^()]*
82                        )*
83                      [)]/x;
84
85my $nestedAngleBrackets;
86   $nestedAngleBrackets = qr /
87                      [<]
88                      [^<>]*
89                        (?:
90                          (??{ $nestedAngleBrackets })
91                          [^<>]*
92                        )*
93                      [>]/x;
94
95my $bal;
96   $bal = qr /([^:]+
97              (??{ $nestedAngleBrackets })?
98              (??{ $nestedParens }))
99              ([^()]*)$/x;
100
101my %signature_map = ();
102
103while (<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}
129close NM;
130
131my $sig;
132for $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