2009-02-25 09:15:00 +01:00
|
|
|
/**************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-06-17 00:01:27 +10:00
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Commercial Usage
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
|
|
|
** accordance with the Qt Commercial License Agreement provided with the
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
** a written agreement between you and Nokia.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
|
|
** General Public License version 2.1 as published by the Free Software
|
|
|
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
|
|
** packaging of this file. Please review the following information to
|
|
|
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
|
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** If you are unsure which license is appropriate for your use, please
|
2009-08-14 09:30:56 +02:00
|
|
|
** contact the sales department at http://qt.nokia.com/contact.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
**************************************************************************/
|
2008-12-02 15:08:31 +01:00
|
|
|
|
2008-12-08 12:59:33 +01:00
|
|
|
#include <cplusplus/pp.h>
|
2009-06-03 12:13:22 +02:00
|
|
|
#include <cplusplus/CppBindings.h>
|
2009-06-04 11:32:01 +02:00
|
|
|
#include <cplusplus/Overview.h>
|
2009-07-13 11:40:54 +02:00
|
|
|
#include <cplusplus/CheckUndefinedSymbols.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
#include "cppmodelmanager.h"
|
|
|
|
#include "cpptoolsconstants.h"
|
|
|
|
#include "cpptoolseditorsupport.h"
|
2009-08-07 13:02:36 +02:00
|
|
|
#include "cppfindreferences.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-03-06 11:51:45 +01:00
|
|
|
#include <functional>
|
|
|
|
#include <QtConcurrentRun>
|
2009-03-11 12:00:07 +01:00
|
|
|
#include <QFutureSynchronizer>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <qtconcurrent/runextensions.h>
|
2009-03-06 11:51:45 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <texteditor/itexteditor.h>
|
|
|
|
#include <texteditor/basetexteditor.h>
|
|
|
|
|
|
|
|
#include <projectexplorer/project.h>
|
|
|
|
#include <projectexplorer/projectexplorer.h>
|
|
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
|
|
|
#include <projectexplorer/session.h>
|
|
|
|
|
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
#include <coreplugin/uniqueidmanager.h>
|
2009-02-23 12:49:56 +01:00
|
|
|
#include <coreplugin/mimedatabase.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
2009-01-13 14:16:36 +01:00
|
|
|
#include <coreplugin/progressmanager/progressmanager.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-10-05 13:43:05 +02:00
|
|
|
#include <extensionsystem/pluginmanager.h>
|
|
|
|
|
2008-12-09 15:25:01 +01:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <TranslationUnit.h>
|
|
|
|
#include <Semantic.h>
|
|
|
|
#include <AST.h>
|
|
|
|
#include <Scope.h>
|
|
|
|
#include <Literals.h>
|
|
|
|
#include <Symbols.h>
|
|
|
|
#include <Names.h>
|
|
|
|
#include <NameVisitor.h>
|
|
|
|
#include <TypeVisitor.h>
|
2009-02-18 16:01:28 +01:00
|
|
|
#include <ASTVisitor.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <Lexer.h>
|
|
|
|
#include <Token.h>
|
|
|
|
|
2009-06-02 16:50:43 +02:00
|
|
|
#include <cplusplus/LookupContext.h>
|
|
|
|
|
2009-04-17 21:11:52 +02:00
|
|
|
#include <QtCore/QCoreApplication>
|
2008-12-09 15:25:01 +01:00
|
|
|
#include <QtCore/QDebug>
|
|
|
|
#include <QtCore/QMutexLocker>
|
|
|
|
#include <QtCore/QTime>
|
2009-02-10 22:56:04 +01:00
|
|
|
#include <QtCore/QTimer>
|
2009-02-24 11:04:52 +01:00
|
|
|
#include <QtConcurrentMap>
|
2009-02-18 16:01:28 +01:00
|
|
|
#include <iostream>
|
|
|
|
#include <sstream>
|
2008-12-09 15:25:01 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
using namespace CppTools;
|
|
|
|
using namespace CppTools::Internal;
|
2008-12-02 12:01:29 +01:00
|
|
|
using namespace CPlusPlus;
|
|
|
|
|
2009-02-18 16:01:28 +01:00
|
|
|
#if defined(QTCREATOR_WITH_DUMP_AST) && defined(Q_CC_GNU)
|
|
|
|
|
|
|
|
#include <cxxabi.h>
|
|
|
|
|
|
|
|
class DumpAST: protected ASTVisitor
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
int depth;
|
|
|
|
|
|
|
|
DumpAST(Control *control)
|
|
|
|
: ASTVisitor(control), depth(0)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
void operator()(AST *ast)
|
|
|
|
{ accept(ast); }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual bool preVisit(AST *ast)
|
|
|
|
{
|
|
|
|
std::ostringstream s;
|
|
|
|
PrettyPrinter pp(control(), s);
|
|
|
|
pp(ast);
|
|
|
|
QString code = QString::fromStdString(s.str());
|
|
|
|
code.replace('\n', ' ');
|
|
|
|
code.replace(QRegExp("\\s+"), " ");
|
|
|
|
|
|
|
|
const char *name = abi::__cxa_demangle(typeid(*ast).name(), 0, 0, 0) + 11;
|
|
|
|
|
|
|
|
QByteArray ind(depth, ' ');
|
|
|
|
ind += name;
|
|
|
|
|
|
|
|
printf("%-40s %s\n", ind.constData(), qPrintable(code));
|
|
|
|
++depth;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void postVisit(AST *)
|
|
|
|
{ --depth; }
|
|
|
|
};
|
|
|
|
|
2009-03-05 09:46:54 +01:00
|
|
|
#endif // QTCREATOR_WITH_DUMP_AST
|
2009-02-18 16:01:28 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
static const char pp_configuration_file[] = "<configuration>";
|
|
|
|
|
|
|
|
static const char pp_configuration[] =
|
|
|
|
"# 1 \"<configuration>\"\n"
|
|
|
|
"#define __cplusplus 1\n"
|
|
|
|
"#define __extension__\n"
|
|
|
|
"#define __context__\n"
|
|
|
|
"#define __range__\n"
|
|
|
|
"#define restrict\n"
|
|
|
|
"#define __restrict\n"
|
2009-07-17 10:54:08 +02:00
|
|
|
"#define __restrict__\n"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-02-23 09:53:26 +01:00
|
|
|
"#define __complex__\n"
|
|
|
|
"#define __imag__\n"
|
|
|
|
"#define __real__\n"
|
|
|
|
|
2009-06-18 17:48:55 +02:00
|
|
|
"#define __builtin_va_arg(a,b) ((b)0)\n"
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
// ### add macros for win32
|
|
|
|
"#define __cdecl\n"
|
|
|
|
"#define QT_WA(x) x\n"
|
|
|
|
"#define API\n"
|
|
|
|
"#define WINAPI\n"
|
|
|
|
"#define CALLBACK\n"
|
|
|
|
"#define STDMETHODCALLTYPE\n"
|
|
|
|
"#define __RPC_FAR\n"
|
|
|
|
"#define APIENTRY\n"
|
|
|
|
"#define __declspec(a)\n"
|
|
|
|
"#define STDMETHOD(method) virtual HRESULT STDMETHODCALLTYPE method\n";
|
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
namespace CppTools {
|
|
|
|
namespace Internal {
|
|
|
|
|
2008-12-08 12:17:39 +01:00
|
|
|
class CppPreprocessor: public CPlusPlus::Client
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
public:
|
2008-12-08 11:08:48 +01:00
|
|
|
CppPreprocessor(QPointer<CppModelManager> modelManager);
|
2009-03-11 12:00:07 +01:00
|
|
|
virtual ~CppPreprocessor();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-07-14 14:23:12 +02:00
|
|
|
void setRevision(unsigned revision);
|
2009-12-07 12:36:16 +01:00
|
|
|
void setWorkingCopy(const QHash<QString, QString> &workingCopy);
|
2008-12-08 11:08:48 +01:00
|
|
|
void setIncludePaths(const QStringList &includePaths);
|
|
|
|
void setFrameworkPaths(const QStringList &frameworkPaths);
|
|
|
|
void setProjectFiles(const QStringList &files);
|
2009-02-23 15:57:37 +01:00
|
|
|
void setTodo(const QStringList &files);
|
|
|
|
|
2009-02-24 11:04:52 +01:00
|
|
|
void run(const QString &fileName);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-02-23 12:49:56 +01:00
|
|
|
void resetEnvironment();
|
|
|
|
|
2009-02-23 15:57:37 +01:00
|
|
|
const QSet<QString> &todo() const
|
|
|
|
{ return m_todo; }
|
|
|
|
|
2009-02-09 12:33:43 +01:00
|
|
|
public: // attributes
|
|
|
|
Snapshot snapshot;
|
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
protected:
|
|
|
|
CPlusPlus::Document::Ptr switchDocument(CPlusPlus::Document::Ptr doc);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-06-15 15:38:20 +02:00
|
|
|
bool includeFile(const QString &absoluteFilePath, QString *result);
|
|
|
|
QString tryIncludeFile(QString &fileName, IncludeType type);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
void mergeEnvironment(CPlusPlus::Document::Ptr doc);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 12:59:33 +01:00
|
|
|
virtual void macroAdded(const Macro ¯o);
|
2009-09-25 16:00:14 +02:00
|
|
|
virtual void passedMacroDefinitionCheck(unsigned offset, const Macro ¯o);
|
|
|
|
virtual void failedMacroDefinitionCheck(unsigned offset, const QByteArray &name);
|
2008-12-08 11:08:48 +01:00
|
|
|
virtual void startExpandingMacro(unsigned offset,
|
2008-12-08 12:17:39 +01:00
|
|
|
const Macro ¯o,
|
2009-03-04 11:47:30 +01:00
|
|
|
const QByteArray &originalText,
|
2009-09-25 16:00:14 +02:00
|
|
|
bool inCondition,
|
2009-03-04 11:47:30 +01:00
|
|
|
const QVector<MacroArgumentReference> &actuals);
|
2008-12-08 12:17:39 +01:00
|
|
|
virtual void stopExpandingMacro(unsigned offset, const Macro ¯o);
|
2008-12-08 11:08:48 +01:00
|
|
|
virtual void startSkippingBlocks(unsigned offset);
|
|
|
|
virtual void stopSkippingBlocks(unsigned offset);
|
2008-12-10 17:21:01 +01:00
|
|
|
virtual void sourceNeeded(QString &fileName, IncludeType type,
|
|
|
|
unsigned line);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
private:
|
|
|
|
QPointer<CppModelManager> m_modelManager;
|
2008-12-08 12:17:39 +01:00
|
|
|
Environment env;
|
2009-03-02 18:15:58 +01:00
|
|
|
Preprocessor preprocess;
|
2008-12-08 11:08:48 +01:00
|
|
|
QStringList m_includePaths;
|
|
|
|
QStringList m_systemIncludePaths;
|
2009-12-07 12:36:16 +01:00
|
|
|
QHash<QString, QString> m_workingCopy;
|
2008-12-08 11:08:48 +01:00
|
|
|
QStringList m_projectFiles;
|
|
|
|
QStringList m_frameworkPaths;
|
|
|
|
QSet<QString> m_included;
|
2009-02-24 11:04:52 +01:00
|
|
|
Document::Ptr m_currentDoc;
|
2009-02-23 15:57:37 +01:00
|
|
|
QSet<QString> m_todo;
|
2009-03-09 12:51:13 +01:00
|
|
|
QSet<QString> m_processed;
|
2009-07-14 14:23:12 +02:00
|
|
|
unsigned m_revision;
|
2008-12-08 11:08:48 +01:00
|
|
|
};
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
} // namespace Internal
|
|
|
|
} // namespace CppTools
|
2008-12-04 17:07:43 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
CppPreprocessor::CppPreprocessor(QPointer<CppModelManager> modelManager)
|
2009-02-09 12:33:43 +01:00
|
|
|
: snapshot(modelManager->snapshot()),
|
|
|
|
m_modelManager(modelManager),
|
2009-07-14 14:23:12 +02:00
|
|
|
preprocess(this, &env),
|
|
|
|
m_revision(0)
|
2009-03-17 14:39:52 +01:00
|
|
|
{ }
|
2009-03-11 12:00:07 +01:00
|
|
|
|
|
|
|
CppPreprocessor::~CppPreprocessor()
|
2008-12-08 11:08:48 +01:00
|
|
|
{ }
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-07-14 14:23:12 +02:00
|
|
|
void CppPreprocessor::setRevision(unsigned revision)
|
|
|
|
{ m_revision = revision; }
|
|
|
|
|
2009-12-07 12:36:16 +01:00
|
|
|
void CppPreprocessor::setWorkingCopy(const QHash<QString, QString> &workingCopy)
|
2008-12-08 11:08:48 +01:00
|
|
|
{ m_workingCopy = workingCopy; }
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
void CppPreprocessor::setIncludePaths(const QStringList &includePaths)
|
|
|
|
{ m_includePaths = includePaths; }
|
|
|
|
|
|
|
|
void CppPreprocessor::setFrameworkPaths(const QStringList &frameworkPaths)
|
|
|
|
{ m_frameworkPaths = frameworkPaths; }
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
void CppPreprocessor::setProjectFiles(const QStringList &files)
|
|
|
|
{ m_projectFiles = files; }
|
|
|
|
|
2009-02-23 15:57:37 +01:00
|
|
|
void CppPreprocessor::setTodo(const QStringList &files)
|
|
|
|
{ m_todo = QSet<QString>::fromList(files); }
|
|
|
|
|
2009-02-24 11:04:52 +01:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2009-03-06 11:51:45 +01:00
|
|
|
class Process: public std::unary_function<Document::Ptr, void>
|
2009-02-24 11:04:52 +01:00
|
|
|
{
|
|
|
|
QPointer<CppModelManager> _modelManager;
|
2009-06-02 16:50:43 +02:00
|
|
|
Snapshot _snapshot;
|
2009-12-07 12:36:16 +01:00
|
|
|
QHash<QString, QString> _workingCopy;
|
2009-06-02 16:50:43 +02:00
|
|
|
Document::Ptr _doc;
|
2009-02-24 11:04:52 +01:00
|
|
|
|
|
|
|
public:
|
2009-06-02 16:50:43 +02:00
|
|
|
Process(QPointer<CppModelManager> modelManager,
|
|
|
|
Snapshot snapshot,
|
2009-12-07 12:36:16 +01:00
|
|
|
const QHash<QString, QString> &workingCopy)
|
2009-06-02 16:50:43 +02:00
|
|
|
: _modelManager(modelManager),
|
|
|
|
_snapshot(snapshot),
|
|
|
|
_workingCopy(workingCopy)
|
2009-02-24 11:04:52 +01:00
|
|
|
{ }
|
|
|
|
|
2009-06-02 16:50:43 +02:00
|
|
|
LookupContext lookupContext(unsigned line, unsigned column) const
|
|
|
|
{ return lookupContext(_doc->findSymbolAt(line, column)); }
|
|
|
|
|
|
|
|
LookupContext lookupContext(Symbol *symbol) const
|
2009-02-24 11:04:52 +01:00
|
|
|
{
|
2009-06-10 12:25:52 +02:00
|
|
|
LookupContext context(symbol, Document::create(QLatin1String("<none>")), _doc, _snapshot);
|
2009-06-02 16:50:43 +02:00
|
|
|
return context;
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(Document::Ptr doc)
|
|
|
|
{
|
|
|
|
_doc = doc;
|
2009-06-26 09:11:14 +02:00
|
|
|
|
|
|
|
Document::CheckMode mode = Document::FastCheck;
|
|
|
|
|
|
|
|
if (_workingCopy.contains(doc->fileName()))
|
|
|
|
mode = Document::FullCheck;
|
|
|
|
|
2009-02-24 11:04:52 +01:00
|
|
|
doc->parse();
|
2009-06-26 09:11:14 +02:00
|
|
|
doc->check(mode);
|
2009-06-02 16:50:43 +02:00
|
|
|
|
2009-06-26 09:11:14 +02:00
|
|
|
if (mode == Document::FullCheck) {
|
2009-06-03 12:13:22 +02:00
|
|
|
// run the binding pass
|
|
|
|
NamespaceBindingPtr ns = bind(doc, _snapshot);
|
|
|
|
|
2009-06-02 16:50:43 +02:00
|
|
|
// check for undefined symbols.
|
2009-06-03 14:16:13 +02:00
|
|
|
CheckUndefinedSymbols checkUndefinedSymbols(doc);
|
|
|
|
checkUndefinedSymbols.setGlobalNamespaceBinding(ns);
|
2009-06-02 16:50:43 +02:00
|
|
|
|
2009-07-13 11:40:54 +02:00
|
|
|
checkUndefinedSymbols(doc->translationUnit()->ast()); // ### FIXME
|
2009-06-02 16:50:43 +02:00
|
|
|
}
|
|
|
|
|
2009-02-24 11:04:52 +01:00
|
|
|
doc->releaseTranslationUnit();
|
|
|
|
|
|
|
|
if (_modelManager)
|
|
|
|
_modelManager->emitDocumentUpdated(doc); // ### TODO: compress
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // end of anonymous namespace
|
|
|
|
|
|
|
|
void CppPreprocessor::run(const QString &fileName)
|
|
|
|
{
|
|
|
|
QString absoluteFilePath = fileName;
|
|
|
|
sourceNeeded(absoluteFilePath, IncludeGlobal, /*line = */ 0);
|
|
|
|
}
|
2008-12-08 11:08:48 +01:00
|
|
|
|
2009-02-23 12:49:56 +01:00
|
|
|
void CppPreprocessor::resetEnvironment()
|
2009-03-09 12:51:13 +01:00
|
|
|
{
|
|
|
|
env.reset();
|
|
|
|
m_processed.clear();
|
|
|
|
}
|
2009-02-23 12:49:56 +01:00
|
|
|
|
2009-06-15 15:38:20 +02:00
|
|
|
bool CppPreprocessor::includeFile(const QString &absoluteFilePath, QString *result)
|
2008-12-08 11:08:48 +01:00
|
|
|
{
|
2009-10-26 15:31:43 +01:00
|
|
|
if (absoluteFilePath.isEmpty() || m_included.contains(absoluteFilePath))
|
2008-12-08 11:08:48 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
if (m_workingCopy.contains(absoluteFilePath)) {
|
|
|
|
m_included.insert(absoluteFilePath);
|
|
|
|
*result = m_workingCopy.value(absoluteFilePath);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
QFileInfo fileInfo(absoluteFilePath);
|
|
|
|
if (! fileInfo.isFile())
|
2008-12-02 12:01:29 +01:00
|
|
|
return false;
|
2008-12-08 11:08:48 +01:00
|
|
|
|
|
|
|
QFile file(absoluteFilePath);
|
|
|
|
if (file.open(QFile::ReadOnly)) {
|
|
|
|
m_included.insert(absoluteFilePath);
|
|
|
|
QTextStream stream(&file);
|
|
|
|
const QString contents = stream.readAll();
|
|
|
|
*result = contents.toUtf8();
|
|
|
|
file.close();
|
|
|
|
return true;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-06-15 15:38:20 +02:00
|
|
|
QString CppPreprocessor::tryIncludeFile(QString &fileName, IncludeType type)
|
2008-12-08 11:08:48 +01:00
|
|
|
{
|
|
|
|
QFileInfo fileInfo(fileName);
|
|
|
|
if (fileName == QLatin1String(pp_configuration_file) || fileInfo.isAbsolute()) {
|
2009-06-15 15:38:20 +02:00
|
|
|
QString contents;
|
2008-12-08 11:08:48 +01:00
|
|
|
includeFile(fileName, &contents);
|
|
|
|
return contents;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type == IncludeLocal && m_currentDoc) {
|
|
|
|
QFileInfo currentFileInfo(m_currentDoc->fileName());
|
|
|
|
QString path = currentFileInfo.absolutePath();
|
|
|
|
path += QLatin1Char('/');
|
|
|
|
path += fileName;
|
|
|
|
path = QDir::cleanPath(path);
|
2009-06-15 15:38:20 +02:00
|
|
|
QString contents;
|
2008-12-08 11:08:48 +01:00
|
|
|
if (includeFile(path, &contents)) {
|
|
|
|
fileName = path;
|
2008-12-02 12:01:29 +01:00
|
|
|
return contents;
|
|
|
|
}
|
2008-12-08 11:08:48 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-11-13 15:19:15 +01:00
|
|
|
foreach (const QString &includePath, m_includePaths) {
|
|
|
|
QString path = includePath;
|
2008-12-08 11:08:48 +01:00
|
|
|
path += QLatin1Char('/');
|
|
|
|
path += fileName;
|
|
|
|
path = QDir::cleanPath(path);
|
2009-06-15 15:38:20 +02:00
|
|
|
QString contents;
|
2008-12-08 11:08:48 +01:00
|
|
|
if (includeFile(path, &contents)) {
|
|
|
|
fileName = path;
|
|
|
|
return contents;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2008-12-08 11:08:48 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
// look in the system include paths
|
|
|
|
foreach (const QString &includePath, m_systemIncludePaths) {
|
|
|
|
QString path = includePath;
|
|
|
|
path += QLatin1Char('/');
|
|
|
|
path += fileName;
|
|
|
|
path = QDir::cleanPath(path);
|
2009-06-15 15:38:20 +02:00
|
|
|
QString contents;
|
2008-12-08 11:08:48 +01:00
|
|
|
if (includeFile(path, &contents)) {
|
|
|
|
fileName = path;
|
|
|
|
return contents;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2008-12-08 11:08:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int index = fileName.indexOf(QLatin1Char('/'));
|
|
|
|
if (index != -1) {
|
|
|
|
QString frameworkName = fileName.left(index);
|
|
|
|
QString name = fileName.mid(index + 1);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
foreach (const QString &frameworkPath, m_frameworkPaths) {
|
|
|
|
QString path = frameworkPath;
|
2008-12-02 12:01:29 +01:00
|
|
|
path += QLatin1Char('/');
|
2008-12-08 11:08:48 +01:00
|
|
|
path += frameworkName;
|
|
|
|
path += QLatin1String(".framework/Headers/");
|
|
|
|
path += name;
|
2009-06-02 14:56:03 +02:00
|
|
|
path = QDir::cleanPath(path);
|
2009-06-15 15:38:20 +02:00
|
|
|
QString contents;
|
2008-12-02 12:01:29 +01:00
|
|
|
if (includeFile(path, &contents)) {
|
|
|
|
fileName = path;
|
|
|
|
return contents;
|
|
|
|
}
|
|
|
|
}
|
2008-12-08 11:08:48 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
QString path = fileName;
|
|
|
|
if (path.at(0) != QLatin1Char('/'))
|
|
|
|
path.prepend(QLatin1Char('/'));
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
foreach (const QString &projectFile, m_projectFiles) {
|
|
|
|
if (projectFile.endsWith(path)) {
|
|
|
|
fileName = projectFile;
|
2009-06-15 15:38:20 +02:00
|
|
|
QString contents;
|
2008-12-08 11:08:48 +01:00
|
|
|
includeFile(fileName, &contents);
|
|
|
|
return contents;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
//qDebug() << "**** file" << fileName << "not found!";
|
2009-06-15 15:38:20 +02:00
|
|
|
return QString();
|
2008-12-08 11:08:48 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 12:59:33 +01:00
|
|
|
void CppPreprocessor::macroAdded(const Macro ¯o)
|
2008-12-08 11:08:48 +01:00
|
|
|
{
|
|
|
|
if (! m_currentDoc)
|
|
|
|
return;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 12:59:33 +01:00
|
|
|
m_currentDoc->appendMacro(macro);
|
2008-12-08 11:08:48 +01:00
|
|
|
}
|
2008-12-04 12:05:04 +01:00
|
|
|
|
2009-09-25 16:00:14 +02:00
|
|
|
void CppPreprocessor::passedMacroDefinitionCheck(unsigned offset, const Macro ¯o)
|
|
|
|
{
|
|
|
|
if (! m_currentDoc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_currentDoc->addMacroUse(macro, offset, macro.name().length(),
|
|
|
|
QVector<MacroArgumentReference>(), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CppPreprocessor::failedMacroDefinitionCheck(unsigned offset, const QByteArray &name)
|
|
|
|
{
|
|
|
|
if (! m_currentDoc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_currentDoc->addUndefinedMacroUse(name, offset);
|
|
|
|
}
|
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
void CppPreprocessor::startExpandingMacro(unsigned offset,
|
2008-12-09 15:23:47 +01:00
|
|
|
const Macro ¯o,
|
2009-03-04 11:47:30 +01:00
|
|
|
const QByteArray &originalText,
|
2009-09-25 16:00:14 +02:00
|
|
|
bool inCondition,
|
2009-03-04 11:47:30 +01:00
|
|
|
const QVector<MacroArgumentReference> &actuals)
|
2008-12-08 11:08:48 +01:00
|
|
|
{
|
|
|
|
if (! m_currentDoc)
|
|
|
|
return;
|
2008-12-04 12:05:04 +01:00
|
|
|
|
2009-09-25 16:00:14 +02:00
|
|
|
//qDebug() << "start expanding:" << macro.name() << "text:" << originalText;
|
|
|
|
m_currentDoc->addMacroUse(macro, offset, originalText.length(), actuals, inCondition);
|
2008-12-08 11:08:48 +01:00
|
|
|
}
|
2008-12-04 12:05:04 +01:00
|
|
|
|
2008-12-08 12:17:39 +01:00
|
|
|
void CppPreprocessor::stopExpandingMacro(unsigned, const Macro &)
|
2008-12-08 11:08:48 +01:00
|
|
|
{
|
|
|
|
if (! m_currentDoc)
|
|
|
|
return;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
//qDebug() << "stop expanding:" << macro.name;
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
void CppPreprocessor::mergeEnvironment(Document::Ptr doc)
|
|
|
|
{
|
|
|
|
if (! doc)
|
|
|
|
return;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
const QString fn = doc->fileName();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-03-09 12:51:13 +01:00
|
|
|
if (m_processed.contains(fn))
|
2008-12-08 11:08:48 +01:00
|
|
|
return;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-03-09 12:51:13 +01:00
|
|
|
m_processed.insert(fn);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-02-23 12:49:56 +01:00
|
|
|
foreach (const Document::Include &incl, doc->includes()) {
|
2009-02-09 12:33:43 +01:00
|
|
|
QString includedFile = incl.fileName();
|
|
|
|
|
2009-12-07 10:54:27 +01:00
|
|
|
if (Document::Ptr includedDoc = snapshot.document(includedFile))
|
2009-03-09 12:51:13 +01:00
|
|
|
mergeEnvironment(includedDoc);
|
2009-02-09 12:33:43 +01:00
|
|
|
else
|
|
|
|
run(includedFile);
|
2008-12-08 12:59:33 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-02-23 12:49:56 +01:00
|
|
|
env.addMacros(doc->definedMacros());
|
2008-12-08 11:08:48 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
void CppPreprocessor::startSkippingBlocks(unsigned offset)
|
|
|
|
{
|
|
|
|
//qDebug() << "start skipping blocks:" << offset;
|
|
|
|
if (m_currentDoc)
|
|
|
|
m_currentDoc->startSkippingBlocks(offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CppPreprocessor::stopSkippingBlocks(unsigned offset)
|
|
|
|
{
|
|
|
|
//qDebug() << "stop skipping blocks:" << offset;
|
|
|
|
if (m_currentDoc)
|
|
|
|
m_currentDoc->stopSkippingBlocks(offset);
|
|
|
|
}
|
|
|
|
|
2008-12-10 17:21:01 +01:00
|
|
|
void CppPreprocessor::sourceNeeded(QString &fileName, IncludeType type,
|
|
|
|
unsigned line)
|
2008-12-08 11:08:48 +01:00
|
|
|
{
|
|
|
|
if (fileName.isEmpty())
|
|
|
|
return;
|
|
|
|
|
2009-06-15 15:38:20 +02:00
|
|
|
QString contents = tryIncludeFile(fileName, type);
|
2009-11-09 13:53:28 +01:00
|
|
|
fileName = QDir::cleanPath(fileName);
|
2008-12-08 11:08:48 +01:00
|
|
|
if (m_currentDoc) {
|
2008-12-10 17:21:01 +01:00
|
|
|
m_currentDoc->addIncludeFile(fileName, line);
|
2009-02-23 12:49:56 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
if (contents.isEmpty() && ! QFileInfo(fileName).isAbsolute()) {
|
2009-04-17 21:11:52 +02:00
|
|
|
QString msg = QCoreApplication::translate(
|
|
|
|
"CppPreprocessor", "%1: No such file or directory").arg(fileName);
|
2009-02-23 12:49:56 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
Document::DiagnosticMessage d(Document::DiagnosticMessage::Warning,
|
|
|
|
m_currentDoc->fileName(),
|
|
|
|
env.currentLine, /*column = */ 0,
|
|
|
|
msg);
|
2009-02-23 12:49:56 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
m_currentDoc->addDiagnosticMessage(d);
|
2009-02-23 12:49:56 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
//qWarning() << "file not found:" << fileName << m_currentDoc->fileName() << env.current_line;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2008-12-08 11:08:48 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-02-23 12:49:56 +01:00
|
|
|
//qDebug() << "parse file:" << fileName << "contents:" << contents.size();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-12-07 10:54:27 +01:00
|
|
|
Document::Ptr doc = snapshot.document(fileName);
|
2009-02-23 12:49:56 +01:00
|
|
|
if (doc) {
|
|
|
|
mergeEnvironment(doc);
|
|
|
|
return;
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-02-23 12:49:56 +01:00
|
|
|
doc = Document::create(fileName);
|
2009-07-14 14:23:12 +02:00
|
|
|
doc->setRevision(m_revision);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-11-05 12:34:02 +01:00
|
|
|
QFileInfo info(fileName);
|
|
|
|
if (info.exists())
|
|
|
|
doc->setLastModified(info.lastModified());
|
|
|
|
|
2009-02-23 12:49:56 +01:00
|
|
|
Document::Ptr previousDoc = switchDocument(doc);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-06-15 15:38:20 +02:00
|
|
|
const QByteArray preprocessedCode = preprocess(fileName, contents);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-02-23 12:49:56 +01:00
|
|
|
doc->setSource(preprocessedCode);
|
2009-02-24 11:04:52 +01:00
|
|
|
doc->tokenize();
|
|
|
|
doc->releaseSource();
|
2009-02-23 12:49:56 +01:00
|
|
|
|
2009-12-07 10:54:27 +01:00
|
|
|
snapshot.insert(doc);
|
2009-03-06 11:51:45 +01:00
|
|
|
m_todo.remove(fileName);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-06-02 16:50:43 +02:00
|
|
|
Process process(m_modelManager, snapshot, m_workingCopy);
|
2009-03-17 14:39:52 +01:00
|
|
|
|
|
|
|
process(doc);
|
2009-02-23 12:49:56 +01:00
|
|
|
|
|
|
|
(void) switchDocument(previousDoc);
|
2008-12-08 11:08:48 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 11:08:48 +01:00
|
|
|
Document::Ptr CppPreprocessor::switchDocument(Document::Ptr doc)
|
|
|
|
{
|
|
|
|
Document::Ptr previousDoc = m_currentDoc;
|
|
|
|
m_currentDoc = doc;
|
|
|
|
return previousDoc;
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-11-05 12:34:02 +01:00
|
|
|
void CppTools::CppModelManagerInterface::updateModifiedSourceFiles()
|
|
|
|
{
|
|
|
|
const Snapshot snapshot = this->snapshot();
|
|
|
|
QStringList sourceFiles;
|
|
|
|
|
|
|
|
foreach (const Document::Ptr doc, snapshot) {
|
|
|
|
const QDateTime lastModified = doc->lastModified();
|
|
|
|
|
|
|
|
if (! lastModified.isNull()) {
|
|
|
|
QFileInfo fileInfo(doc->fileName());
|
|
|
|
|
|
|
|
if (fileInfo.exists() && fileInfo.lastModified() != lastModified)
|
|
|
|
sourceFiles.append(doc->fileName());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
updateSourceFiles(sourceFiles);
|
|
|
|
}
|
|
|
|
|
2009-10-05 13:43:05 +02:00
|
|
|
CppTools::CppModelManagerInterface *CppTools::CppModelManagerInterface::instance()
|
|
|
|
{
|
|
|
|
ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance();
|
|
|
|
return pluginManager->getObject<CppTools::CppModelManagerInterface>();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
/*!
|
|
|
|
\class CppTools::CppModelManager
|
|
|
|
\brief The CppModelManager keeps track of one CppCodeModel instance
|
|
|
|
for each project and all related CppCodeModelPart instances.
|
|
|
|
|
|
|
|
It also takes care of updating the code models when C++ files are
|
2009-05-08 13:01:32 +02:00
|
|
|
modified within Qt Creator.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
2009-01-20 11:52:04 +01:00
|
|
|
CppModelManager::CppModelManager(QObject *parent)
|
2009-11-10 18:02:42 +01:00
|
|
|
: CppModelManagerInterface(parent)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-08-07 13:02:36 +02:00
|
|
|
m_findReferences = new CppFindReferences(this);
|
2009-12-07 12:03:31 +01:00
|
|
|
m_indexerEnabled = qgetenv("QTCREATOR_NO_CODE_INDEXER").isNull();
|
2009-08-07 13:02:36 +02:00
|
|
|
|
2009-07-14 14:23:12 +02:00
|
|
|
m_revision = 0;
|
2009-03-11 12:00:07 +01:00
|
|
|
m_synchronizer.setCancelOnWait(true);
|
|
|
|
|
2009-01-20 11:52:04 +01:00
|
|
|
m_core = Core::ICore::instance(); // FIXME
|
2008-12-04 17:07:43 +01:00
|
|
|
m_dirty = true;
|
|
|
|
|
2009-03-04 11:47:30 +01:00
|
|
|
ProjectExplorer::ProjectExplorerPlugin *pe =
|
2009-03-04 09:38:01 +01:00
|
|
|
ProjectExplorer::ProjectExplorerPlugin::instance();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-03-04 09:38:01 +01:00
|
|
|
QTC_ASSERT(pe, return);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-03-04 09:38:01 +01:00
|
|
|
ProjectExplorer::SessionManager *session = pe->session();
|
2008-12-09 15:25:01 +01:00
|
|
|
QTC_ASSERT(session, return);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-02-10 22:56:04 +01:00
|
|
|
m_updateEditorSelectionsTimer = new QTimer(this);
|
|
|
|
m_updateEditorSelectionsTimer->setInterval(500);
|
|
|
|
m_updateEditorSelectionsTimer->setSingleShot(true);
|
|
|
|
connect(m_updateEditorSelectionsTimer, SIGNAL(timeout()),
|
|
|
|
this, SLOT(updateEditorSelections()));
|
|
|
|
|
2008-12-04 17:07:43 +01:00
|
|
|
connect(session, SIGNAL(projectAdded(ProjectExplorer::Project*)),
|
|
|
|
this, SLOT(onProjectAdded(ProjectExplorer::Project*)));
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
connect(session, SIGNAL(aboutToRemoveProject(ProjectExplorer::Project *)),
|
|
|
|
this, SLOT(onAboutToRemoveProject(ProjectExplorer::Project *)));
|
|
|
|
|
2009-08-13 17:10:53 +02:00
|
|
|
connect(session, SIGNAL(aboutToUnloadSession()),
|
|
|
|
this, SLOT(onAboutToUnloadSession()));
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
qRegisterMetaType<CPlusPlus::Document::Ptr>("CPlusPlus::Document::Ptr");
|
|
|
|
|
|
|
|
// thread connections
|
|
|
|
connect(this, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)),
|
|
|
|
this, SLOT(onDocumentUpdated(CPlusPlus::Document::Ptr)));
|
|
|
|
|
|
|
|
// Listen for editor closed and opened events so that we can keep track of changing files
|
|
|
|
connect(m_core->editorManager(), SIGNAL(editorOpened(Core::IEditor *)),
|
|
|
|
this, SLOT(editorOpened(Core::IEditor *)));
|
|
|
|
|
|
|
|
connect(m_core->editorManager(), SIGNAL(editorAboutToClose(Core::IEditor *)),
|
|
|
|
this, SLOT(editorAboutToClose(Core::IEditor *)));
|
|
|
|
}
|
|
|
|
|
|
|
|
CppModelManager::~CppModelManager()
|
|
|
|
{ }
|
|
|
|
|
2008-12-12 10:07:58 +01:00
|
|
|
Snapshot CppModelManager::snapshot() const
|
2009-03-04 09:38:01 +01:00
|
|
|
{
|
2009-06-02 15:27:13 +02:00
|
|
|
QMutexLocker locker(&protectSnapshot);
|
2009-03-04 09:38:01 +01:00
|
|
|
return m_snapshot;
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 10:44:56 +01:00
|
|
|
void CppModelManager::ensureUpdated()
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&mutex);
|
|
|
|
if (! m_dirty)
|
|
|
|
return;
|
|
|
|
|
2008-12-08 14:48:51 +01:00
|
|
|
m_projectFiles = internalProjectFiles();
|
|
|
|
m_includePaths = internalIncludePaths();
|
|
|
|
m_frameworkPaths = internalFrameworkPaths();
|
|
|
|
m_definedMacros = internalDefinedMacros();
|
2008-12-08 10:44:56 +01:00
|
|
|
m_dirty = false;
|
|
|
|
}
|
|
|
|
|
2008-12-08 14:48:51 +01:00
|
|
|
QStringList CppModelManager::internalProjectFiles() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
QStringList files;
|
|
|
|
QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects);
|
|
|
|
while (it.hasNext()) {
|
|
|
|
it.next();
|
|
|
|
ProjectInfo pinfo = it.value();
|
|
|
|
files += pinfo.sourceFiles;
|
|
|
|
}
|
2008-12-08 14:48:51 +01:00
|
|
|
files.removeDuplicates();
|
2008-12-02 12:01:29 +01:00
|
|
|
return files;
|
|
|
|
}
|
|
|
|
|
2008-12-08 14:48:51 +01:00
|
|
|
QStringList CppModelManager::internalIncludePaths() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
QStringList includePaths;
|
|
|
|
QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects);
|
|
|
|
while (it.hasNext()) {
|
|
|
|
it.next();
|
|
|
|
ProjectInfo pinfo = it.value();
|
|
|
|
includePaths += pinfo.includePaths;
|
|
|
|
}
|
2008-12-08 14:48:51 +01:00
|
|
|
includePaths.removeDuplicates();
|
2008-12-02 12:01:29 +01:00
|
|
|
return includePaths;
|
|
|
|
}
|
|
|
|
|
2008-12-08 14:48:51 +01:00
|
|
|
QStringList CppModelManager::internalFrameworkPaths() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
QStringList frameworkPaths;
|
|
|
|
QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects);
|
|
|
|
while (it.hasNext()) {
|
|
|
|
it.next();
|
|
|
|
ProjectInfo pinfo = it.value();
|
|
|
|
frameworkPaths += pinfo.frameworkPaths;
|
|
|
|
}
|
2008-12-08 14:48:51 +01:00
|
|
|
frameworkPaths.removeDuplicates();
|
2008-12-02 12:01:29 +01:00
|
|
|
return frameworkPaths;
|
|
|
|
}
|
|
|
|
|
2008-12-08 14:48:51 +01:00
|
|
|
QByteArray CppModelManager::internalDefinedMacros() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
QByteArray macros;
|
|
|
|
QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects);
|
|
|
|
while (it.hasNext()) {
|
|
|
|
it.next();
|
|
|
|
ProjectInfo pinfo = it.value();
|
|
|
|
macros += pinfo.defines;
|
|
|
|
}
|
|
|
|
return macros;
|
|
|
|
}
|
|
|
|
|
2009-10-13 12:12:51 +02:00
|
|
|
void CppModelManager::setIncludesInPaths(const QMap<QString, QStringList> &includesInPaths)
|
2009-07-24 12:50:10 +02:00
|
|
|
{
|
|
|
|
QMutexLocker locker(&mutex);
|
|
|
|
QMapIterator<QString, QStringList> i(includesInPaths);
|
|
|
|
while (i.hasNext()) {
|
|
|
|
i.next();
|
|
|
|
m_includesInPaths.insert(i.key(), i.value());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-12 13:45:24 +02:00
|
|
|
void CppModelManager::addEditorSupport(AbstractEditorSupport *editorSupport)
|
|
|
|
{
|
|
|
|
m_addtionalEditorSupport.insert(editorSupport);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CppModelManager::removeEditorSupport(AbstractEditorSupport *editorSupport)
|
|
|
|
{
|
|
|
|
m_addtionalEditorSupport.remove(editorSupport);
|
|
|
|
}
|
|
|
|
|
2009-09-30 13:25:40 +02:00
|
|
|
QList<int> CppModelManager::references(CPlusPlus::Symbol *symbol,
|
|
|
|
CPlusPlus::Document::Ptr doc,
|
|
|
|
const CPlusPlus::Snapshot &snapshot)
|
|
|
|
{
|
2009-10-07 16:11:42 +02:00
|
|
|
NamespaceBindingPtr glo = bind(doc, snapshot);
|
|
|
|
return m_findReferences->references(LookupContext::canonicalSymbol(symbol, glo.data()), doc, snapshot);
|
2009-09-30 13:25:40 +02:00
|
|
|
}
|
|
|
|
|
2009-10-05 15:17:25 +02:00
|
|
|
void CppModelManager::findUsages(CPlusPlus::Symbol *symbol)
|
2009-08-07 13:02:36 +02:00
|
|
|
{
|
2009-09-24 16:51:40 +02:00
|
|
|
if (symbol->identifier())
|
2009-10-05 15:17:25 +02:00
|
|
|
m_findReferences->findUsages(symbol);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CppModelManager::renameUsages(CPlusPlus::Symbol *symbol)
|
|
|
|
{
|
|
|
|
if (symbol->identifier())
|
|
|
|
m_findReferences->renameUsages(symbol);
|
2009-08-07 13:02:36 +02:00
|
|
|
}
|
|
|
|
|
2009-12-07 12:36:16 +01:00
|
|
|
QHash<QString, QString> CppModelManager::buildWorkingCopyList()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-12-07 12:36:16 +01:00
|
|
|
QHash<QString, QString> workingCopy;
|
2008-12-02 12:01:29 +01:00
|
|
|
QMapIterator<TextEditor::ITextEditor *, CppEditorSupport *> it(m_editorSupport);
|
|
|
|
while (it.hasNext()) {
|
|
|
|
it.next();
|
|
|
|
TextEditor::ITextEditor *textEditor = it.key();
|
|
|
|
CppEditorSupport *editorSupport = it.value();
|
|
|
|
QString fileName = textEditor->file()->fileName();
|
2009-03-02 16:30:25 +01:00
|
|
|
workingCopy[fileName] = editorSupport->contents();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2009-05-12 13:45:24 +02:00
|
|
|
QSetIterator<AbstractEditorSupport *> jt(m_addtionalEditorSupport);
|
|
|
|
while (jt.hasNext()) {
|
|
|
|
AbstractEditorSupport *es = jt.next();
|
|
|
|
workingCopy[es->fileName()] = es->contents();
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
// add the project configuration file
|
|
|
|
QByteArray conf(pp_configuration);
|
|
|
|
conf += definedMacros();
|
|
|
|
workingCopy[pp_configuration_file] = conf;
|
|
|
|
|
|
|
|
return workingCopy;
|
|
|
|
}
|
|
|
|
|
2009-12-07 12:36:16 +01:00
|
|
|
QHash<QString, QString> CppModelManager::workingCopy() const
|
2009-10-12 10:38:00 +02:00
|
|
|
{
|
|
|
|
return const_cast<CppModelManager *>(this)->buildWorkingCopyList();
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void CppModelManager::updateSourceFiles(const QStringList &sourceFiles)
|
|
|
|
{ (void) refreshSourceFiles(sourceFiles); }
|
|
|
|
|
2008-12-08 10:44:56 +01:00
|
|
|
QList<CppModelManager::ProjectInfo> CppModelManager::projectInfos() const
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&mutex);
|
|
|
|
|
|
|
|
return m_projects.values();
|
|
|
|
}
|
|
|
|
|
|
|
|
CppModelManager::ProjectInfo CppModelManager::projectInfo(ProjectExplorer::Project *project) const
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&mutex);
|
|
|
|
|
|
|
|
return m_projects.value(project, ProjectInfo(project));
|
|
|
|
}
|
|
|
|
|
|
|
|
void CppModelManager::updateProjectInfo(const ProjectInfo &pinfo)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&mutex);
|
|
|
|
|
|
|
|
if (! pinfo.isValid())
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_projects.insert(pinfo.project, pinfo);
|
2008-12-08 14:48:51 +01:00
|
|
|
m_dirty = true;
|
2009-07-24 12:50:10 +02:00
|
|
|
|
2009-12-07 12:03:31 +01:00
|
|
|
if (m_indexerEnabled) {
|
2009-08-04 18:16:05 +02:00
|
|
|
QFuture<void> result = QtConcurrent::run(&CppModelManager::updateIncludesInPaths,
|
|
|
|
this,
|
|
|
|
pinfo.includePaths,
|
2009-10-01 17:01:13 +02:00
|
|
|
pinfo.frameworkPaths,
|
2009-08-04 18:16:05 +02:00
|
|
|
m_headerSuffixes);
|
|
|
|
|
|
|
|
if (pinfo.includePaths.size() > 1) {
|
|
|
|
m_core->progressManager()->addTask(result, tr("Scanning"),
|
2009-11-26 15:51:10 +01:00
|
|
|
CppTools::Constants::TASK_INDEX);
|
2009-08-04 18:16:05 +02:00
|
|
|
}
|
2009-07-24 12:50:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList CppModelManager::includesInPath(const QString &path) const
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&mutex);
|
|
|
|
return m_includesInPaths.value(path);
|
2008-12-08 10:44:56 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
QFuture<void> CppModelManager::refreshSourceFiles(const QStringList &sourceFiles)
|
|
|
|
{
|
2009-12-07 12:03:31 +01:00
|
|
|
if (! sourceFiles.isEmpty() && m_indexerEnabled) {
|
2009-12-07 12:36:16 +01:00
|
|
|
const QHash<QString, QString> workingCopy = buildWorkingCopyList();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-04 17:07:43 +01:00
|
|
|
CppPreprocessor *preproc = new CppPreprocessor(this);
|
2009-07-14 14:23:12 +02:00
|
|
|
preproc->setRevision(++m_revision);
|
2008-12-04 17:07:43 +01:00
|
|
|
preproc->setProjectFiles(projectFiles());
|
|
|
|
preproc->setIncludePaths(includePaths());
|
|
|
|
preproc->setFrameworkPaths(frameworkPaths());
|
|
|
|
preproc->setWorkingCopy(workingCopy);
|
|
|
|
|
|
|
|
QFuture<void> result = QtConcurrent::run(&CppModelManager::parse,
|
|
|
|
preproc, sourceFiles);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-03-11 12:21:02 +01:00
|
|
|
if (m_synchronizer.futures().size() > 10) {
|
|
|
|
QList<QFuture<void> > futures = m_synchronizer.futures();
|
|
|
|
|
|
|
|
m_synchronizer.clearFutures();
|
|
|
|
|
|
|
|
foreach (QFuture<void> future, futures) {
|
|
|
|
if (! (future.isFinished() || future.isCanceled()))
|
|
|
|
m_synchronizer.addFuture(future);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-11 12:00:07 +01:00
|
|
|
m_synchronizer.addFuture(result);
|
|
|
|
|
2009-11-10 18:02:42 +01:00
|
|
|
if (sourceFiles.count() > 1) {
|
2008-12-02 12:01:29 +01:00
|
|
|
m_core->progressManager()->addTask(result, tr("Indexing"),
|
2009-11-26 15:51:10 +01:00
|
|
|
CppTools::Constants::TASK_INDEX);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-12-07 12:03:31 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
return QFuture<void>();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\fn void CppModelManager::editorOpened(Core::IEditor *editor)
|
|
|
|
\brief If a C++ editor is opened, the model manager listens to content changes
|
|
|
|
in order to update the CppCodeModel accordingly. It also updates the
|
|
|
|
CppCodeModel for the first time with this editor.
|
|
|
|
|
|
|
|
\sa void CppModelManager::editorContentsChanged()
|
|
|
|
*/
|
|
|
|
void CppModelManager::editorOpened(Core::IEditor *editor)
|
|
|
|
{
|
|
|
|
if (isCppEditor(editor)) {
|
|
|
|
TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor *>(editor);
|
2008-12-09 15:25:01 +01:00
|
|
|
QTC_ASSERT(textEditor, return);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
CppEditorSupport *editorSupport = new CppEditorSupport(this);
|
|
|
|
editorSupport->setTextEditor(textEditor);
|
|
|
|
m_editorSupport[textEditor] = editorSupport;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CppModelManager::editorAboutToClose(Core::IEditor *editor)
|
|
|
|
{
|
|
|
|
if (isCppEditor(editor)) {
|
|
|
|
TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor *>(editor);
|
2008-12-09 15:25:01 +01:00
|
|
|
QTC_ASSERT(textEditor, return);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
CppEditorSupport *editorSupport = m_editorSupport.value(textEditor);
|
|
|
|
m_editorSupport.remove(textEditor);
|
|
|
|
delete editorSupport;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CppModelManager::isCppEditor(Core::IEditor *editor) const
|
|
|
|
{
|
|
|
|
Core::UniqueIDManager *uidm = m_core->uniqueIDManager();
|
|
|
|
const int uid = uidm->uniqueIdentifier(ProjectExplorer::Constants::LANG_CXX);
|
|
|
|
return editor->context().contains(uid);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CppModelManager::emitDocumentUpdated(Document::Ptr doc)
|
|
|
|
{ emit documentUpdated(doc); }
|
|
|
|
|
|
|
|
void CppModelManager::onDocumentUpdated(Document::Ptr doc)
|
|
|
|
{
|
|
|
|
const QString fileName = doc->fileName();
|
2009-06-02 15:27:13 +02:00
|
|
|
|
2009-07-14 14:23:12 +02:00
|
|
|
bool outdated = false;
|
|
|
|
|
2009-06-02 15:27:13 +02:00
|
|
|
protectSnapshot.lock();
|
2009-07-14 14:23:12 +02:00
|
|
|
|
2009-12-07 10:54:27 +01:00
|
|
|
Document::Ptr previous = m_snapshot.document(fileName);
|
2009-07-14 14:23:12 +02:00
|
|
|
|
|
|
|
if (previous && (doc->revision() != 0 && doc->revision() < previous->revision()))
|
|
|
|
outdated = true;
|
|
|
|
else
|
|
|
|
m_snapshot.insert(doc);
|
|
|
|
|
2009-06-02 15:27:13 +02:00
|
|
|
protectSnapshot.unlock();
|
|
|
|
|
2009-07-14 14:23:12 +02:00
|
|
|
if (outdated)
|
|
|
|
return;
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QList<Core::IEditor *> openedEditors = m_core->editorManager()->openedEditors();
|
|
|
|
foreach (Core::IEditor *editor, openedEditors) {
|
|
|
|
if (editor->file()->fileName() == fileName) {
|
|
|
|
TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor *>(editor);
|
|
|
|
if (! textEditor)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
TextEditor::BaseTextEditor *ed = qobject_cast<TextEditor::BaseTextEditor *>(textEditor->widget());
|
|
|
|
if (! ed)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
QList<TextEditor::BaseTextEditor::BlockRange> blockRanges;
|
|
|
|
|
2009-02-23 12:49:56 +01:00
|
|
|
foreach (const Document::Block &block, doc->skippedBlocks()) {
|
2008-12-02 12:01:29 +01:00
|
|
|
blockRanges.append(TextEditor::BaseTextEditor::BlockRange(block.begin(), block.end()));
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<QTextEdit::ExtraSelection> selections;
|
|
|
|
|
2008-12-04 12:05:04 +01:00
|
|
|
#ifdef QTCREATOR_WITH_MACRO_HIGHLIGHTING
|
|
|
|
// set up the format for the macros
|
|
|
|
QTextCharFormat macroFormat;
|
|
|
|
macroFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline);
|
|
|
|
|
|
|
|
QTextCursor c = ed->textCursor();
|
2009-02-23 12:49:56 +01:00
|
|
|
foreach (const Document::MacroUse &block, doc->macroUses()) {
|
2008-12-04 12:05:04 +01:00
|
|
|
QTextEdit::ExtraSelection sel;
|
|
|
|
sel.cursor = c;
|
|
|
|
sel.cursor.setPosition(block.begin());
|
|
|
|
sel.cursor.setPosition(block.end(), QTextCursor::KeepAnchor);
|
|
|
|
sel.format = macroFormat;
|
|
|
|
selections.append(sel);
|
|
|
|
}
|
|
|
|
#endif // QTCREATOR_WITH_MACRO_HIGHLIGHTING
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
// set up the format for the errors
|
|
|
|
QTextCharFormat errorFormat;
|
|
|
|
errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline);
|
|
|
|
errorFormat.setUnderlineColor(Qt::red);
|
|
|
|
|
|
|
|
// set up the format for the warnings.
|
|
|
|
QTextCharFormat warningFormat;
|
|
|
|
warningFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline);
|
|
|
|
warningFormat.setUnderlineColor(Qt::darkYellow);
|
|
|
|
|
2009-03-03 14:52:09 +01:00
|
|
|
#ifdef QTCREATOR_WITH_ADVANCED_HIGHLIGHTER
|
2009-03-03 13:46:37 +01:00
|
|
|
QSet<QPair<unsigned, unsigned> > lines;
|
2009-02-23 12:49:56 +01:00
|
|
|
foreach (const Document::DiagnosticMessage &m, doc->diagnosticMessages()) {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (m.fileName() != fileName)
|
|
|
|
continue;
|
2009-03-03 13:46:37 +01:00
|
|
|
|
|
|
|
const QPair<unsigned, unsigned> coordinates = qMakePair(m.line(), m.column());
|
|
|
|
|
|
|
|
if (lines.contains(coordinates))
|
2008-12-02 12:01:29 +01:00
|
|
|
continue;
|
|
|
|
|
2009-03-03 13:46:37 +01:00
|
|
|
lines.insert(coordinates);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
QTextEdit::ExtraSelection sel;
|
|
|
|
if (m.isWarning())
|
|
|
|
sel.format = warningFormat;
|
|
|
|
else
|
|
|
|
sel.format = errorFormat;
|
|
|
|
|
|
|
|
QTextCursor c(ed->document()->findBlockByNumber(m.line() - 1));
|
2009-03-03 13:46:37 +01:00
|
|
|
|
|
|
|
// ### check for generated tokens.
|
|
|
|
|
|
|
|
int column = m.column();
|
|
|
|
|
|
|
|
if (column > c.block().length()) {
|
|
|
|
column = 0;
|
|
|
|
|
|
|
|
const QString text = c.block().text();
|
|
|
|
for (int i = 0; i < text.size(); ++i) {
|
|
|
|
if (! text.at(i).isSpace()) {
|
|
|
|
++column;
|
|
|
|
break;
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
2009-03-03 13:46:37 +01:00
|
|
|
|
|
|
|
if (column != 0)
|
|
|
|
--column;
|
|
|
|
|
|
|
|
c.setPosition(c.position() + column);
|
|
|
|
c.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
2008-12-02 12:01:29 +01:00
|
|
|
sel.cursor = c;
|
|
|
|
selections.append(sel);
|
|
|
|
}
|
2009-03-03 14:52:09 +01:00
|
|
|
#else
|
|
|
|
QSet<int> lines;
|
|
|
|
foreach (const Document::DiagnosticMessage &m, doc->diagnosticMessages()) {
|
|
|
|
if (m.fileName() != fileName)
|
|
|
|
continue;
|
|
|
|
else if (lines.contains(m.line()))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
lines.insert(m.line());
|
2009-02-10 22:56:04 +01:00
|
|
|
|
2009-03-03 14:52:09 +01:00
|
|
|
QTextEdit::ExtraSelection sel;
|
|
|
|
if (m.isWarning())
|
|
|
|
sel.format = warningFormat;
|
|
|
|
else
|
|
|
|
sel.format = errorFormat;
|
|
|
|
|
|
|
|
QTextCursor c(ed->document()->findBlockByNumber(m.line() - 1));
|
|
|
|
const QString text = c.block().text();
|
|
|
|
for (int i = 0; i < text.size(); ++i) {
|
|
|
|
if (! text.at(i).isSpace()) {
|
|
|
|
c.setPosition(c.position() + i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
|
|
|
|
sel.cursor = c;
|
|
|
|
selections.append(sel);
|
|
|
|
}
|
|
|
|
#endif
|
2009-02-10 22:56:04 +01:00
|
|
|
QList<Editor> todo;
|
2009-02-23 12:49:56 +01:00
|
|
|
foreach (const Editor &e, todo) {
|
2009-03-02 16:30:25 +01:00
|
|
|
if (e.textEditor != textEditor)
|
2009-02-10 22:56:04 +01:00
|
|
|
todo.append(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
Editor e;
|
2009-07-10 13:57:21 +02:00
|
|
|
e.revision = ed->document()->revision();
|
2009-03-02 16:30:25 +01:00
|
|
|
e.textEditor = textEditor;
|
2009-02-10 22:56:04 +01:00
|
|
|
e.selections = selections;
|
2009-02-23 17:49:03 +01:00
|
|
|
e.ifdefedOutBlocks = blockRanges;
|
2009-02-10 22:56:04 +01:00
|
|
|
todo.append(e);
|
|
|
|
m_todo = todo;
|
|
|
|
postEditorUpdate();
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-10 22:56:04 +01:00
|
|
|
void CppModelManager::postEditorUpdate()
|
|
|
|
{
|
|
|
|
m_updateEditorSelectionsTimer->start(500);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CppModelManager::updateEditorSelections()
|
|
|
|
{
|
2009-02-23 12:49:56 +01:00
|
|
|
foreach (const Editor &ed, m_todo) {
|
2009-03-02 16:30:25 +01:00
|
|
|
if (! ed.textEditor)
|
2009-02-10 22:56:04 +01:00
|
|
|
continue;
|
|
|
|
|
2009-03-02 16:30:25 +01:00
|
|
|
TextEditor::ITextEditor *textEditor = ed.textEditor;
|
|
|
|
TextEditor::BaseTextEditor *editor = qobject_cast<TextEditor::BaseTextEditor *>(textEditor->widget());
|
2009-07-10 13:57:21 +02:00
|
|
|
|
2009-03-02 16:30:25 +01:00
|
|
|
if (! editor)
|
|
|
|
continue;
|
2009-07-10 13:57:21 +02:00
|
|
|
else if (editor->document()->revision() != ed.revision)
|
|
|
|
continue; // outdated
|
2009-03-02 16:30:25 +01:00
|
|
|
|
|
|
|
editor->setExtraSelections(TextEditor::BaseTextEditor::CodeWarningsSelection,
|
|
|
|
ed.selections);
|
2009-02-23 17:49:03 +01:00
|
|
|
|
2009-03-02 16:30:25 +01:00
|
|
|
editor->setIfdefedOutBlocks(ed.ifdefedOutBlocks);
|
2009-02-10 22:56:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
m_todo.clear();
|
2009-03-02 16:30:25 +01:00
|
|
|
|
2009-02-10 22:56:04 +01:00
|
|
|
}
|
|
|
|
|
2008-12-04 17:07:43 +01:00
|
|
|
void CppModelManager::onProjectAdded(ProjectExplorer::Project *)
|
|
|
|
{
|
2008-12-08 10:44:56 +01:00
|
|
|
QMutexLocker locker(&mutex);
|
2008-12-04 17:07:43 +01:00
|
|
|
m_dirty = true;
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void CppModelManager::onAboutToRemoveProject(ProjectExplorer::Project *project)
|
|
|
|
{
|
2008-12-08 10:44:56 +01:00
|
|
|
do {
|
|
|
|
QMutexLocker locker(&mutex);
|
|
|
|
m_dirty = true;
|
|
|
|
m_projects.remove(project);
|
|
|
|
} while (0);
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
GC();
|
|
|
|
}
|
|
|
|
|
2009-08-13 17:10:53 +02:00
|
|
|
void CppModelManager::onAboutToUnloadSession()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2008-12-04 17:07:43 +01:00
|
|
|
if (m_core->progressManager()) {
|
2008-12-02 12:01:29 +01:00
|
|
|
m_core->progressManager()->cancelTasks(CppTools::Constants::TASK_INDEX);
|
2008-12-04 17:07:43 +01:00
|
|
|
}
|
2008-12-08 10:44:56 +01:00
|
|
|
|
|
|
|
do {
|
|
|
|
QMutexLocker locker(&mutex);
|
|
|
|
m_projects.clear();
|
|
|
|
m_dirty = true;
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
GC();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2009-07-24 12:50:10 +02:00
|
|
|
void CppModelManager::updateIncludesInPaths(QFutureInterface<void> &future,
|
|
|
|
CppModelManager *manager,
|
|
|
|
QStringList paths,
|
2009-10-01 17:01:13 +02:00
|
|
|
QStringList frameworkPaths,
|
2009-07-24 12:50:10 +02:00
|
|
|
QStringList suffixes)
|
|
|
|
{
|
|
|
|
QMap<QString, QStringList> entriesInPaths;
|
2009-08-28 16:54:38 +02:00
|
|
|
typedef QPair<QString, QString> SymLink;
|
|
|
|
typedef QList<SymLink> SymLinks;
|
|
|
|
SymLinks symlinks;
|
2009-07-24 12:50:10 +02:00
|
|
|
int processed = 0;
|
|
|
|
|
|
|
|
future.setProgressRange(0, paths.size());
|
|
|
|
|
2009-10-01 17:01:13 +02:00
|
|
|
// Add framework header directories to path list
|
|
|
|
QStringList frameworkFilter;
|
|
|
|
frameworkFilter << QLatin1String("*.framework");
|
|
|
|
QStringListIterator fwPathIt(frameworkPaths);
|
|
|
|
while (fwPathIt.hasNext()) {
|
|
|
|
const QString &fwPath = fwPathIt.next();
|
|
|
|
QStringList entriesInFrameworkPath;
|
|
|
|
const QStringList &frameworks = QDir(fwPath).entryList(frameworkFilter, QDir::Dirs | QDir::NoDotAndDotDot);
|
|
|
|
QStringListIterator fwIt(frameworks);
|
|
|
|
while (fwIt.hasNext()) {
|
|
|
|
QString framework = fwIt.next();
|
|
|
|
paths.append(fwPath + QLatin1Char('/') + framework + QLatin1String("/Headers"));
|
|
|
|
framework.chop(10); // remove the ".framework"
|
|
|
|
entriesInFrameworkPath.append(framework + QLatin1Char('/'));
|
|
|
|
}
|
|
|
|
entriesInPaths.insert(fwPath, entriesInFrameworkPath);
|
|
|
|
}
|
|
|
|
|
2009-07-24 12:50:10 +02:00
|
|
|
while (!paths.isEmpty()) {
|
|
|
|
if (future.isPaused())
|
|
|
|
future.waitForResume();
|
|
|
|
|
|
|
|
if (future.isCanceled())
|
2009-10-13 12:12:51 +02:00
|
|
|
return;
|
2009-07-24 12:50:10 +02:00
|
|
|
|
|
|
|
const QString path = paths.takeFirst();
|
2009-08-28 16:54:38 +02:00
|
|
|
|
|
|
|
// Skip already scanned paths
|
|
|
|
if (entriesInPaths.contains(path))
|
|
|
|
continue;
|
|
|
|
|
2009-07-24 12:50:10 +02:00
|
|
|
QStringList entries;
|
|
|
|
|
|
|
|
QDirIterator i(path, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
|
|
|
|
while (i.hasNext()) {
|
|
|
|
const QString fileName = i.next();
|
|
|
|
const QFileInfo fileInfo = i.fileInfo();
|
|
|
|
const QString suffix = fileInfo.suffix();
|
|
|
|
if (suffix.isEmpty() || suffixes.contains(suffix)) {
|
2009-08-20 19:38:43 +02:00
|
|
|
QString text = fileInfo.fileName();
|
2009-07-24 12:50:10 +02:00
|
|
|
if (fileInfo.isDir()) {
|
|
|
|
text += QLatin1Char('/');
|
|
|
|
|
|
|
|
// Also scan subdirectory, but avoid endless recursion with symbolic links
|
|
|
|
if (fileInfo.isSymLink()) {
|
2009-08-28 16:54:38 +02:00
|
|
|
QString target = fileInfo.symLinkTarget();
|
|
|
|
|
|
|
|
// Don't add broken symlinks
|
|
|
|
if (!QFileInfo(target).exists())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
QMap<QString, QStringList>::const_iterator result = entriesInPaths.find(target);
|
2009-07-24 12:50:10 +02:00
|
|
|
if (result != entriesInPaths.constEnd()) {
|
|
|
|
entriesInPaths.insert(fileName, result.value());
|
|
|
|
} else {
|
2009-08-28 16:54:38 +02:00
|
|
|
paths.append(target);
|
|
|
|
symlinks.append(SymLink(fileName, target));
|
2009-07-24 12:50:10 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
paths.append(fileName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
entries.append(text);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
entriesInPaths.insert(path, entries);
|
|
|
|
|
|
|
|
++processed;
|
|
|
|
future.setProgressRange(0, processed + paths.size());
|
|
|
|
future.setProgressValue(processed);
|
|
|
|
}
|
2009-08-28 16:54:38 +02:00
|
|
|
// link symlinks
|
|
|
|
QListIterator<SymLink> it(symlinks);
|
|
|
|
it.toBack();
|
|
|
|
while (it.hasPrevious()) {
|
|
|
|
SymLink v = it.previous();
|
|
|
|
QMap<QString, QStringList>::const_iterator result = entriesInPaths.find(v.second);
|
|
|
|
entriesInPaths.insert(v.first, result.value());
|
|
|
|
}
|
2009-07-24 12:50:10 +02:00
|
|
|
|
|
|
|
manager->setIncludesInPaths(entriesInPaths);
|
|
|
|
|
|
|
|
future.reportFinished();
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void CppModelManager::parse(QFutureInterface<void> &future,
|
2008-12-04 17:07:43 +01:00
|
|
|
CppPreprocessor *preproc,
|
|
|
|
QStringList files)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-02-09 12:33:43 +01:00
|
|
|
if (files.isEmpty())
|
|
|
|
return;
|
|
|
|
|
2009-02-23 12:49:56 +01:00
|
|
|
Core::MimeDatabase *db = Core::ICore::instance()->mimeDatabase();
|
|
|
|
QStringList headers, sources;
|
|
|
|
Core::MimeType cSourceTy = db->findByType(QLatin1String("text/x-csrc"));
|
|
|
|
Core::MimeType cppSourceTy = db->findByType(QLatin1String("text/x-c++src"));
|
2009-06-29 11:32:43 +02:00
|
|
|
Core::MimeType mSourceTy = db->findByType(QLatin1String("text/x-objcsrc"));
|
2009-02-23 12:49:56 +01:00
|
|
|
|
2009-03-16 12:31:34 +01:00
|
|
|
Core::MimeType cHeaderTy = db->findByType(QLatin1String("text/x-hdr"));
|
|
|
|
Core::MimeType cppHeaderTy = db->findByType(QLatin1String("text/x-c++hdr"));
|
|
|
|
|
2009-02-23 12:49:56 +01:00
|
|
|
foreach (const QString &file, files) {
|
|
|
|
const QFileInfo fileInfo(file);
|
|
|
|
|
2009-06-29 11:32:43 +02:00
|
|
|
if (cSourceTy.matchesFile(fileInfo) || cppSourceTy.matchesFile(fileInfo) || mSourceTy.matchesFile(fileInfo))
|
2009-02-23 12:49:56 +01:00
|
|
|
sources.append(file);
|
|
|
|
|
2009-03-16 12:31:34 +01:00
|
|
|
else if (cHeaderTy.matchesFile(fileInfo) || cppHeaderTy.matchesFile(fileInfo))
|
2009-02-23 12:49:56 +01:00
|
|
|
headers.append(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (const QString &file, files) {
|
2009-02-09 12:33:43 +01:00
|
|
|
preproc->snapshot.remove(file);
|
|
|
|
}
|
2008-12-03 16:18:33 +01:00
|
|
|
|
2009-02-23 12:49:56 +01:00
|
|
|
files = sources;
|
|
|
|
files += headers;
|
|
|
|
|
2009-02-23 15:57:37 +01:00
|
|
|
preproc->setTodo(files);
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
future.setProgressRange(0, files.size());
|
|
|
|
|
|
|
|
QString conf = QLatin1String(pp_configuration_file);
|
|
|
|
|
2009-02-23 12:49:56 +01:00
|
|
|
bool processingHeaders = false;
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
for (int i = 0; i < files.size(); ++i) {
|
|
|
|
if (future.isPaused())
|
|
|
|
future.waitForResume();
|
|
|
|
|
|
|
|
if (future.isCanceled())
|
|
|
|
break;
|
|
|
|
|
2009-02-24 12:06:09 +01:00
|
|
|
// Change the priority of the background parser thread to idle.
|
|
|
|
QThread::currentThread()->setPriority(QThread::IdlePriority);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
QString fileName = files.at(i);
|
2009-02-23 12:49:56 +01:00
|
|
|
|
|
|
|
bool isSourceFile = false;
|
|
|
|
if (cppSourceTy.matchesFile(fileName) || cSourceTy.matchesFile(fileName))
|
|
|
|
isSourceFile = true;
|
|
|
|
|
|
|
|
if (isSourceFile)
|
|
|
|
(void) preproc->run(conf);
|
|
|
|
|
|
|
|
else if (! processingHeaders) {
|
|
|
|
(void) preproc->run(conf);
|
|
|
|
|
|
|
|
processingHeaders = true;
|
|
|
|
}
|
|
|
|
|
2008-12-04 17:07:43 +01:00
|
|
|
preproc->run(fileName);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-02-23 15:57:37 +01:00
|
|
|
future.setProgressValue(files.size() - preproc->todo().size());
|
|
|
|
|
2009-02-23 12:49:56 +01:00
|
|
|
if (isSourceFile)
|
|
|
|
preproc->resetEnvironment();
|
|
|
|
|
2009-02-24 12:06:09 +01:00
|
|
|
// Restore the previous thread priority.
|
|
|
|
QThread::currentThread()->setPriority(QThread::NormalPriority);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2008-12-03 16:18:33 +01:00
|
|
|
future.setProgressValue(files.size());
|
|
|
|
|
2008-12-04 17:07:43 +01:00
|
|
|
delete preproc;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CppModelManager::GC()
|
|
|
|
{
|
2009-06-02 15:27:13 +02:00
|
|
|
protectSnapshot.lock();
|
2009-12-07 10:54:27 +01:00
|
|
|
Snapshot currentSnapshot = m_snapshot;
|
2009-06-02 15:27:13 +02:00
|
|
|
protectSnapshot.unlock();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
QSet<QString> processed;
|
2008-12-04 17:07:43 +01:00
|
|
|
QStringList todo = projectFiles();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
while (! todo.isEmpty()) {
|
|
|
|
QString fn = todo.last();
|
|
|
|
todo.removeLast();
|
|
|
|
|
|
|
|
if (processed.contains(fn))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
processed.insert(fn);
|
|
|
|
|
2009-12-07 10:54:27 +01:00
|
|
|
if (Document::Ptr doc = currentSnapshot.document(fn)) {
|
2008-12-02 12:01:29 +01:00
|
|
|
todo += doc->includedFiles();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList removedFiles;
|
2009-12-07 10:54:27 +01:00
|
|
|
|
|
|
|
Snapshot newSnapshot;
|
|
|
|
for (Snapshot::const_iterator it = currentSnapshot.begin(); it != currentSnapshot.end(); ++it) {
|
|
|
|
const QString fileName = it.key();
|
|
|
|
|
|
|
|
if (processed.contains(fileName))
|
|
|
|
newSnapshot.insert(it.value());
|
|
|
|
else
|
|
|
|
removedFiles.append(fileName);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
emit aboutToRemoveFiles(removedFiles);
|
2009-06-02 15:27:13 +02:00
|
|
|
|
|
|
|
protectSnapshot.lock();
|
2009-12-07 10:54:27 +01:00
|
|
|
m_snapshot = newSnapshot;
|
2009-06-02 15:27:13 +02:00
|
|
|
protectSnapshot.unlock();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|