~ubuntu-branches/ubuntu/quantal/kdevelop-php/quantal-proposed

« back to all changes in this revision

Viewing changes to phpparsejob.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2010-03-14 10:19:34 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20100314101934-d24i8t1niai087ul
Tags: 1.0.0~beta4-1
New upstream release. (Closes: #573811)

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
 
27
27
#include <kdebug.h>
28
28
#include <klocale.h>
29
 
#include <KZip>
 
29
#include <KFilterDev>
 
30
#include <KMimeType>
30
31
 
31
32
#include <language/duchain/duchainlock.h>
32
33
#include <language/duchain/duchain.h>
36
37
#include <language/highlighting/codehighlighting.h>
37
38
#include <interfaces/icore.h>
38
39
#include <interfaces/ilanguagecontroller.h>
 
40
#include <language/backgroundparser/backgroundparser.h>
 
41
#include <language/backgroundparser/urlparselock.h>
39
42
 
40
43
#include "editorintegrator.h"
41
44
#include "parsesession.h"
49
52
 
50
53
#include <QtCore/QReadLocker>
51
54
#include <QtCore/QThread>
 
55
#include <language/duchain/duchainutils.h>
52
56
 
53
57
using namespace KDevelop;
54
58
 
55
59
namespace Php
56
60
{
57
61
 
58
 
///TODO: push this into kdevplatform - copied from cpp for now
59
 
 
60
 
///Facilities to prevent multiple parse-jobs from processing the same url.
61
 
QMutex urlParseMutex;
62
 
QMap<IndexedString, QPair<Qt::HANDLE, uint> > parsingUrls;
63
 
 
64
 
struct UrlParseLock {
65
 
    UrlParseLock(IndexedString url) : m_url(url) {
66
 
        QMutexLocker lock(&urlParseMutex);
67
 
        while (parsingUrls.contains(m_url) && parsingUrls[m_url].first != QThread::currentThreadId()) {
68
 
            //Wait here until no other thread is updating parsing the url
69
 
            lock.unlock();
70
 
            sleep(1);
71
 
            lock.relock();
72
 
        }
73
 
        if (parsingUrls.contains(m_url)) {
74
 
            ++parsingUrls[m_url].second;
75
 
        } else {
76
 
            parsingUrls.insert(m_url, qMakePair(QThread::currentThreadId(), 1u));
77
 
        }
78
 
    }
79
 
 
80
 
    ~UrlParseLock() {
81
 
        QMutexLocker lock(&urlParseMutex);
82
 
        Q_ASSERT(parsingUrls.contains(m_url));
83
 
        Q_ASSERT(parsingUrls[m_url].first == QThread::currentThreadId());
84
 
        --parsingUrls[m_url].second;
85
 
        if (parsingUrls[m_url].second == 0) {
86
 
            parsingUrls.remove(m_url);
87
 
        }
88
 
    }
89
 
 
90
 
    IndexedString m_url;
91
 
};
92
 
 
93
62
ParseJob::ParseJob(const KUrl &url)
94
63
        : KDevelop::ParseJob(url)
95
64
        , m_parentJob(0)
118
87
 
119
88
    UrlParseLock urlLock(document());
120
89
 
121
 
    {
 
90
    if ( !(minimumFeatures() & TopDUContext::ForceUpdate || minimumFeatures() & Resheduled) ) {
122
91
        DUChainReadLocker lock(DUChain::lock());
123
92
        bool needsUpdate = true;
124
93
        foreach(const ParsingEnvironmentFilePointer &file, DUChain::self()->allEnvironmentFiles(document())) {
129
98
                needsUpdate = false;
130
99
            }
131
100
        }
132
 
        if (!(minimumFeatures() & TopDUContext::ForceUpdate) && !needsUpdate) {
 
101
        if (!needsUpdate) {
133
102
            kDebug() << "Already up to date" << document().str();
134
103
            return;
135
104
        }
144
113
    QString fileName = document().str();
145
114
 
146
115
    if (readFromDisk) {
147
 
        if ( fileName.endsWith(".php.zip", Qt::CaseInsensitive) ) {
148
 
            KZip file(fileName);
149
 
            if ( !file.open(QIODevice::ReadOnly) || !file.directory() ) {
 
116
        if ( fileName.endsWith(".php.gz", Qt::CaseInsensitive) ) {
 
117
            QString mimeType = KMimeType::findByPath(fileName, 0, false)->name ();
 
118
            QIODevice* file = KFilterDev::deviceForFile (fileName, mimeType, false);
 
119
            if ( !file->open(QIODevice::ReadOnly) ) {
150
120
                kDebug() << "Could not open file" << document().str();
151
121
                return abortJob();
152
 
            } else if ( file.directory()->entries().count() != 1 ) {
153
 
                kDebug() << "invalid zip file, too many entries:" << file.directory()->entries();
154
 
                return abortJob();
155
 
            }
156
 
            //NOTE: we only support archives with exactly one file in them
157
 
            const KZipFileEntry* entry = static_cast<const KZipFileEntry*>(file.directory()->entry(file.directory()->entries().first()));
158
 
            if ( !entry ) {
159
 
                kDebug() << "invalid zip file, entry is not a file" << file.directory()->entries().first();
160
 
                return abortJob();
161
 
            }
162
 
            session.setContents(entry->data());
163
 
            file.close();
 
122
            }
 
123
            session.setContents(file->readAll());
 
124
            delete file;
164
125
        } else {
165
 
            QFile file(fileName);
166
 
            //TODO: Read the first lines to determine encoding using Php encoding and use that for the text stream
167
 
 
168
 
            if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
169
 
                /*
170
 
                KDevelop::ProblemPointer p(new KDevelop::Problem());
171
 
                p->setSource(KDevelop::ProblemData::Disk);
172
 
                p->setDescription(i18n("Could not open file '%1'", document().str()));
173
 
                switch (file.error()) {
174
 
                case QFile::ReadError:
175
 
                    p->setExplanation(i18n("File could not be read from."));
176
 
                    break;
177
 
                case QFile::OpenError:
178
 
                    p->setExplanation(i18n("File could not be opened."));
179
 
                    break;
180
 
                case QFile::PermissionsError:
181
 
                    p->setExplanation(i18n("File permissions prevent opening for read."));
182
 
                    break;
183
 
                default:
184
 
                    break;
185
 
                }
186
 
                p->setFinalLocation(KDevelop::DocumentRange(document().str(), KTextEditor::Cursor(0, 0), KTextEditor::Cursor(0, 0)));
187
 
                // TODO addProblem(p);
188
 
                */
189
 
                kWarning() << "Could not open file" << document().str();
190
 
                return abortJob();
191
 
            }
192
 
 
193
 
            QTextStream s(&file);
194
 
 
195
 
//         if( codec )
196
 
//             s.setCodec( QTextCodec::codecForName(codec) );
197
 
            session.setContents(s.readAll());
198
 
            file.close();
 
126
            session.readFile(fileName);
199
127
        }
200
128
    } else {
201
129
        session.setContents(contentsFromEditor());
202
130
        session.setCurrentDocument(document().str());
203
131
    }
204
132
 
205
 
 
206
133
    // 2) parse
207
134
    StartAst* ast = 0;
208
135
    bool matched = session.parse(&ast);
211
138
        return abortJob();
212
139
    }
213
140
 
 
141
    KDevelop::ReferencedTopDUContext toUpdate;
 
142
    {
 
143
        KDevelop::DUChainReadLocker duchainlock(KDevelop::DUChain::lock());
 
144
        toUpdate = KDevelop::DUChainUtils::standardContextForUrl(document().toUrl());
 
145
    }
 
146
 
 
147
    KDevelop::TopDUContext::Features newFeatures = minimumFeatures();
 
148
    if (toUpdate)
 
149
        newFeatures = (KDevelop::TopDUContext::Features)(newFeatures | toUpdate->features());
 
150
 
 
151
    //Remove update-flags like 'Recursive' or 'ForceUpdate'
 
152
    newFeatures = static_cast<KDevelop::TopDUContext::Features>(newFeatures & KDevelop::TopDUContext::AllDeclarationsContextsUsesAndAST);
 
153
 
214
154
    if (matched) {
215
155
        EditorIntegrator editor(&session);
216
156
 
242
182
                                                     &editor, ProblemData::Preprocessor);
243
183
                    continue;
244
184
                }
 
185
                {
 
186
                    DUChainReadLocker lock(DUChain::lock());
 
187
                    bool needsUpdate = true;
 
188
                    foreach(const ParsingEnvironmentFilePointer &file, DUChain::self()->allEnvironmentFiles(i.value())) {
 
189
                        if (file->needsUpdate()) {
 
190
                            needsUpdate = true;
 
191
                            break;
 
192
                        } else {
 
193
                            needsUpdate = false;
 
194
                        }
 
195
                    }
 
196
                    if (!(minimumFeatures() & TopDUContext::ForceUpdateRecursive) && !needsUpdate) {
 
197
                        continue;
 
198
                    }
 
199
                }
245
200
                kDebug() << "parse included file" << i.value().str();
246
201
                ParseJob job(i.value().toUrl());
247
202
                job.setMinimumFeatures(minimumFeatures());
265
220
 
266
221
        setDuChain(chain);
267
222
 
268
 
        if ( minimumFeatures() & TopDUContext::AllDeclarationsContextsAndUses
 
223
        if ( newFeatures & TopDUContext::AllDeclarationsContextsAndUses
269
224
                && document() != internalFunctionFile() )
270
225
        {
271
226
            UseBuilder useBuilder(&editor);
272
227
            useBuilder.buildUses(ast);
273
228
        }
274
229
 
 
230
        if (builder.hadUnresolvedIdentifiers()) {
 
231
            if (!(minimumFeatures() & Resheduled) && KDevelop::ICore::self()->languageController()->backgroundParser()->queuedCount()) {
 
232
                // Need to create new parse job with lower priority
 
233
                kDebug() << "Reschedule file " << document().str() << "for parsing";
 
234
                KDevelop::TopDUContext::Features feat = static_cast<KDevelop::TopDUContext::Features>(
 
235
                        minimumFeatures() | KDevelop::TopDUContext::VisibleDeclarationsAndContexts | Resheduled
 
236
                    );
 
237
                KDevelop::ICore::self()->languageController()->backgroundParser()
 
238
                    ->addDocument(document().toUrl(), feat, 50000);
 
239
 
 
240
            } else {
 
241
                // We haven't resolved all identifiers, but by now, we don't expect to
 
242
                kDebug() << "Builder found unresolved identifiers when they should have been resolved! (if there was no coding error)";
 
243
            }
 
244
        }
 
245
 
275
246
        if (abortRequested()) {
276
247
            return abortJob();
277
248
        }
292
263
            chain->addProblem(p);
293
264
        }
294
265
 
295
 
        chain->setFeatures(minimumFeatures());
 
266
        chain->setFeatures(newFeatures);
296
267
        ParsingEnvironmentFilePointer file = chain->parsingEnvironmentFile();
297
268
 
298
269
        QFileInfo fileInfo(fileName);
333
304
            DUChainReadLocker lock(DUChain::lock());
334
305
            kDebug() << DUChain::self()->chainForDocument(document());
335
306
        }
336
 
        return;
337
307
    }
 
308
 
 
309
    cleanupSmartRevision();
338
310
}
339
311
 
340
312
void ParseJob::setParentJob(ParseJob *job)