ClangCodeModel: Highlight Q_PROPERTY declarations with clangd

We re-use the moc parser for this purpose.

Change-Id: Ib0ef4f727d1f0b862a202a95a3ae9c551cb502a5
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2021-11-26 12:54:50 +01:00
parent 6db5faa2e8
commit 0f9aa307a3
18 changed files with 4050 additions and 9 deletions

View File

@@ -30,6 +30,7 @@ add_qtc_plugin(ClangCodeModel
clangdiagnosticmanager.cpp clangdiagnosticmanager.h
clangdiagnostictooltipwidget.cpp clangdiagnostictooltipwidget.h
clangdquickfixfactory.cpp clangdquickfixfactory.h
clangdqpropertyhighlighter.cpp clangdqpropertyhighlighter.h
clangeditordocumentparser.cpp clangeditordocumentparser.h
clangeditordocumentprocessor.cpp clangeditordocumentprocessor.h
clangfixitoperation.cpp clangfixitoperation.h
@@ -52,6 +53,15 @@ add_qtc_plugin(ClangCodeModel
EXPLICIT_MOC clangcodemodelplugin.h
)
extend_qtc_plugin(ClangCodeModel
SOURCES
moc/parser.cpp moc/parser.h
moc/preprocessor.cpp moc/preprocessor.h
moc/symbols.h
moc/token.cpp moc/token.h
moc/utils.h
)
extend_qtc_plugin(ClangCodeModel
CONDITION WITH_TESTS
SOURCES

View File

@@ -24,6 +24,7 @@ SOURCES += \
clangdiagnosticfilter.cpp \
clangdiagnosticmanager.cpp \
clangdiagnostictooltipwidget.cpp \
clangdqpropertyhighlighter.cpp \
clangeditordocumentparser.cpp \
clangeditordocumentprocessor.cpp \
clangfixitoperation.cpp \
@@ -44,6 +45,9 @@ SOURCES += \
clangdclient.cpp \
clangdquickfixfactory.cpp \
clangdlocatorfilters.cpp \
moc/parser.cpp \
moc/preprocessor.cpp \
moc/token.cpp
HEADERS += \
clangactivationsequencecontextprocessor.h \
@@ -65,6 +69,7 @@ HEADERS += \
clangdiagnosticfilter.h \
clangdiagnosticmanager.h \
clangdiagnostictooltipwidget.h \
clangdqpropertyhighlighter.h \
clangeditordocumentparser.h \
clangeditordocumentprocessor.h \
clangfixitoperation.h \
@@ -86,6 +91,13 @@ HEADERS += \
clangdclient.h \
clangdquickfixfactory.h \
clangdlocatorfilters.h \
moc/keywords.cpp \
moc/parser.h \
moc/ppkeywords.cpp \
moc/preprocessor.h \
moc/symbols.h \
moc/token.h \
moc/utils.h
FORMS += clangprojectsettingswidget.ui

View File

@@ -66,6 +66,8 @@ QtcPlugin {
"clangdiagnostictooltipwidget.h",
"clangdlocatorfilters.cpp",
"clangdlocatorfilters.h",
"clangdqpropertyhighlighter.cpp",
"clangdqpropertyhighlighter.h",
"clangdquickfixfactory.cpp",
"clangdquickfixfactory.h",
"clangeditordocumentparser.cpp",
@@ -106,6 +108,29 @@ QtcPlugin {
"clangutils.h",
]
Group {
name: "moc sources"
prefix: "moc/"
files: [
"parser.cpp",
"parser.h",
"preprocessor.cpp",
"preprocessor.h",
"symbols.h",
"token.cpp",
"token.h",
"utils.h",
]
Group {
name: "weirdly-named moc headers"
files: [
"keywords.cpp",
"ppkeywords.cpp",
]
fileTags: "hpp"
}
}
Group {
name: "Tests"
condition: qtc.testsEnabled

View File

@@ -28,6 +28,7 @@
#include "clangcompletionassistprocessor.h"
#include "clangcompletioncontextanalyzer.h"
#include "clangdiagnosticmanager.h"
#include "clangdqpropertyhighlighter.h"
#include "clangmodelmanagersupport.h"
#include "clangpreprocessorassistproposalitem.h"
#include "clangtextmark.h"
@@ -3232,6 +3233,26 @@ ExtraHighlightingResultsCollector::ExtraHighlightingResultsCollector(
void ExtraHighlightingResultsCollector::collect()
{
for (int i = 0; i < m_results.length(); ++i) {
const HighlightingResult res = m_results.at(i);
if (res.textStyles.mainStyle != C_PREPROCESSOR || res.length != 10)
continue;
const int pos = Utils::Text::positionInText(m_doc, res.line, res.column);
if (subViewLen(m_docContent, pos, 10) != QLatin1String("Q_PROPERTY"))
continue;
int endPos;
if (i < m_results.length() - 1) {
const HighlightingResult nextRes = m_results.at(i + 1);
endPos = Utils::Text::positionInText(m_doc, nextRes.line, nextRes.column);
} else {
endPos = m_docContent.length();
}
const QString qPropertyString = m_docContent.mid(pos, endPos - pos);
QPropertyHighlighter propHighlighter(m_doc, qPropertyString, pos);
for (const HighlightingResult &newRes : propHighlighter.highlight())
m_results.insert(++i, newRes);
}
if (!m_ast.isValid())
return;
visitNode(m_ast);

View File

@@ -0,0 +1,427 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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 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.
**
****************************************************************************/
#include "clangdqpropertyhighlighter.h"
#include "moc/parser.h"
#include "moc/preprocessor.h"
#include "moc/utils.h"
#include <utils/textutils.h>
#include <QVersionNumber>
using namespace TextEditor;
namespace ClangCodeModel {
namespace Internal {
class QPropertyHighlighter::Private
{
public:
QByteArray lexemUntil(Token target);
void highlightProperty();
const QTextDocument *document;
QString input;
int position;
Preprocessor pp;
Parser parser;
TextEditor::HighlightingResults results;
private:
void highlightType();
void highlightAttributes();
void highlightRevision();
bool until(Token target);
void skipCxxAttributes();
void addResult(TextStyle textStyle, int symbolOffset = 0);
};
QPropertyHighlighter::QPropertyHighlighter(const QTextDocument *doc, const QString &input,
int position)
: d(new Private)
{
d->document = doc;
d->input = input;
d->position = position;
d->pp.macros["Q_MOC_RUN"];
d->pp.macros["__cplusplus"];
// Don't stumble over GCC extensions
Macro dummyVariadicFunctionMacro;
dummyVariadicFunctionMacro.isFunction = true;
dummyVariadicFunctionMacro.isVariadic = true;
dummyVariadicFunctionMacro.arguments += Symbol(0, PP_IDENTIFIER, "__VA_ARGS__");
d->pp.macros["__attribute__"] = dummyVariadicFunctionMacro;
d->pp.macros["__declspec"] = dummyVariadicFunctionMacro;
}
QPropertyHighlighter::~QPropertyHighlighter() { delete d; }
const HighlightingResults QPropertyHighlighter::highlight()
{
try {
d->highlightProperty();
return d->results;
} catch (const MocParseException &) {
return {};
}
}
void QPropertyHighlighter::Private::highlightProperty()
{
parser.symbols = pp.preprocessed({}, input.toUtf8());
parser.next(Q_PROPERTY_TOKEN);
parser.next(LPAREN);
highlightType();
parser.next();
addResult(C_FIELD);
highlightAttributes();
}
void QPropertyHighlighter::Private::highlightType()
{
for (;;) {
skipCxxAttributes();
switch (parser.next()) {
case SIGNED:
case UNSIGNED:
case CONST_TOKEN:
case VOLATILE:
addResult(C_KEYWORD);
continue;
case Q_MOC_COMPAT_TOKEN:
case Q_INVOKABLE_TOKEN:
case Q_SCRIPTABLE_TOKEN:
case Q_SIGNALS_TOKEN:
case Q_SLOTS_TOKEN:
case Q_SIGNAL_TOKEN:
case Q_SLOT_TOKEN:
return;
case NOTOKEN:
return;
default:
parser.prev();
break;
}
break;
}
skipCxxAttributes();
parser.test(ENUM) || parser.test(CLASS) || parser.test(STRUCT);
for(;;) {
skipCxxAttributes();
switch (parser.next()) {
case IDENTIFIER:
addResult(C_TYPE);
break;
case CHAR_TOKEN:
case SHORT_TOKEN:
case INT_TOKEN:
case LONG_TOKEN:
addResult(C_KEYWORD);
// preserve '[unsigned] long long', 'short int', 'long int', 'long double'
if (parser.test(LONG_TOKEN) || parser.test(INT_TOKEN) || parser.test(DOUBLE)) {
parser.prev();
continue;
}
break;
case FLOAT_TOKEN:
case DOUBLE:
case VOID_TOKEN:
case BOOL_TOKEN:
case AUTO:
addResult(C_KEYWORD);
break;
case NOTOKEN:
return;
default:
parser.prev();
break;
}
if (parser.test(LANGLE)) {
if (results.size() < 2) {
// '<' cannot start a type
return;
}
until(RANGLE); // TODO: Highlight template parameter?
}
if (parser.test(SCOPE)) {
addResult(C_PUNCTUATION);
} else {
break;
}
}
while (parser.test(CONST_TOKEN) || parser.test(VOLATILE) || parser.test(SIGNED)
|| parser.test(UNSIGNED) || parser.test(STAR) || parser.test(AND)
|| parser.test(ANDAND)) {
TextStyle textStyle = parser.test(CONST_TOKEN) || parser.test(VOLATILE)
? C_KEYWORD
: parser.test(SIGNED) || parser.test(UNSIGNED)
? C_TYPE
: C_PUNCTUATION;
addResult(textStyle);
}
}
void QPropertyHighlighter::Private::highlightAttributes()
{
auto checkIsFunction = [&](const QByteArray &def, const char *name) {
if (def.endsWith(')')) {
QByteArray msg = "Providing a function for ";
msg += name;
msg += " in a property declaration is not be supported in Qt 6.";
parser.error(msg.constData());
}
};
while (parser.test(IDENTIFIER)) {
const QByteArray l = parser.lexem();
if (l[0] == 'C' && l == "CONSTANT") {
addResult(C_KEYWORD);
continue;
} else if (l[0] == 'F' && l == "FINAL") {
addResult(C_KEYWORD);
continue;
} else if (l[0] == 'N' && l == "NAME") {
addResult(C_KEYWORD);
parser.next(IDENTIFIER);
addResult(C_FIELD);
continue;
} else if (l[0] == 'R' && l == "REQUIRED") {
addResult(C_KEYWORD);
continue;
} else if (l[0] == 'R' && l == "REVISION" && parser.test(LPAREN)) {
parser.prev();
highlightRevision();
continue;
}
QByteArray v, v2;
if (parser.test(LPAREN)) {
v = lexemUntil(RPAREN);
v = v.mid(1, v.length() - 2); // removes the '(' and ')'
} else if (parser.test(INTEGER_LITERAL)) {
v = parser.lexem();
if (l != "REVISION")
parser.error(1);
} else {
addResult(C_KEYWORD);
parser.next(IDENTIFIER);
addResult(C_FUNCTION);
v = parser.lexem();
if (parser.test(LPAREN))
v2 = lexemUntil(RPAREN);
else if (v != "true" && v != "false")
v2 = "()";
}
switch (l[0]) {
case 'M':
if (l != "MEMBER")
parser.error(2);
break;
case 'R':
if (l == "READ")
break;
if (l == "RESET")
break;
if (l == "REVISION") {
parser.prev();
highlightRevision();
break;
}
parser.error(2);
break;
case 'S':
if (l == "SCRIPTABLE") {
checkIsFunction(v + v2, "SCRIPTABLE");
} else if (l == "STORED") {
checkIsFunction(v + v2, "STORED");
} else
parser.error(2);
break;
case 'W': if (l != "WRITE") parser.error(2);
break;
case 'B': if (l != "BINDABLE") parser.error(2);
break;
case 'D': if (l != "DESIGNABLE") parser.error(2);
checkIsFunction(v + v2, "DESIGNABLE");
break;
case 'N': if (l != "NOTIFY") parser.error(2);
break;
case 'U': if (l != "USER") parser.error(2);
checkIsFunction(v + v2, "USER");
break;
default:
parser.error(2);
}
}
}
void QPropertyHighlighter::Private::highlightRevision()
{
addResult(C_KEYWORD);
QByteArray revisionString;
const bool hasParen = parser.test(LPAREN);
if (hasParen) {
revisionString = lexemUntil(RPAREN);
revisionString.remove(0, 1);
revisionString.chop(1);
revisionString.replace(',', '.');
} else {
parser.next(INTEGER_LITERAL);
revisionString = parser.lexem();
}
QVersionNumber version = QVersionNumber::fromString(QString::fromUtf8(revisionString));
if (version.isNull() || version.segmentCount() > 2)
parser.error("Invalid revision");
}
QByteArray QPropertyHighlighter::Private::lexemUntil(Token target)
{
int from = parser.index;
until(target);
QByteArray s;
while (from <= parser.index) {
QByteArray n = parser.symbols.at(from++-1).lexem();
if (s.size() && n.size()) {
char prev = s.at(s.size()-1);
char next = n.at(0);
if ((is_ident_char(prev) && is_ident_char(next))
|| (prev == '<' && next == ':')
|| (prev == '>' && next == '>'))
s += ' ';
}
s += n;
}
return s;
}
bool QPropertyHighlighter::Private::until(Token target)
{
int braceCount = 0;
int brackCount = 0;
int parenCount = 0;
int angleCount = 0;
if (parser.index) {
switch(parser.symbols.at(parser.index-1).token) {
case LBRACE: ++braceCount; break;
case LBRACK: ++brackCount; break;
case LPAREN: ++parenCount; break;
case LANGLE: ++angleCount; break;
default: break;
}
}
//when searching commas within the default argument, we should take care of template depth (anglecount)
// unfortunatelly, we do not have enough semantic information to know if '<' is the operator< or
// the beginning of a template type. so we just use heuristics.
int possible = -1;
while (parser.index < parser.symbols.size()) {
Token t = parser.symbols.at(parser.index++).token;
switch (t) {
case LBRACE: ++braceCount; break;
case RBRACE: --braceCount; break;
case LBRACK: ++brackCount; break;
case RBRACK: --brackCount; break;
case LPAREN: ++parenCount; break;
case RPAREN: --parenCount; break;
case LANGLE:
if (parenCount == 0 && braceCount == 0)
++angleCount;
break;
case RANGLE:
if (parenCount == 0 && braceCount == 0)
--angleCount;
break;
case GTGT:
if (parenCount == 0 && braceCount == 0) {
angleCount -= 2;
t = RANGLE;
}
break;
default: break;
}
if (t == target
&& braceCount <= 0
&& brackCount <= 0
&& parenCount <= 0
&& (target != RANGLE || angleCount <= 0)) {
if (target != COMMA || angleCount <= 0)
return true;
possible = parser.index;
}
if (target == COMMA && t == EQ && possible != -1) {
parser.index = possible;
return true;
}
if (braceCount < 0 || brackCount < 0 || parenCount < 0
|| (target == RANGLE && angleCount < 0)) {
--parser.index;
break;
}
if (braceCount <= 0 && t == SEMIC) {
// Abort on semicolon. Allow recovering bad template parsing (QTBUG-31218)
break;
}
}
if (target == COMMA && angleCount != 0 && possible != -1) {
parser.index = possible;
return true;
}
return false;
}
void QPropertyHighlighter::Private::skipCxxAttributes()
{
int rewind = parser.index;
if (parser.test(LBRACK) && parser.test(LBRACK) && until(RBRACK) && parser.test(RBRACK))
return;
parser.index = rewind;
}
void QPropertyHighlighter::Private::addResult(TextStyle textStyle, int symbolOffset)
{
const Symbol &s = parser.symbol_lookup(symbolOffset);
int line, column;
Utils::Text::convertPosition(document, position + s.from, &line, &column);
if (line > 0 && column > 0) {
TextStyles styles;
styles.mainStyle = textStyle;
results << HighlightingResult(line, column, s.len, styles);
}
}
} // namespace Internal
} // namespace ClangCodeModel

View File

@@ -0,0 +1,52 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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 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.
**
****************************************************************************/
#pragma once
#include <texteditor/semantichighlighter.h>
QT_BEGIN_NAMESPACE
class QTextDocument;
QT_END_NAMESPACE
namespace ClangCodeModel {
namespace Internal {
class QPropertyHighlighter
{
public:
QPropertyHighlighter(const QTextDocument *doc, const QString &input, int position);
~QPropertyHighlighter();
const TextEditor::HighlightingResults highlight();
private:
class Private;
Private * const d;
};
} // namespace Internal
} // namespace ClangCodeModel

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,64 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** 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.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "parser.h"
#include "utils.h"
#include <stdio.h>
#include <stdlib.h>
QT_BEGIN_NAMESPACE
#ifdef USE_LEXEM_STORE
Symbol::LexemStore Symbol::lexemStore;
#endif
#ifdef Q_CC_MSVC
#define ErrorFormatString "%s(%d:%d): "
#else
#define ErrorFormatString "%s:%d:%d: "
#endif
void Parser::error(int rollback) {
index -= rollback;
error();
}
void Parser::error(const char *) { throw MocParseException(); }
void Parser::warning(const char *msg) {
if (displayWarnings && msg)
fprintf(stderr, ErrorFormatString "warning: %s\n",
currentFilenames.top().constData(), qMax(0, index > 0 ? symbol().lineNum : 0), 1, msg);
}
void Parser::note(const char *msg) {
if (displayNotes && msg)
fprintf(stderr, ErrorFormatString "note: %s\n",
currentFilenames.top().constData(), qMax(0, index > 0 ? symbol().lineNum : 0), 1, msg);
}
QT_END_NAMESPACE

View File

@@ -0,0 +1,110 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** 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.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef PARSER_H
#define PARSER_H
#include "symbols.h"
#include <stack>
QT_BEGIN_NAMESPACE
struct MocParseException {};
class Parser
{
public:
Parser():index(0), displayWarnings(true), displayNotes(true) {}
Symbols symbols;
int index;
bool displayWarnings;
bool displayNotes;
struct IncludePath
{
inline explicit IncludePath(const QByteArray &_path)
: path(_path), isFrameworkPath(false) {}
QByteArray path;
bool isFrameworkPath;
};
QList<IncludePath> includes;
std::stack<QByteArray, QByteArrayList> currentFilenames;
inline bool hasNext() const { return (index < symbols.size()); }
inline Token next() { if (index >= symbols.size()) return NOTOKEN; return symbols.at(index++).token; }
inline Token peek() { if (index >= symbols.size()) return NOTOKEN; return symbols.at(index).token; }
bool test(Token);
void next(Token);
void next(Token, const char *msg);
inline void prev() {--index;}
inline Token lookup(int k = 1);
inline const Symbol &symbol_lookup(int k = 1) { return symbols.at(index-1+k);}
inline Token token() { return symbols.at(index-1).token;}
inline QByteArray lexem() { return symbols.at(index-1).lexem();}
inline QByteArray unquotedLexem() { return symbols.at(index-1).unquotedLexem();}
inline const Symbol &symbol() { return symbols.at(index-1);}
Q_NORETURN void error(int rollback);
Q_NORETURN void error(const char *msg = nullptr);
void warning(const char * = nullptr);
void note(const char * = nullptr);
};
inline bool Parser::test(Token token)
{
if (index < symbols.size() && symbols.at(index).token == token) {
++index;
return true;
}
return false;
}
inline Token Parser::lookup(int k)
{
const int l = index - 1 + k;
return l < symbols.size() ? symbols.at(l).token : NOTOKEN;
}
inline void Parser::next(Token token)
{
if (!test(token))
error();
}
inline void Parser::next(Token token, const char *msg)
{
if (!test(token))
error(msg);
}
QT_END_NAMESPACE
#endif

View File

@@ -0,0 +1,235 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** 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.
**
** $QT_END_LICENSE$
**
****************************************************************************/
// auto generated
// DO NOT EDIT.
static const short pp_keyword_trans[][128] = {
{0,0,0,0,0,0,0,0,0,98,12,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
98,76,96,13,1,60,62,97,9,10,58,56,11,57,102,59,
6,6,6,6,6,6,6,6,6,6,92,0,7,81,8,91,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,0,101,0,61,1,
0,1,2,3,4,1,1,1,1,1,1,1,1,1,5,1,
1,1,1,1,1,1,1,1,1,1,1,0,68,0,71,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,79,87,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,88,80,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,93,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,14,34,0,0,0,20,0,0,0,0,0,0,
0,0,0,0,0,22,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,21,0,0,0,0,0,0,0,44,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,27,0,0,0,0,0,0,0,0,0,30,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,35,0,40,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,
0,0,0,38,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,99,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,65,0,0,0,0,0,0,0,0,0,0,0,0,0,69,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
103,103,103,103,103,103,103,103,103,103,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
static const struct
{
PP_Token token;
short next;
char defchar;
short defnext;
PP_Token ident;
} pp_keywords[] = {
{PP_NOTOKEN, 0, 0, 0, PP_NOTOKEN},
{PP_CHARACTER, 0, 0, 0, PP_NOTOKEN},
{PP_CHARACTER, 0, 105, 63, PP_NOTOKEN},
{PP_CHARACTER, 0, 111, 72, PP_NOTOKEN},
{PP_CHARACTER, 0, 101, 50, PP_NOTOKEN},
{PP_CHARACTER, 0, 111, 77, PP_NOTOKEN},
{PP_DIGIT, 0, 0, 0, PP_NOTOKEN},
{PP_LANGLE, 1, 0, 0, PP_NOTOKEN},
{PP_RANGLE, 2, 0, 0, PP_NOTOKEN},
{PP_LPAREN, 0, 0, 0, PP_NOTOKEN},
{PP_RPAREN, 0, 0, 0, PP_NOTOKEN},
{PP_COMMA, 0, 0, 0, PP_NOTOKEN},
{PP_NEWLINE, 0, 0, 0, PP_NOTOKEN},
{PP_HASH, 3, 0, 0, PP_HASH},
{PP_HASH, 0, 101, 15, PP_HASH},
{PP_HASH, 0, 102, 16, PP_HASH},
{PP_HASH, 0, 105, 17, PP_HASH},
{PP_HASH, 0, 110, 18, PP_HASH},
{PP_HASH, 0, 101, 19, PP_HASH},
{PP_DEFINE, 0, 0, 0, PP_HASH},
{PP_HASH, 4, 0, 0, PP_HASH},
{PP_IF, 5, 0, 0, PP_HASH},
{PP_HASH, 0, 110, 23, PP_HASH},
{PP_HASH, 0, 100, 24, PP_HASH},
{PP_HASH, 0, 101, 25, PP_HASH},
{PP_HASH, 0, 102, 26, PP_HASH},
{PP_UNDEF, 0, 0, 0, PP_HASH},
{PP_HASH, 0, 101, 28, PP_HASH},
{PP_HASH, 0, 102, 29, PP_HASH},
{PP_IFDEF, 0, 0, 0, PP_HASH},
{PP_HASH, 0, 100, 31, PP_HASH},
{PP_HASH, 0, 101, 32, PP_HASH},
{PP_HASH, 0, 102, 33, PP_HASH},
{PP_IFNDEF, 0, 0, 0, PP_HASH},
{PP_HASH, 6, 0, 0, PP_HASH},
{PP_HASH, 7, 0, 0, PP_HASH},
{PP_HASH, 0, 102, 37, PP_HASH},
{PP_ELIF, 0, 0, 0, PP_HASH},
{PP_HASH, 0, 101, 39, PP_HASH},
{PP_ELSE, 0, 0, 0, PP_HASH},
{PP_HASH, 0, 100, 41, PP_HASH},
{PP_HASH, 0, 105, 42, PP_HASH},
{PP_HASH, 0, 102, 43, PP_HASH},
{PP_ENDIF, 0, 0, 0, PP_HASH},
{PP_HASH, 0, 99, 45, PP_HASH},
{PP_HASH, 0, 108, 46, PP_HASH},
{PP_HASH, 0, 117, 47, PP_HASH},
{PP_HASH, 0, 100, 48, PP_HASH},
{PP_HASH, 0, 101, 49, PP_HASH},
{PP_INCLUDE, 0, 0, 0, PP_HASH},
{PP_CHARACTER, 0, 102, 51, PP_CHARACTER},
{PP_CHARACTER, 0, 105, 52, PP_CHARACTER},
{PP_CHARACTER, 0, 110, 53, PP_CHARACTER},
{PP_CHARACTER, 0, 101, 54, PP_CHARACTER},
{PP_CHARACTER, 0, 100, 55, PP_CHARACTER},
{PP_DEFINED, 0, 0, 0, PP_CHARACTER},
{PP_PLUS, 0, 0, 0, PP_NOTOKEN},
{PP_MINUS, 0, 0, 0, PP_NOTOKEN},
{PP_STAR, 0, 0, 0, PP_NOTOKEN},
{PP_SLASH, 8, 0, 0, PP_NOTOKEN},
{PP_PERCENT, 0, 58, 94, PP_NOTOKEN},
{PP_HAT, 0, 0, 0, PP_NOTOKEN},
{PP_AND, 0, 38, 89, PP_NOTOKEN},
{PP_CHARACTER, 0, 116, 64, PP_CHARACTER},
{PP_CHARACTER, 9, 0, 0, PP_CHARACTER},
{PP_CHARACTER, 0, 110, 66, PP_CHARACTER},
{PP_CHARACTER, 0, 100, 67, PP_CHARACTER},
{PP_AND, 0, 0, 0, PP_CHARACTER},
{PP_OR, 0, 124, 90, PP_NOTOKEN},
{PP_CHARACTER, 0, 114, 70, PP_CHARACTER},
{PP_OR, 0, 0, 0, PP_CHARACTER},
{PP_TILDE, 0, 0, 0, PP_NOTOKEN},
{PP_CHARACTER, 0, 109, 73, PP_CHARACTER},
{PP_CHARACTER, 0, 112, 74, PP_CHARACTER},
{PP_CHARACTER, 0, 108, 75, PP_CHARACTER},
{PP_TILDE, 0, 0, 0, PP_CHARACTER},
{PP_NOT, 0, 61, 83, PP_NOTOKEN},
{PP_CHARACTER, 0, 116, 78, PP_CHARACTER},
{PP_NOT, 0, 95, 84, PP_CHARACTER},
{PP_LTLT, 0, 0, 0, PP_NOTOKEN},
{PP_GTGT, 0, 0, 0, PP_NOTOKEN},
{PP_INCOMPLETE, 0, 61, 82, PP_NOTOKEN},
{PP_EQEQ, 0, 0, 0, PP_NOTOKEN},
{PP_NE, 0, 0, 0, PP_NOTOKEN},
{PP_CHARACTER, 0, 101, 85, PP_CHARACTER},
{PP_CHARACTER, 0, 113, 86, PP_CHARACTER},
{PP_NE, 0, 0, 0, PP_CHARACTER},
{PP_LE, 0, 0, 0, PP_NOTOKEN},
{PP_GE, 0, 0, 0, PP_NOTOKEN},
{PP_ANDAND, 0, 0, 0, PP_NOTOKEN},
{PP_OROR, 0, 0, 0, PP_NOTOKEN},
{PP_QUESTION, 0, 0, 0, PP_NOTOKEN},
{PP_COLON, 0, 0, 0, PP_NOTOKEN},
{PP_HASHHASH, 0, 0, 0, PP_NOTOKEN},
{PP_INCOMPLETE, 0, 37, 95, PP_NOTOKEN},
{PP_INCOMPLETE, 0, 58, 93, PP_NOTOKEN},
{PP_QUOTE, 0, 0, 0, PP_NOTOKEN},
{PP_SINGLEQUOTE, 0, 0, 0, PP_NOTOKEN},
{PP_WHITESPACE, 0, 0, 0, PP_NOTOKEN},
{PP_CPP_COMMENT, 0, 0, 0, PP_NOTOKEN},
{PP_C_COMMENT, 0, 0, 0, PP_NOTOKEN},
{PP_BACKSLASH, 0, 0, 0, PP_NOTOKEN},
{PP_INCOMPLETE, 10, 0, 0, PP_NOTOKEN},
{PP_FLOATING_LITERAL, 0, 0, 0, PP_NOTOKEN}
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,92 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** 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.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef PREPROCESSOR_H
#define PREPROCESSOR_H
#include "parser.h"
#include <qlist.h>
#include <qset.h>
#include <stdio.h>
QT_BEGIN_NAMESPACE
struct Macro
{
Macro() : isFunction(false), isVariadic(false) {}
bool isFunction;
bool isVariadic;
Symbols arguments;
Symbols symbols;
};
#ifdef USE_LEXEM_STORE
typedef QByteArray MacroName;
#else
typedef SubArray MacroName;
#endif
typedef QHash<MacroName, Macro> Macros;
class QFile;
class Preprocessor : public Parser
{
public:
Preprocessor(){}
static bool preprocessOnly;
QList<QByteArray> frameworks;
QSet<QByteArray> preprocessedIncludes;
QHash<QByteArray, QByteArray> nonlocalIncludePathResolutionCache;
Macros macros;
QByteArray resolveInclude(const QByteArray &filename, const QByteArray &relativeTo);
Symbols preprocessed(const QByteArray &filename, QByteArray input);
void parseDefineArguments(Macro *m);
void skipUntilEndif();
bool skipBranch();
void substituteUntilNewline(Symbols &substituted);
static Symbols macroExpandIdentifier(Preprocessor *that, SymbolStack &symbols, int lineNum, QByteArray *macroName);
static void macroExpand(Symbols *into, Preprocessor *that, const Symbols &toExpand, int &index, int lineNum, bool one,
const QSet<QByteArray> &excludeSymbols = QSet<QByteArray>());
int evaluateCondition();
enum TokenizeMode { TokenizeCpp, TokenizePreprocessor, PreparePreprocessorStatement, TokenizePreprocessorStatement, TokenizeInclude, PrepareDefine, TokenizeDefine };
static Symbols tokenize(const QByteArray &input, int lineNum = 1, TokenizeMode mode = TokenizeCpp);
private:
void until(Token);
void preprocess(const QByteArray &filename, Symbols &preprocessed);
};
QT_END_NAMESPACE
#endif // PREPROCESSOR_H

View File

@@ -0,0 +1,193 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** 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.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef SYMBOLS_H
#define SYMBOLS_H
#include "token.h"
#include <qdebug.h>
#include <qhash.h>
#include <qlist.h>
#include <qstack.h>
#include <qstring.h>
QT_BEGIN_NAMESPACE
//#define USE_LEXEM_STORE
struct SubArray
{
inline SubArray():from(0),len(-1){}
inline SubArray(const QByteArray &a):array(a),from(0), len(a.size()){}
inline SubArray(const char *s):array(s),from(0) { len = array.size(); }
inline SubArray(const QByteArray &a, int from, int len):array(a), from(from), len(len){}
QByteArray array;
int from, len;
inline bool operator==(const SubArray &other) const {
if (len != other.len)
return false;
for (int i = 0; i < len; ++i)
if (array.at(from + i) != other.array.at(other.from + i))
return false;
return true;
}
};
inline size_t qHash(const SubArray &key)
{
return qHash(QLatin1String(key.array.constData() + key.from, key.len));
}
struct Symbol
{
#ifdef USE_LEXEM_STORE
typedef QHash<SubArray, QHashDummyValue> LexemStore;
static LexemStore lexemStore;
inline Symbol() : lineNum(-1),token(NOTOKEN){}
inline Symbol(int lineNum, Token token):
lineNum(lineNum), token(token){}
inline Symbol(int lineNum, Token token, const QByteArray &lexem):
lineNum(lineNum), token(token),lex(lexem){}
inline Symbol(int lineNum, Token token, const QByteArray &lexem, int from, int len):
lineNum(lineNum), token(token){
LexemStore::const_iterator it = lexemStore.constFind(SubArray(lexem, from, len));
if (it != lexemStore.constEnd()) {
lex = it.key().array;
} else {
lex = lexem.mid(from, len);
lexemStore.insert(lex, QHashDummyValue());
}
}
int lineNum;
Token token;
inline QByteArray unquotedLexem() const { return lex.mid(1, lex.length()-2); }
inline QByteArray lexem() const { return lex; }
inline operator QByteArray() const { return lex; }
QByteArray lex;
#else
inline Symbol() : lineNum(-1),token(NOTOKEN), from(0),len(-1) {}
inline Symbol(int lineNum, Token token):
lineNum(lineNum), token(token), from(0), len(-1) {}
inline Symbol(int lineNum, Token token, const QByteArray &lexem):
lineNum(lineNum), token(token), lex(lexem), from(0) { len = lex.size(); }
inline Symbol(int lineNum, Token token, const QByteArray &lexem, int from, int len):
lineNum(lineNum), token(token),lex(lexem),from(from), len(len){}
int lineNum;
Token token;
inline QByteArray lexem() const { return lex.mid(from, len); }
inline QByteArray unquotedLexem() const { return lex.mid(from+1, len-2); }
inline operator SubArray() const { return SubArray(lex, from, len); }
bool operator==(const Symbol& o) const
{
return SubArray(lex, from, len) == SubArray(o.lex, o.from, o.len);
}
QByteArray lex;
int from, len;
#endif
};
Q_DECLARE_TYPEINFO(Symbol, Q_RELOCATABLE_TYPE);
typedef QList<Symbol> Symbols;
struct SafeSymbols {
Symbols symbols;
QByteArray expandedMacro;
QSet<QByteArray> excludedSymbols;
int index;
};
Q_DECLARE_TYPEINFO(SafeSymbols, Q_RELOCATABLE_TYPE);
class SymbolStack : public QStack<SafeSymbols>
{
public:
inline bool hasNext() {
while (!isEmpty() && top().index >= top().symbols.size())
pop();
return !isEmpty();
}
inline Token next() {
while (!isEmpty() && top().index >= top().symbols.size())
pop();
if (isEmpty())
return NOTOKEN;
return top().symbols.at(top().index++).token;
}
bool test(Token);
inline const Symbol &symbol() const { return top().symbols.at(top().index-1); }
inline Token token() { return symbol().token; }
inline QByteArray lexem() const { return symbol().lexem(); }
inline QByteArray unquotedLexem() { return symbol().unquotedLexem(); }
bool dontReplaceSymbol(const QByteArray &name);
QSet<QByteArray> excludeSymbols();
};
inline bool SymbolStack::test(Token token)
{
int stackPos = size() - 1;
while (stackPos >= 0 && at(stackPos).index >= at(stackPos).symbols.size())
--stackPos;
if (stackPos < 0)
return false;
if (at(stackPos).symbols.at(at(stackPos).index).token == token) {
next();
return true;
}
return false;
}
inline bool SymbolStack::dontReplaceSymbol(const QByteArray &name)
{
for (int i = 0; i < size(); ++i) {
if (name == at(i).expandedMacro || at(i).excludedSymbols.contains(name))
return true;
}
return false;
}
inline QSet<QByteArray> SymbolStack::excludeSymbols()
{
QSet<QByteArray> set;
for (int i = 0; i < size(); ++i) {
set << at(i).expandedMacro;
set += at(i).excludedSymbols;
}
return set;
}
QT_END_NAMESPACE
#endif // SYMBOLS_H

View File

@@ -0,0 +1,45 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** 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.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "token.h"
QT_BEGIN_NAMESPACE
#if defined(DEBUG_MOC)
const char *tokenTypeName(Token t)
{
switch (t) {
#define CREATE_CASE(Name) case Name: return #Name;
FOR_ALL_TOKENS(CREATE_CASE)
#undef CREATE_CASE
}
return "";
}
#endif
QT_END_NAMESPACE

View File

@@ -0,0 +1,276 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** 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.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef TOKEN_H
#define TOKEN_H
#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
#define FOR_ALL_TOKENS(F) \
F(NOTOKEN) \
F(IDENTIFIER) \
F(INTEGER_LITERAL) \
F(CHARACTER_LITERAL) \
F(STRING_LITERAL) \
F(BOOLEAN_LITERAL) \
F(HEADER_NAME) \
F(LANGLE) \
F(RANGLE) \
F(LPAREN) \
F(RPAREN) \
F(ELIPSIS) \
F(LBRACK) \
F(RBRACK) \
F(LBRACE) \
F(RBRACE) \
F(EQ) \
F(SCOPE) \
F(SEMIC) \
F(COLON) \
F(DOTSTAR) \
F(QUESTION) \
F(DOT) \
F(DYNAMIC_CAST) \
F(STATIC_CAST) \
F(REINTERPRET_CAST) \
F(CONST_CAST) \
F(TYPEID) \
F(THIS) \
F(TEMPLATE) \
F(THROW) \
F(TRY) \
F(CATCH) \
F(TYPEDEF) \
F(FRIEND) \
F(CLASS) \
F(NAMESPACE) \
F(ENUM) \
F(STRUCT) \
F(UNION) \
F(VIRTUAL) \
F(PRIVATE) \
F(PROTECTED) \
F(PUBLIC) \
F(EXPORT) \
F(AUTO) \
F(REGISTER) \
F(EXTERN) \
F(MUTABLE) \
F(ASM) \
F(USING) \
F(INLINE) \
F(EXPLICIT) \
F(STATIC) \
F(CONST_TOKEN) \
F(VOLATILE) \
F(OPERATOR) \
F(SIZEOF) \
F(NEW) \
F(DELETE) \
F(PLUS) \
F(MINUS) \
F(STAR) \
F(SLASH) \
F(PERCENT) \
F(HAT) \
F(AND) \
F(OR) \
F(TILDE) \
F(NOT) \
F(PLUS_EQ) \
F(MINUS_EQ) \
F(STAR_EQ) \
F(SLASH_EQ) \
F(PERCENT_EQ) \
F(HAT_EQ) \
F(AND_EQ) \
F(OR_EQ) \
F(LTLT) \
F(GTGT) \
F(GTGT_EQ) \
F(LTLT_EQ) \
F(EQEQ) \
F(NE) \
F(LE) \
F(GE) \
F(ANDAND) \
F(OROR) \
F(INCR) \
F(DECR) \
F(COMMA) \
F(ARROW_STAR) \
F(ARROW) \
F(CHAR_TOKEN) \
F(WCHAR_TOKEN) \
F(BOOL_TOKEN) \
F(SHORT_TOKEN) \
F(INT_TOKEN) \
F(LONG_TOKEN) \
F(SIGNED) \
F(UNSIGNED) \
F(FLOAT_TOKEN) \
F(DOUBLE) \
F(VOID_TOKEN) \
F(CASE) \
F(DEFAULT) \
F(IF) \
F(ELSE) \
F(SWITCH) \
F(WHILE) \
F(DO) \
F(FOR) \
F(BREAK) \
F(CONTINUE) \
F(GOTO) \
F(SIGNALS) \
F(SLOTS) \
F(RETURN) \
F(Q_OBJECT_TOKEN) \
F(Q_GADGET_TOKEN) \
F(Q_NAMESPACE_TOKEN) \
F(Q_NAMESPACE_EXPORT_TOKEN) \
F(Q_PROPERTY_TOKEN) \
F(Q_PLUGIN_METADATA_TOKEN) \
F(Q_ENUMS_TOKEN) \
F(Q_ENUM_TOKEN) \
F(Q_ENUM_NS_TOKEN) \
F(Q_FLAGS_TOKEN) \
F(Q_FLAG_TOKEN) \
F(Q_FLAG_NS_TOKEN) \
F(Q_DECLARE_FLAGS_TOKEN) \
F(Q_DECLARE_INTERFACE_TOKEN) \
F(Q_DECLARE_METATYPE_TOKEN) \
F(Q_CLASSINFO_TOKEN) \
F(Q_INTERFACES_TOKEN) \
F(Q_SIGNALS_TOKEN) \
F(Q_SLOTS_TOKEN) \
F(Q_SIGNAL_TOKEN) \
F(Q_SLOT_TOKEN) \
F(Q_PRIVATE_SLOT_TOKEN) \
F(Q_MOC_COMPAT_TOKEN) \
F(Q_INVOKABLE_TOKEN) \
F(Q_SCRIPTABLE_TOKEN) \
F(Q_PRIVATE_PROPERTY_TOKEN) \
F(Q_REVISION_TOKEN) \
F(Q_MOC_INCLUDE_TOKEN) \
F(SPECIAL_TREATMENT_MARK) \
F(MOC_INCLUDE_BEGIN) \
F(MOC_INCLUDE_END) \
F(CPP_COMMENT) \
F(C_COMMENT) \
F(FLOATING_LITERAL) \
F(HASH) \
F(QUOTE) \
F(SINGLEQUOTE) \
F(LANGLE_SCOPE) \
F(DIGIT) \
F(CHARACTER) \
F(NEWLINE) \
F(WHITESPACE) \
F(BACKSLASH) \
F(INCOMPLETE) \
F(PP_DEFINE) \
F(PP_UNDEF) \
F(PP_IF) \
F(PP_IFDEF) \
F(PP_IFNDEF) \
F(PP_ELIF) \
F(PP_ELSE) \
F(PP_ENDIF) \
F(PP_INCLUDE) \
F(PP_HASHHASH) \
F(PP_HASH) \
F(PP_DEFINED) \
F(PP_INCOMPLETE) \
F(PP_MOC_TRUE) \
F(PP_MOC_FALSE)
enum Token {
#define CREATE_ENUM_VALUE(Name) Name,
FOR_ALL_TOKENS(CREATE_ENUM_VALUE)
#undef CREATE_ENUM_VALUE
// aliases
PP_AND = AND,
PP_ANDAND = ANDAND,
PP_BACKSLASH = BACKSLASH,
PP_CHARACTER = CHARACTER,
PP_CHARACTER_LITERAL = CHARACTER_LITERAL,
PP_COLON = COLON,
PP_COMMA = COMMA,
PP_CPP_COMMENT = CPP_COMMENT,
PP_C_COMMENT = C_COMMENT,
PP_DIGIT = DIGIT,
PP_EQEQ = EQEQ,
PP_FLOATING_LITERAL = FLOATING_LITERAL,
PP_GE = GE,
PP_GTGT = GTGT,
PP_HAT = HAT,
PP_IDENTIFIER = IDENTIFIER,
PP_INTEGER_LITERAL = INTEGER_LITERAL,
PP_LANGLE = LANGLE,
PP_LE = LE,
PP_LPAREN = LPAREN,
PP_LTLT = LTLT,
PP_MINUS = MINUS,
PP_NE = NE,
PP_NEWLINE = NEWLINE,
PP_NOTOKEN = NOTOKEN,
PP_NOT = NOT,
PP_OR = OR,
PP_OROR = OROR,
PP_PERCENT = PERCENT,
PP_PLUS = PLUS,
PP_QUESTION = QUESTION,
PP_QUOTE = QUOTE,
PP_RANGLE = RANGLE,
PP_RPAREN = RPAREN,
PP_SINGLEQUOTE = SINGLEQUOTE,
PP_SLASH = SLASH,
PP_STAR = STAR,
PP_STRING_LITERAL = STRING_LITERAL,
PP_TILDE = TILDE,
PP_WHITESPACE = WHITESPACE,
Q_META_TOKEN_BEGIN = Q_OBJECT_TOKEN,
Q_META_TOKEN_END = SPECIAL_TREATMENT_MARK
};
// for debugging only
#if defined(DEBUG_MOC)
const char *tokenTypeName(Token t);
#endif
typedef Token PP_Token;
QT_END_NAMESPACE
#endif // TOKEN_H

View File

@@ -0,0 +1,110 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** 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.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef UTILS_H
#define UTILS_H
#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
inline bool is_whitespace(char s)
{
return (s == ' ' || s == '\t' || s == '\n');
}
inline bool is_space(char s)
{
return (s == ' ' || s == '\t');
}
inline bool is_ident_start(char s)
{
return ((s >= 'a' && s <= 'z')
|| (s >= 'A' && s <= 'Z')
|| s == '_' || s == '$'
);
}
inline bool is_ident_char(char s)
{
return ((s >= 'a' && s <= 'z')
|| (s >= 'A' && s <= 'Z')
|| (s >= '0' && s <= '9')
|| s == '_' || s == '$'
);
}
inline bool is_identifier(const char *s, int len)
{
if (len < 1)
return false;
if (!is_ident_start(*s))
return false;
for (int i = 1; i < len; ++i)
if (!is_ident_char(s[i]))
return false;
return true;
}
inline bool is_digit_char(char s)
{
return (s >= '0' && s <= '9');
}
inline bool is_octal_char(char s)
{
return (s >= '0' && s <= '7');
}
inline bool is_hex_char(char s)
{
return ((s >= 'a' && s <= 'f')
|| (s >= 'A' && s <= 'F')
|| (s >= '0' && s <= '9')
);
}
inline const char *skipQuote(const char *data)
{
while (*data && (*data != '\"')) {
if (*data == '\\') {
++data;
if (!*data) break;
}
++data;
}
if (*data) //Skip last quote
++data;
return data;
}
QT_END_NAMESPACE
#endif // UTILS_H

View File

@@ -1056,12 +1056,26 @@ void ClangdTestHighlighting::test_data()
<< QList<int>{C_PREPROCESSOR} << 0;
QTest::newRow("Q_PROPERTY (property name)") << 599 << 52 << 599 << 56
<< QList<int>{C_FIELD} << 0;
QTest::newRow("Q_PROPERTY (READ keyword)") << 599 << 57 << 599 << 61
<< QList<int>{C_KEYWORD} << 0;
QTest::newRow("Q_PROPERTY (getter)") << 599 << 62 << 599 << 69
<< QList<int>{C_FUNCTION} << 0;
QTest::newRow("Q_PROPERTY (WRITE keyword)") << 599 << 70 << 599 << 75
<< QList<int>{C_KEYWORD} << 0;
QTest::newRow("Q_PROPERTY (setter)") << 599 << 76 << 599 << 83
<< QList<int>{C_FUNCTION} << 0;
QTest::newRow("Q_PROPERTY (NOTIFY keyword)") << 599 << 84 << 599 << 90
<< QList<int>{C_KEYWORD} << 0;
QTest::newRow("Q_PROPERTY (notifier)") << 599 << 91 << 599 << 102
<< QList<int>{C_FUNCTION} << 0;
QTest::newRow("Q_PROPERTY (SCRIPTABLE keyword)") << 599 << 103 << 599 << 113
<< QList<int>{C_KEYWORD} << 0;
QTest::newRow("Q_PROPERTY (REVISION keyword)") << 599 << 119 << 599 << 127
<< QList<int>{C_KEYWORD} << 0;
QTest::newRow("Q_PROPERTY (type)") << 600 << 22 << 600 << 29
<< QList<int>{C_TYPE} << 0;
QTest::newRow("Q_PROPERTY (REVISION keyword [new])") << 600 << 46 << 600 << 54
<< QList<int>{C_KEYWORD} << 0;
QTest::newRow("multi-line Q_PROPERTY (macro name)") << 704 << 5 << 704 << 15
<< QList<int>{C_PREPROCESSOR} << 0;
QTest::newRow("multi-line Q_PROPERTY (property name)") << 718 << 13 << 718 << 17
@@ -1298,13 +1312,6 @@ void ClangdTestHighlighting::test()
"https://github.com/clangd/clangd/issues/878",
Abort);
}
QEXPECT_FAIL("Q_PROPERTY (property name)", "FIXME: How to do this?", Abort);
QEXPECT_FAIL("Q_PROPERTY (getter)", "FIXME: How to do this?", Abort);
QEXPECT_FAIL("Q_PROPERTY (notifier)", "FIXME: How to do this?", Abort);
QEXPECT_FAIL("Q_PROPERTY (type)", "FIXME: How to do this?", Abort);
QEXPECT_FAIL("multi-line Q_PROPERTY (property name)", "FIXME: How to do this?", Abort);
QEXPECT_FAIL("multi-line Q_PROPERTY (getter)", "FIXME: How to do this?", Abort);
QEXPECT_FAIL("multi-line Q_PROPERTY (notifier)", "FIXME: How to do this?", Abort);
QEXPECT_FAIL("old-style signal (signal)", "check if and how we want to support this", Abort);
QEXPECT_FAIL("old-style signal (signal parameter)",
"check if and how we want to support this", Abort);

View File

@@ -596,8 +596,8 @@ Undeclared u;
#define SIGNAL(arg) #arg
#define SLOT(arg) #arg
class Property {
Q_PROPERTY(const volatile unsigned long long * prop READ getProp WRITE setProp NOTIFY propChanged)
Q_PROPERTY(const QString str READ getStr)
Q_PROPERTY(const volatile unsigned long long * prop READ getProp WRITE setProp NOTIFY propChanged SCRIPTABLE true REVISION 1)
Q_PROPERTY(const QString str READ getStr REVISION(1,0))
};
struct X {