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>
40
43
#include "editorintegrator.h"
41
44
#include "parsesession.h"
50
53
#include <QtCore/QReadLocker>
51
54
#include <QtCore/QThread>
55
#include <language/duchain/duchainutils.h>
53
57
using namespace KDevelop;
58
///TODO: push this into kdevplatform - copied from cpp for now
60
///Facilities to prevent multiple parse-jobs from processing the same url.
62
QMap<IndexedString, QPair<Qt::HANDLE, uint> > parsingUrls;
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
73
if (parsingUrls.contains(m_url)) {
74
++parsingUrls[m_url].second;
76
parsingUrls.insert(m_url, qMakePair(QThread::currentThreadId(), 1u));
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);
93
62
ParseJob::ParseJob(const KUrl &url)
94
63
: KDevelop::ParseJob(url)
119
88
UrlParseLock urlLock(document());
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())) {
144
113
QString fileName = document().str();
146
115
if (readFromDisk) {
147
if ( fileName.endsWith(".php.zip", Qt::CaseInsensitive) ) {
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();
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()));
159
kDebug() << "invalid zip file, entry is not a file" << file.directory()->entries().first();
162
session.setContents(entry->data());
123
session.setContents(file->readAll());
165
QFile file(fileName);
166
//TODO: Read the first lines to determine encoding using Php encoding and use that for the text stream
168
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
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."));
177
case QFile::OpenError:
178
p->setExplanation(i18n("File could not be opened."));
180
case QFile::PermissionsError:
181
p->setExplanation(i18n("File permissions prevent opening for read."));
186
p->setFinalLocation(KDevelop::DocumentRange(document().str(), KTextEditor::Cursor(0, 0), KTextEditor::Cursor(0, 0)));
187
// TODO addProblem(p);
189
kWarning() << "Could not open file" << document().str();
193
QTextStream s(&file);
196
// s.setCodec( QTextCodec::codecForName(codec) );
197
session.setContents(s.readAll());
126
session.readFile(fileName);
201
129
session.setContents(contentsFromEditor());
202
130
session.setCurrentDocument(document().str());
207
134
StartAst* ast = 0;
208
135
bool matched = session.parse(&ast);
211
138
return abortJob();
141
KDevelop::ReferencedTopDUContext toUpdate;
143
KDevelop::DUChainReadLocker duchainlock(KDevelop::DUChain::lock());
144
toUpdate = KDevelop::DUChainUtils::standardContextForUrl(document().toUrl());
147
KDevelop::TopDUContext::Features newFeatures = minimumFeatures();
149
newFeatures = (KDevelop::TopDUContext::Features)(newFeatures | toUpdate->features());
151
//Remove update-flags like 'Recursive' or 'ForceUpdate'
152
newFeatures = static_cast<KDevelop::TopDUContext::Features>(newFeatures & KDevelop::TopDUContext::AllDeclarationsContextsUsesAndAST);
215
155
EditorIntegrator editor(&session);
242
182
&editor, ProblemData::Preprocessor);
186
DUChainReadLocker lock(DUChain::lock());
187
bool needsUpdate = true;
188
foreach(const ParsingEnvironmentFilePointer &file, DUChain::self()->allEnvironmentFiles(i.value())) {
189
if (file->needsUpdate()) {
196
if (!(minimumFeatures() & TopDUContext::ForceUpdateRecursive) && !needsUpdate) {
245
200
kDebug() << "parse included file" << i.value().str();
246
201
ParseJob job(i.value().toUrl());
247
202
job.setMinimumFeatures(minimumFeatures());
266
221
setDuChain(chain);
268
if ( minimumFeatures() & TopDUContext::AllDeclarationsContextsAndUses
223
if ( newFeatures & TopDUContext::AllDeclarationsContextsAndUses
269
224
&& document() != internalFunctionFile() )
271
226
UseBuilder useBuilder(&editor);
272
227
useBuilder.buildUses(ast);
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
237
KDevelop::ICore::self()->languageController()->backgroundParser()
238
->addDocument(document().toUrl(), feat, 50000);
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)";
275
246
if (abortRequested()) {
276
247
return abortJob();