~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to tools/porting/src/fileporter.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the porting application of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
#include <iostream>
 
29
#include <QFile>
 
30
#include <QDir>
 
31
#include <QFileInfo>
 
32
#include <QHash>
 
33
#include <QDebug>
 
34
#include "preprocessorcontrol.h"
 
35
#include "fileporter.h"
 
36
#include "replacetoken.h"
 
37
#include "logger.h"
 
38
#include "tokenizer.h"
 
39
 
 
40
using namespace TokenEngine;
 
41
using namespace Rpp;
 
42
using std::cout;
 
43
using std::endl;
 
44
 
 
45
FilePorter::FilePorter(PreprocessorCache &preprocessorCache)
 
46
:preprocessorCache(preprocessorCache)
 
47
,tokenReplacementRules(PortingRules::instance()->getTokenReplacementRules())
 
48
,replaceToken(tokenReplacementRules)
 
49
{
 
50
    foreach(QString headerName, PortingRules::instance()->getHeaderList(PortingRules::Qt4)) {
 
51
        qt4HeaderNames.insert(headerName.toLatin1());
 
52
    }
 
53
}
 
54
 
 
55
/*
 
56
    Ports a file given by fileName, which should be an aboslute file path.
 
57
*/
 
58
void FilePorter::port(QString fileName)
 
59
{
 
60
    //Get file tokens from cache.
 
61
    TokenContainer sourceTokens = preprocessorCache.sourceTokens(fileName);
 
62
    if(sourceTokens.count() == 0)
 
63
        return;
 
64
 
 
65
    Logger::instance()->beginSection();
 
66
 
 
67
    //Perform token replacements.
 
68
    QByteArray portedContents =
 
69
        replaceToken.getTokenTextReplacements(sourceTokens).apply(sourceTokens.fullText());
 
70
 
 
71
    //This step needs to be done after the token replacements, since
 
72
    //we need to know which new class names that has been inserted in the source.
 
73
    portedContents = includeAnalyse(portedContents);
 
74
 
 
75
    //check if any changes has been made.
 
76
    if(portedContents == sourceTokens.fullText()) {
 
77
        Logger::instance()->addEntry(
 
78
            new PlainLogEntry("Info", "Porting",  QLatin1String("No changes made to file ") + fileName));
 
79
        Logger::instance()->commitSection();
 
80
        return;
 
81
    }
 
82
 
 
83
    //Write file, commit log if write was successful
 
84
    FileWriter::WriteResult result = FileWriter::instance()->writeFileVerbously(fileName, portedContents);
 
85
    Logger *logger = Logger::instance();
 
86
    if (result == FileWriter::WriteSucceeded) {
 
87
        logger->commitSection();
 
88
    } else if (result == FileWriter::WriteFailed) {
 
89
        logger->revertSection();
 
90
        logger->addEntry(
 
91
            new PlainLogEntry("Error", "Porting",  QLatin1String("Error writing to file ") + fileName));
 
92
    } else if (result == FileWriter::WriteSkipped) {
 
93
        logger->revertSection();
 
94
        logger->addEntry(
 
95
            new PlainLogEntry("Error", "Porting",  QLatin1String("User skipped file ") + fileName));
 
96
    } else {
 
97
        // Internal error.
 
98
        logger->revertSection();
 
99
        const QString errorString = QLatin1String("Internal error in qt3to4 - FileWriter returned invalid result code while writing to ") + fileName;
 
100
        logger->addEntry(new PlainLogEntry("Error", "Porting", errorString));
 
101
    }
 
102
}
 
103
 
 
104
QSet<QByteArray> FilePorter::usedQtModules()
 
105
{
 
106
    return m_usedQtModules;
 
107
}
 
108
 
 
109
QByteArray FilePorter::includeAnalyse(QByteArray fileContents)
 
110
{
 
111
    // Tokenize file contents agein, since it has changed.
 
112
    QVector<TokenEngine::Token> tokens  = tokenizer.tokenize(fileContents);
 
113
    TokenEngine::TokenContainer tokenContainer(fileContents, tokens);
 
114
    IncludeDirectiveAnalyzer includeDirectiveAnalyzer(tokenContainer);
 
115
 
 
116
    // Get list of used classes.
 
117
    QSet<QByteArray> classes = includeDirectiveAnalyzer.usedClasses();
 
118
 
 
119
    // Iterate class list and find which modules are used. This info is used elswhere
 
120
    // by when porting the .pro file.
 
121
    const QHash<QByteArray, QByteArray> classLibraryList = PortingRules::instance()->getClassLibraryList();
 
122
    foreach(const QByteArray className, classes) {
 
123
        m_usedQtModules.insert(classLibraryList.value(className));
 
124
    }
 
125
 
 
126
    // Get list of included headers.
 
127
    QSet<QByteArray> headers = includeDirectiveAnalyzer.includedHeaders();
 
128
 
 
129
    // Find classes that is missing an include directive and that has a needHeader rule.
 
130
    const QHash<QByteArray, QByteArray> neededHeaders = PortingRules::instance()->getNeededHeaders();
 
131
    QList<QByteArray> insertHeaders;
 
132
    foreach(const QByteArray className, classes) {
 
133
        if (!headers.contains(className.toLower() + ".h") &&
 
134
            !headers.contains(className)) {
 
135
            const QByteArray insertHeader = neededHeaders.value(className);
 
136
            if (insertHeader != QByteArray())
 
137
                insertHeaders.append("#include <" + insertHeader + ">");
 
138
        }
 
139
    }
 
140
 
 
141
    // Insert include directives undeclared classes.
 
142
    int insertCount = insertHeaders.count();
 
143
    if (insertCount > 0) {
 
144
        QByteArray insertText;
 
145
        QByteArray logText;
 
146
 
 
147
        insertText += "//Added by qt3to4:\n";
 
148
        logText += "In file ";
 
149
        logText += Logger::instance()->globalState.value("currentFileName");
 
150
        logText += ": Added the following include directives:\n";
 
151
        foreach (QByteArray headerName, insertHeaders) {
 
152
            insertText = insertText + headerName + "\n";
 
153
            logText += "\t";
 
154
            logText += headerName + " ";
 
155
        }
 
156
 
 
157
        const int insertLine = 0;
 
158
        Logger::instance()->updateLineNumbers(insertLine, insertCount + 1);
 
159
        const int insertPos = includeDirectiveAnalyzer.insertPos();
 
160
        fileContents.insert(insertPos, insertText);
 
161
        Logger::instance()->addEntry(new PlainLogEntry("Info", "Porting", logText));
 
162
    }
 
163
 
 
164
    return fileContents;
 
165
}
 
