Files
qt-creator/src/libs/cplusplus/CppDocument.h
Nikolai Kosjar beac7b9539 C++: Fix highlighting after "invalid code"
For the semantic info document we do not expand function like macros and
because of that certain macro invocations lead to invalid code that we
need to handle, e.g.:

	Q_GLOBAL_STATIC(CppTools::SymbolFinder, symbolFinder)
	class Foo {};

This change makes parsing Foo in the semantic info document successfully
again, which affects highlighting of that class.

Change-Id: I389265ac64d3f0b8b8f406d38fa58d78820b14ba
Reviewed-by: Erik Verbruggen <erik.verbruggen@theqtcompany.com>
2014-11-19 16:10:56 +01:00

448 lines
13 KiB
C++

/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://www.qt.io/licensing. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CPLUSPLUS_CPPDOCUMENT_H
#define CPLUSPLUS_CPPDOCUMENT_H
#include "Macro.h"
#include <cplusplus/CPlusPlusForwardDeclarations.h>
#include <cplusplus/PreprocessorClient.h>
#include <cplusplus/DependencyTable.h>
#include <QSharedPointer>
#include <QDateTime>
#include <QHash>
#include <QFileInfo>
#include <QAtomicInt>
// in debug mode: make dumpers widely available without an extra include
#ifdef QT_DEBUG
#include "Dumpers.h"
#endif
namespace CPlusPlus {
class Macro;
class MacroArgumentReference;
class LookupContext;
class CPLUSPLUS_EXPORT Document
{
Document(const Document &other);
void operator =(const Document &other);
Document(const QString &fileName);
public:
typedef QSharedPointer<Document> Ptr;
public:
~Document();
unsigned revision() const;
void setRevision(unsigned revision);
unsigned editorRevision() const;
void setEditorRevision(unsigned editorRevision);
QDateTime lastModified() const;
void setLastModified(const QDateTime &lastModified);
QString fileName() const;
void appendMacro(const Macro &macro);
void addMacroUse(const Macro &macro,
unsigned bytesOffset, unsigned bytesLength,
unsigned utf16charsOffset, unsigned utf16charLength,
unsigned beginLine, const QVector<MacroArgumentReference> &range);
void addUndefinedMacroUse(const QByteArray &name,
unsigned bytesOffset, unsigned utf16charsOffset);
Control *control() const;
TranslationUnit *translationUnit() const;
bool skipFunctionBody() const;
void setSkipFunctionBody(bool skipFunctionBody);
unsigned globalSymbolCount() const;
Symbol *globalSymbolAt(unsigned index) const;
Namespace *globalNamespace() const;
void setGlobalNamespace(Namespace *globalNamespace); // ### internal
QList<Macro> definedMacros() const
{ return _definedMacros; }
QString functionAt(int line, int column, int *lineOpeningDeclaratorParenthesis = 0,
int *lineClosingBrace = 0) const;
Symbol *lastVisibleSymbolAt(unsigned line, unsigned column = 0) const;
Scope *scopeAt(unsigned line, unsigned column = 0);
QByteArray utf8Source() const;
void setUtf8Source(const QByteArray &utf8Source);
QByteArray fingerprint() const { return m_fingerprint; }
void setFingerprint(const QByteArray &fingerprint)
{ m_fingerprint = fingerprint; }
void startSkippingBlocks(unsigned utf16charsOffset);
void stopSkippingBlocks(unsigned utf16charsOffset);
enum ParseMode { // ### keep in sync with CPlusPlus::TranslationUnit
ParseTranlationUnit,
ParseDeclaration,
ParseExpression,
ParseDeclarator,
ParseStatement
};
bool isTokenized() const;
void tokenize();
void setRetryHarderToParseDeclarations(bool yesno);
bool isParsed() const;
bool parse(ParseMode mode = ParseTranlationUnit);
enum CheckMode {
Unchecked,
FullCheck,
FastCheck
};
void check(CheckMode mode = FullCheck);
static Ptr create(const QString &fileName);
class CPLUSPLUS_EXPORT DiagnosticMessage
{
public:
enum Level {
Warning,
Error,
Fatal
};
public:
DiagnosticMessage(int level, const QString &fileName,
unsigned line, unsigned column,
const QString &text,
unsigned length = 0)
: _level(level),
_line(line),
_fileName(fileName),
_column(column),
_length(length),
_text(text)
{ }
int level() const
{ return _level; }
bool isWarning() const
{ return _level == Warning; }
bool isError() const
{ return _level == Error; }
bool isFatal() const
{ return _level == Fatal; }
QString fileName() const
{ return _fileName; }
unsigned line() const
{ return _line; }
unsigned column() const
{ return _column; }
unsigned length() const
{ return _length; }
QString text() const
{ return _text; }
bool operator==(const DiagnosticMessage &other) const;
bool operator!=(const DiagnosticMessage &other) const;
private:
int _level;
unsigned _line;
QString _fileName;
unsigned _column;
unsigned _length;
QString _text;
};
void addDiagnosticMessage(const DiagnosticMessage &d)
{ _diagnosticMessages.append(d); }
void clearDiagnosticMessages()
{ _diagnosticMessages.clear(); }
QList<DiagnosticMessage> diagnosticMessages() const
{ return _diagnosticMessages; }
class Block
{
unsigned _bytesBegin;
unsigned _bytesEnd;
unsigned _utf16charsBegin;
unsigned _utf16charsEnd;
public:
inline Block(unsigned bytesBegin = 0, unsigned bytesEnd = 0,
unsigned utf16charsBegin = 0, unsigned utf16charsEnd = 0)
: _bytesBegin(bytesBegin),
_bytesEnd(bytesEnd),
_utf16charsBegin(utf16charsBegin),
_utf16charsEnd(utf16charsEnd)
{}
inline unsigned bytesBegin() const
{ return _bytesBegin; }
inline unsigned bytesEnd() const
{ return _bytesEnd; }
inline unsigned utf16charsBegin() const
{ return _utf16charsBegin; }
inline unsigned utf16charsEnd() const
{ return _utf16charsEnd; }
bool containsUtf16charOffset(unsigned utf16charOffset) const
{ return utf16charOffset >= _utf16charsBegin && utf16charOffset < _utf16charsEnd; }
};
class Include {
QString _resolvedFileName;
QString _unresolvedFileName;
unsigned _line;
Client::IncludeType _type;
public:
Include(const QString &unresolvedFileName, const QString &resolvedFileName, unsigned line,
Client::IncludeType type)
: _resolvedFileName(resolvedFileName)
, _unresolvedFileName(unresolvedFileName)
, _line(line)
, _type(type)
{ }
QString resolvedFileName() const
{ return _resolvedFileName; }
QString unresolvedFileName() const
{ return _unresolvedFileName; }
unsigned line() const
{ return _line; }
Client::IncludeType type() const
{ return _type; }
};
class MacroUse: public Block {
Macro _macro;
QVector<Block> _arguments;
unsigned _beginLine;
public:
inline MacroUse(const Macro &macro,
unsigned bytesBegin, unsigned bytesEnd,
unsigned utf16charsBegin, unsigned utf16charsEnd,
unsigned beginLine)
: Block(bytesBegin, bytesEnd, utf16charsBegin, utf16charsEnd),
_macro(macro),
_beginLine(beginLine)
{ }
const Macro &macro() const
{ return _macro; }
bool isFunctionLike() const
{ return _macro.isFunctionLike(); }
QVector<Block> arguments() const
{ return _arguments; }
unsigned beginLine() const
{ return _beginLine; }
private:
void setArguments(const QVector<Block> &arguments)
{ _arguments = arguments; }
void addArgument(const Block &block)
{ _arguments.append(block); }
friend class Document;
};
class UndefinedMacroUse: public Block {
QByteArray _name;
public:
inline UndefinedMacroUse(
const QByteArray &name,
unsigned bytesBegin,
unsigned utf16charsBegin)
: Block(bytesBegin,
bytesBegin + name.length(),
utf16charsBegin,
utf16charsBegin + QString::fromUtf8(name, name.size()).size()),
_name(name)
{ }
QByteArray name() const
{
return _name;
}
};
QStringList includedFiles() const;
void addIncludeFile(const Include &include);
QList<Include> resolvedIncludes() const
{ return _resolvedIncludes; }
QList<Include> unresolvedIncludes() const
{ return _unresolvedIncludes; }
QList<Block> skippedBlocks() const
{ return _skippedBlocks; }
QList<MacroUse> macroUses() const
{ return _macroUses; }
QList<UndefinedMacroUse> undefinedMacroUses() const
{ return _undefinedMacroUses; }
void setIncludeGuardMacroName(const QByteArray &includeGuardMacroName)
{ _includeGuardMacroName = includeGuardMacroName; }
QByteArray includeGuardMacroName() const
{ return _includeGuardMacroName; }
const Macro *findMacroDefinitionAt(unsigned line) const;
const MacroUse *findMacroUseAt(unsigned utf16charsOffset) const;
const UndefinedMacroUse *findUndefinedMacroUseAt(unsigned utf16charsOffset) const;
void keepSourceAndAST();
void releaseSourceAndAST();
CheckMode checkMode() const
{ return static_cast<CheckMode>(_checkMode); }
private:
QString _fileName;
Control *_control;
TranslationUnit *_translationUnit;
Namespace *_globalNamespace;
/// All messages generated during lexical/syntactic/semantic analysis.
QList<DiagnosticMessage> _diagnosticMessages;
QList<Include> _resolvedIncludes;
QList<Include> _unresolvedIncludes;
QList<Macro> _definedMacros;
QList<Block> _skippedBlocks;
QList<MacroUse> _macroUses;
QList<UndefinedMacroUse> _undefinedMacroUses;
/// the macro name of the include guard, if there is one.
QByteArray _includeGuardMacroName;
QByteArray m_fingerprint;
QByteArray _source;
QDateTime _lastModified;
QAtomicInt _keepSourceAndASTCount;
unsigned _revision;
unsigned _editorRevision;
quint8 _checkMode;
friend class Snapshot;
};
class CPLUSPLUS_EXPORT Snapshot
{
typedef QHash<QString, Document::Ptr> Base;
public:
Snapshot();
~Snapshot();
typedef Base::const_iterator iterator;
typedef Base::const_iterator const_iterator;
typedef QPair<Document::Ptr, unsigned> IncludeLocation;
int size() const; // ### remove
bool isEmpty() const;
void insert(Document::Ptr doc); // ### remove
void remove(const QString &fileName); // ### remove
const_iterator begin() const { return _documents.begin(); }
const_iterator end() const { return _documents.end(); }
bool contains(const QString &fileName) const;
Document::Ptr document(const QString &fileName) const;
const_iterator find(const QString &fileName) const;
Snapshot simplified(Document::Ptr doc) const;
Document::Ptr preprocessedDocument(const QByteArray &source,
const QString &fileName) const;
Document::Ptr documentFromSource(const QByteArray &preprocessedDocument,
const QString &fileName) const;
QSet<QString> allIncludesForDocument(const QString &fileName) const;
QList<IncludeLocation> includeLocationsOfDocument(const QString &fileName) const;
QStringList filesDependingOn(const QString &fileName) const;
void updateDependencyTable() const;
bool operator==(const Snapshot &other) const;
private:
void allIncludesForDocument_helper(const QString &fileName, QSet<QString> &result) const;
mutable DependencyTable m_deps;
Base _documents;
};
} // namespace CPlusPlus
#endif // CPLUSPLUS_CPPDOCUMENT_H