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