166
 
 
167
IncludeDirectiveAnalyzer::IncludeDirectiveAnalyzer(const TokenEngine::TokenContainer &fileContents)
 
168
:fileContents(fileContents)
 
169
{
 
170
    const QVector<Type> lexical = RppLexer().lex(fileContents);
 
171
    source = Preprocessor().parse(fileContents, lexical, &mempool);
 
172
    foundInsertPos = false;
 
173
    foundQtHeader = false;
 
174
    ifSectionCount = 0;
 
175
    insertTokenIndex = 0;
 
176
 
 
177
    evaluateItem(source);
 
178
}
 
179
 
 
180
/*
 
181
    Returns a position indicating where new include directives should be inserted.
 
182
*/
 
183
int IncludeDirectiveAnalyzer::insertPos()
 
184
{
 
185
    const TokenEngine::Token insertToken = fileContents.token(insertTokenIndex);
 
186
    return insertToken.start;
 
187
}
 
188
 
 
189
/*
 
190
    Returns a set of all headers included from this file.
 
191
*/
 
192
QSet<QByteArray> IncludeDirectiveAnalyzer::includedHeaders()
 
193
{
 
194
    return m_includedHeaders;
 
195
}
 
196
 
 
197
/*
 
198
    Returns a list of used Qt classes.
 
199
*/
 
200
QSet<QByteArray> IncludeDirectiveAnalyzer::usedClasses()
 
201
{
 
202
    return m_usedClasses;
 
203
}
 
204
 
 
205
/*
 
206
    Set insetionTokenindex to a token near other #include directives, preferably
 
207
    just after a block of include directives that includes other Qt headers.
 
208
*/
 
209
void IncludeDirectiveAnalyzer::evaluateIncludeDirective(const IncludeDirective *directive)
 
210
{
 
211
    const QByteArray filename = directive->filename();
 
212
    if (filename.isEmpty())
 
213
        return;
 
214
 
 
215
    m_includedHeaders.insert(filename);
 
216
 
 
217
    if (foundInsertPos || ifSectionCount > 1)
 
218
        return;
 
219
 
 
220
    const bool isQtHeader = (filename.at(0) == 'q' || filename.at(0) == 'Q');
 
221
    if (!isQtHeader && foundQtHeader) {
 
222
        foundInsertPos = true;
 
223
        return;
 
224
    }
 
225
 
 
226
    if (isQtHeader)
 
227
        foundQtHeader = true;
 
228
 
 
229
    // Get the last token for this directive.
 
230
    TokenEngine::TokenSection tokenSection = directive->text();
 
231
    const int newLineToken = 1;
 
232
    insertTokenIndex = tokenSection.containerIndex(tokenSection.count() - 1) + newLineToken;
 
233
}
 
234
 
 
235
/*
 
236
    Avoid inserting inside IfSections, except in the first one
 
237
    we see, which probably is the header multiple inclusion guard.
 
238
*/
 
239
void IncludeDirectiveAnalyzer::evaluateIfSection(const IfSection *ifSection)
 
240
{
 
241
    ++ifSectionCount;
 
242
    RppTreeWalker::evaluateIfSection(ifSection);
 
243
    --ifSectionCount;
 
244
}
 
245
 
 
246
/*
 
247
    Read all IdTokens and look for Qt class names.  Also, on
 
248
    the first IdToken set foundInsertPos to true
 
249
 
 
250
*/
 
251
void IncludeDirectiveAnalyzer::evaluateText(const Text *textLine)
 
252
{
 
253
    const int numTokens = textLine->count();
 
254
    for (int t = 0; t < numTokens; ++t) {
 
255
        Rpp::Token *token = textLine->token(t);
 
256
        if (token->toIdToken()) {
 
257
            foundInsertPos = true;
 
258
            const int containerIndex = token->index();
 
259
            const QByteArray tokenText = fileContents.text(containerIndex);
 
260
            if (tokenText[0] == 'Q')
 
261
                m_usedClasses.insert(tokenText);
 
262
        }
 
263
    }
 
264
}