Files
qt-creator/src/libs/cplusplus/CppDocument.cpp

907 lines
25 KiB
C++
Raw Normal View History

/****************************************************************************
2008-12-02 12:01:29 +01:00
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
2008-12-02 12:01:29 +01:00
**
** This file is part of Qt Creator.
2008-12-02 12:01:29 +01: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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
2010-12-17 16:01:08 +01:00
**
****************************************************************************/
2008-12-02 12:01:29 +01:00
#include "CppDocument.h"
#include "FastPreprocessor.h"
#include "LookupContext.h"
#include "Overview.h"
2008-12-09 15:25:01 +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
#include <QByteArray>
#include <QBitArray>
#include <QDir>
#include <QDebug>
2008-12-02 12:01:29 +01:00
/*!
\namespace CPlusPlus
The namespace for C++ related tools.
*/
2008-12-02 12:01:29 +01:00
using namespace CPlusPlus;
namespace {
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->line() < line || (s->line() == line && s->column() <= column)) {
// skip blocks
if (!s->asBlock())
symbol = s;
return true;
}
return false;
}
};
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 */
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)
{
if (! _scope) {
2010-08-11 12:26:02 +02:00
Scope *scope = symbol;
2010-08-11 12:26:02 +02:00
for (unsigned i = 0; i < scope->memberCount(); ++i) {
accept(scope->memberAt(i));
if (_scope)
return false;
}
unsigned startLine, startColumn;
2010-07-19 10:42:07 +02:00
_unit->getPosition(scope->startOffset(), &startLine, &startColumn);
if (_line > startLine || (_line == startLine && _column >= startColumn)) {
unsigned endLine, endColumn;
2010-07-19 10:42:07 +02:00
_unit->getPosition(scope->endOffset(), &endLine, &endColumn);
if (_line < endLine || (_line == endLine && _column < endColumn))
_scope = scope;
}
}
return false;
}
using SymbolVisitor::visit;
bool preVisit(Symbol *) override
{ return ! _scope; }
bool visit(UsingNamespaceDirective *) override { return false; }
bool visit(UsingDeclaration *) override { return false; }
bool visit(NamespaceAlias *) override { return false; }
bool visit(Declaration *) override { return false; }
bool visit(Argument *) override { return false; }
bool visit(TypenameArgument *) override { return false; }
bool visit(BaseClass *) override { return false; }
bool visit(ForwardClassDeclaration *) override { return false; }
bool visit(Enum *symbol) override
{ return process(symbol); }
bool visit(Function *symbol) override
{ return process(symbol); }
bool visit(Namespace *symbol) override
{ return process(symbol); }
bool visit(Class *symbol) override
{ return process(symbol); }
bool visit(Block *symbol) override
{ return process(symbol); }
bool visit(Template *symbol) override
{
if (Symbol *decl = symbol->declaration()) {
if (decl->isFunction() || decl->isClass() || decl->isDeclaration())
return process(symbol);
}
return true;
}
// Objective-C
bool visit(ObjCBaseClass *) override { return false; }
bool visit(ObjCBaseProtocol *) override { return false; }
bool visit(ObjCForwardClassDeclaration *) override { return false; }
bool visit(ObjCForwardProtocolDeclaration *) override { return false; }
bool visit(ObjCPropertyDeclaration *) override { return false; }
2010-05-20 16:07:11 +02:00
bool visit(ObjCClass *symbol) override
2010-05-20 16:07:11 +02:00
{ return process(symbol); }
bool visit(ObjCProtocol *symbol) override
2010-05-20 16:07:11 +02:00
{ return process(symbol); }
bool visit(ObjCMethod *symbol) override
2010-05-20 16:07:11 +02:00
{ return process(symbol); }
};
#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
{ }
void report(int level,
const StringLiteral *fileId,
unsigned line, unsigned column,
const char *format, va_list ap) override
2008-12-02 14:09:21 +01:00
{
2009-06-04 11:42:02 +02:00
if (level == Error) {
++errorCount;
#ifdef DO_NOT_DUMP_ALL_PARSER_ERRORS
2009-06-04 11:42:02 +02:00
if (errorCount >= MAX_MESSAGE_COUNT)
return; // ignore the error
#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
const QString message = QString::vasprintf(format, ap);
2008-12-02 12:01:29 +01: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
2008-12-02 12:01:29 +01:00
Document::Document(const QString &fileName)
: _fileName(QDir::cleanPath(fileName)),
_globalNamespace(0),
_revision(0),
_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();
const StringLiteral *fileId = _control->stringLiteral(localFileName.constData(),
2009-12-01 11:33:13 +01:00
localFileName.size());
2008-12-02 12:01:29 +01:00
_translationUnit = new TranslationUnit(_control, fileId);
_translationUnit->setLanguageFeatures(LanguageFeatures::defaultFeatures());
2008-12-02 12:01:29 +01:00
}
Document::~Document()
{
delete _translationUnit;
_translationUnit = 0;
if (_control) {
delete _control->diagnosticClient();
delete _control;
}
_control = 0;
2008-12-02 12:01:29 +01:00
}
Control *Document::control() const
2008-12-02 14:09:21 +01:00
{
return _control;
}
2008-12-02 12:01:29 +01:00
Control *Document::swapControl(Control *newControl)
{
if (newControl) {
const StringLiteral *fileId = newControl->stringLiteral(_translationUnit->fileId()->chars(),
_translationUnit->fileId()->size());
const auto newTranslationUnit = new TranslationUnit(newControl, fileId);
newTranslationUnit->setLanguageFeatures(_translationUnit->languageFeatures());
delete _translationUnit;
_translationUnit = newTranslationUnit;
} else {
delete _translationUnit;
_translationUnit = 0;
}
Control *oldControl = _control;
_control = newControl;
return oldControl;
}
unsigned Document::revision() const
{
return _revision;
}
void Document::setRevision(unsigned revision)
{
_revision = revision;
}
unsigned Document::editorRevision() const
{
return _editorRevision;
}
void Document::setEditorRevision(unsigned editorRevision)
{
_editorRevision = editorRevision;
}
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
{
QStringList files;
foreach (const Include &i, _resolvedIncludes)
files.append(i.resolvedFileName());
files.removeDuplicates();
return files;
2008-12-02 14:09:21 +01:00
}
2008-12-02 12:01:29 +01:00
// This assumes to be called with a QDir::cleanPath cleaned fileName.
void Document::addIncludeFile(const Document::Include &include)
2008-12-02 14:09:21 +01: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 &macro)
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
}
void Document::addMacroUse(const Macro &macro,
unsigned bytesOffset, unsigned bytesLength,
unsigned utf16charsOffset, unsigned utf16charLength,
unsigned beginLine,
const QVector<MacroArgumentReference> &actuals)
{
MacroUse use(macro,
bytesOffset, bytesOffset + bytesLength,
utf16charsOffset, utf16charsOffset + utf16charLength,
beginLine);
foreach (const MacroArgumentReference &actual, actuals) {
const Block arg(actual.bytesOffset(),
actual.bytesOffset() + actual.bytesLength(),
actual.utf16charsOffset(),
actual.utf16charsOffset() + actual.utf16charsLength());
use.addArgument(arg);
}
_macroUses.append(use);
}
void Document::addUndefinedMacroUse(const QByteArray &name,
unsigned bytesOffset, unsigned utf16charsOffset)
{
QByteArray copy(name.data(), name.size());
UndefinedMacroUse use(copy, bytesOffset, utf16charsOffset);
_undefinedMacroUses.append(use);
}
/*!
\class Document::MacroUse
\brief The MacroUse class represents the usage of a macro in a
\l {Document}.
\sa Document::UndefinedMacroUse
*/
/*!
\class Document::UndefinedMacroUse
\brief The UndefinedMacroUse class represents a macro that was looked for,
but not found.
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
void Document::setGlobalNamespace(Namespace *globalNamespace)
{
_globalNamespace = globalNamespace;
}
/*!
* 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
* implication is that this function will return an empty string when the line/column is on the
* return type.
*
* \param line the line number, starting with line 1
* \param column the column number, starting with column 1
* \param lineOpeningDeclaratorParenthesis optional output parameter, the line of the opening
parenthesis of the declarator starting with 1
* \param lineClosingBrace optional output parameter, the line of the closing brace starting with 1
*/
QString Document::functionAt(int line, int column, int *lineOpeningDeclaratorParenthesis,
int *lineClosingBrace) const
{
if (line < 1 || column < 1)
return QString();
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 = symbol->asScope();
if (!scope)
scope = symbol->enclosingScope();
while (scope && !scope->isFunction() )
scope = scope->enclosingScope();
if (!scope)
return QString();
// We found the function scope
if (lineOpeningDeclaratorParenthesis) {
unsigned line;
translationUnit()->getPosition(scope->startOffset(), &line);
*lineOpeningDeclaratorParenthesis = static_cast<int>(line);
}
if (lineClosingBrace) {
unsigned line;
translationUnit()->getPosition(scope->endOffset(), &line);
*lineClosingBrace = static_cast<int>(line);
}
const QList<const Name *> fullyQualifiedName = LookupContext::fullyQualifiedName(scope);
return Overview().prettyName(fullyQualifiedName);
}
Scope *Document::scopeAt(unsigned line, unsigned column)
{
FindScopeAt findScopeAt(_translationUnit, line, column);
if (Scope *scope = findScopeAt(_globalNamespace))
return scope;
2010-08-11 12:26:02 +02:00
return globalNamespace();
}
2010-05-17 13:01:56 +02:00
Symbol *Document::lastVisibleSymbolAt(unsigned line, unsigned column) const
2008-12-02 14:09:21 +01:00
{
LastVisibleSymbolAt lastVisibleSymbolAt(globalNamespace());
return lastVisibleSymbolAt(line, column);
2008-12-02 12:01:29 +01:00
}
const Macro *Document::findMacroDefinitionAt(unsigned line) const
{
foreach (const Macro &macro, _definedMacros) {
if (macro.line() == line)
return &macro;
}
return 0;
}
const Document::MacroUse *Document::findMacroUseAt(unsigned utf16charsOffset) const
{
foreach (const Document::MacroUse &use, _macroUses) {
if (use.containsUtf16charOffset(utf16charsOffset)
&& (utf16charsOffset < use.utf16charsBegin() + use.macro().nameToQString().size())) {
return &use;
}
}
return 0;
}
const Document::UndefinedMacroUse *Document::findUndefinedMacroUseAt(unsigned utf16charsOffset) const
{
foreach (const Document::UndefinedMacroUse &use, _undefinedMacroUses) {
if (use.containsUtf16charOffset(utf16charsOffset)
&& (utf16charsOffset < use.utf16charsBegin()
+ QString::fromUtf8(use.name(), use.name().size()).length()))
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;
}
QByteArray Document::utf8Source() const
2009-06-05 14:29:57 +02:00
{ return _source; }
void Document::setUtf8Source(const QByteArray &source)
2008-12-02 14:09:21 +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
LanguageFeatures Document::languageFeatures() const
{
if (TranslationUnit *tu = translationUnit())
return tu->languageFeatures();
return LanguageFeatures::defaultFeatures();
}
void Document::setLanguageFeatures(LanguageFeatures features)
{
if (TranslationUnit *tu = translationUnit())
tu->setLanguageFeatures(features);
}
void Document::startSkippingBlocks(unsigned utf16charsOffset)
2008-12-02 14:09:21 +01:00
{
_skippedBlocks.append(Block(0, 0, utf16charsOffset, 0));
2008-12-02 14:09:21 +01:00
}
2008-12-02 12:01:29 +01:00
void Document::stopSkippingBlocks(unsigned utf16charsOffset)
2008-12-02 12:01:29 +01:00
{
2009-02-10 22:56:04 +01:00
if (_skippedBlocks.isEmpty())
return;
unsigned start = _skippedBlocks.back().utf16charsBegin();
if (start > utf16charsOffset)
2008-12-02 12:01:29 +01:00
_skippedBlocks.removeLast(); // Ignore this block, it's invalid.
else
_skippedBlocks.back() = Block(0, 0, start, utf16charsOffset);
2008-12-02 12:01:29 +01:00
}
bool Document::isTokenized() const
{
return _translationUnit->isTokenized();
}
void Document::tokenize()
{
_translationUnit->tokenize();
}
bool Document::isParsed() const
{
return _translationUnit->isParsed();
}
bool Document::parse(ParseMode mode)
2008-12-02 14:09:21 +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;
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
{
Q_ASSERT(!_globalNamespace);
2008-12-02 12:01:29 +01: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);
if (mode == FastCheck)
2009-06-26 09:11:14 +02:00
semantic.setSkipFunctionBodies(true);
2008-12-02 12:01:29 +01:00
if (! _translationUnit->ast())
return; // nothing to do.
if (TranslationUnitAST *ast = _translationUnit->ast()->asTranslationUnit())
2010-08-13 15:28:22 +02:00
semantic(ast, _globalNamespace);
else if (StatementAST *ast = _translationUnit->ast()->asStatement())
semantic(ast, _globalNamespace);
else if (ExpressionAST *ast = _translationUnit->ast()->asExpression())
2010-08-13 15:28:22 +02:00
semantic(ast, _globalNamespace);
else if (DeclarationAST *ast = translationUnit()->ast()->asDeclaration())
semantic(ast, _globalNamespace);
2008-12-02 12:01:29 +01:00
}
void Document::keepSourceAndAST()
{
_keepSourceAndASTCount.ref();
}
void Document::releaseSourceAndAST()
2008-12-02 14:09:21 +01:00
{
if (!_keepSourceAndASTCount.deref()) {
_source.clear();
_translationUnit->release();
if (_control)
_control->squeeze();
}
2008-12-02 14:09:21 +01: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);
}
Snapshot::Snapshot()
{
}
Snapshot::~Snapshot()
{
}
int Snapshot::size() const
{
return _documents.size();
}
bool Snapshot::isEmpty() const
{
return _documents.isEmpty();
}
Snapshot::const_iterator Snapshot::find(const Utils::FilePath &fileName) const
{
return _documents.find(fileName);
}
void Snapshot::remove(const Utils::FilePath &fileName)
{
_documents.remove(fileName);
}
bool Snapshot::contains(const Utils::FilePath &fileName) const
{
return _documents.contains(fileName);
}
void Snapshot::insert(Document::Ptr doc)
{
if (doc) {
_documents.insert(Utils::FilePath::fromString(doc->fileName()), doc);
m_deps.files.clear(); // Will trigger re-build when accessed.
}
}
static QList<Macro> macrosDefinedUntilLine(const QList<Macro> &macros, int line)
{
QList<Macro> filtered;
foreach (const Macro &macro, macros) {
if (macro.line() <= unsigned(line))
filtered.append(macro);
else
break;
}
return filtered;
}
Document::Ptr Snapshot::preprocessedDocument(const QByteArray &source,
const Utils::FilePath &fileName,
int withDefinedMacrosFromDocumentUntilLine) const
{
Document::Ptr newDoc = Document::create(fileName.toString());
if (Document::Ptr thisDocument = document(fileName)) {
newDoc->_revision = thisDocument->_revision;
newDoc->_editorRevision = thisDocument->_editorRevision;
newDoc->_lastModified = thisDocument->_lastModified;
newDoc->_resolvedIncludes = thisDocument->_resolvedIncludes;
newDoc->_unresolvedIncludes = thisDocument->_unresolvedIncludes;
newDoc->setLanguageFeatures(thisDocument->languageFeatures());
if (withDefinedMacrosFromDocumentUntilLine != -1) {
newDoc->_definedMacros = macrosDefinedUntilLine(thisDocument->_definedMacros,
withDefinedMacrosFromDocumentUntilLine);
}
}
FastPreprocessor pp(*this);
const bool mergeDefinedMacrosOfDocument = !newDoc->_definedMacros.isEmpty();
const QByteArray preprocessedCode = pp.run(newDoc, source, mergeDefinedMacrosOfDocument);
newDoc->setUtf8Source(preprocessedCode);
return newDoc;
}
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);
if (Document::Ptr thisDocument = document(fileName)) {
newDoc->_revision = thisDocument->_revision;
newDoc->_editorRevision = thisDocument->_editorRevision;
newDoc->_lastModified = thisDocument->_lastModified;
newDoc->_resolvedIncludes = thisDocument->_resolvedIncludes;
newDoc->_unresolvedIncludes = thisDocument->_unresolvedIncludes;
newDoc->_definedMacros = thisDocument->_definedMacros;
newDoc->_macroUses = thisDocument->_macroUses;
newDoc->setLanguageFeatures(thisDocument->languageFeatures());
}
newDoc->setUtf8Source(preprocessedCode);
2009-06-24 16:40:30 +02:00
return newDoc;
}
QSet<QString> Snapshot::allIncludesForDocument(const QString &fileName) const
{
QSet<QString> result;
allIncludesForDocument_helper(fileName, result);
return result;
}
QList<Snapshot::IncludeLocation> Snapshot::includeLocationsOfDocument(const QString &fileName) const
{
QList<IncludeLocation> result;
for (const_iterator cit = begin(), citEnd = end(); cit != citEnd; ++cit) {
const Document::Ptr doc = cit.value();
foreach (const Document::Include &includeFile, doc->resolvedIncludes()) {
if (includeFile.resolvedFileName() == fileName)
result.append(qMakePair(doc, includeFile.line()));
}
}
return result;
}
Utils::FilePathList Snapshot::filesDependingOn(const Utils::FilePath &fileName) const
{
updateDependencyTable();
return m_deps.filesDependingOn(fileName);
}
void Snapshot::updateDependencyTable() const
{
if (m_deps.files.isEmpty())
m_deps.build(*this);
}
bool Snapshot::operator==(const Snapshot &other) const
{
return _documents == other._documents;
}
void Snapshot::allIncludesForDocument_helper(const QString &fileName, QSet<QString> &result) const
2009-07-10 11:59:01 +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
}
Document::Ptr Snapshot::document(const Utils::FilePath &fileName) const
2009-07-10 11:59:01 +02:00
{
return _documents.value(fileName);
}
2009-07-10 11:59:01 +02:00
Snapshot Snapshot::simplified(Document::Ptr doc) const
{
Snapshot snapshot;
2009-07-10 11:59:01 +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
}
return snapshot;
}