| 
									
										
										
										
											2014-08-19 15:59:29 +02:00
										 |  |  | /****************************************************************************
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). | 
					
						
							|  |  |  | ** Contact: http://www.qt-project.org/legal
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** This file is part of Qt Creator. | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Commercial License Usage | 
					
						
							|  |  |  | ** Licensees holding valid commercial Qt licenses may use this file in | 
					
						
							|  |  |  | ** accordance with the commercial license agreement provided with the | 
					
						
							|  |  |  | ** Software or, alternatively, in accordance with the terms contained in | 
					
						
							|  |  |  | ** a written agreement between you and Digia.  For licensing terms and | 
					
						
							| 
									
										
										
										
											2014-10-15 14:46:23 +02:00
										 |  |  | ** conditions see http://www.qt.io/licensing.  For further information
 | 
					
						
							|  |  |  | ** use the contact form at http://www.qt.io/contact-us.
 | 
					
						
							| 
									
										
										
										
											2014-08-19 15:59:29 +02:00
										 |  |  | ** | 
					
						
							|  |  |  | ** GNU Lesser General Public License Usage | 
					
						
							|  |  |  | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
					
						
							| 
									
										
										
										
											2014-10-15 14:46:23 +02:00
										 |  |  | ** General Public License version 2.1 or version 3 as published by the Free | 
					
						
							|  |  |  | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and | 
					
						
							|  |  |  | ** LICENSE.LGPLv3 included in the packaging of this file.  Please review the | 
					
						
							|  |  |  | ** following information to ensure the GNU Lesser General Public License | 
					
						
							|  |  |  | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
 | 
					
						
							|  |  |  | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 | 
					
						
							| 
									
										
										
										
											2014-08-19 15:59:29 +02:00
										 |  |  | ** | 
					
						
							|  |  |  | ** In addition, as a special exception, Digia gives you certain additional | 
					
						
							|  |  |  | ** rights.  These rights are described in the Digia Qt LGPL Exception | 
					
						
							|  |  |  | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ****************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "cppsemanticinfoupdater.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-26 14:26:28 +02:00
										 |  |  | #include "cpplocalsymbols.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-19 15:59:29 +02:00
										 |  |  | #include <utils/qtcassert.h>
 | 
					
						
							|  |  |  | #include <utils/runextensions.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <cplusplus/Control.h>
 | 
					
						
							|  |  |  | #include <cplusplus/CppDocument.h>
 | 
					
						
							|  |  |  | #include <cplusplus/TranslationUnit.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum { debug = 0 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace CPlusPlus; | 
					
						
							|  |  |  | using namespace CppTools; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace CppTools { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SemanticInfoUpdaterPrivate | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     class FuturizedTopLevelDeclarationProcessor: public CPlusPlus::TopLevelDeclarationProcessor | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         FuturizedTopLevelDeclarationProcessor(QFutureInterface<void> &future): m_future(future) {} | 
					
						
							|  |  |  |         bool processDeclaration(CPlusPlus::DeclarationAST *) { return !isCanceled(); } | 
					
						
							|  |  |  |         bool isCanceled() { return m_future.isCanceled(); } | 
					
						
							|  |  |  |     private: | 
					
						
							|  |  |  |         QFutureInterface<void> m_future; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2014-08-26 14:26:28 +02:00
										 |  |  |     SemanticInfoUpdaterPrivate(SemanticInfoUpdater *q); | 
					
						
							| 
									
										
										
										
											2014-08-19 15:59:29 +02:00
										 |  |  |     ~SemanticInfoUpdaterPrivate(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SemanticInfo semanticInfo() const; | 
					
						
							|  |  |  |     void setSemanticInfo(const SemanticInfo &semanticInfo, bool emitSignal); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SemanticInfo update(const SemanticInfo::Source &source, | 
					
						
							|  |  |  |                         bool emitSignalWhenFinished, | 
					
						
							|  |  |  |                         FuturizedTopLevelDeclarationProcessor *processor); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool reuseCurrentSemanticInfo(const SemanticInfo::Source &source, bool emitSignalWhenFinished); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void update_helper(QFutureInterface<void> &future, const SemanticInfo::Source source); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     SemanticInfoUpdater *q; | 
					
						
							|  |  |  |     mutable QMutex m_lock; | 
					
						
							|  |  |  |     SemanticInfo m_semanticInfo; | 
					
						
							|  |  |  |     QFuture<void> m_future; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-26 14:26:28 +02:00
										 |  |  | SemanticInfoUpdaterPrivate::SemanticInfoUpdaterPrivate(SemanticInfoUpdater *q) | 
					
						
							| 
									
										
										
										
											2014-08-19 15:59:29 +02:00
										 |  |  |     : q(q) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SemanticInfoUpdaterPrivate::~SemanticInfoUpdaterPrivate() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_future.cancel(); | 
					
						
							|  |  |  |     m_future.waitForFinished(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SemanticInfo SemanticInfoUpdaterPrivate::semanticInfo() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QMutexLocker locker(&m_lock); | 
					
						
							|  |  |  |     return m_semanticInfo; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SemanticInfoUpdaterPrivate::setSemanticInfo(const SemanticInfo &semanticInfo, bool emitSignal) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QMutexLocker locker(&m_lock); | 
					
						
							|  |  |  |         m_semanticInfo = semanticInfo; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (emitSignal) { | 
					
						
							|  |  |  |         if (debug) | 
					
						
							|  |  |  |             qDebug() << "SemanticInfoUpdater: emiting new info"; | 
					
						
							|  |  |  |         emit q->updated(semanticInfo); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SemanticInfo SemanticInfoUpdaterPrivate::update(const SemanticInfo::Source &source, | 
					
						
							|  |  |  |                                                 bool emitSignalWhenFinished, | 
					
						
							|  |  |  |                                                 FuturizedTopLevelDeclarationProcessor *processor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug() << "SemanticInfoUpdater: update() - source revision" << source.revision; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SemanticInfo newSemanticInfo; | 
					
						
							|  |  |  |     newSemanticInfo.revision = source.revision; | 
					
						
							| 
									
										
										
										
											2014-08-26 14:26:28 +02:00
										 |  |  |     newSemanticInfo.snapshot = source.snapshot; | 
					
						
							| 
									
										
										
										
											2014-08-19 15:59:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Document::Ptr doc = newSemanticInfo.snapshot.preprocessedDocument(source.code, source.fileName); | 
					
						
							|  |  |  |     if (processor) | 
					
						
							|  |  |  |         doc->control()->setTopLevelDeclarationProcessor(processor); | 
					
						
							|  |  |  |     doc->check(); | 
					
						
							|  |  |  |     if (processor && processor->isCanceled()) | 
					
						
							|  |  |  |         newSemanticInfo.complete = false; | 
					
						
							|  |  |  |     newSemanticInfo.doc = doc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug() << "SemanticInfoUpdater: update() - re-calculated document. Canceled =" | 
					
						
							|  |  |  |                  << !newSemanticInfo.complete; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     setSemanticInfo(newSemanticInfo, emitSignalWhenFinished); | 
					
						
							|  |  |  |     return newSemanticInfo; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool SemanticInfoUpdaterPrivate::reuseCurrentSemanticInfo(const SemanticInfo::Source &source, | 
					
						
							|  |  |  |                                                           bool emitSignalWhenFinished) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const SemanticInfo currentSemanticInfo = semanticInfo(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!source.force | 
					
						
							|  |  |  |             && currentSemanticInfo.complete | 
					
						
							|  |  |  |             && currentSemanticInfo.revision == source.revision | 
					
						
							|  |  |  |             && currentSemanticInfo.doc | 
					
						
							|  |  |  |             && currentSemanticInfo.doc->translationUnit()->ast() | 
					
						
							| 
									
										
										
										
											2014-08-26 14:26:28 +02:00
										 |  |  |             && currentSemanticInfo.doc->fileName() == source.fileName | 
					
						
							| 
									
										
										
										
											2014-10-14 11:37:40 +02:00
										 |  |  |             && !currentSemanticInfo.snapshot.isEmpty() | 
					
						
							|  |  |  |             && currentSemanticInfo.snapshot == source.snapshot) { | 
					
						
							| 
									
										
										
										
											2014-08-19 15:59:29 +02:00
										 |  |  |         SemanticInfo newSemanticInfo; | 
					
						
							|  |  |  |         newSemanticInfo.revision = source.revision; | 
					
						
							| 
									
										
										
										
											2014-08-26 14:26:28 +02:00
										 |  |  |         newSemanticInfo.snapshot = source.snapshot; | 
					
						
							| 
									
										
										
										
											2014-08-19 15:59:29 +02:00
										 |  |  |         newSemanticInfo.doc = currentSemanticInfo.doc; | 
					
						
							|  |  |  |         setSemanticInfo(newSemanticInfo, emitSignalWhenFinished); | 
					
						
							|  |  |  |         if (debug) | 
					
						
							|  |  |  |             qDebug() << "SemanticInfoUpdater: re-using current semantic info - source.revision" | 
					
						
							|  |  |  |                      << source.revision; | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SemanticInfoUpdaterPrivate::update_helper(QFutureInterface<void> &future, | 
					
						
							|  |  |  |                                                const SemanticInfo::Source source) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     FuturizedTopLevelDeclarationProcessor processor(future); | 
					
						
							|  |  |  |     update(source, true, &processor); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-26 14:26:28 +02:00
										 |  |  | SemanticInfoUpdater::SemanticInfoUpdater() | 
					
						
							|  |  |  |     : d(new SemanticInfoUpdaterPrivate(this)) | 
					
						
							| 
									
										
										
										
											2014-08-19 15:59:29 +02:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SemanticInfoUpdater::~SemanticInfoUpdater() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     d->m_future.cancel(); | 
					
						
							|  |  |  |     d->m_future.waitForFinished(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SemanticInfo SemanticInfoUpdater::update(const SemanticInfo::Source &source) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug() << "SemanticInfoUpdater: update() - synchronous"; | 
					
						
							|  |  |  |     d->m_future.cancel(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const bool emitSignalWhenFinished = false; | 
					
						
							|  |  |  |     if (d->reuseCurrentSemanticInfo(source, emitSignalWhenFinished)) { | 
					
						
							|  |  |  |         d->m_future = QFuture<void>(); | 
					
						
							|  |  |  |         return semanticInfo(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return d->update(source, emitSignalWhenFinished, 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SemanticInfoUpdater::updateDetached(const SemanticInfo::Source source) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |         qDebug() << "SemanticInfoUpdater: updateDetached() - asynchronous"; | 
					
						
							|  |  |  |     d->m_future.cancel(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const bool emitSignalWhenFinished = true; | 
					
						
							|  |  |  |     if (d->reuseCurrentSemanticInfo(source, emitSignalWhenFinished)) { | 
					
						
							|  |  |  |         d->m_future = QFuture<void>(); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     d->m_future = QtConcurrent::run<SemanticInfoUpdaterPrivate, void, const SemanticInfo::Source> | 
					
						
							|  |  |  |             (&SemanticInfoUpdaterPrivate::update_helper, d.data(), source); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SemanticInfo SemanticInfoUpdater::semanticInfo() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return d->semanticInfo(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace CppTools
 |