tests/auto/bic/qbic.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 
       
    43 #include "qbic.h"
       
    44 
       
    45 #include "QtCore/qfile.h"
       
    46 #include "QtCore/qdebug.h"
       
    47 
       
    48 void QBic::addBlacklistedClass(const QString &wildcard)
       
    49 {
       
    50     blackList.append(QRegExp(wildcard, Qt::CaseSensitive, QRegExp::Wildcard));
       
    51 }
       
    52 
       
    53 void QBic::removeBlacklistedClass(const QString &wildcard)
       
    54 {
       
    55     blackList.removeAll(QRegExp(wildcard, Qt::CaseSensitive, QRegExp::Wildcard));
       
    56 }
       
    57 
       
    58 bool QBic::isBlacklisted(const QString &className) const
       
    59 {
       
    60     for (int i = 0; i < blackList.count(); ++i)
       
    61         if (blackList.at(i).exactMatch(className))
       
    62             return true;
       
    63     return false;
       
    64 }
       
    65 
       
    66 static QStringList normalizedVTable(const QStringList &entry)
       
    67 {
       
    68     QStringList normalized;
       
    69 
       
    70     for (int i = 2; i < entry.count(); ++i) {
       
    71         const QString line = entry.at(i).simplified();
       
    72         bool isOk = false;
       
    73         int num = line.left(line.indexOf(QLatin1Char(' '))).toInt(&isOk);
       
    74         if (!isOk) {
       
    75             qWarning("unrecognized line: %s", qPrintable(line));
       
    76             continue;
       
    77         }
       
    78 
       
    79         QString sym = line.mid(line.indexOf(QLatin1Char(' ')) + 1);
       
    80         if (sym.startsWith(QLatin1Char('('))) {
       
    81             if (sym.endsWith(QLatin1Char(')'))) {
       
    82                 sym = sym.mid(sym.lastIndexOf('(') + 1);
       
    83                 sym.chop(1);
       
    84             } else {
       
    85                 sym = sym.mid(sym.lastIndexOf(QLatin1Char(')')) + 1);
       
    86             }
       
    87         } else {
       
    88             sym = sym.left(sym.indexOf(QLatin1Char('(')));
       
    89         }
       
    90 
       
    91         if (sym.startsWith(QLatin1String("& ")))
       
    92             sym.remove(1, 1);
       
    93 
       
    94         if (sym.startsWith(QLatin1String("-0")) || sym.startsWith(QLatin1String("0"))) {
       
    95             if (sym.endsWith('u'))
       
    96                 sym.chop(1);
       
    97 
       
    98             bool isOk = false;
       
    99             qint64 num = sym.toLongLong(&isOk, 16);
       
   100             if (!isOk) {
       
   101                 qWarning("unrecognized token: %s", qPrintable(sym));
       
   102                 continue;
       
   103             }
       
   104             if (sizeof(void*) == 4)
       
   105                 sym = QString::number(int(num));
       
   106             else
       
   107                 sym = QString::number(num);
       
   108         }
       
   109 
       
   110         normalized << QString::number(num) + QLatin1Char(' ') + sym;
       
   111     }
       
   112 
       
   113     return normalized;
       
   114 }
       
   115 
       
   116 QBic::Info QBic::parseOutput(const QByteArray &ba) const
       
   117 {
       
   118     Info info;
       
   119     const QStringList source = QString::fromLatin1(ba).split("\n\n");
       
   120 
       
   121     foreach(QString str, source) {
       
   122         QStringList entry = str.split('\n');
       
   123         if (entry.count() < 2)
       
   124             continue;
       
   125         if (entry.at(0).startsWith("Class ")) {
       
   126             const QString className = entry.at(0).mid(6);
       
   127             if (isBlacklisted(className))
       
   128                 continue;
       
   129             QRegExp rx("size=(\\d+)");
       
   130             if  (rx.indexIn(entry.at(1)) == -1) {
       
   131                 qWarning("Could not parse class information for className %s", className.toLatin1().constData());
       
   132                 continue;
       
   133             }
       
   134             info.classSizes[className] = rx.cap(1).toInt();
       
   135         } else if (entry.at(0).startsWith("Vtable for ")) {
       
   136             const QString className = entry.at(0).mid(11);
       
   137             if (isBlacklisted(className))
       
   138                 continue;
       
   139             info.classVTables[className] = normalizedVTable(entry);
       
   140         }
       
   141     }
       
   142 
       
   143     return info;
       
   144 }
       
   145 
       
   146 QBic::Info QBic::parseFile(const QString &fileName) const
       
   147 {
       
   148     QFile f(fileName);
       
   149     if (!f.open(QIODevice::ReadOnly | QIODevice::Text))
       
   150         return Info();
       
   151 
       
   152     QByteArray ba = f.readAll();
       
   153     f.close();
       
   154 
       
   155     return parseOutput(ba);
       
   156 }
       
   157 
       
   158 enum VTableDiffResult { Match, Mismatch, Reimp };
       
   159 static VTableDiffResult diffVTableEntry(const QString &v1, const QString &v2)
       
   160 {
       
   161     if (v1 == v2)
       
   162         return Match;
       
   163     if (v2.endsWith(QLatin1String("__cxa_pure_virtual")))
       
   164         return Reimp;
       
   165     if (!v1.contains(QLatin1String("::")) || !v2.contains(QLatin1String("::")))
       
   166         return Mismatch;
       
   167 
       
   168     const QString sym1 = v1.mid(v1.lastIndexOf(QLatin1String("::")) + 2);
       
   169     const QString sym2 = v2.mid(v2.lastIndexOf(QLatin1String("::")) + 2);
       
   170 
       
   171     if (sym1 == sym2)
       
   172         return Reimp;
       
   173 
       
   174     return Mismatch;
       
   175 }
       
   176 
       
   177 QBic::VTableDiff QBic::diffVTables(const Info &oldLib, const Info &newLib) const
       
   178 {
       
   179     VTableDiff result;
       
   180 
       
   181     for (QHash<QString, QStringList>::const_iterator it = newLib.classVTables.constBegin();
       
   182             it != newLib.classVTables.constEnd(); ++it) {
       
   183         if (!oldLib.classVTables.contains(it.key())) {
       
   184             result.addedVTables.append(it.key());
       
   185             continue;
       
   186         }
       
   187         const QStringList oldVTable = oldLib.classVTables.value(it.key());
       
   188         const QStringList vTable = it.value();
       
   189         if (vTable.count() != oldVTable.count()) {
       
   190             result.modifiedVTables.append(QPair<QString, QString>(it.key(),
       
   191                         QLatin1String("size mismatch")));
       
   192             continue;
       
   193         }
       
   194 
       
   195         for (int i = 0; i < vTable.count(); ++i) {
       
   196             VTableDiffResult diffResult = diffVTableEntry(vTable.at(i), oldVTable.at(i));
       
   197             switch (diffResult) {
       
   198             case Match:
       
   199                 // do nothing
       
   200                 break;
       
   201             case Mismatch:
       
   202                 result.modifiedVTables.append(QPair<QString, QString>(oldVTable.at(i),
       
   203                             vTable.at(i)));
       
   204                 break;
       
   205             case Reimp:
       
   206                 result.reimpMethods.append(QPair<QString, QString>(oldVTable.at(i), vTable.at(i)));
       
   207                 break;
       
   208             }
       
   209         }
       
   210     }
       
   211 
       
   212     for (QHash<QString, QStringList>::const_iterator it = oldLib.classVTables.constBegin();
       
   213             it != oldLib.classVTables.constEnd(); ++it) {
       
   214         if (!newLib.classVTables.contains(it.key()))
       
   215             result.removedVTables.append(it.key());
       
   216     }
       
   217 
       
   218     return result;
       
   219 }
       
   220 
       
   221 QBic::SizeDiff QBic::diffSizes(const Info &oldLib, const Info &newLib) const
       
   222 {
       
   223     QBic::SizeDiff result;
       
   224 
       
   225     for (QHash<QString, int>::const_iterator it = newLib.classSizes.constBegin();
       
   226             it != newLib.classSizes.constEnd(); ++it) {
       
   227         if (!oldLib.classSizes.contains(it.key())) {
       
   228             result.added.append(it.key());
       
   229             continue;
       
   230         }
       
   231         int oldSize = oldLib.classSizes.value(it.key());
       
   232         int newSize = it.value();
       
   233 
       
   234         if (oldSize != newSize)
       
   235             result.mismatch.append(it.key());
       
   236     }
       
   237 
       
   238     for (QHash<QString, int>::const_iterator it = oldLib.classSizes.constBegin();
       
   239             it != oldLib.classSizes.constEnd(); ++it) {
       
   240         if (!newLib.classSizes.contains(it.key()))
       
   241             result.removed.append(it.key());
       
   242     }
       
   243 
       
   244     return result;
       
   245 }
       
   246