2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2013-01-28 17:12:19 +01:00
|
|
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
2012-10-02 09:12:39 +02:00
|
|
|
** Contact: http://www.qt-project.org/legal
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and Digia. For licensing terms and
|
|
|
|
|
** conditions see http://qt.digia.com/licensing. For further information
|
|
|
|
|
** use the contact form at http://qt.digia.com/contact-us.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2012-10-02 09:12:39 +02: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.
|
|
|
|
|
**
|
|
|
|
|
** In addition, as a special exception, Digia gives you certain additional
|
|
|
|
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
#include "CppDocument.h"
|
2009-06-03 16:16:20 +02:00
|
|
|
#include "FastPreprocessor.h"
|
2010-05-11 12:47:20 +02:00
|
|
|
#include "LookupContext.h"
|
|
|
|
|
#include "Overview.h"
|
2008-12-09 15:25:01 +01:00
|
|
|
|
2013-03-27 18:54:03 +01:00
|
|
|
#include <cplusplus/Bind.h>
|
|
|
|
|
#include <cplusplus/Control.h>
|
|
|
|
|
#include <cplusplus/TranslationUnit.h>
|
|
|
|
|
#include <cplusplus/DiagnosticClient.h>
|
|
|
|
|
#include <cplusplus/Literals.h>
|
|
|
|
|
#include <cplusplus/Symbols.h>
|
|
|
|
|
#include <cplusplus/Names.h>
|
|
|
|
|
#include <cplusplus/AST.h>
|
|
|
|
|
#include <cplusplus/ASTPatternBuilder.h>
|
|
|
|
|
#include <cplusplus/ASTMatcher.h>
|
|
|
|
|
#include <cplusplus/Scope.h>
|
|
|
|
|
#include <cplusplus/SymbolVisitor.h>
|
|
|
|
|
#include <cplusplus/NameVisitor.h>
|
|
|
|
|
#include <cplusplus/TypeVisitor.h>
|
|
|
|
|
#include <cplusplus/CoreTypes.h>
|
2008-12-02 14:09:21 +01:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QByteArray>
|
|
|
|
|
#include <QBitArray>
|
|
|
|
|
#include <QDir>
|
2012-08-06 13:42:46 +02:00
|
|
|
#include <QDebug>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-09-25 16:00:14 +02:00
|
|
|
/*!
|
|
|
|
|
\namespace CPlusPlus
|
|
|
|
|
The namespace for C++ related tools.
|
|
|
|
|
*/
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
using namespace CPlusPlus;
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
2010-08-17 13:42:04 +02:00
|
|
|
class LastVisibleSymbolAt: protected SymbolVisitor
|
|
|
|
|
{
|
|
|
|
|
Symbol *root;
|
|
|
|
|
unsigned line;
|
|
|
|
|
unsigned column;
|
|
|
|
|
Symbol *symbol;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
LastVisibleSymbolAt(Symbol *root)
|
|
|
|
|
: root(root), line(0), column(0), symbol(0) {}
|
|
|
|
|
|
|
|
|
|
Symbol *operator()(unsigned line, unsigned column)
|
|
|
|
|
{
|
|
|
|
|
this->line = line;
|
|
|
|
|
this->column = column;
|
|
|
|
|
this->symbol = 0;
|
|
|
|
|
accept(root);
|
|
|
|
|
if (! symbol)
|
|
|
|
|
symbol = root;
|
|
|
|
|
return symbol;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
bool preVisit(Symbol *s)
|
|
|
|
|
{
|
|
|
|
|
if (s->asBlock()) {
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
if (s->line() < line || (s->line() == line && s->column() <= column))
|
2010-08-17 13:42:04 +02:00
|
|
|
return true;
|
|
|
|
|
// skip blocks
|
|
|
|
|
} if (s->line() < line || (s->line() == line && s->column() <= column)) {
|
|
|
|
|
symbol = s;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2010-05-12 12:53:16 +02:00
|
|
|
class FindScopeAt: protected SymbolVisitor
|
|
|
|
|
{
|
|
|
|
|
TranslationUnit *_unit;
|
|
|
|
|
unsigned _line;
|
|
|
|
|
unsigned _column;
|
|
|
|
|
Scope *_scope;
|
|
|
|
|
|
|
|
|
|
public:
|
2010-07-16 15:24:42 +02:00
|
|
|
/** line and column should be 1-based */
|
2010-05-12 12:53:16 +02:00
|
|
|
FindScopeAt(TranslationUnit *unit, unsigned line, unsigned column)
|
|
|
|
|
: _unit(unit), _line(line), _column(column), _scope(0) {}
|
|
|
|
|
|
|
|
|
|
Scope *operator()(Symbol *symbol)
|
|
|
|
|
{
|
|
|
|
|
accept(symbol);
|
|
|
|
|
return _scope;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
2010-08-11 12:26:02 +02:00
|
|
|
bool process(Scope *symbol)
|
2010-05-12 12:53:16 +02:00
|
|
|
{
|
|
|
|
|
if (! _scope) {
|
2010-08-11 12:26:02 +02:00
|
|
|
Scope *scope = symbol;
|
2010-05-12 12:53:16 +02:00
|
|
|
|
2010-08-11 12:26:02 +02:00
|
|
|
for (unsigned i = 0; i < scope->memberCount(); ++i) {
|
|
|
|
|
accept(scope->memberAt(i));
|
2010-05-12 12:53:16 +02:00
|
|
|
|
|
|
|
|
if (_scope)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned startLine, startColumn;
|
2010-07-19 10:42:07 +02:00
|
|
|
_unit->getPosition(scope->startOffset(), &startLine, &startColumn);
|
2010-05-12 12:53:16 +02:00
|
|
|
|
|
|
|
|
if (_line > startLine || (_line == startLine && _column >= startColumn)) {
|
|
|
|
|
unsigned endLine, endColumn;
|
2010-07-19 10:42:07 +02:00
|
|
|
_unit->getPosition(scope->endOffset(), &endLine, &endColumn);
|
2010-05-12 12:53:16 +02:00
|
|
|
|
2011-08-10 12:16:25 +02:00
|
|
|
if (_line < endLine || (_line == endLine && _column < endColumn))
|
2010-05-12 12:53:16 +02:00
|
|
|
_scope = scope;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using SymbolVisitor::visit;
|
|
|
|
|
|
|
|
|
|
virtual bool preVisit(Symbol *)
|
|
|
|
|
{ return ! _scope; }
|
|
|
|
|
|
|
|
|
|
virtual bool visit(UsingNamespaceDirective *) { return false; }
|
|
|
|
|
virtual bool visit(UsingDeclaration *) { return false; }
|
|
|
|
|
virtual bool visit(NamespaceAlias *) { return false; }
|
|
|
|
|
virtual bool visit(Declaration *) { return false; }
|
|
|
|
|
virtual bool visit(Argument *) { return false; }
|
|
|
|
|
virtual bool visit(TypenameArgument *) { return false; }
|
|
|
|
|
virtual bool visit(BaseClass *) { return false; }
|
|
|
|
|
virtual bool visit(ForwardClassDeclaration *) { return false; }
|
|
|
|
|
|
|
|
|
|
virtual bool visit(Enum *symbol)
|
|
|
|
|
{ return process(symbol); }
|
|
|
|
|
|
|
|
|
|
virtual bool visit(Function *symbol)
|
|
|
|
|
{ return process(symbol); }
|
|
|
|
|
|
|
|
|
|
virtual bool visit(Namespace *symbol)
|
|
|
|
|
{ return process(symbol); }
|
|
|
|
|
|
|
|
|
|
virtual bool visit(Class *symbol)
|
|
|
|
|
{ return process(symbol); }
|
|
|
|
|
|
|
|
|
|
virtual bool visit(Block *symbol)
|
|
|
|
|
{ return process(symbol); }
|
|
|
|
|
|
2013-05-16 10:15:02 +02:00
|
|
|
virtual bool visit(Template *symbol)
|
|
|
|
|
{
|
2013-06-07 08:15:19 +02:00
|
|
|
if (Symbol *decl = symbol->declaration()) {
|
|
|
|
|
if (decl->isFunction() || decl->isClass())
|
|
|
|
|
return process(symbol);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2013-05-16 10:15:02 +02:00
|
|
|
}
|
|
|
|
|
|
2010-05-12 12:53:16 +02:00
|
|
|
// Objective-C
|
|
|
|
|
virtual bool visit(ObjCBaseClass *) { return false; }
|
|
|
|
|
virtual bool visit(ObjCBaseProtocol *) { return false; }
|
|
|
|
|
virtual bool visit(ObjCForwardClassDeclaration *) { return false; }
|
|
|
|
|
virtual bool visit(ObjCForwardProtocolDeclaration *) { return false; }
|
|
|
|
|
virtual bool visit(ObjCPropertyDeclaration *) { return false; }
|
2010-05-20 16:07:11 +02:00
|
|
|
|
|
|
|
|
virtual bool visit(ObjCClass *symbol)
|
|
|
|
|
{ return process(symbol); }
|
|
|
|
|
|
|
|
|
|
virtual bool visit(ObjCProtocol *symbol)
|
|
|
|
|
{ return process(symbol); }
|
|
|
|
|
|
|
|
|
|
virtual bool visit(ObjCMethod *symbol)
|
|
|
|
|
{ return process(symbol); }
|
2010-05-12 12:53:16 +02:00
|
|
|
};
|
|
|
|
|
|
2010-07-03 18:41:31 +02:00
|
|
|
|
2012-03-26 15:18:01 +02:00
|
|
|
#define DO_NOT_DUMP_ALL_PARSER_ERRORS
|
|
|
|
|
|
2008-12-02 14:09:21 +01:00
|
|
|
class DocumentDiagnosticClient : public DiagnosticClient
|
|
|
|
|
{
|
|
|
|
|
enum { MAX_MESSAGE_COUNT = 10 };
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
DocumentDiagnosticClient(Document *doc, QList<Document::DiagnosticMessage> *messages)
|
|
|
|
|
: doc(doc),
|
2009-06-04 11:42:02 +02:00
|
|
|
messages(messages),
|
|
|
|
|
errorCount(0)
|
2008-12-02 14:09:21 +01:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
virtual void report(int level,
|
2009-12-01 11:33:13 +01:00
|
|
|
const StringLiteral *fileId,
|
2008-12-02 14:09:21 +01:00
|
|
|
unsigned line, unsigned column,
|
|
|
|
|
const char *format, va_list ap)
|
|
|
|
|
{
|
2009-06-04 11:42:02 +02:00
|
|
|
if (level == Error) {
|
|
|
|
|
++errorCount;
|
|
|
|
|
|
2012-03-26 15:18:01 +02:00
|
|
|
#ifdef DO_NOT_DUMP_ALL_PARSER_ERRORS
|
2009-06-04 11:42:02 +02:00
|
|
|
if (errorCount >= MAX_MESSAGE_COUNT)
|
|
|
|
|
return; // ignore the error
|
2012-03-26 15:18:01 +02:00
|
|
|
#endif // DO_NOT_DUMP_ALL_PARSER_ERRORS
|
2009-06-04 11:42:02 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-02 14:09:21 +01:00
|
|
|
const QString fileName = QString::fromUtf8(fileId->chars(), fileId->size());
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-02 14:09:21 +01:00
|
|
|
if (fileName != doc->fileName())
|
|
|
|
|
return;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-02 14:09:21 +01:00
|
|
|
QString message;
|
|
|
|
|
message.vsprintf(format, ap);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-03-26 15:18:01 +02:00
|
|
|
#ifndef DO_NOT_DUMP_ALL_PARSER_ERRORS
|
|
|
|
|
{
|
|
|
|
|
const char *levelStr = "Unknown level";
|
|
|
|
|
if (level == Document::DiagnosticMessage::Warning) levelStr = "Warning";
|
|
|
|
|
if (level == Document::DiagnosticMessage::Error) levelStr = "Error";
|
|
|
|
|
if (level == Document::DiagnosticMessage::Fatal) levelStr = "Fatal";
|
|
|
|
|
qDebug("%s:%u:%u: %s: %s", fileId->chars(), line, column, levelStr, message.toUtf8().constData());
|
|
|
|
|
}
|
|
|
|
|
#endif // DO_NOT_DUMP_ALL_PARSER_ERRORS
|
|
|
|
|
|
2008-12-02 14:09:21 +01:00
|
|
|
Document::DiagnosticMessage m(convertLevel(level), doc->fileName(),
|
|
|
|
|
line, column, message);
|
|
|
|
|
messages->append(m);
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-02 14:09:21 +01:00
|
|
|
static int convertLevel(int level) {
|
|
|
|
|
switch (level) {
|
|
|
|
|
case Warning: return Document::DiagnosticMessage::Warning;
|
|
|
|
|
case Error: return Document::DiagnosticMessage::Error;
|
|
|
|
|
case Fatal: return Document::DiagnosticMessage::Fatal;
|
|
|
|
|
default: return Document::DiagnosticMessage::Error;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2008-12-02 14:09:21 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-06-04 11:42:02 +02:00
|
|
|
private:
|
2008-12-02 14:09:21 +01:00
|
|
|
Document *doc;
|
|
|
|
|
QList<Document::DiagnosticMessage> *messages;
|
2009-06-04 11:42:02 +02:00
|
|
|
int errorCount;
|
2008-12-02 14:09:21 +01:00
|
|
|
};
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-02 14:09:21 +01:00
|
|
|
} // anonymous namespace
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-09-25 16:00:14 +02:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
Document::Document(const QString &fileName)
|
2009-11-09 13:53:28 +01:00
|
|
|
: _fileName(QDir::cleanPath(fileName)),
|
2009-07-14 14:23:12 +02:00
|
|
|
_globalNamespace(0),
|
2009-12-15 15:52:55 +01:00
|
|
|
_revision(0),
|
2011-08-25 12:35:55 +02:00
|
|
|
_editorRevision(0),
|
|
|
|
|
_checkMode(0)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
_control = new Control();
|
|
|
|
|
|
|
|
|
|
_control->setDiagnosticClient(new DocumentDiagnosticClient(this, &_diagnosticMessages));
|
|
|
|
|
|
|
|
|
|
const QByteArray localFileName = fileName.toUtf8();
|
2010-08-11 14:24:28 +02:00
|
|
|
const StringLiteral *fileId = _control->stringLiteral(localFileName.constData(),
|
2009-12-01 11:33:13 +01:00
|
|
|
localFileName.size());
|
2013-10-06 02:41:22 +02:00
|
|
|
LanguageFeatures features;
|
|
|
|
|
features.qtEnabled = true;
|
|
|
|
|
features.qtMocRunEnabled = true;
|
|
|
|
|
features.qtKeywordsEnabled = true;
|
|
|
|
|
features.cxx11Enabled = true;
|
|
|
|
|
features.objCEnabled = true;
|
2008-12-02 12:01:29 +01:00
|
|
|
_translationUnit = new TranslationUnit(_control, fileId);
|
2013-10-06 02:41:22 +02:00
|
|
|
_translationUnit->setLanguageFeatures(features);
|
2008-12-02 12:01:29 +01:00
|
|
|
(void) _control->switchTranslationUnit(_translationUnit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Document::~Document()
|
|
|
|
|
{
|
|
|
|
|
delete _translationUnit;
|
|
|
|
|
delete _control->diagnosticClient();
|
|
|
|
|
delete _control;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Control *Document::control() const
|
2008-12-02 14:09:21 +01:00
|
|
|
{
|
|
|
|
|
return _control;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-07-14 14:23:12 +02:00
|
|
|
unsigned Document::revision() const
|
|
|
|
|
{
|
|
|
|
|
return _revision;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Document::setRevision(unsigned revision)
|
|
|
|
|
{
|
|
|
|
|
_revision = revision;
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-15 15:52:55 +01:00
|
|
|
unsigned Document::editorRevision() const
|
|
|
|
|
{
|
|
|
|
|
return _editorRevision;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Document::setEditorRevision(unsigned editorRevision)
|
|
|
|
|
{
|
|
|
|
|
_editorRevision = editorRevision;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-05 12:34:02 +01:00
|
|
|
QDateTime Document::lastModified() const
|
|
|
|
|
{
|
|
|
|
|
return _lastModified;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Document::setLastModified(const QDateTime &lastModified)
|
|
|
|
|
{
|
|
|
|
|
_lastModified = lastModified;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QString Document::fileName() const
|
2008-12-02 14:09:21 +01:00
|
|
|
{
|
|
|
|
|
return _fileName;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
QStringList Document::includedFiles() const
|
2008-12-02 14:09:21 +01:00
|
|
|
{
|
2008-12-10 17:21:01 +01:00
|
|
|
QStringList files;
|
2013-07-25 11:21:31 +02:00
|
|
|
foreach (const Include &i, _resolvedIncludes)
|
2013-06-06 09:35:40 +02:00
|
|
|
files.append(i.resolvedFileName());
|
2008-12-10 17:21:01 +01:00
|
|
|
files.removeDuplicates();
|
|
|
|
|
return files;
|
2008-12-02 14:09:21 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-12-19 18:14:28 +01:00
|
|
|
// This assumes to be called with a QDir::cleanPath cleaned fileName.
|
2013-06-06 09:35:40 +02:00
|
|
|
void Document::addIncludeFile(const Document::Include &include)
|
2008-12-02 14:09:21 +01:00
|
|
|
{
|
2013-07-25 11:21:31 +02:00
|
|
|
if (include.resolvedFileName().isEmpty())
|
|
|
|
|
_unresolvedIncludes.append(include);
|
|
|
|
|
else
|
|
|
|
|
_resolvedIncludes.append(include);
|
2008-12-02 14:09:21 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-08 12:59:33 +01:00
|
|
|
void Document::appendMacro(const Macro ¯o)
|
2008-12-02 14:09:21 +01:00
|
|
|
{
|
2008-12-08 12:59:33 +01:00
|
|
|
_definedMacros.append(macro);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-03-04 11:47:30 +01:00
|
|
|
void Document::addMacroUse(const Macro ¯o, unsigned offset, unsigned length,
|
2009-12-21 14:47:22 +01:00
|
|
|
unsigned beginLine,
|
2012-03-26 15:18:01 +02:00
|
|
|
const QVector<MacroArgumentReference> &actuals)
|
2008-12-04 12:05:04 +01:00
|
|
|
{
|
2009-12-21 14:47:22 +01:00
|
|
|
MacroUse use(macro, offset, offset + length, beginLine);
|
2009-03-04 11:47:30 +01:00
|
|
|
|
|
|
|
|
foreach (const MacroArgumentReference &actual, actuals) {
|
|
|
|
|
const Block arg(actual.position(), actual.position() + actual.length());
|
|
|
|
|
|
|
|
|
|
use.addArgument(arg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_macroUses.append(use);
|
2008-12-04 12:05:04 +01:00
|
|
|
}
|
|
|
|
|
|
2009-09-25 16:00:14 +02:00
|
|
|
void Document::addUndefinedMacroUse(const QByteArray &name, unsigned offset)
|
|
|
|
|
{
|
|
|
|
|
QByteArray copy(name.data(), name.size());
|
|
|
|
|
UndefinedMacroUse use(copy, offset);
|
|
|
|
|
_undefinedMacroUses.append(use);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\class Document::MacroUse
|
2013-06-05 14:29:24 +02:00
|
|
|
\brief The MacroUse class represents the usage of a macro in a
|
|
|
|
|
\l {Document}.
|
2009-09-25 16:00:14 +02:00
|
|
|
\sa Document::UndefinedMacroUse
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\class Document::UndefinedMacroUse
|
2013-06-05 14:29:24 +02:00
|
|
|
\brief The UndefinedMacroUse class represents a macro that was looked for,
|
|
|
|
|
but not found.
|
2009-09-25 16:00:14 +02:00
|
|
|
|
|
|
|
|
Holds data about the reference to a macro in an \tt{#ifdef} or \tt{#ifndef}
|
|
|
|
|
or argument to the \tt{defined} operator inside an \tt{#if} or \tt{#elif} that does
|
|
|
|
|
not exist.
|
|
|
|
|
|
|
|
|
|
\sa Document::undefinedMacroUses(), Document::MacroUse, Macro
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QByteArray Document::UndefinedMacroUse::name() const
|
|
|
|
|
|
|
|
|
|
Returns the name of the macro that was not found.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QList<UndefinedMacroUse> Document::undefinedMacroUses() const
|
|
|
|
|
|
|
|
|
|
Returns a list of referenced but undefined macros.
|
|
|
|
|
|
|
|
|
|
\sa Document::macroUses(), Document::definedMacros(), Macro
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QList<MacroUse> Document::macroUses() const
|
|
|
|
|
|
|
|
|
|
Returns a list of macros used.
|
|
|
|
|
|
|
|
|
|
\sa Document::undefinedMacroUses(), Document::definedMacros(), Macro
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QList<Macro> Document::definedMacros() const
|
|
|
|
|
|
|
|
|
|
Returns the list of macros defined.
|
|
|
|
|
|
|
|
|
|
\sa Document::macroUses(), Document::undefinedMacroUses()
|
|
|
|
|
*/
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
TranslationUnit *Document::translationUnit() const
|
2008-12-02 14:09:21 +01:00
|
|
|
{
|
|
|
|
|
return _translationUnit;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
bool Document::skipFunctionBody() const
|
2008-12-02 14:09:21 +01:00
|
|
|
{
|
|
|
|
|
return _translationUnit->skipFunctionBody();
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
void Document::setSkipFunctionBody(bool skipFunctionBody)
|
2008-12-02 14:09:21 +01:00
|
|
|
{
|
|
|
|
|
_translationUnit->setSkipFunctionBody(skipFunctionBody);
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
unsigned Document::globalSymbolCount() const
|
|
|
|
|
{
|
|
|
|
|
if (! _globalNamespace)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return _globalNamespace->memberCount();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Symbol *Document::globalSymbolAt(unsigned index) const
|
2008-12-02 14:09:21 +01:00
|
|
|
{
|
|
|
|
|
return _globalNamespace->memberAt(index);
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
Namespace *Document::globalNamespace() const
|
2008-12-02 14:09:21 +01:00
|
|
|
{
|
|
|
|
|
return _globalNamespace;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-03-18 15:21:07 +01:00
|
|
|
void Document::setGlobalNamespace(Namespace *globalNamespace)
|
|
|
|
|
{
|
|
|
|
|
_globalNamespace = globalNamespace;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-02 14:55:56 +02:00
|
|
|
/*!
|
|
|
|
|
* Extract the function name including scope at the given position.
|
|
|
|
|
*
|
|
|
|
|
* Note that a function (scope) starts at the name of that function, not at the return type. The
|
2013-10-07 13:34:40 +02:00
|
|
|
* implication is that this function will return an empty string when the line/column is on the
|
2013-05-02 14:55:56 +02:00
|
|
|
* return type.
|
|
|
|
|
*
|
|
|
|
|
* \param line the line number, starting with line 1
|
|
|
|
|
* \param column the column number, starting with column 1
|
|
|
|
|
*/
|
|
|
|
|
QString Document::functionAt(int line, int column) const
|
|
|
|
|
{
|
|
|
|
|
if (line < 1 || column < 1)
|
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
|
|
CPlusPlus::Symbol *symbol = lastVisibleSymbolAt(line, column);
|
|
|
|
|
if (!symbol)
|
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
|
|
// Find the enclosing function scope (which might be several levels up, or we might be standing
|
|
|
|
|
// on it)
|
|
|
|
|
Scope *scope;
|
|
|
|
|
if (symbol->isScope())
|
|
|
|
|
scope = symbol->asScope();
|
|
|
|
|
else
|
|
|
|
|
scope = symbol->enclosingScope();
|
|
|
|
|
|
|
|
|
|
while (scope && !scope->isFunction() )
|
|
|
|
|
scope = scope->enclosingScope();
|
|
|
|
|
|
|
|
|
|
if (!scope)
|
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
|
|
// We found the function scope, extract its name.
|
|
|
|
|
const Overview o;
|
|
|
|
|
QString rc = o.prettyName(scope->name());
|
|
|
|
|
|
|
|
|
|
// Prepend namespace "Foo::Foo::foo()" up to empty root namespace
|
|
|
|
|
for (const Symbol *owner = scope->enclosingNamespace();
|
|
|
|
|
owner; owner = owner->enclosingNamespace()) {
|
|
|
|
|
const QString name = o.prettyName(owner->name());
|
|
|
|
|
if (name.isEmpty()) {
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
rc.prepend(QLatin1String("::"));
|
|
|
|
|
rc.prepend(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-12 12:53:16 +02:00
|
|
|
Scope *Document::scopeAt(unsigned line, unsigned column)
|
|
|
|
|
{
|
|
|
|
|
FindScopeAt findScopeAt(_translationUnit, line, column);
|
2010-05-12 14:41:25 +02:00
|
|
|
if (Scope *scope = findScopeAt(_globalNamespace))
|
|
|
|
|
return scope;
|
2010-08-11 12:26:02 +02:00
|
|
|
return globalNamespace();
|
2010-05-12 12:53:16 +02:00
|
|
|
}
|
|
|
|
|
|
2010-05-17 13:01:56 +02:00
|
|
|
Symbol *Document::lastVisibleSymbolAt(unsigned line, unsigned column) const
|
2008-12-02 14:09:21 +01:00
|
|
|
{
|
2010-08-17 13:42:04 +02:00
|
|
|
LastVisibleSymbolAt lastVisibleSymbolAt(globalNamespace());
|
|
|
|
|
return lastVisibleSymbolAt(line, column);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-12-21 14:47:22 +01:00
|
|
|
const Macro *Document::findMacroDefinitionAt(unsigned line) const
|
|
|
|
|
{
|
|
|
|
|
foreach (const Macro ¯o, _definedMacros) {
|
|
|
|
|
if (macro.line() == line)
|
|
|
|
|
return ¯o;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Document::MacroUse *Document::findMacroUseAt(unsigned offset) const
|
|
|
|
|
{
|
|
|
|
|
foreach (const Document::MacroUse &use, _macroUses) {
|
2012-03-08 15:53:28 +01:00
|
|
|
if (use.contains(offset) && (offset < use.begin() + use.macro().name().length()))
|
2009-12-21 14:47:22 +01:00
|
|
|
return &use;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Document::UndefinedMacroUse *Document::findUndefinedMacroUseAt(unsigned offset) const
|
|
|
|
|
{
|
|
|
|
|
foreach (const Document::UndefinedMacroUse &use, _undefinedMacroUses) {
|
2012-03-08 15:53:28 +01:00
|
|
|
if (use.contains(offset) && (offset < use.begin() + use.name().length()))
|
2009-12-21 14:47:22 +01:00
|
|
|
return &use;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
Document::Ptr Document::create(const QString &fileName)
|
|
|
|
|
{
|
|
|
|
|
Document::Ptr doc(new Document(fileName));
|
|
|
|
|
return doc;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-12 17:53:56 +01:00
|
|
|
QByteArray Document::utf8Source() const
|
2009-06-05 14:29:57 +02:00
|
|
|
{ return _source; }
|
|
|
|
|
|
2012-01-12 17:53:56 +01:00
|
|
|
void Document::setUtf8Source(const QByteArray &source)
|
2008-12-02 14:09:21 +01:00
|
|
|
{
|
2009-02-24 11:04:52 +01:00
|
|
|
_source = source;
|
|
|
|
|
_translationUnit->setSource(_source.constBegin(), _source.size());
|
2008-12-02 14:09:21 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
void Document::startSkippingBlocks(unsigned start)
|
2008-12-02 14:09:21 +01:00
|
|
|
{
|
|
|
|
|
_skippedBlocks.append(Block(start, 0));
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
void Document::stopSkippingBlocks(unsigned stop)
|
|
|
|
|
{
|
2009-02-10 22:56:04 +01:00
|
|
|
if (_skippedBlocks.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
unsigned start = _skippedBlocks.back().begin();
|
|
|
|
|
if (start > stop)
|
|
|
|
|
_skippedBlocks.removeLast(); // Ignore this block, it's invalid.
|
|
|
|
|
else
|
|
|
|
|
_skippedBlocks.back() = Block(start, stop);
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-24 11:04:52 +01:00
|
|
|
bool Document::isTokenized() const
|
|
|
|
|
{
|
|
|
|
|
return _translationUnit->isTokenized();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Document::tokenize()
|
|
|
|
|
{
|
|
|
|
|
_translationUnit->tokenize();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Document::isParsed() const
|
|
|
|
|
{
|
|
|
|
|
return _translationUnit->isParsed();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-03 14:01:19 +01:00
|
|
|
bool Document::parse(ParseMode mode)
|
2008-12-02 14:09:21 +01:00
|
|
|
{
|
2008-12-03 14:01:19 +01:00
|
|
|
TranslationUnit::ParseMode m = TranslationUnit::ParseTranlationUnit;
|
|
|
|
|
switch (mode) {
|
|
|
|
|
case ParseTranlationUnit:
|
|
|
|
|
m = TranslationUnit::ParseTranlationUnit;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ParseDeclaration:
|
|
|
|
|
m = TranslationUnit::ParseDeclaration;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ParseExpression:
|
|
|
|
|
m = TranslationUnit::ParseExpression;
|
|
|
|
|
break;
|
|
|
|
|
|
2009-03-30 15:07:30 +02:00
|
|
|
case ParseDeclarator:
|
|
|
|
|
m = TranslationUnit::ParseDeclarator;
|
|
|
|
|
break;
|
|
|
|
|
|
2008-12-03 14:01:19 +01:00
|
|
|
case ParseStatement:
|
|
|
|
|
m = TranslationUnit::ParseStatement;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _translationUnit->parse(m);
|
2008-12-02 14:09:21 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-06-26 09:11:14 +02:00
|
|
|
void Document::check(CheckMode mode)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2008-12-10 15:43:17 +01:00
|
|
|
Q_ASSERT(!_globalNamespace);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-08-25 12:35:55 +02:00
|
|
|
_checkMode = mode;
|
|
|
|
|
|
2009-09-30 16:13:43 +02:00
|
|
|
if (! isParsed())
|
|
|
|
|
parse();
|
|
|
|
|
|
2010-08-13 15:28:22 +02:00
|
|
|
_globalNamespace = _control->newNamespace(0);
|
|
|
|
|
Bind semantic(_translationUnit);
|
2011-08-23 12:25:31 +02:00
|
|
|
if (mode == FastCheck)
|
2009-06-26 09:11:14 +02:00
|
|
|
semantic.setSkipFunctionBodies(true);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-03 14:01:19 +01:00
|
|
|
if (! _translationUnit->ast())
|
|
|
|
|
return; // nothing to do.
|
|
|
|
|
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
if (TranslationUnitAST *ast = _translationUnit->ast()->asTranslationUnit())
|
2010-08-13 15:28:22 +02:00
|
|
|
semantic(ast, _globalNamespace);
|
2013-01-14 14:45:36 +01:00
|
|
|
else if (StatementAST *ast = _translationUnit->ast()->asStatement())
|
|
|
|
|
semantic(ast, _globalNamespace);
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
else if (ExpressionAST *ast = _translationUnit->ast()->asExpression())
|
2010-08-13 15:28:22 +02:00
|
|
|
semantic(ast, _globalNamespace);
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
else if (DeclarationAST *ast = translationUnit()->ast()->asDeclaration())
|
2011-08-10 09:50:04 +02:00
|
|
|
semantic(ast, _globalNamespace);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-23 12:02:29 +02:00
|
|
|
void Document::keepSourceAndAST()
|
2010-12-03 10:13:15 +01:00
|
|
|
{
|
2011-08-23 12:02:29 +02:00
|
|
|
_keepSourceAndASTCount.ref();
|
2009-02-24 11:04:52 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-23 12:02:29 +02:00
|
|
|
void Document::releaseSourceAndAST()
|
2008-12-02 14:09:21 +01:00
|
|
|
{
|
2011-08-23 12:02:29 +02:00
|
|
|
if (!_keepSourceAndASTCount.deref()) {
|
|
|
|
|
_source.clear();
|
|
|
|
|
_translationUnit->release();
|
2011-08-23 12:25:31 +02:00
|
|
|
_control->squeeze();
|
2011-08-23 12:02:29 +02:00
|
|
|
}
|
2008-12-02 14:09:21 +01:00
|
|
|
}
|
2009-03-04 11:47:30 +01:00
|
|
|
|
2011-08-31 09:58:40 +02:00
|
|
|
bool Document::DiagnosticMessage::operator==(const Document::DiagnosticMessage &other) const
|
|
|
|
|
{
|
|
|
|
|
return
|
|
|
|
|
_line == other._line &&
|
|
|
|
|
_column == other._column &&
|
|
|
|
|
_length == other._length &&
|
|
|
|
|
_level == other._level &&
|
|
|
|
|
_fileName == other._fileName &&
|
|
|
|
|
_text == other._text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Document::DiagnosticMessage::operator!=(const Document::DiagnosticMessage &other) const
|
|
|
|
|
{
|
|
|
|
|
return !operator==(other);
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-04 11:47:30 +01:00
|
|
|
Snapshot::Snapshot()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Snapshot::~Snapshot()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-07 10:54:27 +01:00
|
|
|
int Snapshot::size() const
|
|
|
|
|
{
|
|
|
|
|
return _documents.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Snapshot::isEmpty() const
|
|
|
|
|
{
|
|
|
|
|
return _documents.isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Snapshot::const_iterator Snapshot::find(const QString &fileName) const
|
|
|
|
|
{
|
|
|
|
|
return _documents.find(fileName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Snapshot::remove(const QString &fileName)
|
|
|
|
|
{
|
|
|
|
|
_documents.remove(fileName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Snapshot::contains(const QString &fileName) const
|
|
|
|
|
{
|
|
|
|
|
return _documents.contains(fileName);
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-04 11:47:30 +01:00
|
|
|
void Snapshot::insert(Document::Ptr doc)
|
|
|
|
|
{
|
|
|
|
|
if (doc)
|
2009-12-07 10:54:27 +01:00
|
|
|
_documents.insert(doc->fileName(), doc);
|
2009-03-04 11:47:30 +01:00
|
|
|
}
|
|
|
|
|
|
2013-08-19 15:47:51 +02:00
|
|
|
Document::Ptr Snapshot::preprocessedDocument(const QByteArray &source,
|
|
|
|
|
const QString &fileName) const
|
2009-06-03 16:16:20 +02:00
|
|
|
{
|
2012-10-11 16:16:01 +02:00
|
|
|
Document::Ptr newDoc = Document::create(fileName);
|
|
|
|
|
if (Document::Ptr thisDocument = document(fileName)) {
|
|
|
|
|
newDoc->_revision = thisDocument->_revision;
|
|
|
|
|
newDoc->_editorRevision = thisDocument->_editorRevision;
|
|
|
|
|
newDoc->_lastModified = thisDocument->_lastModified;
|
2013-07-25 11:21:31 +02:00
|
|
|
newDoc->_resolvedIncludes = thisDocument->_resolvedIncludes;
|
|
|
|
|
newDoc->_unresolvedIncludes = thisDocument->_unresolvedIncludes;
|
2012-10-11 16:16:01 +02:00
|
|
|
}
|
|
|
|
|
|
2009-06-03 16:16:20 +02:00
|
|
|
FastPreprocessor pp(*this);
|
2012-10-11 16:16:01 +02:00
|
|
|
const QByteArray preprocessedCode = pp.run(newDoc, source);
|
|
|
|
|
newDoc->setUtf8Source(preprocessedCode);
|
|
|
|
|
return newDoc;
|
2009-06-03 16:16:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Document::Ptr Snapshot::documentFromSource(const QByteArray &preprocessedCode,
|
|
|
|
|
const QString &fileName) const
|
|
|
|
|
{
|
2009-06-24 16:40:30 +02:00
|
|
|
Document::Ptr newDoc = Document::create(fileName);
|
2009-06-03 16:16:20 +02:00
|
|
|
|
2009-12-07 10:54:27 +01:00
|
|
|
if (Document::Ptr thisDocument = document(fileName)) {
|
2009-11-05 12:34:02 +01:00
|
|
|
newDoc->_revision = thisDocument->_revision;
|
2009-12-15 15:52:55 +01:00
|
|
|
newDoc->_editorRevision = thisDocument->_editorRevision;
|
2009-11-05 12:34:02 +01:00
|
|
|
newDoc->_lastModified = thisDocument->_lastModified;
|
2013-07-25 11:21:31 +02:00
|
|
|
newDoc->_resolvedIncludes = thisDocument->_resolvedIncludes;
|
|
|
|
|
newDoc->_unresolvedIncludes = thisDocument->_unresolvedIncludes;
|
2009-06-03 16:16:20 +02:00
|
|
|
newDoc->_definedMacros = thisDocument->_definedMacros;
|
2009-10-15 16:24:15 +02:00
|
|
|
newDoc->_macroUses = thisDocument->_macroUses;
|
2009-06-03 16:16:20 +02:00
|
|
|
}
|
|
|
|
|
|
2012-01-12 17:53:56 +01:00
|
|
|
newDoc->setUtf8Source(preprocessedCode);
|
2009-06-24 16:40:30 +02:00
|
|
|
return newDoc;
|
2009-06-03 16:16:20 +02:00
|
|
|
}
|
|
|
|
|
|
2013-04-11 12:51:06 +02:00
|
|
|
QSet<QString> Snapshot::allIncludesForDocument(const QString &fileName) const
|
2009-12-02 17:05:36 +01:00
|
|
|
{
|
2013-04-11 12:51:06 +02:00
|
|
|
QSet<QString> result;
|
|
|
|
|
allIncludesForDocument_helper(fileName, result);
|
|
|
|
|
return result;
|
2009-12-02 17:05:36 +01:00
|
|
|
}
|
|
|
|
|
|
2013-04-11 12:51:06 +02:00
|
|
|
void Snapshot::allIncludesForDocument_helper(const QString &fileName, QSet<QString> &result) const
|
2009-07-10 11:59:01 +02:00
|
|
|
{
|
2013-04-11 12:51:06 +02:00
|
|
|
if (Document::Ptr doc = document(fileName)) {
|
|
|
|
|
foreach (const QString &inc, doc->includedFiles()) {
|
|
|
|
|
if (!result.contains(inc)) {
|
|
|
|
|
result.insert(inc);
|
|
|
|
|
allIncludesForDocument_helper(inc, result);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-10 11:59:01 +02:00
|
|
|
}
|
|
|
|
|
|
2013-04-11 12:51:06 +02:00
|
|
|
Document::Ptr Snapshot::document(const QString &fileName) const
|
2009-07-10 11:59:01 +02:00
|
|
|
{
|
2013-04-11 12:51:06 +02:00
|
|
|
return _documents.value(fileName);
|
|
|
|
|
}
|
2009-07-10 11:59:01 +02:00
|
|
|
|
2013-04-11 12:51:06 +02:00
|
|
|
Snapshot Snapshot::simplified(Document::Ptr doc) const
|
|
|
|
|
{
|
|
|
|
|
Snapshot snapshot;
|
2009-07-10 11:59:01 +02:00
|
|
|
|
2013-04-11 12:51:06 +02:00
|
|
|
if (doc) {
|
|
|
|
|
snapshot.insert(doc);
|
|
|
|
|
foreach (const QString &fileName, allIncludesForDocument(doc->fileName()))
|
|
|
|
|
if (Document::Ptr inc = document(fileName))
|
|
|
|
|
snapshot.insert(inc);
|
2009-07-10 11:59:01 +02:00
|
|
|
}
|
2010-05-11 12:47:20 +02:00
|
|
|
|
2013-04-11 12:51:06 +02:00
|
|
|
return snapshot;
|
|
|
|
|
}
|