2009-02-25 09:15:00 +01:00
|
|
|
/**************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
**
|
2012-01-26 18:33:46 +01:00
|
|
|
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2011-11-02 15:59:12 +01:00
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
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
|
|
|
**
|
2011-04-13 08:42:33 +02:00
|
|
|
** 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
|
|
|
**
|
2010-12-17 16:01:08 +01:00
|
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
2011-04-13 08:42:33 +02:00
|
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
**
|
2011-04-13 08:42:33 +02:00
|
|
|
** Other Usage
|
|
|
|
**
|
|
|
|
** Alternatively, this file may be used in accordance with the terms and
|
|
|
|
** conditions contained in a signed written agreement between you and Nokia.
|
|
|
|
**
|
2010-12-17 16:01:08 +01:00
|
|
|
** If you have questions regarding the use of this file, please contact
|
2011-11-02 15:59:12 +01:00
|
|
|
** Nokia at qt-info@nokia.com.
|
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-04 11:32:01 +02:00
|
|
|
#include <cplusplus/Overview.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
#include "cppmodelmanager.h"
|
2012-02-21 10:00:32 +01:00
|
|
|
#include "cppcompletionassist.h"
|
2012-02-20 12:39:08 +01:00
|
|
|
#include "cpphighlightingsupport.h"
|
|
|
|
#include "cpphighlightingsupportinternal.h"
|
2010-12-03 13:49:35 +01:00
|
|
|
#include "abstracteditorsupport.h"
|
2010-02-03 13:21:08 +10:00
|
|
|
#ifndef ICHECK_BUILD
|
|
|
|
# include "cpptoolsconstants.h"
|
|
|
|
# include "cpptoolseditorsupport.h"
|
|
|
|
# include "cppfindreferences.h"
|
|
|
|
#endif
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-03-06 11:51:45 +01:00
|
|
|
#include <functional>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QtConcurrentRun>
|
2010-02-03 13:21:08 +10:00
|
|
|
#ifndef ICHECK_BUILD
|
2012-02-15 10:42:41 +01:00
|
|
|
# include <QFutureSynchronizer>
|
2012-02-09 09:35:03 +01:00
|
|
|
# include <utils/runextensions.h>
|
2010-02-03 13:21:08 +10: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/mimedatabase.h>
|
|
|
|
# include <coreplugin/editormanager/editormanager.h>
|
|
|
|
# include <coreplugin/progressmanager/progressmanager.h>
|
|
|
|
# include <extensionsystem/pluginmanager.h>
|
|
|
|
#else
|
2012-02-15 10:42:41 +01:00
|
|
|
# include <QDir>
|
2010-02-03 13:21:08 +10:00
|
|
|
#endif
|
2009-10-05 13:43:05 +02:00
|
|
|
|
2008-12-09 15:25:01 +01:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <TranslationUnit.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>
|
2010-03-18 15:21:07 +01:00
|
|
|
#include <Parser.h>
|
|
|
|
#include <Control.h>
|
2010-12-03 10:13:15 +01:00
|
|
|
#include <CoreTypes.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QCoreApplication>
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QMutexLocker>
|
|
|
|
#include <QTime>
|
|
|
|
#include <QTimer>
|
2009-02-24 11:04:52 +01:00
|
|
|
#include <QtConcurrentMap>
|
2010-04-26 14:02:09 +02:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QTextBlock>
|
2010-04-26 14:02:09 +02:00
|
|
|
|
2009-02-18 16:01:28 +01:00
|
|
|
#include <iostream>
|
|
|
|
#include <sstream>
|
2008-12-09 15:25:01 +01:00
|
|
|
|
2012-02-16 15:09:56 +01:00
|
|
|
namespace CPlusPlus {
|
|
|
|
uint qHash(const CppModelManagerInterface::ProjectPart &p)
|
|
|
|
{
|
2012-03-14 10:25:55 +01:00
|
|
|
uint h = qHash(p.defines) ^ p.language ^ ((int) p.cxx11Enabled);
|
2012-02-16 15:09:56 +01:00
|
|
|
|
|
|
|
foreach (const QString &i, p.includePaths)
|
|
|
|
h ^= qHash(i);
|
|
|
|
|
|
|
|
foreach (const QString &f, p.frameworkPaths)
|
|
|
|
h ^= qHash(f);
|
|
|
|
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
bool operator==(const CppModelManagerInterface::ProjectPart &p1,
|
|
|
|
const CppModelManagerInterface::ProjectPart &p2)
|
|
|
|
{
|
|
|
|
if (p1.defines != p2.defines)
|
|
|
|
return false;
|
|
|
|
if (p1.language != p2.language)
|
|
|
|
return false;
|
2012-03-14 10:25:55 +01:00
|
|
|
if (p1.cxx11Enabled != p2.cxx11Enabled)
|
2012-02-16 15:09:56 +01:00
|
|
|
return false;
|
|
|
|
if (p1.includePaths != p2.includePaths)
|
|
|
|
return false;
|
|
|
|
return p1.frameworkPaths == p2.frameworkPaths;
|
|
|
|
}
|
|
|
|
} // namespace CPlusPlus
|
|
|
|
|
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"
|
2009-12-10 16:20:34 +01:00
|
|
|
"#define __stdcall\n"
|
2008-12-02 12:01:29 +01:00
|
|
|
"#define QT_WA(x) x\n"
|
|
|
|
"#define CALLBACK\n"
|
|
|
|
"#define STDMETHODCALLTYPE\n"
|
|
|
|
"#define __RPC_FAR\n"
|
|
|
|
"#define __declspec(a)\n"
|
2011-09-06 16:45:47 +02:00
|
|
|
"#define STDMETHOD(method) virtual HRESULT STDMETHODCALLTYPE method\n"
|
|
|
|
"#define __try try\n"
|
|
|
|
"#define __except catch\n"
|
2011-09-08 11:30:48 +02:00
|
|
|
"#define __finally\n"
|
|
|
|
"#define __inline inline\n"
|
|
|
|
"#define __forceinline inline\n";
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-01-19 15:26:08 +10:00
|
|
|
#ifndef ICHECK_BUILD
|
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)
|
2011-08-23 14:05:47 +02:00
|
|
|
{
|
|
|
|
preprocess.setKeepComments(true);
|
|
|
|
}
|
2009-03-11 12:00:07 +01:00
|
|
|
|
2010-01-19 15:26:08 +10:00
|
|
|
#else
|
|
|
|
|
|
|
|
CppPreprocessor::CppPreprocessor(QPointer<CPlusPlus::ParseManager> modelManager)
|
|
|
|
: preprocess(this, &env),
|
|
|
|
m_revision(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
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; }
|
|
|
|
|
2010-12-03 13:49:35 +01:00
|
|
|
void CppPreprocessor::setWorkingCopy(const CppModelManagerInterface::WorkingCopy &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)
|
2010-03-15 18:09:29 +01:00
|
|
|
{
|
|
|
|
m_includePaths.clear();
|
|
|
|
|
|
|
|
for (int i = 0; i < includePaths.size(); ++i) {
|
2010-03-17 14:49:42 +01:00
|
|
|
const QString &path = includePaths.at(i);
|
2010-03-15 18:09:29 +01:00
|
|
|
|
|
|
|
#ifdef Q_OS_DARWIN
|
|
|
|
if (i + 1 < includePaths.size() && path.endsWith(QLatin1String(".framework/Headers"))) {
|
|
|
|
const QFileInfo pathInfo(path);
|
|
|
|
const QFileInfo frameworkFileInfo(pathInfo.path());
|
|
|
|
const QString frameworkName = frameworkFileInfo.baseName();
|
|
|
|
|
|
|
|
const QFileInfo nextIncludePath = includePaths.at(i + 1);
|
|
|
|
if (nextIncludePath.fileName() == frameworkName) {
|
|
|
|
// We got a QtXXX.framework/Headers followed by $QTDIR/include/QtXXX.
|
|
|
|
// In this case we prefer to include files from $QTDIR/include/QtXXX.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_includePaths.append(path);
|
|
|
|
#else
|
|
|
|
m_includePaths.append(path);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
2008-12-08 11:08:48 +01:00
|
|
|
|
|
|
|
void CppPreprocessor::setFrameworkPaths(const QStringList &frameworkPaths)
|
2010-04-13 11:14:34 +02:00
|
|
|
{
|
|
|
|
m_frameworkPaths.clear();
|
|
|
|
|
|
|
|
foreach (const QString &frameworkPath, frameworkPaths) {
|
|
|
|
addFrameworkPath(frameworkPath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the given framework path, and expand private frameworks.
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
// <framework-path>/ApplicationServices.framework
|
|
|
|
// has private frameworks in:
|
|
|
|
// <framework-path>/ApplicationServices.framework/Frameworks
|
|
|
|
// if the "Frameworks" folder exists inside the top level framework.
|
|
|
|
void CppPreprocessor::addFrameworkPath(const QString &frameworkPath)
|
|
|
|
{
|
|
|
|
// The algorithm below is a bit too eager, but that's because we're not getting
|
|
|
|
// in the frameworks we're linking against. If we would have that, then we could
|
|
|
|
// add only those private frameworks.
|
|
|
|
if (!m_frameworkPaths.contains(frameworkPath)) {
|
|
|
|
m_frameworkPaths.append(frameworkPath);
|
|
|
|
}
|
|
|
|
|
|
|
|
const QDir frameworkDir(frameworkPath);
|
|
|
|
const QStringList filter = QStringList() << QLatin1String("*.framework");
|
|
|
|
foreach (const QFileInfo &framework, frameworkDir.entryInfoList(filter)) {
|
|
|
|
if (!framework.isDir())
|
|
|
|
continue;
|
|
|
|
const QFileInfo privateFrameworks(framework.absoluteFilePath(), QLatin1String("Frameworks"));
|
|
|
|
if (privateFrameworks.exists() && privateFrameworks.isDir()) {
|
|
|
|
addFrameworkPath(privateFrameworks.absoluteFilePath());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
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); }
|
|
|
|
|
2010-01-19 15:26:08 +10:00
|
|
|
#ifndef ICHECK_BUILD
|
2010-02-03 13:21:08 +10: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;
|
|
|
|
Document::Ptr _doc;
|
2010-05-10 10:19:37 +02:00
|
|
|
Document::CheckMode _mode;
|
2009-02-24 11:04:52 +01:00
|
|
|
|
|
|
|
public:
|
2009-06-02 16:50:43 +02:00
|
|
|
Process(QPointer<CppModelManager> modelManager,
|
2010-05-10 10:19:37 +02:00
|
|
|
Document::Ptr doc,
|
|
|
|
const Snapshot &snapshot,
|
2009-12-15 15:26:40 +01:00
|
|
|
const CppModelManager::WorkingCopy &workingCopy)
|
2009-06-02 16:50:43 +02:00
|
|
|
: _modelManager(modelManager),
|
|
|
|
_snapshot(snapshot),
|
2010-05-10 10:19:37 +02:00
|
|
|
_doc(doc),
|
|
|
|
_mode(Document::FastCheck)
|
2009-06-02 16:50:43 +02:00
|
|
|
{
|
2009-06-26 09:11:14 +02:00
|
|
|
|
2010-05-10 10:19:37 +02:00
|
|
|
if (workingCopy.contains(_doc->fileName()))
|
|
|
|
_mode = Document::FullCheck;
|
|
|
|
}
|
2009-06-26 09:11:14 +02:00
|
|
|
|
2010-05-10 10:19:37 +02:00
|
|
|
void operator()()
|
|
|
|
{
|
|
|
|
_doc->check(_mode);
|
2010-09-02 12:50:37 +02:00
|
|
|
|
2009-02-24 11:04:52 +01:00
|
|
|
if (_modelManager)
|
2010-05-10 10:19:37 +02:00
|
|
|
_modelManager->emitDocumentUpdated(_doc); // ### TODO: compress
|
2011-08-23 12:02:29 +02:00
|
|
|
|
|
|
|
_doc->releaseSourceAndAST();
|
2009-02-24 11:04:52 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end of anonymous namespace
|
2010-02-03 13:21:08 +10:00
|
|
|
#endif
|
2009-02-24 11:04:52 +01:00
|
|
|
|
|
|
|
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-12-15 15:52:55 +01:00
|
|
|
bool CppPreprocessor::includeFile(const QString &absoluteFilePath, QString *result, unsigned *revision)
|
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);
|
2009-12-15 15:52:55 +01:00
|
|
|
const QPair<QString, unsigned> r = m_workingCopy.get(absoluteFilePath);
|
|
|
|
*result = r.first;
|
|
|
|
*revision = r.second;
|
2008-12-08 11:08:48 +01:00
|
|
|
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);
|
2011-09-06 11:28:47 +02:00
|
|
|
if (file.open(QFile::ReadOnly | QFile::Text)) {
|
2008-12-08 11:08:48 +01:00
|
|
|
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-12-15 15:52:55 +01:00
|
|
|
QString CppPreprocessor::tryIncludeFile(QString &fileName, IncludeType type, unsigned *revision)
|
2010-05-10 09:54:30 +02:00
|
|
|
{
|
|
|
|
if (type == IncludeGlobal) {
|
|
|
|
const QString fn = m_fileNameCache.value(fileName);
|
|
|
|
|
|
|
|
if (! fn.isEmpty()) {
|
|
|
|
fileName = fn;
|
|
|
|
|
|
|
|
if (revision)
|
|
|
|
*revision = 0;
|
|
|
|
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const QString originalFileName = fileName;
|
|
|
|
const QString contents = tryIncludeFile_helper(fileName, type, revision);
|
|
|
|
if (type == IncludeGlobal)
|
|
|
|
m_fileNameCache.insert(originalFileName, fileName);
|
|
|
|
return contents;
|
|
|
|
}
|
|
|
|
|
2010-10-03 09:23:48 +02:00
|
|
|
static inline void appendDirSeparatorIfNeeded(QString &path)
|
|
|
|
{
|
|
|
|
if (!path.endsWith(QLatin1Char('/'), Qt::CaseInsensitive))
|
|
|
|
path += QLatin1Char('/');
|
|
|
|
}
|
|
|
|
|
2010-05-10 09:54:30 +02:00
|
|
|
QString CppPreprocessor::tryIncludeFile_helper(QString &fileName, IncludeType type, unsigned *revision)
|
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;
|
2009-12-15 15:52:55 +01:00
|
|
|
includeFile(fileName, &contents, revision);
|
2008-12-08 11:08:48 +01:00
|
|
|
return contents;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type == IncludeLocal && m_currentDoc) {
|
|
|
|
QFileInfo currentFileInfo(m_currentDoc->fileName());
|
|
|
|
QString path = currentFileInfo.absolutePath();
|
2010-10-03 09:23:48 +02:00
|
|
|
appendDirSeparatorIfNeeded(path);
|
2008-12-08 11:08:48 +01:00
|
|
|
path += fileName;
|
|
|
|
path = QDir::cleanPath(path);
|
2009-06-15 15:38:20 +02:00
|
|
|
QString contents;
|
2009-12-15 15:52:55 +01:00
|
|
|
if (includeFile(path, &contents, revision)) {
|
2008-12-08 11:08:48 +01:00
|
|
|
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;
|
2010-10-03 09:23:48 +02:00
|
|
|
appendDirSeparatorIfNeeded(path);
|
2008-12-08 11:08:48 +01:00
|
|
|
path += fileName;
|
|
|
|
path = QDir::cleanPath(path);
|
2009-06-15 15:38:20 +02:00
|
|
|
QString contents;
|
2009-12-15 15:52:55 +01:00
|
|
|
if (includeFile(path, &contents, revision)) {
|
2008-12-08 11:08:48 +01:00
|
|
|
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;
|
2010-10-03 09:23:48 +02:00
|
|
|
appendDirSeparatorIfNeeded(path);
|
2008-12-08 11:08:48 +01:00
|
|
|
path += fileName;
|
|
|
|
path = QDir::cleanPath(path);
|
2009-06-15 15:38:20 +02:00
|
|
|
QString contents;
|
2009-12-15 15:52:55 +01:00
|
|
|
if (includeFile(path, &contents, revision)) {
|
2008-12-08 11:08:48 +01:00
|
|
|
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;
|
2010-10-03 09:23:48 +02:00
|
|
|
appendDirSeparatorIfNeeded(path);
|
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;
|
2009-12-15 15:52:55 +01:00
|
|
|
if (includeFile(path, &contents, revision)) {
|
2008-12-02 12:01:29 +01:00
|
|
|
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;
|
2009-12-15 15:52:55 +01:00
|
|
|
includeFile(fileName, &contents, revision);
|
2008-12-08 11:08:48 +01:00
|
|
|
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;
|
|
|
|
|
2009-12-21 14:47:22 +01:00
|
|
|
m_currentDoc->addMacroUse(macro, offset, macro.name().length(), env.currentLine,
|
2009-09-25 16:00:14 +02:00
|
|
|
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;
|
2009-12-21 14:47:22 +01:00
|
|
|
m_currentDoc->addMacroUse(macro, offset, originalText.length(), env.currentLine,
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2009-12-15 15:52:55 +01:00
|
|
|
void CppPreprocessor::sourceNeeded(QString &fileName, IncludeType type, unsigned line)
|
2008-12-08 11:08:48 +01:00
|
|
|
{
|
|
|
|
if (fileName.isEmpty())
|
|
|
|
return;
|
|
|
|
|
2009-12-15 15:52:55 +01:00
|
|
|
unsigned editorRevision = 0;
|
|
|
|
QString contents = tryIncludeFile(fileName, type, &editorRevision);
|
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);
|
2009-12-15 15:52:55 +01:00
|
|
|
doc->setEditorRevision(editorRevision);
|
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
|
|
|
|
2012-01-12 17:53:56 +01:00
|
|
|
doc->setUtf8Source(preprocessedCode);
|
2011-08-23 12:02:29 +02:00
|
|
|
doc->keepSourceAndAST();
|
2009-02-24 11:04:52 +01:00
|
|
|
doc->tokenize();
|
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
|
|
|
|
2010-01-19 15:26:08 +10:00
|
|
|
#ifndef ICHECK_BUILD
|
2010-05-10 10:19:37 +02:00
|
|
|
Process process(m_modelManager, doc, snapshot, m_workingCopy);
|
2009-03-17 14:39:52 +01:00
|
|
|
|
2010-05-10 10:19:37 +02:00
|
|
|
process();
|
2009-02-23 12:49:56 +01:00
|
|
|
|
|
|
|
(void) switchDocument(previousDoc);
|
2010-01-19 15:26:08 +10:00
|
|
|
#else
|
2010-12-03 10:13:15 +01:00
|
|
|
doc->releaseSource();
|
2010-01-19 15:26:08 +10:00
|
|
|
Document::CheckMode mode = Document::FastCheck;
|
|
|
|
mode = Document::FullCheck;
|
|
|
|
doc->parse();
|
|
|
|
doc->check(mode);
|
2010-04-23 15:25:05 +02:00
|
|
|
|
|
|
|
(void) switchDocument(previousDoc);
|
2010-01-19 15:26:08 +10:00
|
|
|
#endif
|
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
|
|
|
|
2010-01-19 15:26:08 +10:00
|
|
|
#ifndef ICHECK_BUILD
|
2010-12-03 13:49:35 +01:00
|
|
|
void CppModelManager::updateModifiedSourceFiles()
|
2009-11-05 12:34:02 +01:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-12-03 13:49:35 +01:00
|
|
|
CppModelManager *CppModelManager::instance()
|
2009-10-05 13:43:05 +02:00
|
|
|
{
|
|
|
|
ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance();
|
2010-12-03 13:49:35 +01:00
|
|
|
return pluginManager->getObject<CppModelManager>();
|
2009-10-05 13:43:05 +02:00
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
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();
|
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*)));
|
|
|
|
|
2012-03-05 22:30:59 +01:00
|
|
|
connect(session, SIGNAL(aboutToRemoveProject(ProjectExplorer::Project*)),
|
|
|
|
this, SLOT(onAboutToRemoveProject(ProjectExplorer::Project*)));
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-02-10 12:46:33 +01:00
|
|
|
connect(session, SIGNAL(aboutToUnloadSession(QString)),
|
2009-08-13 17:10:53 +02:00
|
|
|
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)));
|
2011-08-31 09:58:40 +02:00
|
|
|
connect(this, SIGNAL(extraDiagnosticsUpdated(QString)),
|
|
|
|
this, SLOT(onExtraDiagnosticsUpdated(QString)));
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
// Listen for editor closed and opened events so that we can keep track of changing files
|
2012-03-05 22:30:59 +01:00
|
|
|
connect(Core::ICore::editorManager(), SIGNAL(editorOpened(Core::IEditor*)),
|
|
|
|
this, SLOT(editorOpened(Core::IEditor*)));
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-03-05 22:30:59 +01:00
|
|
|
connect(Core::ICore::editorManager(), SIGNAL(editorAboutToClose(Core::IEditor*)),
|
|
|
|
this, SLOT(editorAboutToClose(Core::IEditor*)));
|
2012-02-20 12:39:08 +01:00
|
|
|
|
2012-02-21 10:00:32 +01:00
|
|
|
m_completionFallback = new InternalCompletionAssistProvider;
|
|
|
|
m_completionAssistProvider = m_completionFallback;
|
|
|
|
ExtensionSystem::PluginManager::instance()->addObject(m_completionAssistProvider);
|
2012-02-20 12:39:08 +01:00
|
|
|
m_highlightingFallback = new CppHighlightingSupportInternalFactory;
|
|
|
|
m_highlightingFactory = m_highlightingFallback;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
CppModelManager::~CppModelManager()
|
2012-02-20 12:39:08 +01:00
|
|
|
{
|
2012-02-21 10:00:32 +01:00
|
|
|
ExtensionSystem::PluginManager::instance()->removeObject(m_completionAssistProvider);
|
2012-02-20 12:39:08 +01:00
|
|
|
delete m_completionFallback;
|
|
|
|
delete m_highlightingFallback;
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
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();
|
2012-02-16 15:09:56 +01:00
|
|
|
foreach (const ProjectPart::Ptr &part, pinfo.projectParts())
|
|
|
|
files += part->sourceFiles;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
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();
|
2012-02-16 15:09:56 +01:00
|
|
|
foreach (const ProjectPart::Ptr &part, pinfo.projectParts())
|
|
|
|
includePaths += part->includePaths;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
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();
|
2012-02-16 15:09:56 +01:00
|
|
|
foreach (const ProjectPart::Ptr &part, pinfo.projectParts())
|
|
|
|
frameworkPaths += part->frameworkPaths;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
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();
|
2012-02-16 15:09:56 +01:00
|
|
|
foreach (const ProjectPart::Ptr &part, pinfo.projectParts())
|
|
|
|
macros += part->defines;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
return macros;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-05-31 12:09:28 +02:00
|
|
|
QList<int> CppModelManager::references(CPlusPlus::Symbol *symbol, const LookupContext &context)
|
2009-09-30 13:25:40 +02:00
|
|
|
{
|
2010-05-31 12:09:28 +02:00
|
|
|
return m_findReferences->references(symbol, context);
|
2009-09-30 13:25:40 +02:00
|
|
|
}
|
|
|
|
|
2010-05-31 12:09:28 +02:00
|
|
|
void CppModelManager::findUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context)
|
2009-08-07 13:02:36 +02:00
|
|
|
{
|
2009-09-24 16:51:40 +02:00
|
|
|
if (symbol->identifier())
|
2010-05-31 12:09:28 +02:00
|
|
|
m_findReferences->findUsages(symbol, context);
|
2009-10-05 15:17:25 +02:00
|
|
|
}
|
|
|
|
|
2010-07-20 11:02:37 +02:00
|
|
|
void CppModelManager::renameUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context,
|
|
|
|
const QString &replacement)
|
2009-10-05 15:17:25 +02:00
|
|
|
{
|
|
|
|
if (symbol->identifier())
|
2010-07-20 11:02:37 +02:00
|
|
|
m_findReferences->renameUsages(symbol, context, replacement);
|
2009-08-07 13:02:36 +02:00
|
|
|
}
|
|
|
|
|
2009-12-21 14:54:10 +01:00
|
|
|
void CppModelManager::findMacroUsages(const CPlusPlus::Macro ¯o)
|
|
|
|
{
|
|
|
|
m_findReferences->findMacroUses(macro);
|
|
|
|
}
|
|
|
|
|
2009-12-15 15:16:46 +01:00
|
|
|
CppModelManager::WorkingCopy CppModelManager::buildWorkingCopyList()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-12-15 15:16:46 +01:00
|
|
|
WorkingCopy 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();
|
2012-02-14 16:43:51 +01:00
|
|
|
QString fileName = textEditor->document()->fileName();
|
2009-12-15 15:52:55 +01:00
|
|
|
workingCopy.insert(fileName, editorSupport->contents(), editorSupport->editorRevision());
|
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();
|
2009-12-15 15:26:40 +01:00
|
|
|
workingCopy.insert(es->fileName(), es->contents());
|
2009-05-12 13:45:24 +02:00
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
// add the project configuration file
|
|
|
|
QByteArray conf(pp_configuration);
|
|
|
|
conf += definedMacros();
|
2009-12-15 15:26:40 +01:00
|
|
|
workingCopy.insert(pp_configuration_file, conf);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
return workingCopy;
|
|
|
|
}
|
|
|
|
|
2009-12-15 15:16:46 +01:00
|
|
|
CppModelManager::WorkingCopy CppModelManager::workingCopy() const
|
2009-10-12 10:38:00 +02:00
|
|
|
{
|
|
|
|
return const_cast<CppModelManager *>(this)->buildWorkingCopyList();
|
|
|
|
}
|
|
|
|
|
2010-03-02 12:51:47 +01:00
|
|
|
QFuture<void> CppModelManager::updateSourceFiles(const QStringList &sourceFiles)
|
|
|
|
{ return refreshSourceFiles(sourceFiles); }
|
2008-12-02 12:01:29 +01:00
|
|
|
|
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)
|
|
|
|
{
|
2012-02-16 15:09:56 +01:00
|
|
|
#if 0
|
|
|
|
// Tons of debug output...
|
|
|
|
qDebug()<<"========= CppModelManager::updateProjectInfo ======";
|
|
|
|
qDebug()<<" for project:"<< pinfo.project.data()->file()->fileName();
|
|
|
|
foreach (const ProjectPart::Ptr &part, pinfo.projectParts) {
|
|
|
|
qDebug() << "=== part ===";
|
|
|
|
qDebug() << "language:" << (part->language == CXX ? "C++" : "ObjC++");
|
|
|
|
qDebug() << "compilerflags:" << part->flags;
|
|
|
|
qDebug() << "precompiled header:" << part->precompiledHeaders;
|
|
|
|
qDebug() << "defines:" << part->defines;
|
|
|
|
qDebug() << "includes:" << part->includePaths;
|
|
|
|
qDebug() << "frameworkPaths:" << part->frameworkPaths;
|
|
|
|
qDebug() << "sources:" << part->sourceFiles;
|
|
|
|
qDebug() << "";
|
|
|
|
}
|
|
|
|
|
|
|
|
qDebug() << "";
|
|
|
|
#endif
|
2008-12-08 10:44:56 +01:00
|
|
|
QMutexLocker locker(&mutex);
|
|
|
|
|
|
|
|
if (! pinfo.isValid())
|
|
|
|
return;
|
|
|
|
|
2012-02-16 15:09:56 +01:00
|
|
|
ProjectExplorer::Project *project = pinfo.project().data();
|
|
|
|
m_projects.insert(project, pinfo);
|
2008-12-08 14:48:51 +01:00
|
|
|
m_dirty = true;
|
2012-02-16 15:09:56 +01:00
|
|
|
|
|
|
|
m_srcToProjectPart.clear();
|
|
|
|
|
2012-02-23 13:58:34 +01:00
|
|
|
foreach (const ProjectInfo &projectInfo, m_projects.values())
|
|
|
|
foreach (const ProjectPart::Ptr &projectPart, projectInfo.projectParts())
|
|
|
|
foreach (const QString &sourceFile, projectPart->sourceFiles)
|
|
|
|
m_srcToProjectPart[sourceFile].append(projectPart);
|
2012-02-16 15:09:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QList<CppModelManager::ProjectPart::Ptr> CppModelManager::projectPart(const QString &fileName) const
|
|
|
|
{
|
|
|
|
QList<CppModelManager::ProjectPart::Ptr> parts = m_srcToProjectPart.value(fileName);
|
|
|
|
if (!parts.isEmpty())
|
|
|
|
return parts;
|
|
|
|
|
|
|
|
//### FIXME: This is a DIRTY hack!
|
|
|
|
if (fileName.endsWith(".h")) {
|
|
|
|
QString cppFile = fileName.mid(0, fileName.length() - 2) + QLatin1String(".cpp");
|
|
|
|
parts = m_srcToProjectPart.value(cppFile);
|
|
|
|
if (!parts.isEmpty())
|
|
|
|
return parts;
|
|
|
|
}
|
|
|
|
|
|
|
|
DependencyTable table;
|
|
|
|
table.build(snapshot());
|
|
|
|
QStringList deps = table.filesDependingOn(fileName);
|
|
|
|
foreach (const QString &dep, deps) {
|
|
|
|
parts = m_srcToProjectPart.value(dep);
|
|
|
|
if (!parts.isEmpty())
|
|
|
|
return parts;
|
|
|
|
}
|
|
|
|
|
|
|
|
return parts;
|
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-15 15:16:46 +01:00
|
|
|
const WorkingCopy 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();
|
|
|
|
|
2010-02-01 14:00:07 +01:00
|
|
|
foreach (const QFuture<void> &future, futures) {
|
2009-03-11 12:21:02 +01:00
|
|
|
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) {
|
2012-01-24 15:36:40 +01:00
|
|
|
Core::ICore::progressManager()->addTask(result, tr("Parsing"),
|
|
|
|
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
|
|
|
|
{
|
2010-06-25 17:37:59 +02:00
|
|
|
return editor->context().contains(ProjectExplorer::Constants::LANG_CXX);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CppModelManager::emitDocumentUpdated(Document::Ptr doc)
|
2010-06-25 17:37:59 +02:00
|
|
|
{
|
|
|
|
emit documentUpdated(doc);
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2011-08-31 09:58:40 +02:00
|
|
|
updateEditor(doc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CppModelManager::onExtraDiagnosticsUpdated(const QString &fileName)
|
|
|
|
{
|
|
|
|
protectSnapshot.lock();
|
|
|
|
Document::Ptr doc = m_snapshot.document(fileName);
|
|
|
|
protectSnapshot.unlock();
|
|
|
|
if (doc)
|
|
|
|
updateEditor(doc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CppModelManager::updateEditor(Document::Ptr doc)
|
|
|
|
{
|
|
|
|
const QString fileName = doc->fileName();
|
|
|
|
|
2012-01-24 15:36:40 +01:00
|
|
|
QList<Core::IEditor *> openedEditors = Core::ICore::editorManager()->openedEditors();
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (Core::IEditor *editor, openedEditors) {
|
2012-02-14 16:43:51 +01:00
|
|
|
if (editor->document()->fileName() == fileName) {
|
2008-12-02 12:01:29 +01:00
|
|
|
TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor *>(editor);
|
|
|
|
if (! textEditor)
|
|
|
|
continue;
|
|
|
|
|
2011-02-21 16:02:26 +01:00
|
|
|
TextEditor::BaseTextEditorWidget *ed = qobject_cast<TextEditor::BaseTextEditorWidget *>(textEditor->widget());
|
2008-12-02 12:01:29 +01:00
|
|
|
if (! ed)
|
|
|
|
continue;
|
|
|
|
|
2011-02-21 16:02:26 +01:00
|
|
|
QList<TextEditor::BaseTextEditorWidget::BlockRange> blockRanges;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-02-23 12:49:56 +01:00
|
|
|
foreach (const Document::Block &block, doc->skippedBlocks()) {
|
2011-02-21 16:02:26 +01:00
|
|
|
blockRanges.append(TextEditor::BaseTextEditorWidget::BlockRange(block.begin(), block.end()));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QList<QTextEdit::ExtraSelection> selections;
|
|
|
|
|
|
|
|
// 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
|
|
|
QSet<int> lines;
|
2011-08-24 10:55:48 +02:00
|
|
|
QList<Document::DiagnosticMessage> messages = doc->diagnosticMessages();
|
|
|
|
messages += extraDiagnostics(doc->fileName());
|
|
|
|
foreach (const Document::DiagnosticMessage &m, messages) {
|
2009-03-03 14:52:09 +01:00
|
|
|
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;
|
2011-08-24 12:01:50 +02:00
|
|
|
sel.format.setToolTip(m.text());
|
2009-03-03 14:52:09 +01:00
|
|
|
selections.append(sel);
|
|
|
|
}
|
2012-02-20 14:16:15 +01:00
|
|
|
|
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;
|
2011-02-21 16:02:26 +01:00
|
|
|
TextEditor::BaseTextEditorWidget *editor = qobject_cast<TextEditor::BaseTextEditorWidget *>(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
|
|
|
|
2011-02-21 16:02:26 +01:00
|
|
|
editor->setExtraSelections(TextEditor::BaseTextEditorWidget::CodeWarningsSelection,
|
2009-03-02 16:30:25 +01:00
|
|
|
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
|
|
|
{
|
2012-01-24 15:36:40 +01:00
|
|
|
if (Core::ProgressManager *pm = Core::ICore::progressManager()) {
|
|
|
|
pm->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
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2012-01-24 15:36:40 +01:00
|
|
|
const Core::MimeDatabase *mimeDb = Core::ICore::mimeDatabase();
|
2010-05-07 10:23:37 +02:00
|
|
|
Core::MimeType cSourceTy = mimeDb->findByType(QLatin1String("text/x-csrc"));
|
|
|
|
Core::MimeType cppSourceTy = mimeDb->findByType(QLatin1String("text/x-c++src"));
|
|
|
|
Core::MimeType mSourceTy = mimeDb->findByType(QLatin1String("text/x-objcsrc"));
|
2010-02-23 15:54:30 +01:00
|
|
|
|
2010-02-22 16:00:47 +01:00
|
|
|
QStringList sources;
|
|
|
|
QStringList headers;
|
2010-05-07 10:23:37 +02:00
|
|
|
|
|
|
|
QStringList suffixes = cSourceTy.suffixes();
|
|
|
|
suffixes += cppSourceTy.suffixes();
|
|
|
|
suffixes += mSourceTy.suffixes();
|
|
|
|
|
|
|
|
foreach (const QString &file, files) {
|
|
|
|
QFileInfo info(file);
|
|
|
|
|
|
|
|
preproc->snapshot.remove(file);
|
|
|
|
|
|
|
|
if (suffixes.contains(info.suffix()))
|
|
|
|
sources.append(file);
|
|
|
|
else
|
|
|
|
headers.append(file);
|
|
|
|
}
|
2008-12-03 16:18:33 +01:00
|
|
|
|
2010-02-22 16:00:47 +01:00
|
|
|
const int sourceCount = sources.size();
|
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;
|
|
|
|
|
2010-02-22 16:00:47 +01:00
|
|
|
const QString fileName = files.at(i);
|
2009-02-23 12:49:56 +01:00
|
|
|
|
2010-02-22 16:00:47 +01:00
|
|
|
const bool isSourceFile = i < sourceCount;
|
2009-02-23 12:49:56 +01:00
|
|
|
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();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2008-12-03 16:18:33 +01:00
|
|
|
future.setProgressValue(files.size());
|
2011-07-05 10:46:46 +02:00
|
|
|
preproc->modelManager()->finishedRefreshingSourceFiles(files);
|
2008-12-03 16:18:33 +01:00
|
|
|
|
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
|
|
|
}
|
2010-12-03 13:49:35 +01:00
|
|
|
|
2011-07-05 10:46:46 +02:00
|
|
|
void CppModelManager::finishedRefreshingSourceFiles(const QStringList &files)
|
|
|
|
{
|
|
|
|
emit sourceFilesRefreshed(files);
|
|
|
|
}
|
|
|
|
|
2012-02-07 15:09:08 +01:00
|
|
|
CppCompletionSupport *CppModelManager::completionSupport(Core::IEditor *editor) const
|
|
|
|
{
|
2012-02-20 12:39:08 +01:00
|
|
|
if (TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor *>(editor))
|
2012-02-21 10:00:32 +01:00
|
|
|
return m_completionAssistProvider->completionSupport(textEditor);
|
2012-02-07 15:09:08 +01:00
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-02-21 10:00:32 +01:00
|
|
|
void CppModelManager::setCppCompletionAssistProvider(CppCompletionAssistProvider *completionAssistProvider)
|
2012-02-20 12:39:08 +01:00
|
|
|
{
|
2012-02-21 10:00:32 +01:00
|
|
|
ExtensionSystem::PluginManager::instance()->removeObject(m_completionAssistProvider);
|
|
|
|
if (completionAssistProvider)
|
|
|
|
m_completionAssistProvider = completionAssistProvider;
|
2012-02-20 12:39:08 +01:00
|
|
|
else
|
2012-02-21 10:00:32 +01:00
|
|
|
m_completionAssistProvider = m_completionFallback;
|
|
|
|
ExtensionSystem::PluginManager::instance()->addObject(m_completionAssistProvider);
|
2012-02-20 12:39:08 +01:00
|
|
|
}
|
|
|
|
|
2012-02-07 15:09:08 +01:00
|
|
|
CppHighlightingSupport *CppModelManager::highlightingSupport(Core::IEditor *editor) const
|
|
|
|
{
|
2012-02-20 12:39:08 +01:00
|
|
|
if (TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor *>(editor))
|
|
|
|
return m_highlightingFactory->highlightingSupport(textEditor);
|
2012-02-07 15:09:08 +01:00
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
2011-08-24 10:55:48 +02:00
|
|
|
|
2012-02-20 12:39:08 +01:00
|
|
|
void CppModelManager::setHighlightingSupportFactory(CppHighlightingSupportFactory *highlightingFactory)
|
|
|
|
{
|
|
|
|
if (highlightingFactory)
|
|
|
|
m_highlightingFactory = highlightingFactory;
|
|
|
|
else
|
|
|
|
m_highlightingFactory = m_highlightingFallback;
|
|
|
|
}
|
|
|
|
|
2011-08-24 10:55:48 +02:00
|
|
|
void CppModelManager::setExtraDiagnostics(const QString &fileName, int kind,
|
|
|
|
const QList<Document::DiagnosticMessage> &diagnostics)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&protectExtraDiagnostics);
|
2011-08-31 09:58:40 +02:00
|
|
|
if (m_extraDiagnostics[fileName][kind] == diagnostics)
|
|
|
|
return;
|
2011-08-24 10:55:48 +02:00
|
|
|
m_extraDiagnostics[fileName].insert(kind, diagnostics);
|
|
|
|
}
|
2011-08-31 09:58:40 +02:00
|
|
|
emit extraDiagnosticsUpdated(fileName);
|
2011-08-24 10:55:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QList<Document::DiagnosticMessage> CppModelManager::extraDiagnostics(const QString &fileName, int kind) const
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&protectExtraDiagnostics);
|
|
|
|
if (kind == -1) {
|
|
|
|
QList<Document::DiagnosticMessage> messages;
|
|
|
|
foreach (const QList<Document::DiagnosticMessage> &list, m_extraDiagnostics.value(fileName))
|
|
|
|
messages += list;
|
|
|
|
return messages;
|
|
|
|
}
|
|
|
|
return m_extraDiagnostics.value(fileName).value(kind);
|
|
|
|
}
|
|
|
|
|
2010-01-19 15:26:08 +10:00
|
|
|
#endif
|
2008-12-02 12:01:29 +01:00
|
|
|
|