summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
authorhjk <qtc-committer@nokia.com>2009-01-26 16:19:24 +0100
committerhjk <qtc-committer@nokia.com>2009-01-26 16:19:24 +0100
commitfe0533de2a634ca377c2d8a0073e0eb2cbf89abf (patch)
tree29d3d30e6cc5a1068a94097a5660bc4d133a205f /src/shared
parentc85ba53365d606192069a841ed806979f17d80bc (diff)
downloadqt-creator-fe0533de2a634ca377c2d8a0073e0eb2cbf89abf.tar.gz
Fixes: move all files in shared/* to src/shared/*
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/cpaster/cgi.cpp427
-rw-r--r--src/shared/cpaster/cgi.h59
-rw-r--r--src/shared/cpaster/cpaster.pri14
-rw-r--r--src/shared/cpaster/fetcher.cpp79
-rw-r--r--src/shared/cpaster/fetcher.h66
-rw-r--r--src/shared/cpaster/poster.cpp76
-rw-r--r--src/shared/cpaster/poster.h64
-rw-r--r--src/shared/cpaster/splitter.cpp95
-rw-r--r--src/shared/cpaster/splitter.h54
-rw-r--r--src/shared/cpaster/view.cpp185
-rw-r--r--src/shared/cpaster/view.h66
-rw-r--r--src/shared/cpaster/view.ui208
-rw-r--r--src/shared/cplusplus/AST.cpp3985
-rw-r--r--src/shared/cplusplus/AST.h1989
-rw-r--r--src/shared/cplusplus/ASTVisitor.cpp105
-rw-r--r--src/shared/cplusplus/ASTVisitor.h200
-rw-r--r--src/shared/cplusplus/ASTfwd.h178
-rw-r--r--src/shared/cplusplus/Array.cpp34
-rw-r--r--src/shared/cplusplus/Array.h135
-rw-r--r--src/shared/cplusplus/CPlusPlusForwardDeclarations.h140
-rw-r--r--src/shared/cplusplus/CheckDeclaration.cpp374
-rw-r--r--src/shared/cplusplus/CheckDeclaration.h106
-rw-r--r--src/shared/cplusplus/CheckDeclarator.cpp258
-rw-r--r--src/shared/cplusplus/CheckDeclarator.h110
-rw-r--r--src/shared/cplusplus/CheckExpression.cpp369
-rw-r--r--src/shared/cplusplus/CheckExpression.h127
-rw-r--r--src/shared/cplusplus/CheckName.cpp348
-rw-r--r--src/shared/cplusplus/CheckName.h92
-rw-r--r--src/shared/cplusplus/CheckSpecifier.cpp392
-rw-r--r--src/shared/cplusplus/CheckSpecifier.h95
-rw-r--r--src/shared/cplusplus/CheckStatement.cpp239
-rw-r--r--src/shared/cplusplus/CheckStatement.h102
-rw-r--r--src/shared/cplusplus/Control.cpp636
-rw-r--r--src/shared/cplusplus/Control.h180
-rw-r--r--src/shared/cplusplus/CoreTypes.cpp237
-rw-r--r--src/shared/cplusplus/CoreTypes.h217
-rw-r--r--src/shared/cplusplus/DiagnosticClient.cpp63
-rw-r--r--src/shared/cplusplus/DiagnosticClient.h86
-rw-r--r--src/shared/cplusplus/FullySpecifiedType.cpp204
-rw-r--r--src/shared/cplusplus/FullySpecifiedType.h158
-rw-r--r--src/shared/cplusplus/Keywords.cpp1348
-rw-r--r--src/shared/cplusplus/Keywords.kwgen86
-rw-r--r--src/shared/cplusplus/Lexer.cpp680
-rw-r--r--src/shared/cplusplus/Lexer.h159
-rw-r--r--src/shared/cplusplus/LiteralTable.cpp34
-rw-r--r--src/shared/cplusplus/LiteralTable.h181
-rw-r--r--src/shared/cplusplus/Literals.cpp138
-rw-r--r--src/shared/cplusplus/Literals.h122
-rw-r--r--src/shared/cplusplus/MemoryPool.cpp130
-rw-r--r--src/shared/cplusplus/MemoryPool.h120
-rw-r--r--src/shared/cplusplus/Name.cpp133
-rw-r--r--src/shared/cplusplus/Name.h103
-rw-r--r--src/shared/cplusplus/NameVisitor.cpp67
-rw-r--r--src/shared/cplusplus/NameVisitor.h86
-rw-r--r--src/shared/cplusplus/Names.cpp262
-rw-r--r--src/shared/cplusplus/Names.h241
-rw-r--r--src/shared/cplusplus/ObjectiveCAtKeywords.cpp464
-rw-r--r--src/shared/cplusplus/Parser.cpp3810
-rw-r--r--src/shared/cplusplus/Parser.h292
-rw-r--r--src/shared/cplusplus/PrettyPrinter.cpp1293
-rw-r--r--src/shared/cplusplus/PrettyPrinter.h163
-rw-r--r--src/shared/cplusplus/Scope.cpp310
-rw-r--r--src/shared/cplusplus/Scope.h198
-rw-r--r--src/shared/cplusplus/Semantic.cpp198
-rw-r--r--src/shared/cplusplus/Semantic.h109
-rw-r--r--src/shared/cplusplus/SemanticCheck.cpp72
-rw-r--r--src/shared/cplusplus/SemanticCheck.h78
-rw-r--r--src/shared/cplusplus/Symbol.cpp421
-rw-r--r--src/shared/cplusplus/Symbol.h266
-rw-r--r--src/shared/cplusplus/SymbolVisitor.cpp66
-rw-r--r--src/shared/cplusplus/SymbolVisitor.h90
-rw-r--r--src/shared/cplusplus/Symbols.cpp484
-rw-r--r--src/shared/cplusplus/Symbols.h338
-rw-r--r--src/shared/cplusplus/Token.cpp140
-rw-r--r--src/shared/cplusplus/Token.h336
-rw-r--r--src/shared/cplusplus/TranslationUnit.cpp474
-rw-r--r--src/shared/cplusplus/TranslationUnit.h201
-rw-r--r--src/shared/cplusplus/Type.cpp198
-rw-r--r--src/shared/cplusplus/Type.h124
-rw-r--r--src/shared/cplusplus/TypeVisitor.cpp67
-rw-r--r--src/shared/cplusplus/TypeVisitor.h92
-rw-r--r--src/shared/cplusplus/cplusplus.pri77
-rw-r--r--src/shared/designerintegrationv2/README.txt10
-rw-r--r--src/shared/designerintegrationv2/designerintegration.pri11
-rw-r--r--src/shared/designerintegrationv2/formresizer.cpp197
-rw-r--r--src/shared/designerintegrationv2/formresizer.h103
-rw-r--r--src/shared/designerintegrationv2/sizehandlerect.cpp192
-rw-r--r--src/shared/designerintegrationv2/sizehandlerect.h86
-rw-r--r--src/shared/designerintegrationv2/widgethost.cpp109
-rw-r--r--src/shared/designerintegrationv2/widgethost.h83
-rw-r--r--src/shared/designerintegrationv2/widgethostconstants.h45
-rw-r--r--src/shared/help/bookmarkdialog.ui146
-rw-r--r--src/shared/help/bookmarkmanager.cpp866
-rw-r--r--src/shared/help/bookmarkmanager.h199
-rw-r--r--src/shared/help/contentwindow.cpp165
-rw-r--r--src/shared/help/contentwindow.h78
-rw-r--r--src/shared/help/filternamedialog.cpp65
-rw-r--r--src/shared/help/filternamedialog.h59
-rw-r--r--src/shared/help/filternamedialog.ui67
-rw-r--r--src/shared/help/help.pri26
-rw-r--r--src/shared/help/helpviewer.cpp531
-rw-r--r--src/shared/help/helpviewer.h163
-rw-r--r--src/shared/help/indexwindow.cpp208
-rw-r--r--src/shared/help/indexwindow.h82
-rw-r--r--src/shared/help/topicchooser.cpp78
-rw-r--r--src/shared/help/topicchooser.h64
-rw-r--r--src/shared/help/topicchooser.ui116
-rw-r--r--src/shared/indenter/README9
-rw-r--r--src/shared/indenter/constants.cpp66
-rw-r--r--src/shared/indenter/indenter.h145
-rw-r--r--src/shared/indenter/indenter.pri5
-rw-r--r--src/shared/indenter/indenter_impl.h1112
-rw-r--r--src/shared/indenter/test/main.cpp182
-rw-r--r--src/shared/indenter/test/test.pro10
-rw-r--r--src/shared/namespace_global.h52
-rw-r--r--src/shared/proparser/abstractproitemvisitor.h62
-rw-r--r--src/shared/proparser/images/append.pngbin0 -> 514 bytes
-rw-r--r--src/shared/proparser/images/other.pngbin0 -> 1499 bytes
-rw-r--r--src/shared/proparser/images/profile.pngbin0 -> 452 bytes
-rw-r--r--src/shared/proparser/images/remove.pngbin0 -> 497 bytes
-rw-r--r--src/shared/proparser/images/scope.pngbin0 -> 350 bytes
-rw-r--r--src/shared/proparser/images/set.pngbin0 -> 473 bytes
-rw-r--r--src/shared/proparser/images/value.pngbin0 -> 599 bytes
-rw-r--r--src/shared/proparser/procommandmanager.cpp164
-rw-r--r--src/shared/proparser/procommandmanager.h112
-rw-r--r--src/shared/proparser/proeditor.cpp383
-rw-r--r--src/shared/proparser/proeditor.h128
-rw-r--r--src/shared/proparser/proeditor.ui143
-rw-r--r--src/shared/proparser/proeditormodel.cpp988
-rw-r--r--src/shared/proparser/proeditormodel.h156
-rw-r--r--src/shared/proparser/profileevaluator.cpp2340
-rw-r--r--src/shared/proparser/profileevaluator.h96
-rw-r--r--src/shared/proparser/proiteminfo.cpp241
-rw-r--r--src/shared/proparser/proiteminfo.h137
-rw-r--r--src/shared/proparser/proiteminfo.xml110
-rw-r--r--src/shared/proparser/proitems.cpp320
-rw-r--r--src/shared/proparser/proitems.h228
-rw-r--r--src/shared/proparser/proparser.pri35
-rw-r--r--src/shared/proparser/proparser.qrc12
-rw-r--r--src/shared/proparser/proparserutils.h302
-rw-r--r--src/shared/proparser/prowriter.cpp208
-rw-r--r--src/shared/proparser/prowriter.h79
-rw-r--r--src/shared/proparser/proxml.cpp208
-rw-r--r--src/shared/proparser/proxml.h60
-rw-r--r--src/shared/proparser/valueeditor.cpp500
-rw-r--r--src/shared/proparser/valueeditor.h119
-rw-r--r--src/shared/proparser/valueeditor.ui384
-rw-r--r--src/shared/qrceditor/qrceditor.cpp402
-rw-r--r--src/shared/qrceditor/qrceditor.h109
-rw-r--r--src/shared/qrceditor/qrceditor.pri28
-rw-r--r--src/shared/qrceditor/qrceditor.ui131
-rw-r--r--src/shared/qrceditor/resourcefile.cpp985
-rw-r--r--src/shared/qrceditor/resourcefile_p.h269
-rw-r--r--src/shared/qrceditor/resourceview.cpp663
-rw-r--r--src/shared/qrceditor/resourceview.h186
-rw-r--r--src/shared/qrceditor/test/main.cpp43
-rw-r--r--src/shared/qrceditor/test/mainwindow.cpp102
-rw-r--r--src/shared/qrceditor/test/mainwindow.h58
-rw-r--r--src/shared/qrceditor/test/test.pro11
-rw-r--r--src/shared/qrceditor/undocommands.cpp193
-rw-r--r--src/shared/qrceditor/undocommands_p.h165
-rw-r--r--src/shared/qscripthighlighter/README3
-rw-r--r--src/shared/qscripthighlighter/qscripthighlighter.cpp482
-rw-r--r--src/shared/qscripthighlighter/qscripthighlighter.h73
-rw-r--r--src/shared/qscripthighlighter/qscripthighlighter.pri4
-rw-r--r--src/shared/qscripthighlighter/test/main.cpp50
-rw-r--r--src/shared/qscripthighlighter/test/test.pro10
-rw-r--r--src/shared/qtextended_integration.h99
-rw-r--r--src/shared/qtlockedfile/README.txt10
-rw-r--r--src/shared/qtlockedfile/namespace.patch70
-rw-r--r--src/shared/qtlockedfile/qtlockedfile.cpp162
-rw-r--r--src/shared/qtlockedfile/qtlockedfile.h81
-rw-r--r--src/shared/qtlockedfile/qtlockedfile.pri13
-rw-r--r--src/shared/qtlockedfile/qtlockedfile_unix.cpp111
-rw-r--r--src/shared/qtlockedfile/qtlockedfile_win.cpp207
-rw-r--r--src/shared/qtsingleapplication/README.txt10
-rw-r--r--src/shared/qtsingleapplication/namespace.patch133
-rw-r--r--src/shared/qtsingleapplication/qtlocalpeer.cpp176
-rw-r--r--src/shared/qtsingleapplication/qtlocalpeer.h69
-rw-r--r--src/shared/qtsingleapplication/qtsingleapplication.cpp145
-rw-r--r--src/shared/qtsingleapplication/qtsingleapplication.h85
-rw-r--r--src/shared/qtsingleapplication/qtsingleapplication.pri14
-rw-r--r--src/shared/qtsingleapplication/qtsinglecoreapplication.cpp72
-rw-r--r--src/shared/qtsingleapplication/qtsinglecoreapplication.h63
-rw-r--r--src/shared/qtsingleapplication/qtsinglecoreapplication.pri14
-rw-r--r--src/shared/scriptwrapper/README58
-rw-r--r--src/shared/scriptwrapper/interface_wrap_helpers.h92
-rw-r--r--src/shared/scriptwrapper/scriptwrapper.pri3
-rw-r--r--src/shared/scriptwrapper/wrap_helpers.h335
189 files changed, 45637 insertions, 0 deletions
diff --git a/src/shared/cpaster/cgi.cpp b/src/shared/cpaster/cgi.cpp
new file mode 100644
index 0000000000..fddbbc18a2
--- /dev/null
+++ b/src/shared/cpaster/cgi.cpp
@@ -0,0 +1,427 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "cgi.h"
+
+#include <QByteArray>
+
+
+const char *cgi_chars = "0123456789abcdef"; // RFC 1738 suggests lower-case to be optimal
+
+QString CGI::encodeURL(const QString &rawText)
+{
+ QByteArray utf = rawText.toUtf8();
+ QString enc;
+ enc.reserve(utf.length()); // Make sure we at least have space for a normal US-ASCII URL
+
+ QByteArray::const_iterator it = utf.constBegin();
+ while (it != utf.constEnd()) {
+ char ch = *it;
+ if (('A' <= ch && ch <= 'Z')
+ || ('a' <= ch && ch <= 'z')
+ || ('0' <= ch && ch <= '9'))
+ enc.append(*it);
+ else if (ch == ' ')
+ enc.append('+');
+ else {
+ switch (ch) {
+ case '-': case '_':
+ case '(': case ')':
+ case '.': case '!':
+ case '~': case '*':
+ case '\'':
+ enc.append(ch);
+ break;
+ default:
+ ushort c1 = (*it & 0xF0) >> 4;
+ ushort c2 = (*it & 0x0F);
+ enc.append('%');
+ enc.append(QChar(*(cgi_chars + c1)));
+ enc.append(QChar(*(cgi_chars + c2)));
+ break;
+ }
+ }
+ ++it;
+ }
+ return enc;
+}
+
+QString CGI::decodeURL(const QString &urlText)
+{
+ QByteArray dec;
+ QString::const_iterator it = urlText.constBegin();
+ while (it != urlText.constEnd()) {
+ ushort ch = (*it).unicode();
+ switch (ch) {
+ case '%':
+ {
+ char c1 = char(0x00ff & (*(++it)).unicode());
+ char c2 = char(0x00ff & (*(++it)).unicode());
+ ushort v = 0;
+ if ('A' <= c1 && c1 <= 'Z')
+ v = c1 - 'A' + 10;
+ else if ('a' <= c1 && c1 <= 'z')
+ v = c1 - 'a' + 10;
+ else if ('0' <= c1 && c1 <= '9')
+ v = c1 - '0';
+ else
+ continue; // Malformed URL!
+ v <<= 4; // c1 was MSB half
+ if ('A' <= c2 && c2 <= 'Z')
+ v |= c2 - 'A' + 10;
+ else if ('a' <= c2 && c2 <= 'z')
+ v |= c2 - 'a' + 10;
+ else if ('0' <= c2 && c2 <= '9')
+ v |= c2 - '0';
+ else
+ continue; // Malformed URL!
+ dec.append((char)v);
+ }
+ break;
+ case '+':
+ dec.append(' ');
+ break;
+ default:
+ dec.append(*it);
+ break;
+ }
+ ++it;
+ }
+ return QString::fromUtf8(dec.constData(), dec.length());
+}
+
+// -------------------------------------------------------------------------------------------------
+inline const char *unicodeToHTML(ushort unicode_char)
+{
+ switch (unicode_char) {
+ // Latin -------------------------------
+ case 0x0022: return "quot"; // (34 ) quotation mark = APL quote
+ case 0x0026: return "amp"; // (38 ) ampersand
+ case 0x003C: return "lt"; // (60 ) less-than sign
+ case 0x003E: return "gt"; // (62 ) greater-than sign
+ case 0x00A0: return "nbsp"; // (160 ) no-break space = non-breaking space
+ case 0x00A1: return "iexcl"; // (161 ) inverted exclamation mark
+ case 0x00A2: return "cent"; // (162 ) cent sign
+ case 0x00A3: return "pound"; // (163 ) pound sign
+ case 0x00A4: return "curren"; // (164 ) currency sign
+ case 0x00A5: return "yen"; // (165 ) yen sign = yuan sign
+ case 0x00A6: return "brvbar"; // (166 ) broken bar = broken vertical bar
+ case 0x00A7: return "sect"; // (167 ) section sign
+ case 0x00A8: return "uml"; // (168 ) diaeresis = spacing diaeresis
+ case 0x00A9: return "copy"; // (169 ) copyright sign
+ case 0x00AA: return "ordf"; // (170 ) feminine ordinal indicator
+ case 0x00AB: return "laquo"; // (171 ) left-pointing double angle quotation mark = left pointing guillemet
+ case 0x00AC: return "not"; // (172 ) not sign
+ case 0x00AD: return "shy"; // (173 ) soft hyphen = discretionary hyphen
+ case 0x00AE: return "reg"; // (174 ) registered sign = registered trade mark sign
+ case 0x00AF: return "macr"; // (175 ) macron = spacing macron = overline = APL overbar
+ case 0x00B0: return "deg"; // (176 ) degree sign
+ case 0x00B1: return "plusmn"; // (177 ) plus-minus sign = plus-or-minus sign
+ case 0x00B2: return "sup2"; // (178 ) superscript two = superscript digit two = squared
+ case 0x00B3: return "sup3"; // (179 ) superscript three = superscript digit three = cubed
+ case 0x00B4: return "acute"; // (180 ) acute accent = spacing acute
+ case 0x00B5: return "micro"; // (181 ) micro sign
+ case 0x00B6: return "para"; // (182 ) pilcrow sign = paragraph sign
+ case 0x00B7: return "middot"; // (183 ) middle dot = Georgian comma = Greek middle dot
+ case 0x00B8: return "cedil"; // (184 ) cedilla = spacing cedilla
+ case 0x00B9: return "sup1"; // (185 ) superscript one = superscript digit one
+ case 0x00BA: return "ordm"; // (186 ) masculine ordinal indicator
+ case 0x00BB: return "raquo"; // (187 ) right-pointing double angle quotation mark = right pointing guillemet
+ case 0x00BC: return "frac14"; // (188 ) vulgar fraction one quarter = fraction one quarter
+ case 0x00BD: return "frac12"; // (189 ) vulgar fraction one half = fraction one half
+ case 0x00BE: return "frac34"; // (190 ) vulgar fraction three quarters = fraction three quarters
+ case 0x00BF: return "iquest"; // (191 ) inverted question mark = turned question mark
+ case 0x00C0: return "Agrave"; // (192 ) capital letter A with grave = capital letter À
+ case 0x00C1: return "Aacute"; // (193 ) capital letter A with acute
+ case 0x00C2: return "Acirc"; // (194 ) capital letter A with circumflex
+ case 0x00C3: return "Atilde"; // (195 ) capital letter A with tilde
+ case 0x00C4: return "Auml"; // (196 ) capital letter A with diaeresis
+ case 0x00C5: return "Aring"; // (197 ) capital letter A with ring above = capital letter Å
+ case 0x00C6: return "AElig"; // (198 ) capital letter AE = capital ligature Æ
+ case 0x00C7: return "Ccedil"; // (199 ) capital letter C with cedilla
+ case 0x00C8: return "Egrave"; // (200 ) capital letter E with grave
+ case 0x00C9: return "Eacute"; // (201 ) capital letter E with acute
+ case 0x00CA: return "Ecirc"; // (202 ) capital letter E with circumflex
+ case 0x00CB: return "Euml"; // (203 ) capital letter E with diaeresis
+ case 0x00CC: return "Igrave"; // (204 ) capital letter I with grave
+ case 0x00CD: return "Iacute"; // (205 ) capital letter I with acute
+ case 0x00CE: return "Icirc"; // (206 ) capital letter I with circumflex
+ case 0x00CF: return "Iuml"; // (207 ) capital letter I with diaeresis
+ case 0x00D0: return "ETH"; // (208 ) capital letter ETH
+ case 0x00D1: return "Ntilde"; // (209 ) capital letter N with tilde
+ case 0x00D2: return "Ograve"; // (210 ) capital letter O with grave
+ case 0x00D3: return "Oacute"; // (211 ) capital letter O with acute
+ case 0x00D4: return "Ocirc"; // (212 ) capital letter O with circumflex
+ case 0x00D5: return "Otilde"; // (213 ) capital letter O with tilde
+ case 0x00D6: return "Ouml"; // (214 ) capital letter O with diaeresis
+ case 0x00D7: return "times"; // (215 ) multiplication sign
+ case 0x00D8: return "Oslash"; // (216 ) capital letter O with stroke = capital letter Ø
+ case 0x00D9: return "Ugrave"; // (217 ) capital letter U with grave
+ case 0x00DA: return "Uacute"; // (218 ) capital letter U with acute
+ case 0x00DB: return "Ucirc"; // (219 ) capital letter U with circumflex
+ case 0x00DC: return "Uuml"; // (220 ) capital letter U with diaeresis
+ case 0x00DD: return "Yacute"; // (221 ) capital letter Y with acute
+ case 0x00DE: return "THORN"; // (222 ) capital letter THORN
+ case 0x00DF: return "szlig"; // (223 ) small letter sharp s = ess-zed
+ case 0x00E0: return "agrave"; // (224 ) small letter a with grave = small letter à
+ case 0x00E1: return "aacute"; // (225 ) small letter a with acute
+ case 0x00E2: return "acirc"; // (226 ) small letter a with circumflex
+ case 0x00E3: return "atilde"; // (227 ) small letter a with tilde
+ case 0x00E4: return "auml"; // (228 ) small letter a with diaeresis
+ case 0x00E5: return "aring"; // (229 ) small letter a with ring above = small letter å
+ case 0x00E6: return "aelig"; // (230 ) small letter ae = small letter æ
+ case 0x00E7: return "ccedil"; // (231 ) small letter c with cedilla
+ case 0x00E8: return "egrave"; // (232 ) small letter e with grave
+ case 0x00E9: return "eacute"; // (233 ) small letter e with acute
+ case 0x00EA: return "ecirc"; // (234 ) small letter e with circumflex
+ case 0x00EB: return "euml"; // (235 ) small letter e with diaeresis
+ case 0x00EC: return "igrave"; // (236 ) small letter i with grave
+ case 0x00ED: return "iacute"; // (237 ) small letter i with acute
+ case 0x00EE: return "icirc"; // (238 ) small letter i with circumflex
+ case 0x00EF: return "iuml"; // (239 ) small letter i with diaeresis
+ case 0x00F0: return "eth"; // (240 ) small letter eth
+ case 0x00F1: return "ntilde"; // (241 ) small letter n with tilde
+ case 0x00F2: return "ograve"; // (242 ) small letter o with grave
+ case 0x00F3: return "oacute"; // (243 ) small letter o with acute
+ case 0x00F4: return "ocirc"; // (244 ) small letter o with circumflex
+ case 0x00F5: return "otilde"; // (245 ) small letter o with tilde
+ case 0x00F6: return "ouml"; // (246 ) small letter o with diaeresis
+ case 0x00F7: return "divide"; // (247 ) division sign
+ case 0x00F8: return "oslash"; // (248 ) small letter o with stroke = small letter ø
+ case 0x00F9: return "ugrave"; // (249 ) small letter u with grave
+ case 0x00FA: return "uacute"; // (250 ) small letter u with acute
+ case 0x00FB: return "ucirc"; // (251 ) small letter u with circumflex
+ case 0x00FC: return "uuml"; // (252 ) small letter u with diaeresis
+ case 0x00FD: return "yacute"; // (253 ) small letter y with acute
+ case 0x00FE: return "thorn"; // (254 ) small letter thorn
+ case 0x00FF: return "yuml"; // (255 ) small letter y with diaeresis
+ case 0x0152: return "OElig"; // (338 ) capital ligature OE
+ case 0x0153: return "oelig"; // (339 ) small ligature oe
+ case 0x0160: return "Scaron"; // (352 ) capital letter S with caron
+ case 0x0161: return "scaron"; // (353 ) small letter s with caron
+ case 0x0178: return "Yuml"; // (376 ) capital letter Y with diaeresis
+ case 0x0192: return "fnof"; // (402 ) small f with hook = function = florin
+ case 0x02C6: return "circ"; // (710 ) modifier letter circumflex accent
+ case 0x02DC: return "tilde"; // (732 ) small tilde
+ // Greek -------------------------------
+ case 0x0391: return "Alpha"; // (913 ) capital letter alpha
+ case 0x0392: return "Beta"; // (914 ) capital letter beta
+ case 0x0393: return "Gamma"; // (915 ) capital letter gamma
+ case 0x0394: return "Delta"; // (916 ) capital letter delta
+ case 0x0395: return "Epsilon"; // (917 ) capital letter epsilon
+ case 0x0396: return "Zeta"; // (918 ) capital letter zeta
+ case 0x0397: return "Eta"; // (919 ) capital letter eta
+ case 0x0398: return "Theta"; // (920 ) capital letter theta
+ case 0x0399: return "Iota"; // (921 ) capital letter iota
+ case 0x039A: return "Kappa"; // (922 ) capital letter kappa
+ case 0x039B: return "Lambda"; // (923 ) capital letter lambda
+ case 0x039C: return "Mu"; // (924 ) capital letter mu
+ case 0x039D: return "Nu"; // (925 ) capital letter nu
+ case 0x039E: return "Xi"; // (926 ) capital letter xi
+ case 0x039F: return "Omicron"; // (927 ) capital letter omicron
+ case 0x03A0: return "Pi"; // (928 ) capital letter pi
+ case 0x03A1: return "Rho"; // (929 ) capital letter rho
+ case 0x03A3: return "Sigma"; // (931 ) capital letter sigma
+ case 0x03A4: return "Tau"; // (932 ) capital letter tau
+ case 0x03A5: return "Upsilon"; // (933 ) capital letter upsilon
+ case 0x03A6: return "Phi"; // (934 ) capital letter phi
+ case 0x03A7: return "Chi"; // (935 ) capital letter chi
+ case 0x03A8: return "Psi"; // (936 ) capital letter psi
+ case 0x03A9: return "Omega"; // (937 ) capital letter omega
+ case 0x03B1: return "alpha"; // (945 ) small letter alpha
+ case 0x03B2: return "beta"; // (946 ) small letter beta
+ case 0x03B3: return "gamma"; // (947 ) small letter gamma
+ case 0x03B4: return "delta"; // (948 ) small letter delta
+ case 0x03B5: return "epsilon"; // (949 ) small letter epsilon
+ case 0x03B6: return "zeta"; // (950 ) small letter zeta
+ case 0x03B7: return "eta"; // (951 ) small letter eta
+ case 0x03B8: return "theta"; // (952 ) small letter theta
+ case 0x03B9: return "iota"; // (953 ) small letter iota
+ case 0x03BA: return "kappa"; // (954 ) small letter kappa
+ case 0x03BB: return "lambda"; // (955 ) small letter lambda
+ case 0x03BC: return "mu"; // (956 ) small letter mu
+ case 0x03BD: return "nu"; // (957 ) small letter nu
+ case 0x03BE: return "xi"; // (958 ) small letter xi
+ case 0x03BF: return "omicron"; // (959 ) small letter omicron
+ case 0x03C0: return "pi"; // (960 ) small letter pi
+ case 0x03C1: return "rho"; // (961 ) small letter rho
+ case 0x03C2: return "sigmaf"; // (962 ) small letter final sigma
+ case 0x03C3: return "sigma"; // (963 ) small letter sigma
+ case 0x03C4: return "tau"; // (964 ) small letter tau
+ case 0x03C5: return "upsilon"; // (965 ) small letter upsilon
+ case 0x03C6: return "phi"; // (966 ) small letter phi
+ case 0x03C7: return "chi"; // (967 ) small letter chi
+ case 0x03C8: return "psi"; // (968 ) small letter psi
+ case 0x03C9: return "omega"; // (969 ) small letter omega
+ case 0x03D1: return "thetasym";// (977 ) small letter theta symbol
+ case 0x03D2: return "upsih"; // (978 ) upsilon with hook symbol
+ case 0x03D6: return "piv"; // (982 ) pi symbol
+ // General Punctuation -----------------
+ case 0x2002: return "ensp"; // (8194) en space
+ case 0x2003: return "emsp"; // (8195) em space
+ case 0x2009: return "thinsp"; // (8201) thin space
+ case 0x200C: return "zwnj"; // (8204) zero width non-joiner
+ case 0x200D: return "zwj"; // (8205) zero width joiner
+ case 0x200E: return "lrm"; // (8206) left-to-right mark
+ case 0x200F: return "rlm"; // (8207) right-to-left mark
+ case 0x2013: return "ndash"; // (8211) en dash
+ case 0x2014: return "mdash"; // (8212) em dash
+ case 0x2018: return "lsquo"; // (8216) left single quotation mark
+ case 0x2019: return "rsquo"; // (8217) right single quotation mark
+ case 0x201A: return "sbquo"; // (8218) single low-9 quotation mark
+ case 0x201C: return "ldquo"; // (8220) left double quotation mark
+ case 0x201D: return "rdquo"; // (8221) right double quotation mark
+ case 0x201E: return "bdquo"; // (8222) double low-9 quotation mark
+ case 0x2020: return "dagger"; // (8224) dagger
+ case 0x2021: return "Dagger"; // (8225) double dagger
+ case 0x2022: return "bull"; // (8226) bullet = black small circle
+ case 0x2026: return "hellip"; // (8230) horizontal ellipsis = three dot leader
+ case 0x2030: return "permil"; // (8240) per mille sign
+ case 0x2032: return "prime"; // (8242) prime = minutes = feet
+ case 0x2033: return "Prime"; // (8243) double prime = seconds = inches
+ case 0x2039: return "lsaquo"; // (8249) single left-pointing angle quotation mark
+ case 0x203A: return "rsaquo"; // (8250) single right-pointing angle quotation mark
+ case 0x203E: return "oline"; // (8254) overline = spacing overscore
+ case 0x2044: return "frasl"; // (8260) fraction slash
+ // Currency Symbols --------------------
+ case 0x20AC: return "euro"; // (8364) euro sign
+ // Letterlike Symbols ------------------
+ case 0x2111: return "image"; // (8465) blackletter capital I = imaginary part
+ case 0x2118: return "weierp"; // (8472) script capital P = power set = Weierstrass p
+ case 0x211C: return "real"; // (8476) blackletter capital R = real part symbol
+ case 0x2122: return "trade"; // (8482) trade mark sign
+ case 0x2135: return "alefsym"; // (8501) alef symbol = first transfinite cardinal
+ // Arrows ------------------------------
+ case 0x2190: return "larr"; // (8592) leftwards arrow
+ case 0x2191: return "uarr"; // (8593) upwards arrow
+ case 0x2192: return "rarr"; // (8594) rightwards arrow
+ case 0x2193: return "darr"; // (8595) downwards arrow
+ case 0x2194: return "harr"; // (8596) left right arrow
+ case 0x21B5: return "crarr"; // (8629) downwards arrow with corner leftwards = carriage return
+ case 0x21D0: return "lArr"; // (8656) leftwards double arrow
+ case 0x21D1: return "uArr"; // (8657) upwards double arrow
+ case 0x21D2: return "rArr"; // (8658) rightwards double arrow
+ case 0x21D3: return "dArr"; // (8659) downwards double arrow
+ case 0x21D4: return "hArr"; // (8660) left right double arrow
+ // Mathematical Operators --------------
+ case 0x2200: return "forall"; // (8704) for all
+ case 0x2202: return "part"; // (8706) partial differential
+ case 0x2203: return "exist"; // (8707) there exists
+ case 0x2205: return "empty"; // (8709) empty set = null set = diameter
+ case 0x2207: return "nabla"; // (8711) nabla = backward difference
+ case 0x2208: return "isin"; // (8712) element of
+ case 0x2209: return "notin"; // (8713) not an element of
+ case 0x220B: return "ni"; // (8715) contains as member
+ case 0x220F: return "prod"; // (8719) n-ary product = product sign
+ case 0x2211: return "sum"; // (8721) n-ary sumation
+ case 0x2212: return "minus"; // (8722) minus sign
+ case 0x2217: return "lowast"; // (8727) asterisk operator
+ case 0x221A: return "radic"; // (8730) square root = radical sign
+ case 0x221D: return "prop"; // (8733) proportional to
+ case 0x221E: return "infin"; // (8734) infinity
+ case 0x2220: return "ang"; // (8736) angle
+ case 0x2227: return "and"; // (8743) logical and = wedge
+ case 0x2228: return "or"; // (8744) logical or = vee
+ case 0x2229: return "cap"; // (8745) intersection = cap
+ case 0x222A: return "cup"; // (8746) union = cup
+ case 0x222B: return "int"; // (8747) integral
+ case 0x2234: return "there4"; // (8756) therefore
+ case 0x223C: return "sim"; // (8764) tilde operator = varies with = similar to
+ case 0x2245: return "cong"; // (8773) approximately equal to
+ case 0x2248: return "asymp"; // (8776) almost equal to = asymptotic to
+ case 0x2260: return "ne"; // (8800) not equal to
+ case 0x2261: return "equiv"; // (8801) identical to
+ case 0x2264: return "le"; // (8804) less-than or equal to
+ case 0x2265: return "ge"; // (8805) greater-than or equal to
+ case 0x2282: return "sub"; // (8834) subset of
+ case 0x2283: return "sup"; // (8835) superset of
+ case 0x2284: return "nsub"; // (8836) not a subset of
+ case 0x2286: return "sube"; // (8838) subset of or equal to
+ case 0x2287: return "supe"; // (8839) superset of or equal to
+ case 0x2295: return "oplus"; // (8853) circled plus = direct sum
+ case 0x2297: return "otimes"; // (8855) circled times = vector product
+ case 0x22A5: return "perp"; // (8869) up tack = orthogonal to = perpendicular
+ case 0x22C5: return "sdot"; // (8901) dot operator
+ // Miscellaneous Technical -------------
+ case 0x2308: return "lceil"; // (8968) left ceiling = apl upstile
+ case 0x2309: return "rceil"; // (8969) right ceiling
+ case 0x230A: return "lfloor"; // (8970) left floor = apl downstile
+ case 0x230B: return "rfloor"; // (8971) right floor
+ case 0x2329: return "lang"; // (9001) left-pointing angle bracket = bra
+ case 0x232A: return "rang"; // (9002) right-pointing angle bracket = ket
+ // Geometric Shapes --------------------
+ case 0x25CA: return "loz"; // (9674) lozenge
+ // Miscellaneous Symbols ---------------
+ case 0x2660: return "spades"; // (9824) black spade suit
+ case 0x2663: return "clubs"; // (9827) black club suit = shamrock
+ case 0x2665: return "hearts"; // (9829) black heart suit = valentine
+ case 0x2666: return "diams"; // (9830) black diamond suit
+ default: break;
+ }
+ return 0;
+}
+
+QString CGI::encodeHTML(const QString &rawText, int conversionFlags)
+{
+ QString enc;
+ enc.reserve(rawText.length()); // at least
+
+ QString::const_iterator it = rawText.constBegin();
+ while (it != rawText.constEnd()) {
+ const char *html = unicodeToHTML((*it).unicode());
+ if (html) {
+ enc.append('&');
+ enc.append(html);
+ enc.append(';');
+ } else if ((conversionFlags & CGI::LineBreaks)
+ && ((*it).toLatin1() == '\n')) {
+ enc.append("<BR>\n");
+ } else if ((conversionFlags & CGI::Spaces)
+ && ((*it).toLatin1() == ' ')) {
+ enc.append("&nbsp;");
+ } else if ((conversionFlags & CGI::Tabs)
+ && ((*it).toLatin1() == '\t')) {
+ enc.append("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
+ } else if ((*it).unicode() > 0x00FF) {
+ enc.append("&#");
+ enc.append(QString::number((*it).unicode()));
+ enc.append(';');
+ } else {
+ enc.append(*it);
+ }
+ ++it;
+ }
+
+ return enc;
+}
+
diff --git a/src/shared/cpaster/cgi.h b/src/shared/cpaster/cgi.h
new file mode 100644
index 0000000000..b615ee79fe
--- /dev/null
+++ b/src/shared/cpaster/cgi.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef CGI_H
+#define CGI_H
+
+#include <QString>
+
+class CGI
+{
+public:
+ static QString encodeURL(const QString &rawText);
+ static QString decodeURL(const QString &urlText);
+
+ enum HTMLconvertFlags {
+ Normal,
+ LineBreaks = 0x0001,
+ Spaces = 0x0002,
+ Tabs = 0x0004
+ };
+
+ static QString encodeHTML(const QString &rawText, int conversionFlags = 0);
+
+private:
+ inline short charToHex(const QChar &ch);
+ inline QChar hexToChar(const QString &hx);
+};
+
+#endif // CGI_H
diff --git a/src/shared/cpaster/cpaster.pri b/src/shared/cpaster/cpaster.pri
new file mode 100644
index 0000000000..146b9d393b
--- /dev/null
+++ b/src/shared/cpaster/cpaster.pri
@@ -0,0 +1,14 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += $$PWD/cgi.h \
+ $$PWD/fetcher.h \
+ $$PWD/poster.h \
+ $$PWD/splitter.h \
+ $$PWD/view.h
+SOURCES += $$PWD/cgi.cpp \
+ $$PWD/fetcher.cpp \
+ $$PWD/poster.cpp \
+ $$PWD/splitter.cpp \
+ $$PWD/view.cpp
+
+FORMS += $$PWD/view.ui
diff --git a/src/shared/cpaster/fetcher.cpp b/src/shared/cpaster/fetcher.cpp
new file mode 100644
index 0000000000..11cfb9d24e
--- /dev/null
+++ b/src/shared/cpaster/fetcher.cpp
@@ -0,0 +1,79 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "fetcher.h"
+#include "cgi.h"
+
+#include <QCoreApplication>
+#include <QByteArray>
+#include <QDebug>
+
+Fetcher::Fetcher(const QString &host)
+ : QHttp(host)
+{
+ m_host = host;
+ m_status = 0;
+ m_hadError = false;
+ connect(this, SIGNAL(requestFinished(int,bool)), SLOT(gotRequestFinished(int,bool)));
+ connect(this, SIGNAL(readyRead(QHttpResponseHeader)), SLOT(gotReadyRead(QHttpResponseHeader)));
+}
+
+int Fetcher::fetch(const QString &url)
+{
+// qDebug("Fetcher::fetch(%s)", qPrintable(url));
+ return QHttp::get(url);
+}
+
+int Fetcher::fetch(int pasteID)
+{
+ return fetch("http://" + m_host + "/?format=raw&id=" + QString::number(pasteID));
+}
+
+void Fetcher::gotRequestFinished(int, bool error)
+{
+ m_hadError = error;
+ QCoreApplication::exit(error ? -1 : 0); // ends event-loop
+}
+
+void Fetcher::gotReadyRead(const QHttpResponseHeader & /* resp */)
+{
+ m_body += QHttp::readAll();
+
+ // Hackish check for No Such Paste, as codepaster doesn't send a HTTP code indicating such, or
+ // sends a redirect to an url indicating failure...
+ if (m_body.contains("<B>No such paste!</B>")) {
+ m_body.clear();
+ m_status = -1;
+ m_hadError = true;
+ }
+}
diff --git a/src/shared/cpaster/fetcher.h b/src/shared/cpaster/fetcher.h
new file mode 100644
index 0000000000..e532d88a1e
--- /dev/null
+++ b/src/shared/cpaster/fetcher.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef FETCHER_H
+#define FETCHER_H
+
+#include <QHttp>
+#include <QHttpResponseHeader>
+#include <QString>
+
+class Fetcher : public QHttp
+{
+ Q_OBJECT
+public:
+ Fetcher(const QString &host);
+
+ int fetch(const QString &url);
+ int fetch(int pasteID);
+
+ QByteArray &body() { return m_body; }
+
+ int status() { return m_status; }
+ bool hadError() { return m_hadError; }
+
+private slots:
+ void gotRequestFinished(int id, bool error);
+ void gotReadyRead(const QHttpResponseHeader &resp);
+
+private:
+ QString m_host;
+ int m_status;
+ bool m_hadError;
+ QByteArray m_body;
+};
+
+#endif // FETCHER_H
diff --git a/src/shared/cpaster/poster.cpp b/src/shared/cpaster/poster.cpp
new file mode 100644
index 0000000000..b55cb8e850
--- /dev/null
+++ b/src/shared/cpaster/poster.cpp
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "poster.h"
+#include "cgi.h"
+
+#include <QCoreApplication>
+#include <QByteArray>
+#include <QDebug>
+
+Poster::Poster(const QString &host)
+ : QHttp(host)
+{
+ m_status = 0;
+ m_hadError = false;
+ connect(this, SIGNAL(requestFinished(int,bool)), SLOT(gotRequestFinished(int,bool)));
+ connect(this, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), SLOT(gotResponseHeaderReceived(QHttpResponseHeader)));
+}
+
+void Poster::post(const QString &description, const QString &comment,
+ const QString &text, const QString &user)
+{
+
+ QByteArray data = "command=processcreate&submit=submit&highlight_type=0&description=";
+ data += CGI::encodeURL(description).toLatin1();
+ data += "&comment=";
+ data += CGI::encodeURL(comment).toLatin1();
+ data += "&code=";
+ data += CGI::encodeURL(text).toLatin1();
+ data += "&poster=";
+ data += CGI::encodeURL(user).toLatin1();
+// qDebug("POST [%s]", data.constData());
+
+ QHttp::post("/", data);
+}
+
+void Poster::gotRequestFinished(int, bool error)
+{
+ m_hadError = error;
+ QCoreApplication::exit(error ? -1 : 0); // ends event-loop
+}
+
+void Poster::gotResponseHeaderReceived(const QHttpResponseHeader &resp)
+{
+ m_url = resp.value("location");
+}
diff --git a/src/shared/cpaster/poster.h b/src/shared/cpaster/poster.h
new file mode 100644
index 0000000000..fb1121b6d6
--- /dev/null
+++ b/src/shared/cpaster/poster.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef POSTER_H
+#define POSTER_H
+
+#include <QHttp>
+#include <QHttpResponseHeader>
+#include <QString>
+
+class Poster : public QHttp
+{
+ Q_OBJECT
+public:
+ Poster(const QString &host);
+
+ void post(const QString &description, const QString &comment,
+ const QString &text, const QString &user);
+
+ QString pastedUrl() { return m_url; }
+ int status() { return m_status; }
+ bool hadError() { return m_hadError; }
+
+private slots:
+ void gotRequestFinished(int id, bool error);
+ void gotResponseHeaderReceived(const QHttpResponseHeader &resp);
+
+private:
+ QString m_url;
+ int m_status;
+ bool m_hadError;
+};
+
+#endif // POSTER_H
diff --git a/src/shared/cpaster/splitter.cpp b/src/shared/cpaster/splitter.cpp
new file mode 100644
index 0000000000..3b79d0153a
--- /dev/null
+++ b/src/shared/cpaster/splitter.cpp
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "splitter.h"
+
+#include <QRegExp>
+
+FileDataList splitDiffToFiles(const QByteArray &data)
+{
+ FileDataList ret;
+ QString strData = data;
+ QString splitExpression;
+
+ if (data.contains("==== ") && data.contains(" ====\n")) {
+ // Perforce diff
+ splitExpression = "==== ([^\\n\\r]+) - ([^\\n\\r]+) ====";
+
+ } else if (data.contains("--- ") && data.contains("\n+++ ")) {
+ // Unified contextual diff
+ splitExpression = "\\-\\-\\- ([^\\n\\r]*)"
+ "\\n\\+\\+\\+ ([^\\n\\r]*)";
+
+ } else if (data.contains("*** ") && data.contains("\n--- ")) {
+ // Copied contextual diff
+ splitExpression = "\\*\\*\\* ([^\\n\\r]*) [0-9\\-]* [0-9:\\.]*[^\\n\\r]*"
+ "\\n\\-\\-\\- ([^\\n\\r]*) [0-9\\-]* [0-9:\\.]*[^\\n\\r]*";
+
+ } else {
+ ret.append(FileData("<not a diff>", data));
+ return ret;
+ }
+
+ int splitIndex = 0, previousSplit = -1;
+ QRegExp splitExpr(splitExpression);
+ QString filename, content;
+ // The algorithm works like this:
+ // On the first match we only get the filename of the first patch part
+ // On the second match (if any) we get the diff content, and the name of the next file patch
+
+ while (-1 != (splitIndex = splitExpr.indexIn(strData,splitIndex))) {
+ if (!filename.isEmpty()) {
+ QString content = strData.mid(previousSplit, splitIndex - previousSplit);
+ ret.append(FileData(filename, content.toLatin1()));
+ }
+
+ // If the first index in not at the beginning of the file, then we know there's content
+ // we're about to skip, which is common in commit diffs, so we get that content and give it
+ // a 'fake' filename.
+ if (previousSplit == -1 && splitIndex > 0 && filename.isEmpty()) {
+ QString content = strData.left(splitIndex);
+ ret.append(FileData("<Header information>", content.toLatin1()));
+ }
+
+ filename = splitExpr.cap(1);
+ previousSplit = splitIndex;
+ ++splitIndex;
+ }
+ // Append the last patch content
+ if (!filename.isEmpty()) {
+ QString content = strData.mid(previousSplit);
+ ret.append(FileData(filename, content.toLatin1()));
+ }
+
+ return ret;
+}
diff --git a/src/shared/cpaster/splitter.h b/src/shared/cpaster/splitter.h
new file mode 100644
index 0000000000..57fb334940
--- /dev/null
+++ b/src/shared/cpaster/splitter.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef SPLITTER_H
+#define SPLITTER_H
+
+#include <QByteArray>
+#include <QList>
+#include <QString>
+
+struct FileData
+{
+ FileData(const QString &f, const QByteArray &c)
+ { filename = f; content = c; }
+
+ QString filename;
+ QByteArray content;
+};
+
+typedef QList<FileData> FileDataList;
+
+FileDataList splitDiffToFiles(const QByteArray &data);
+
+#endif // SPLITTER_H
diff --git a/src/shared/cpaster/view.cpp b/src/shared/cpaster/view.cpp
new file mode 100644
index 0000000000..a38c576350
--- /dev/null
+++ b/src/shared/cpaster/view.cpp
@@ -0,0 +1,185 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "view.h"
+
+#include <QFontMetrics>
+#include <QPainter>
+#include <QScrollBar>
+#include <QPushButton>
+#include <QSettings>
+
+class ColumnIndicatorTextEdit : public QTextEdit
+{
+public:
+ ColumnIndicatorTextEdit(QWidget *parent) : QTextEdit(parent), m_columnIndicator(0)
+ {
+ QFont font;
+ font.setFamily(QString::fromUtf8("Courier New"));
+ //font.setPointSizeF(8.0);
+ setFont(font);
+ setReadOnly(true);
+ QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ sizePolicy.setVerticalStretch(3);
+ setSizePolicy(sizePolicy);
+ int cmx = 0, cmy = 0, cmw = 0, cmh = 0;
+ getContentsMargins(&cmx, &cmy, &cmw, &cmh);
+ m_columnIndicator = QFontMetrics(font).width('W') * 100 + cmx + 1;
+ m_columnIndicatorFont.setFamily(QString::fromUtf8("Times"));
+ m_columnIndicatorFont.setPointSizeF(7.0);
+ }
+
+ int m_columnIndicator;
+ QFont m_columnIndicatorFont;
+
+protected:
+ virtual void paintEvent(QPaintEvent *event);
+};
+
+void ColumnIndicatorTextEdit::paintEvent(QPaintEvent *event)
+{
+ QTextEdit::paintEvent(event);
+
+ QPainter p(viewport());
+ p.setFont(m_columnIndicatorFont);
+ p.setPen(QPen(QColor(0xa0, 0xa0, 0xa0, 0xa0)));
+ p.drawLine(m_columnIndicator, 0, m_columnIndicator, viewport()->height());
+ int yOffset = verticalScrollBar()->value();
+ p.drawText(m_columnIndicator + 1, m_columnIndicatorFont.pointSize() - yOffset, "100");
+}
+
+// -------------------------------------------------------------------------------------------------
+
+
+View::View(QWidget *parent)
+ : QDialog(parent)
+{
+ m_ui.setupUi(this);
+
+ // Swap out the Patch View widget with a ColumnIndicatorTextEdit, which will indicate column 100
+ delete m_ui.uiPatchView;
+ m_ui.uiPatchView = new ColumnIndicatorTextEdit(m_ui.groupBox);
+ m_ui.vboxLayout1->addWidget(m_ui.uiPatchView);
+ m_ui.buttonBox->button(QDialogButtonBox::Ok)->setText("Paste");
+ connect(m_ui.uiPatchList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(contentChanged()));
+}
+
+View::~View()
+{
+}
+
+QString View::getUser()
+{
+ const QString username = m_ui.uiUsername->text();
+ if (username.isEmpty() || username == "<Username>")
+ return "Anonymous";
+ return username;
+}
+
+QString View::getDescription()
+{
+ const QString description = m_ui.uiDescription->text();
+ if (description == "<Description>")
+ return QString();
+ return description;
+}
+
+QString View::getComment()
+{
+ const QString comment = m_ui.uiComment->toPlainText();
+ if (comment == "<Comment>")
+ return QString();
+ return comment;
+}
+
+QByteArray View::getContent()
+{
+ QByteArray newContent;
+ for (int i = 0; i < m_ui.uiPatchList->count(); ++i) {
+ QListWidgetItem *item = m_ui.uiPatchList->item(i);
+ if (item->checkState() != Qt::Unchecked)
+ newContent += m_parts.at(i).content;
+ }
+ return newContent;
+}
+
+void View::contentChanged()
+{
+ m_ui.uiPatchView->setPlainText(getContent());
+}
+
+int View::show(const QString &user, const QString &description, const QString &comment,
+ const FileDataList &parts)
+{
+ if (user.isEmpty())
+ m_ui.uiUsername->setText("<Username>");
+ else
+ m_ui.uiUsername->setText(user);
+
+ if (description.isEmpty())
+ m_ui.uiDescription->setText("<Description>");
+ else
+ m_ui.uiDescription->setText(description);
+
+ if (comment.isEmpty())
+ m_ui.uiComment->setPlainText("<Comment>");
+ else
+ m_ui.uiComment->setPlainText(comment);
+
+ QByteArray content;
+ m_parts = parts;
+ m_ui.uiPatchList->clear();
+ foreach (const FileData part, parts) {
+ QListWidgetItem *itm = new QListWidgetItem(part.filename, m_ui.uiPatchList);
+ itm->setCheckState(Qt::Checked);
+ itm->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
+ content += part.content;
+ }
+ m_ui.uiPatchView->setPlainText(content);
+
+ m_ui.uiDescription->setFocus();
+ m_ui.uiDescription->selectAll();
+
+ // (Re)store dialog size
+ QSettings settings("Trolltech", "cpaster");
+ int h = settings.value("/gui/height", height()).toInt();
+ int w = settings.value("/gui/width",
+ ((ColumnIndicatorTextEdit*)m_ui.uiPatchView)->m_columnIndicator + 50)
+ .toInt();
+ resize(w, h);
+ int ret = QDialog::exec();
+ settings.setValue("/gui/height", height());
+ settings.setValue("/gui/width", width());
+
+ return ret;
+}
diff --git a/src/shared/cpaster/view.h b/src/shared/cpaster/view.h
new file mode 100644
index 0000000000..79485b5dbe
--- /dev/null
+++ b/src/shared/cpaster/view.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef VIEW_H
+#define VIEW_H
+
+#include <QDialog>
+#include <QByteArray>
+
+#include "splitter.h"
+#include "ui_view.h"
+
+class View : public QDialog
+{
+ Q_OBJECT
+public:
+ View(QWidget *parent);
+ ~View();
+
+ int show(const QString &user, const QString &description, const QString &comment,
+ const FileDataList &parts);
+
+ QString getUser();
+ QString getDescription();
+ QString getComment();
+ QByteArray getContent();
+
+private slots:
+ void contentChanged();
+
+private:
+ Ui::ViewDialog m_ui;
+ FileDataList m_parts;
+};
+
+#endif // VIEW_H
diff --git a/src/shared/cpaster/view.ui b/src/shared/cpaster/view.ui
new file mode 100644
index 0000000000..b8ede8d1d4
--- /dev/null
+++ b/src/shared/cpaster/view.ui
@@ -0,0 +1,208 @@
+<ui version="4.0" >
+ <class>ViewDialog</class>
+ <widget class="QDialog" name="ViewDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>500</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Send to Codepaster</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>&amp;Username:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>uiUsername</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="uiUsername" >
+ <property name="text" >
+ <string>&lt;Username></string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>&amp;Description:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>uiDescription</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="uiDescription" >
+ <property name="text" >
+ <string>&lt;Description></string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTextEdit" name="uiComment" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="MinimumExpanding" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>16777215</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="tabChangesFocus" >
+ <bool>true</bool>
+ </property>
+ <property name="html" >
+ <string>&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
+p, li { white-space: pre-wrap; }
+&lt;/style>&lt;/head>&lt;body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+&lt;p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">&amp;lt;Comment&amp;gt;&lt;/p>&lt;/body>&lt;/html></string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>Parts to send to codepaster</string>
+ </property>
+ <property name="flat" >
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="spacing" >
+ <number>2</number>
+ </property>
+ <property name="leftMargin" >
+ <number>0</number>
+ </property>
+ <property name="topMargin" >
+ <number>0</number>
+ </property>
+ <property name="rightMargin" >
+ <number>0</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QListWidget" name="uiPatchList" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="uniformItemSizes" >
+ <bool>true</bool>
+ </property>
+ <item>
+ <property name="text" >
+ <string>Patch 1</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Patch 2</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTextEdit" name="uiPatchView" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>3</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font" >
+ <font>
+ <family>Courier New</family>
+ </font>
+ </property>
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>uiUsername</tabstop>
+ <tabstop>uiDescription</tabstop>
+ <tabstop>uiComment</tabstop>
+ <tabstop>buttonBox</tabstop>
+ <tabstop>uiPatchList</tabstop>
+ <tabstop>uiPatchView</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ViewDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ViewDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/shared/cplusplus/AST.cpp b/src/shared/cplusplus/AST.cpp
new file mode 100644
index 0000000000..3d710db366
--- /dev/null
+++ b/src/shared/cplusplus/AST.cpp
@@ -0,0 +1,3985 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "AST.h"
+#include "ASTVisitor.h"
+#include "MemoryPool.h"
+
+#include <cassert>
+#include <cstddef>
+#include <algorithm>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+AST::AST()
+{ }
+
+AST::~AST()
+{ assert(0); }
+
+AccessDeclarationAST *AST::asAccessDeclaration()
+{ return dynamic_cast<AccessDeclarationAST *>(this); }
+
+ArrayAccessAST *AST::asArrayAccess()
+{ return dynamic_cast<ArrayAccessAST *>(this); }
+
+ArrayDeclaratorAST *AST::asArrayDeclarator()
+{ return dynamic_cast<ArrayDeclaratorAST *>(this); }
+
+ArrayInitializerAST *AST::asArrayInitializer()
+{ return dynamic_cast<ArrayInitializerAST *>(this); }
+
+AsmDefinitionAST *AST::asAsmDefinition()
+{ return dynamic_cast<AsmDefinitionAST *>(this); }
+
+AttributeAST *AST::asAttribute()
+{ return dynamic_cast<AttributeAST *>(this); }
+
+AttributeSpecifierAST *AST::asAttributeSpecifier()
+{ return dynamic_cast<AttributeSpecifierAST *>(this); }
+
+BaseSpecifierAST *AST::asBaseSpecifier()
+{ return dynamic_cast<BaseSpecifierAST *>(this); }
+
+QtMethodAST *AST::asQtMethod()
+{ return dynamic_cast<QtMethodAST *>(this); }
+
+BinaryExpressionAST *AST::asBinaryExpression()
+{ return dynamic_cast<BinaryExpressionAST *>(this); }
+
+BoolLiteralAST *AST::asBoolLiteral()
+{ return dynamic_cast<BoolLiteralAST *>(this); }
+
+BreakStatementAST *AST::asBreakStatement()
+{ return dynamic_cast<BreakStatementAST *>(this); }
+
+CallAST *AST::asCall()
+{ return dynamic_cast<CallAST *>(this); }
+
+CaseStatementAST *AST::asCaseStatement()
+{ return dynamic_cast<CaseStatementAST *>(this); }
+
+CastExpressionAST *AST::asCastExpression()
+{ return dynamic_cast<CastExpressionAST *>(this); }
+
+CatchClauseAST *AST::asCatchClause()
+{ return dynamic_cast<CatchClauseAST *>(this); }
+
+ClassSpecifierAST *AST::asClassSpecifier()
+{ return dynamic_cast<ClassSpecifierAST *>(this); }
+
+CompoundLiteralAST *AST::asCompoundLiteral()
+{ return dynamic_cast<CompoundLiteralAST *>(this); }
+
+CompoundStatementAST *AST::asCompoundStatement()
+{ return dynamic_cast<CompoundStatementAST *>(this); }
+
+ConditionAST *AST::asCondition()
+{ return dynamic_cast<ConditionAST *>(this); }
+
+ConditionalExpressionAST *AST::asConditionalExpression()
+{ return dynamic_cast<ConditionalExpressionAST *>(this); }
+
+ContinueStatementAST *AST::asContinueStatement()
+{ return dynamic_cast<ContinueStatementAST *>(this); }
+
+ConversionFunctionIdAST *AST::asConversionFunctionId()
+{ return dynamic_cast<ConversionFunctionIdAST *>(this); }
+
+CoreDeclaratorAST *AST::asCoreDeclarator()
+{ return dynamic_cast<CoreDeclaratorAST *>(this); }
+
+CppCastExpressionAST *AST::asCppCastExpression()
+{ return dynamic_cast<CppCastExpressionAST *>(this); }
+
+CtorInitializerAST *AST::asCtorInitializer()
+{ return dynamic_cast<CtorInitializerAST *>(this); }
+
+DeclarationAST *AST::asDeclaration()
+{ return dynamic_cast<DeclarationAST *>(this); }
+
+DeclarationStatementAST *AST::asDeclarationStatement()
+{ return dynamic_cast<DeclarationStatementAST *>(this); }
+
+DeclaratorAST *AST::asDeclarator()
+{ return dynamic_cast<DeclaratorAST *>(this); }
+
+DeclaratorIdAST *AST::asDeclaratorId()
+{ return dynamic_cast<DeclaratorIdAST *>(this); }
+
+DeclaratorListAST *AST::asDeclaratorList()
+{ return dynamic_cast<DeclaratorListAST *>(this); }
+
+DeleteExpressionAST *AST::asDeleteExpression()
+{ return dynamic_cast<DeleteExpressionAST *>(this); }
+
+DestructorNameAST *AST::asDestructorName()
+{ return dynamic_cast<DestructorNameAST *>(this); }
+
+DoStatementAST *AST::asDoStatement()
+{ return dynamic_cast<DoStatementAST *>(this); }
+
+ElaboratedTypeSpecifierAST *AST::asElaboratedTypeSpecifier()
+{ return dynamic_cast<ElaboratedTypeSpecifierAST *>(this); }
+
+EmptyDeclarationAST *AST::asEmptyDeclaration()
+{ return dynamic_cast<EmptyDeclarationAST *>(this); }
+
+EnumSpecifierAST *AST::asEnumSpecifier()
+{ return dynamic_cast<EnumSpecifierAST *>(this); }
+
+EnumeratorAST *AST::asEnumerator()
+{ return dynamic_cast<EnumeratorAST *>(this); }
+
+ExceptionDeclarationAST *AST::asExceptionDeclaration()
+{ return dynamic_cast<ExceptionDeclarationAST *>(this); }
+
+ExceptionSpecificationAST *AST::asExceptionSpecification()
+{ return dynamic_cast<ExceptionSpecificationAST *>(this); }
+
+ExpressionAST *AST::asExpression()
+{ return dynamic_cast<ExpressionAST *>(this); }
+
+ExpressionListAST *AST::asExpressionList()
+{ return dynamic_cast<ExpressionListAST *>(this); }
+
+ExpressionOrDeclarationStatementAST *AST::asExpressionOrDeclarationStatement()
+{ return dynamic_cast<ExpressionOrDeclarationStatementAST *>(this); }
+
+ExpressionStatementAST *AST::asExpressionStatement()
+{ return dynamic_cast<ExpressionStatementAST *>(this); }
+
+ForStatementAST *AST::asForStatement()
+{ return dynamic_cast<ForStatementAST *>(this); }
+
+FunctionDeclaratorAST *AST::asFunctionDeclarator()
+{ return dynamic_cast<FunctionDeclaratorAST *>(this); }
+
+FunctionDefinitionAST *AST::asFunctionDefinition()
+{ return dynamic_cast<FunctionDefinitionAST *>(this); }
+
+GotoStatementAST *AST::asGotoStatement()
+{ return dynamic_cast<GotoStatementAST *>(this); }
+
+IfStatementAST *AST::asIfStatement()
+{ return dynamic_cast<IfStatementAST *>(this); }
+
+LabeledStatementAST *AST::asLabeledStatement()
+{ return dynamic_cast<LabeledStatementAST *>(this); }
+
+LinkageBodyAST *AST::asLinkageBody()
+{ return dynamic_cast<LinkageBodyAST *>(this); }
+
+LinkageSpecificationAST *AST::asLinkageSpecification()
+{ return dynamic_cast<LinkageSpecificationAST *>(this); }
+
+MemInitializerAST *AST::asMemInitializer()
+{ return dynamic_cast<MemInitializerAST *>(this); }
+
+MemberAccessAST *AST::asMemberAccess()
+{ return dynamic_cast<MemberAccessAST *>(this); }
+
+NameAST *AST::asName()
+{ return dynamic_cast<NameAST *>(this); }
+
+NamedTypeSpecifierAST *AST::asNamedTypeSpecifier()
+{ return dynamic_cast<NamedTypeSpecifierAST *>(this); }
+
+NamespaceAST *AST::asNamespace()
+{ return dynamic_cast<NamespaceAST *>(this); }
+
+NamespaceAliasDefinitionAST *AST::asNamespaceAliasDefinition()
+{ return dynamic_cast<NamespaceAliasDefinitionAST *>(this); }
+
+NestedDeclaratorAST *AST::asNestedDeclarator()
+{ return dynamic_cast<NestedDeclaratorAST *>(this); }
+
+NestedExpressionAST *AST::asNestedExpression()
+{ return dynamic_cast<NestedExpressionAST *>(this); }
+
+NestedNameSpecifierAST *AST::asNestedNameSpecifier()
+{ return dynamic_cast<NestedNameSpecifierAST *>(this); }
+
+NewDeclaratorAST *AST::asNewDeclarator()
+{ return dynamic_cast<NewDeclaratorAST *>(this); }
+
+NewExpressionAST *AST::asNewExpression()
+{ return dynamic_cast<NewExpressionAST *>(this); }
+
+NewInitializerAST *AST::asNewInitializer()
+{ return dynamic_cast<NewInitializerAST *>(this); }
+
+NewTypeIdAST *AST::asNewTypeId()
+{ return dynamic_cast<NewTypeIdAST *>(this); }
+
+NumericLiteralAST *AST::asNumericLiteral()
+{ return dynamic_cast<NumericLiteralAST *>(this); }
+
+OperatorAST *AST::asOperator()
+{ return dynamic_cast<OperatorAST *>(this); }
+
+OperatorFunctionIdAST *AST::asOperatorFunctionId()
+{ return dynamic_cast<OperatorFunctionIdAST *>(this); }
+
+ParameterDeclarationAST *AST::asParameterDeclaration()
+{ return dynamic_cast<ParameterDeclarationAST *>(this); }
+
+ParameterDeclarationClauseAST *AST::asParameterDeclarationClause()
+{ return dynamic_cast<ParameterDeclarationClauseAST *>(this); }
+
+PointerAST *AST::asPointer()
+{ return dynamic_cast<PointerAST *>(this); }
+
+PointerToMemberAST *AST::asPointerToMember()
+{ return dynamic_cast<PointerToMemberAST *>(this); }
+
+PostIncrDecrAST *AST::asPostIncrDecr()
+{ return dynamic_cast<PostIncrDecrAST *>(this); }
+
+PostfixAST *AST::asPostfix()
+{ return dynamic_cast<PostfixAST *>(this); }
+
+PostfixDeclaratorAST *AST::asPostfixDeclarator()
+{ return dynamic_cast<PostfixDeclaratorAST *>(this); }
+
+PostfixExpressionAST *AST::asPostfixExpression()
+{ return dynamic_cast<PostfixExpressionAST *>(this); }
+
+PtrOperatorAST *AST::asPtrOperator()
+{ return dynamic_cast<PtrOperatorAST *>(this); }
+
+QualifiedNameAST *AST::asQualifiedName()
+{ return dynamic_cast<QualifiedNameAST *>(this); }
+
+ReferenceAST *AST::asReference()
+{ return dynamic_cast<ReferenceAST *>(this); }
+
+ReturnStatementAST *AST::asReturnStatement()
+{ return dynamic_cast<ReturnStatementAST *>(this); }
+
+SimpleDeclarationAST *AST::asSimpleDeclaration()
+{ return dynamic_cast<SimpleDeclarationAST *>(this); }
+
+SimpleNameAST *AST::asSimpleName()
+{ return dynamic_cast<SimpleNameAST *>(this); }
+
+SimpleSpecifierAST *AST::asSimpleSpecifier()
+{ return dynamic_cast<SimpleSpecifierAST *>(this); }
+
+SizeofExpressionAST *AST::asSizeofExpression()
+{ return dynamic_cast<SizeofExpressionAST *>(this); }
+
+SpecifierAST *AST::asSpecifier()
+{ return dynamic_cast<SpecifierAST *>(this); }
+
+StatementAST *AST::asStatement()
+{ return dynamic_cast<StatementAST *>(this); }
+
+StringLiteralAST *AST::asStringLiteral()
+{ return dynamic_cast<StringLiteralAST *>(this); }
+
+SwitchStatementAST *AST::asSwitchStatement()
+{ return dynamic_cast<SwitchStatementAST *>(this); }
+
+TemplateArgumentListAST *AST::asTemplateArgumentList()
+{ return dynamic_cast<TemplateArgumentListAST *>(this); }
+
+TemplateDeclarationAST *AST::asTemplateDeclaration()
+{ return dynamic_cast<TemplateDeclarationAST *>(this); }
+
+TemplateIdAST *AST::asTemplateId()
+{ return dynamic_cast<TemplateIdAST *>(this); }
+
+TemplateTypeParameterAST *AST::asTemplateTypeParameter()
+{ return dynamic_cast<TemplateTypeParameterAST *>(this); }
+
+ThisExpressionAST *AST::asThisExpression()
+{ return dynamic_cast<ThisExpressionAST *>(this); }
+
+ThrowExpressionAST *AST::asThrowExpression()
+{ return dynamic_cast<ThrowExpressionAST *>(this); }
+
+TranslationUnitAST *AST::asTranslationUnit()
+{ return dynamic_cast<TranslationUnitAST *>(this); }
+
+TryBlockStatementAST *AST::asTryBlockStatement()
+{ return dynamic_cast<TryBlockStatementAST *>(this); }
+
+TypeConstructorCallAST *AST::asTypeConstructorCall()
+{ return dynamic_cast<TypeConstructorCallAST *>(this); }
+
+TypeIdAST *AST::asTypeId()
+{ return dynamic_cast<TypeIdAST *>(this); }
+
+TypeidExpressionAST *AST::asTypeidExpression()
+{ return dynamic_cast<TypeidExpressionAST *>(this); }
+
+TypenameCallExpressionAST *AST::asTypenameCallExpression()
+{ return dynamic_cast<TypenameCallExpressionAST *>(this); }
+
+TypenameTypeParameterAST *AST::asTypenameTypeParameter()
+{ return dynamic_cast<TypenameTypeParameterAST *>(this); }
+
+TypeofSpecifierAST *AST::asTypeofSpecifier()
+{ return dynamic_cast<TypeofSpecifierAST *>(this); }
+
+UnaryExpressionAST *AST::asUnaryExpression()
+{ return dynamic_cast<UnaryExpressionAST *>(this); }
+
+UsingAST *AST::asUsing()
+{ return dynamic_cast<UsingAST *>(this); }
+
+UsingDirectiveAST *AST::asUsingDirective()
+{ return dynamic_cast<UsingDirectiveAST *>(this); }
+
+WhileStatementAST *AST::asWhileStatement()
+{ return dynamic_cast<WhileStatementAST *>(this); }
+
+void AST::accept(ASTVisitor *visitor)
+{
+ if (visitor->preVisit(this))
+ accept0(visitor);
+ visitor->postVisit(this);
+}
+
+unsigned AttributeSpecifierAST::firstToken() const
+{
+ return attribute_token;
+}
+
+unsigned AttributeSpecifierAST::lastToken() const
+{
+ if (second_rparen_token)
+ return second_rparen_token + 1;
+ else if (first_rparen_token)
+ return first_rparen_token + 1;
+ else if (attributes)
+ return attributes->lastToken();
+ else if (second_lparen_token)
+ return second_lparen_token + 1;
+ else if (first_lparen_token)
+ return first_lparen_token + 1;
+ return attribute_token + 1;
+}
+
+AttributeSpecifierAST *AttributeSpecifierAST::clone(MemoryPool *pool) const
+{
+ AttributeSpecifierAST *ast = new (pool) AttributeSpecifierAST;
+ ast->attribute_token = attribute_token;
+ ast->first_lparen_token = first_lparen_token;
+ ast->second_lparen_token = second_lparen_token;
+ if (attributes)
+ ast->attributes = attributes->clone(pool);
+ ast->first_rparen_token = first_rparen_token;
+ ast->second_rparen_token = second_rparen_token;
+ return ast;
+}
+
+void AttributeSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (AttributeAST *attr = attributes; attr; attr = attr->next)
+ accept(attr, visitor);
+ }
+}
+
+unsigned AttributeAST::firstToken() const
+{
+ return identifier_token;
+}
+
+unsigned AttributeAST::lastToken() const
+{
+ if (rparen_token)
+ return rparen_token + 1;
+
+ for (ExpressionListAST *it = expression_list;
+ it->expression && it->next; it = it->next) {
+ if (! it->next && it->expression) {
+ return it->expression->lastToken();
+ }
+ }
+
+ if (tag_token)
+ return tag_token + 1;
+
+ if (lparen_token)
+ return lparen_token + 1;
+
+ return identifier_token + 1;
+}
+
+AttributeAST *AttributeAST::clone(MemoryPool *pool) const
+{
+ AttributeAST *ast = new (pool) AttributeAST;
+ ast->identifier_token = identifier_token;
+ ast->lparen_token = lparen_token;
+ ast->tag_token = tag_token;
+ if (expression_list)
+ ast->expression_list = expression_list->clone(pool);
+ ast->rparen_token = rparen_token;
+ if (next)
+ ast->next = next->clone(pool);
+ return ast;
+}
+
+void AttributeAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (ExpressionListAST *it = expression_list; it; it = it->next)
+ accept(it->expression, visitor);
+ }
+}
+
+AccessDeclarationAST *AccessDeclarationAST::clone(MemoryPool *pool) const
+{
+ AccessDeclarationAST *ast = new (pool) AccessDeclarationAST;
+ ast->access_specifier_token = access_specifier_token;
+ ast->slots_token = slots_token;
+ ast->colon_token = colon_token;
+ return ast;
+}
+
+void AccessDeclarationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned AccessDeclarationAST::firstToken() const
+{
+ return access_specifier_token;
+}
+
+unsigned AccessDeclarationAST::lastToken() const
+{
+ if (colon_token)
+ return colon_token + 1;
+ else if (slots_token)
+ return slots_token + 1;
+ return access_specifier_token + 1;
+}
+
+ArrayAccessAST *ArrayAccessAST::clone(MemoryPool *pool) const
+{
+ ArrayAccessAST *ast = new (pool) ArrayAccessAST;
+ ast->lbracket_token = lbracket_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ ast->rbracket_token = rbracket_token;
+ return ast;
+}
+
+void ArrayAccessAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned ArrayAccessAST::firstToken() const
+{
+ return lbracket_token;
+}
+
+unsigned ArrayAccessAST::lastToken() const
+{
+ if (rbracket_token)
+ return rbracket_token + 1;
+ else if (expression)
+ return expression->lastToken();
+ return lbracket_token + 1;
+}
+
+ArrayDeclaratorAST *ArrayDeclaratorAST::clone(MemoryPool *pool) const
+{
+ ArrayDeclaratorAST *ast = new (pool) ArrayDeclaratorAST;
+ ast->lbracket_token = lbracket_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ ast->rbracket_token = rbracket_token;
+ return ast;
+}
+
+void ArrayDeclaratorAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(this->expression, visitor);
+ }
+}
+
+unsigned ArrayDeclaratorAST::firstToken() const
+{
+ return lbracket_token;
+}
+
+unsigned ArrayDeclaratorAST::lastToken() const
+{
+ if (rbracket_token)
+ return rbracket_token + 1;
+ else if (expression)
+ return expression->lastToken();
+ return lbracket_token + 1;
+}
+
+ArrayInitializerAST *ArrayInitializerAST::clone(MemoryPool *pool) const
+{
+ ArrayInitializerAST *ast = new (pool) ArrayInitializerAST;
+ ast->lbrace_token = lbrace_token;
+ if (expression_list)
+ ast->expression_list = expression_list->clone(pool);
+ ast->rbrace_token = rbrace_token;
+ return ast;
+}
+
+void ArrayInitializerAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (ExpressionListAST *expr = expression_list; expr; expr = expr->next)
+ accept(expr->expression, visitor);
+ }
+}
+
+unsigned ArrayInitializerAST::firstToken() const
+{
+ return lbrace_token;
+}
+
+unsigned ArrayInitializerAST::lastToken() const
+{
+ if (rbrace_token)
+ return rbrace_token + 1;
+
+ for (ExpressionListAST *it = expression_list; it; it = it->next) {
+ if (! it->next && it->expression)
+ return it->expression->lastToken();
+ }
+
+ return lbrace_token + 1;
+}
+
+AsmDefinitionAST *AsmDefinitionAST::clone(MemoryPool *pool) const
+{
+ AsmDefinitionAST *ast = new (pool) AsmDefinitionAST;
+ ast->asm_token = asm_token;
+ if (cv_qualifier_seq)
+ ast->cv_qualifier_seq = cv_qualifier_seq->clone(pool);
+ ast->lparen_token = lparen_token;
+ ast->rparen_token = rparen_token;
+ ast->semicolon_token = semicolon_token;
+ return ast;
+}
+
+void AsmDefinitionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = cv_qualifier_seq; spec;
+ spec = spec->next)
+ accept(spec, visitor);
+ }
+}
+
+unsigned AsmDefinitionAST::firstToken() const
+{
+ return asm_token;
+}
+
+unsigned AsmDefinitionAST::lastToken() const
+{
+ if (semicolon_token)
+ return semicolon_token + 1;
+ else if (rparen_token)
+ return rparen_token + 1;
+ else if (lparen_token)
+ return lparen_token + 1;
+ for (SpecifierAST *it = cv_qualifier_seq; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ return asm_token + 1;
+}
+
+BaseSpecifierAST *BaseSpecifierAST::clone(MemoryPool *pool) const
+{
+ BaseSpecifierAST *ast = new (pool) BaseSpecifierAST;
+ ast->token_virtual = token_virtual;
+ ast->token_access_specifier = token_access_specifier;
+ if (name)
+ ast->name = name->clone(pool);
+ if (next)
+ ast->next = next->clone(pool);
+ return ast;
+}
+
+void BaseSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ }
+}
+
+unsigned BaseSpecifierAST::firstToken() const
+{
+ if (token_virtual && token_access_specifier)
+ return std::min(token_virtual, token_access_specifier);
+ return name->firstToken();
+}
+
+unsigned BaseSpecifierAST::lastToken() const
+{
+ if (name)
+ return name->lastToken();
+ else if (token_virtual && token_access_specifier)
+ return std::min(token_virtual, token_access_specifier) + 1;
+ else if (token_virtual)
+ return token_virtual + 1;
+ else if (token_access_specifier)
+ return token_access_specifier + 1;
+ // assert?
+ return 0;
+}
+
+unsigned QtMethodAST::firstToken() const
+{ return method_token; }
+
+unsigned QtMethodAST::lastToken() const
+{
+ if (rparen_token)
+ return rparen_token + 1;
+ else if (declarator)
+ return declarator->lastToken();
+ else if (lparen_token)
+ return lparen_token + 1;
+ return method_token + 1;
+}
+
+QtMethodAST *QtMethodAST::clone(MemoryPool *pool) const
+{
+ QtMethodAST *ast = new (pool) QtMethodAST;
+ ast->method_token = method_token;
+ ast->lparen_token = lparen_token;
+ if (declarator)
+ ast->declarator = declarator->clone(pool);
+ ast->rparen_token = rparen_token;
+ return ast;
+}
+
+void QtMethodAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declarator, visitor);
+ }
+}
+
+BinaryExpressionAST *BinaryExpressionAST::clone(MemoryPool *pool) const
+{
+ BinaryExpressionAST *ast = new (pool) BinaryExpressionAST;
+ if (left_expression)
+ ast->left_expression = left_expression->clone(pool);
+ ast->binary_op_token = binary_op_token;
+ if (right_expression)
+ ast->right_expression = right_expression->clone(pool);
+ return ast;
+}
+
+void BinaryExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(left_expression, visitor);
+ accept(right_expression, visitor);
+ }
+}
+
+unsigned BinaryExpressionAST::firstToken() const
+{
+ return left_expression->firstToken();
+}
+
+unsigned BinaryExpressionAST::lastToken() const
+{
+ if (right_expression)
+ return right_expression->lastToken();
+ else if (binary_op_token)
+ return binary_op_token + 1;
+ return left_expression->lastToken();
+}
+
+BoolLiteralAST *BoolLiteralAST::clone(MemoryPool *pool) const
+{
+ BoolLiteralAST *ast = new (pool) BoolLiteralAST;
+ ast->token = token;
+ return ast;
+}
+
+void BoolLiteralAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned BoolLiteralAST::firstToken() const
+{
+ return token;
+}
+
+unsigned BoolLiteralAST::lastToken() const
+{
+ return token + 1;
+}
+
+CompoundLiteralAST *CompoundLiteralAST::clone(MemoryPool *pool) const
+{
+ CompoundLiteralAST *ast = new (pool) CompoundLiteralAST;
+ ast->lparen_token = lparen_token;
+ if (type_id)
+ ast->type_id = type_id->clone(pool);
+ ast->rparen_token = rparen_token;
+ if (initializer)
+ ast->initializer = initializer->clone(pool);
+ return ast;
+}
+
+void CompoundLiteralAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(type_id, visitor);
+ accept(initializer, visitor);
+ }
+}
+
+unsigned CompoundLiteralAST::firstToken() const
+{
+ return lparen_token;
+}
+
+unsigned CompoundLiteralAST::lastToken() const
+{
+ if (initializer)
+ return initializer->lastToken();
+ else if (rparen_token)
+ return rparen_token + 1;
+ else if (type_id)
+ return type_id->lastToken();
+ return lparen_token + 1;
+}
+
+BreakStatementAST *BreakStatementAST::clone(MemoryPool *pool) const
+{
+ BreakStatementAST *ast = new (pool) BreakStatementAST;
+ ast->break_token = break_token;
+ ast->semicolon_token = semicolon_token;
+ return ast;
+}
+
+void BreakStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned BreakStatementAST::firstToken() const
+{
+ return break_token;
+}
+
+unsigned BreakStatementAST::lastToken() const
+{
+ if (semicolon_token)
+ return semicolon_token + 1;
+ return break_token + 1;
+}
+
+CallAST *CallAST::clone(MemoryPool *pool) const
+{
+ CallAST *ast = new (pool) CallAST;
+ ast->lparen_token = lparen_token;
+ if (expression_list)
+ ast->expression_list = expression_list;
+ ast->rparen_token = rparen_token;
+ return ast;
+}
+
+void CallAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (ExpressionListAST *expr = expression_list;
+ expr; expr = expr->next)
+ accept(expr->expression, visitor);
+ }
+}
+
+unsigned CallAST::firstToken() const
+{
+ return lparen_token;
+}
+
+unsigned CallAST::lastToken() const
+{
+ if (rparen_token)
+ return rparen_token + 1;
+ for (ExpressionListAST *it = expression_list; it; it = it->next) {
+ if (! it->next && it->expression)
+ return it->expression->lastToken();
+ }
+ return lparen_token + 1;
+}
+
+CaseStatementAST *CaseStatementAST::clone(MemoryPool *pool) const
+{
+ CaseStatementAST *ast = new (pool) CaseStatementAST;
+ ast->case_token = case_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ ast->colon_token = colon_token;
+ if (statement)
+ ast->statement = statement->clone(pool);
+ return ast;
+}
+
+void CaseStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned CaseStatementAST::firstToken() const
+{
+ return case_token;
+}
+
+unsigned CaseStatementAST::lastToken() const
+{
+ if (statement)
+ return statement->lastToken();
+ else if (colon_token)
+ return colon_token + 1;
+ else if (expression)
+ return expression->lastToken();
+ return case_token + 1;
+}
+
+CastExpressionAST *CastExpressionAST::clone(MemoryPool *pool) const
+{
+ CastExpressionAST *ast = new (pool) CastExpressionAST;
+ ast->lparen_token = lparen_token;
+ if (type_id)
+ ast->type_id = type_id->clone(pool);
+ ast->rparen_token = rparen_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ return ast;
+}
+
+void CastExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned CastExpressionAST::firstToken() const
+{
+ return lparen_token;
+}
+
+unsigned CastExpressionAST::lastToken() const
+{
+ if (expression)
+ return expression->lastToken();
+ else if (rparen_token)
+ return rparen_token + 1;
+ else if (type_id)
+ return type_id->lastToken();
+ return lparen_token + 1;
+}
+
+CatchClauseAST *CatchClauseAST::clone(MemoryPool *pool) const
+{
+ CatchClauseAST *ast = new (pool) CatchClauseAST;
+ ast->catch_token = catch_token;
+ ast->lparen_token = lparen_token;
+ if (exception_declaration)
+ ast->exception_declaration = exception_declaration->clone(pool);
+ ast->rparen_token = rparen_token;
+ if (statement)
+ ast->statement = statement->clone(pool);
+ if (next)
+ ast->next = next->clone(pool);
+ return ast;
+}
+
+void CatchClauseAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(exception_declaration, visitor);
+ accept(statement, visitor);
+ }
+}
+
+unsigned CatchClauseAST::firstToken() const
+{
+ return catch_token;
+}
+
+unsigned CatchClauseAST::lastToken() const
+{
+ if (statement)
+ return statement->lastToken();
+ else if (rparen_token)
+ return rparen_token + 1;
+ for (DeclarationAST *it = exception_declaration; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ if (lparen_token)
+ return lparen_token + 1;
+
+ return catch_token + 1;
+}
+
+ClassSpecifierAST *ClassSpecifierAST::clone(MemoryPool *pool) const
+{
+ ClassSpecifierAST *ast = new (pool) ClassSpecifierAST;
+ ast->classkey_token = classkey_token;
+ if (attributes)
+ ast->attributes = attributes->clone(pool);
+ if (name)
+ ast->name = name->clone(pool);
+ ast->colon_token = colon_token;
+ if (base_clause)
+ ast->base_clause = base_clause->clone(pool);
+ ast->lbrace_token = lbrace_token;
+ if (member_specifiers)
+ ast->member_specifiers = member_specifiers->clone(pool);
+ ast->rbrace_token = rbrace_token;
+ return ast;
+}
+
+void ClassSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = attributes; spec; spec = spec->next)
+ accept(spec, visitor);
+ accept(name, visitor);
+ for (BaseSpecifierAST *spec = base_clause; spec; spec = spec->next)
+ accept(spec, visitor);
+ for (DeclarationAST *decl = member_specifiers; decl; decl = decl->next)
+ accept(decl, visitor);
+ }
+}
+
+unsigned ClassSpecifierAST::firstToken() const
+{
+ return classkey_token;
+}
+
+unsigned ClassSpecifierAST::lastToken() const
+{
+ if (rbrace_token)
+ return rbrace_token + 1;
+
+ for (DeclarationAST *it = member_specifiers; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ if (lbrace_token)
+ return lbrace_token + 1;
+
+ for (BaseSpecifierAST *it = base_clause; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ if (colon_token)
+ return colon_token + 1;
+
+ if (name)
+ return name->lastToken();
+
+ for (SpecifierAST *it = attributes; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ return classkey_token + 1;
+}
+
+CompoundStatementAST *CompoundStatementAST::clone(MemoryPool *pool) const
+{
+ CompoundStatementAST *ast = new (pool) CompoundStatementAST;
+ ast->lbrace_token = lbrace_token;
+ if (statements)
+ ast->statements = statements->clone(pool);
+ ast->rbrace_token = rbrace_token;
+ return ast;
+}
+
+void CompoundStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (StatementAST *stmt = statements; stmt; stmt = stmt->next)
+ accept(stmt, visitor);
+ }
+}
+
+unsigned CompoundStatementAST::firstToken() const
+{
+ return lbrace_token;
+}
+
+unsigned CompoundStatementAST::lastToken() const
+{
+ if (rbrace_token)
+ return rbrace_token + 1;
+
+ for (StatementAST *it = statements; it ; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ return lbrace_token + 1;
+}
+
+ConditionAST *ConditionAST::clone(MemoryPool *pool) const
+{
+ ConditionAST *ast = new (pool) ConditionAST;
+ if (type_specifier)
+ ast->type_specifier = type_specifier->clone(pool);
+ if (declarator)
+ ast->declarator = declarator->clone(pool);
+ return ast;
+}
+
+void ConditionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = type_specifier; spec; spec = spec->next)
+ accept(spec, visitor);
+ accept(declarator, visitor);
+ }
+}
+
+unsigned ConditionAST::firstToken() const
+{
+ if (type_specifier)
+ return type_specifier->firstToken();
+
+ return declarator->firstToken();
+}
+
+unsigned ConditionAST::lastToken() const
+{
+ if (declarator)
+ return declarator->lastToken();
+
+ for (SpecifierAST *it = type_specifier; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ // ### assert?
+ return 0;
+}
+
+ConditionalExpressionAST *ConditionalExpressionAST::clone(MemoryPool *pool) const
+{
+ ConditionalExpressionAST *ast = new (pool) ConditionalExpressionAST;
+ if (condition)
+ ast->condition = condition->clone(pool);
+ ast->question_token = question_token;
+ if (left_expression)
+ ast->left_expression = left_expression->clone(pool);
+ ast->colon_token = colon_token;
+ if (right_expression)
+ ast->right_expression = right_expression->clone(pool);
+ return ast;
+}
+
+void ConditionalExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(condition, visitor);
+ accept(left_expression, visitor);
+ accept(right_expression, visitor);
+ }
+}
+
+unsigned ConditionalExpressionAST::firstToken() const
+{
+ return condition->firstToken();
+}
+
+unsigned ConditionalExpressionAST::lastToken() const
+{
+ if (right_expression)
+ return right_expression->lastToken();
+ else if (colon_token)
+ return colon_token + 1;
+ else if (left_expression)
+ return left_expression->lastToken();
+ else if (question_token)
+ return question_token + 1;
+ else if (condition)
+ return condition->lastToken();
+ // ### assert?
+ return 0;
+}
+
+ContinueStatementAST *ContinueStatementAST::clone(MemoryPool *pool) const
+{
+ ContinueStatementAST *ast = new (pool) ContinueStatementAST;
+ ast->continue_token = continue_token;
+ ast->semicolon_token = semicolon_token;
+ return ast;
+}
+
+void ContinueStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned ContinueStatementAST::firstToken() const
+{
+ return continue_token;
+}
+
+unsigned ContinueStatementAST::lastToken() const
+{
+ if (semicolon_token)
+ return semicolon_token + 1;
+ return continue_token + 1;
+}
+
+ConversionFunctionIdAST *ConversionFunctionIdAST::clone(MemoryPool *pool) const
+{
+ ConversionFunctionIdAST *ast = new (pool) ConversionFunctionIdAST;
+ ast->operator_token = operator_token;
+ if (type_specifier)
+ ast->type_specifier = type_specifier->clone(pool);
+ if (ptr_operators)
+ ast->ptr_operators = ptr_operators->clone(pool);
+ return ast;
+}
+
+void ConversionFunctionIdAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = type_specifier; spec; spec = spec->next)
+ accept(spec, visitor);
+ for (PtrOperatorAST *ptr_op = ptr_operators; ptr_op;
+ ptr_op = static_cast<PtrOperatorAST *>(ptr_op->next))
+ accept(ptr_op, visitor);
+ }
+}
+
+unsigned ConversionFunctionIdAST::firstToken() const
+{
+ return operator_token;
+}
+
+unsigned ConversionFunctionIdAST::lastToken() const
+{
+ for (PtrOperatorAST *it = ptr_operators; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ for (SpecifierAST *it = type_specifier; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ return operator_token + 1;
+}
+
+CppCastExpressionAST *CppCastExpressionAST::clone(MemoryPool *pool) const
+{
+ CppCastExpressionAST *ast = new (pool) CppCastExpressionAST;
+ ast->cast_token = cast_token;
+ ast->less_token = less_token;
+ if (type_id)
+ ast->type_id = type_id->clone(pool);
+ ast->greater_token = greater_token;
+ ast->lparen_token = lparen_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ ast->rparen_token = rparen_token;
+ return ast;
+}
+
+void CppCastExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(type_id, visitor);
+ accept(expression, visitor);
+ }
+}
+
+unsigned CppCastExpressionAST::firstToken() const
+{
+ return cast_token;
+}
+
+unsigned CppCastExpressionAST::lastToken() const
+{
+ if (rparen_token)
+ return rparen_token + 1;
+ else if (expression)
+ return expression->lastToken();
+ else if (lparen_token)
+ return lparen_token + 1;
+ else if (greater_token)
+ return greater_token + 1;
+ else if (type_id)
+ return type_id->lastToken();
+ else if (less_token)
+ return less_token + 1;
+ return cast_token + 1;
+}
+
+CtorInitializerAST *CtorInitializerAST::clone(MemoryPool *pool) const
+{
+ CtorInitializerAST *ast = new (pool) CtorInitializerAST;
+ ast->colon_token = colon_token;
+ if (member_initializers)
+ ast->member_initializers = member_initializers->clone(pool);
+ return ast;
+}
+
+void CtorInitializerAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (MemInitializerAST *mem_init = member_initializers;
+ mem_init; mem_init = mem_init->next)
+ accept(mem_init, visitor);
+ }
+}
+
+unsigned CtorInitializerAST::firstToken() const
+{
+ return colon_token;
+}
+
+unsigned CtorInitializerAST::lastToken() const
+{
+ for (MemInitializerAST *it = member_initializers; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ return colon_token + 1;
+}
+
+DeclaratorAST *DeclaratorAST::clone(MemoryPool *pool) const
+{
+ DeclaratorAST *ast = new (pool) DeclaratorAST;
+ if (ptr_operators)
+ ast->ptr_operators = ptr_operators->clone(pool);
+ if (core_declarator)
+ ast->core_declarator = core_declarator->clone(pool);
+ if (postfix_declarators)
+ ast->postfix_declarators = postfix_declarators->clone(pool);
+ if (attributes)
+ ast->attributes = attributes->clone(pool);
+ if (initializer)
+ ast->initializer = initializer->clone(pool);
+ return ast;
+}
+
+void DeclaratorAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (PtrOperatorAST *ptr_op = ptr_operators; ptr_op; ptr_op = ptr_op->next) {
+ accept(ptr_op, visitor);
+ }
+ accept(core_declarator, visitor);
+ for (PostfixDeclaratorAST *fx = postfix_declarators; fx; fx = fx->next) {
+ accept(fx, visitor);
+ }
+ accept(attributes, visitor);
+ accept(initializer, visitor);
+ }
+}
+
+unsigned DeclaratorAST::firstToken() const
+{
+ if (ptr_operators)
+ return ptr_operators->firstToken();
+ else if (core_declarator)
+ return core_declarator->firstToken();
+ else if (postfix_declarators)
+ return postfix_declarators->firstToken();
+ else if (attributes)
+ return attributes->firstToken();
+ else if (initializer)
+ return initializer->firstToken();
+ // ### assert?
+ return 0;
+}
+
+unsigned DeclaratorAST::lastToken() const
+{
+ if (initializer)
+ return initializer->lastToken();
+
+ for (SpecifierAST *it = attributes; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ for (PostfixDeclaratorAST *it = postfix_declarators; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ if (core_declarator)
+ return core_declarator->lastToken();
+
+ for (PtrOperatorAST *it = ptr_operators; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ // ### assert?
+ return 0;
+}
+
+DeclarationStatementAST *DeclarationStatementAST::clone(MemoryPool *pool) const
+{
+ DeclarationStatementAST *ast = new (pool) DeclarationStatementAST;
+ if (declaration)
+ ast->declaration = declaration->clone(pool);
+ return ast;
+}
+
+void DeclarationStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declaration, visitor);
+ }
+}
+
+unsigned DeclarationStatementAST::firstToken() const
+{
+ return declaration->firstToken();
+}
+
+unsigned DeclarationStatementAST::lastToken() const
+{
+ return declaration->lastToken();
+}
+
+DeclaratorIdAST *DeclaratorIdAST::clone(MemoryPool *pool) const
+{
+ DeclaratorIdAST *ast = new (pool) DeclaratorIdAST;
+ if (name)
+ ast->name = name->clone(pool);
+ return ast;
+}
+
+void DeclaratorIdAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ }
+}
+
+unsigned DeclaratorIdAST::firstToken() const
+{
+ return name->firstToken();
+}
+
+unsigned DeclaratorIdAST::lastToken() const
+{
+ return name->lastToken();
+}
+
+DeclaratorListAST *DeclaratorListAST::clone(MemoryPool *pool) const
+{
+ DeclaratorListAST *ast = new (pool) DeclaratorListAST;
+ if (declarator)
+ ast->declarator = declarator->clone(pool);
+ if (next)
+ ast->next = next->clone(pool);
+ return ast;
+}
+
+void DeclaratorListAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (DeclaratorListAST *it = this; it; it = it->next)
+ accept(it->declarator, visitor);
+ }
+}
+
+unsigned DeclaratorListAST::firstToken() const
+{
+ return declarator->firstToken();
+}
+
+unsigned DeclaratorListAST::lastToken() const
+{
+ for (const DeclaratorListAST *it = this; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ return 0;
+}
+
+DeleteExpressionAST *DeleteExpressionAST::clone(MemoryPool *pool) const
+{
+ DeleteExpressionAST *ast = new (pool) DeleteExpressionAST;
+ ast->scope_token = scope_token;
+ ast->delete_token = delete_token;
+ ast->lbracket_token = lbracket_token;
+ ast->rbracket_token = rbracket_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ return ast;
+}
+
+void DeleteExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned DeleteExpressionAST::firstToken() const
+{
+ if (scope_token)
+ return scope_token;
+ return delete_token;
+}
+
+unsigned DeleteExpressionAST::lastToken() const
+{
+ if (expression)
+ return expression->lastToken();
+ else if (rbracket_token)
+ return rbracket_token + 1;
+ else if (lbracket_token)
+ return lbracket_token + 1;
+ else if (delete_token)
+ return delete_token + 1;
+ return scope_token + 1;
+}
+
+DestructorNameAST *DestructorNameAST::clone(MemoryPool *pool) const
+{
+ DestructorNameAST *ast = new (pool) DestructorNameAST;
+ ast->tilde_token = tilde_token;
+ ast->identifier_token = identifier_token;
+ return ast;
+}
+
+void DestructorNameAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned DestructorNameAST::firstToken() const
+{
+ return tilde_token;
+}
+
+unsigned DestructorNameAST::lastToken() const
+{
+ if (identifier_token)
+ return identifier_token + 1;
+ return tilde_token + 1;
+}
+
+DoStatementAST *DoStatementAST::clone(MemoryPool *pool) const
+{
+ DoStatementAST *ast = new (pool) DoStatementAST;
+ ast->do_token = do_token;
+ if (statement)
+ ast->statement = statement->clone(pool);
+ ast->while_token = while_token;
+ ast->lparen_token = lparen_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ ast->rparen_token = rparen_token;
+ ast->semicolon_token = semicolon_token;
+ return ast;
+}
+
+void DoStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ accept(expression, visitor);
+ }
+}
+
+unsigned DoStatementAST::firstToken() const
+{
+ return do_token;
+}
+
+unsigned DoStatementAST::lastToken() const
+{
+ if (semicolon_token)
+ return semicolon_token + 1;
+ else if (rparen_token)
+ return rparen_token + 1;
+ else if (expression)
+ return expression->lastToken();
+ else if (lparen_token)
+ return lparen_token + 1;
+ else if (while_token)
+ return while_token + 1;
+ else if (statement)
+ return statement->lastToken();
+ return do_token + 1;
+}
+
+ElaboratedTypeSpecifierAST *ElaboratedTypeSpecifierAST::clone(MemoryPool *pool) const
+{
+ ElaboratedTypeSpecifierAST *ast = new (pool) ElaboratedTypeSpecifierAST;
+ ast->classkey_token = classkey_token;
+ if (name)
+ ast->name = name->clone(pool);
+ return ast;
+}
+
+void ElaboratedTypeSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ }
+}
+
+unsigned ElaboratedTypeSpecifierAST::firstToken() const
+{
+ return classkey_token;
+}
+
+unsigned ElaboratedTypeSpecifierAST::lastToken() const
+{
+ if (name)
+ return name->lastToken();
+ return classkey_token + 1;
+}
+
+EmptyDeclarationAST *EmptyDeclarationAST::clone(MemoryPool *pool) const
+{
+ EmptyDeclarationAST *ast = new (pool) EmptyDeclarationAST;
+ ast->semicolon_token = semicolon_token;
+ return ast;
+}
+
+void EmptyDeclarationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned EmptyDeclarationAST::firstToken() const
+{
+ return semicolon_token;
+}
+
+unsigned EmptyDeclarationAST::lastToken() const
+{
+ return semicolon_token + 1;
+}
+
+EnumSpecifierAST *EnumSpecifierAST::clone(MemoryPool *pool) const
+{
+ EnumSpecifierAST *ast = new (pool) EnumSpecifierAST;
+ ast->enum_token = enum_token;
+ if (name)
+ ast->name = name->clone(pool);
+ ast->lbrace_token = lbrace_token;
+ if (enumerators)
+ ast->enumerators = enumerators->clone(pool);
+ ast->rbrace_token = rbrace_token;
+ return ast;
+}
+
+void EnumSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ for (EnumeratorAST *enumerator = enumerators; enumerator;
+ enumerator = enumerator->next)
+ accept(enumerator, visitor);
+ }
+}
+
+unsigned EnumSpecifierAST::firstToken() const
+{
+ return enum_token;
+}
+
+unsigned EnumSpecifierAST::lastToken() const
+{
+ if (rbrace_token)
+ return rbrace_token + 1;
+
+ for (EnumeratorAST *it = enumerators; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ if (lbrace_token)
+ return lbrace_token + 1;
+ if (name)
+ return name->lastToken();
+
+ return enum_token + 1;
+}
+
+EnumeratorAST *EnumeratorAST::clone(MemoryPool *pool) const
+{
+ EnumeratorAST *ast = new (pool) EnumeratorAST;
+ ast->identifier_token = identifier_token;
+ ast->equal_token = equal_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ if (next)
+ ast->next = next->clone(pool);
+ return ast;
+}
+
+void EnumeratorAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned EnumeratorAST::firstToken() const
+{
+ return identifier_token;
+}
+
+unsigned EnumeratorAST::lastToken() const
+{
+ if (expression)
+ return expression->lastToken();
+ else if (equal_token)
+ return equal_token + 1;
+ return identifier_token + 1;
+}
+
+ExceptionDeclarationAST *ExceptionDeclarationAST::clone(MemoryPool *pool) const
+{
+ ExceptionDeclarationAST *ast = new (pool) ExceptionDeclarationAST;
+ if (type_specifier)
+ ast->type_specifier = type_specifier->clone(pool);
+ if (declarator)
+ ast->declarator = declarator->clone(pool);
+ ast->dot_dot_dot_token = dot_dot_dot_token;
+ return ast;
+}
+
+void ExceptionDeclarationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = type_specifier; spec; spec = spec->next)
+ accept(spec, visitor);
+ accept(declarator, visitor);
+ }
+}
+
+unsigned ExceptionDeclarationAST::firstToken() const
+{
+ if (type_specifier)
+ return type_specifier->firstToken();
+ if (declarator)
+ return declarator->firstToken();
+ return dot_dot_dot_token;
+}
+
+unsigned ExceptionDeclarationAST::lastToken() const
+{
+ if (dot_dot_dot_token)
+ return dot_dot_dot_token + 1;
+ else if (declarator)
+ return declarator->lastToken();
+ for (SpecifierAST *it = type_specifier; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ return 0;
+}
+
+ExceptionSpecificationAST *ExceptionSpecificationAST::clone(MemoryPool *pool) const
+{
+ ExceptionSpecificationAST *ast = new (pool) ExceptionSpecificationAST;
+ ast->throw_token = throw_token;
+ ast->lparen_token = lparen_token;
+ ast->dot_dot_dot_token = dot_dot_dot_token;
+ if (type_ids)
+ ast->type_ids = type_ids->clone(pool);
+ ast->rparen_token = rparen_token;
+ return ast;
+}
+
+void ExceptionSpecificationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (ExpressionListAST *type_id = type_ids; type_id;
+ type_id = type_id->next)
+ accept(type_id->expression, visitor);
+ }
+}
+
+unsigned ExceptionSpecificationAST::firstToken() const
+{
+ return throw_token;
+}
+
+unsigned ExceptionSpecificationAST::lastToken() const
+{
+ if (rparen_token)
+ return rparen_token + 1;
+
+ for (ExpressionListAST *it = type_ids; it; it = it->next) {
+ if (! it->next && it->expression)
+ return it->expression->lastToken();
+ }
+
+ if (dot_dot_dot_token)
+ return dot_dot_dot_token + 1;
+ else if (lparen_token)
+ return lparen_token + 1;
+
+ return throw_token + 1;
+}
+
+ExpressionListAST *ExpressionListAST::clone(MemoryPool *pool) const
+{
+ ExpressionListAST *ast = new (pool) ExpressionListAST;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ if (next)
+ ast->next = next->clone(pool);
+ return ast;
+}
+
+void ExpressionListAST::accept0(ASTVisitor *visitor)
+{
+ for (const ExpressionListAST *it = this; it; it = it->next) {
+ accept(it->expression, visitor);
+ }
+}
+
+unsigned ExpressionListAST::firstToken() const
+{
+ return expression->firstToken();
+}
+
+unsigned ExpressionListAST::lastToken() const
+{
+ for (const ExpressionListAST *it = this; it; it = it->next) {
+ if (! it->next)
+ return it->expression->lastToken();
+ }
+ return 0;
+}
+
+ExpressionOrDeclarationStatementAST *ExpressionOrDeclarationStatementAST::clone(MemoryPool *pool) const
+{
+ ExpressionOrDeclarationStatementAST *ast = new (pool) ExpressionOrDeclarationStatementAST;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ if (declaration)
+ ast->declaration = declaration->clone(pool);
+ return ast;
+}
+
+void ExpressionOrDeclarationStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declaration, visitor);
+ accept(expression, visitor);
+ }
+}
+
+unsigned ExpressionOrDeclarationStatementAST::firstToken() const
+{
+ return declaration->firstToken();
+}
+
+unsigned ExpressionOrDeclarationStatementAST::lastToken() const
+{
+ return declaration->lastToken();
+}
+
+ExpressionStatementAST *ExpressionStatementAST::clone(MemoryPool *pool) const
+{
+ ExpressionStatementAST *ast = new (pool) ExpressionStatementAST;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ ast->semicolon_token = semicolon_token;
+ return ast;
+}
+
+void ExpressionStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned ExpressionStatementAST::firstToken() const
+{
+ if (expression)
+ return expression->firstToken();
+ return semicolon_token;
+}
+
+unsigned ExpressionStatementAST::lastToken() const
+{
+ if (semicolon_token)
+ return semicolon_token + 1;
+ else if (expression)
+ return expression->lastToken();
+ // ### assert?
+ return 0;
+}
+
+ForStatementAST *ForStatementAST::clone(MemoryPool *pool) const
+{
+ ForStatementAST *ast = new (pool) ForStatementAST;
+ ast->for_token = for_token;
+ ast->lparen_token = lparen_token;
+ if (initializer)
+ ast->initializer = initializer->clone(pool);
+ if (condition)
+ ast->condition = condition->clone(pool);
+ ast->semicolon_token = semicolon_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ ast->rparen_token = rparen_token;
+ if (statement)
+ ast->statement = statement->clone(pool);
+ return ast;
+}
+
+void ForStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(initializer, visitor);
+ accept(condition, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+}
+
+unsigned ForStatementAST::firstToken() const
+{
+ return for_token;
+}
+
+unsigned ForStatementAST::lastToken() const
+{
+ if (statement)
+ return statement->lastToken();
+ else if (rparen_token)
+ return rparen_token + 1;
+ else if (expression)
+ return expression->lastToken();
+ else if (semicolon_token)
+ return semicolon_token + 1;
+ else if (condition)
+ return condition->lastToken();
+ else if (initializer)
+ return initializer->lastToken();
+ else if (lparen_token)
+ return lparen_token + 1;
+
+ return for_token + 1;
+}
+
+FunctionDeclaratorAST *FunctionDeclaratorAST::clone(MemoryPool *pool) const
+{
+ FunctionDeclaratorAST *ast = new (pool) FunctionDeclaratorAST;
+ ast->lparen_token = lparen_token;
+ if (parameters)
+ ast->parameters = parameters->clone(pool);
+ ast->rparen_token = rparen_token;
+ if (cv_qualifier_seq)
+ ast->cv_qualifier_seq = cv_qualifier_seq->clone(pool);
+ if (exception_specification)
+ ast->exception_specification = exception_specification->clone(pool);
+ return ast;
+}
+
+void FunctionDeclaratorAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned FunctionDeclaratorAST::firstToken() const
+{
+ return lparen_token;
+}
+
+unsigned FunctionDeclaratorAST::lastToken() const
+{
+ if (exception_specification)
+ return exception_specification->lastToken();
+
+ for (SpecifierAST *it = cv_qualifier_seq; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ if (rparen_token)
+ return rparen_token + 1;
+ else if (parameters)
+ return parameters->lastToken();
+
+ return lparen_token + 1;
+}
+
+FunctionDefinitionAST *FunctionDefinitionAST::clone(MemoryPool *pool) const
+{
+ FunctionDefinitionAST *ast = new (pool) FunctionDefinitionAST;
+ if (decl_specifier_seq)
+ ast->decl_specifier_seq = decl_specifier_seq->clone(pool);
+ if (declarator)
+ ast->declarator = declarator->clone(pool);
+ if (ctor_initializer)
+ ast->ctor_initializer = ctor_initializer->clone(pool);
+ if (function_body)
+ ast->function_body = function_body->clone(pool);
+ return ast;
+}
+
+void FunctionDefinitionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = decl_specifier_seq; spec;
+ spec = spec->next)
+ accept(spec, visitor);
+ accept(declarator, visitor);
+ accept(ctor_initializer, visitor);
+ accept(function_body, visitor);
+ }
+}
+
+unsigned FunctionDefinitionAST::firstToken() const
+{
+ if (decl_specifier_seq)
+ return decl_specifier_seq->firstToken();
+ else if (declarator)
+ return declarator->firstToken();
+ else if (ctor_initializer)
+ return ctor_initializer->firstToken();
+ return function_body->firstToken();
+}
+
+unsigned FunctionDefinitionAST::lastToken() const
+{
+ if (function_body)
+ return function_body->lastToken();
+ else if (ctor_initializer)
+ return ctor_initializer->lastToken();
+ if (declarator)
+ return declarator->lastToken();
+
+ for (SpecifierAST *it = decl_specifier_seq; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ // ### assert
+ return 0;
+}
+
+GotoStatementAST *GotoStatementAST::clone(MemoryPool *pool) const
+{
+ GotoStatementAST *ast = new (pool) GotoStatementAST;
+ ast->goto_token = goto_token;
+ ast->identifier_token = identifier_token;
+ ast->semicolon_token = semicolon_token;
+ return ast;
+}
+
+void GotoStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned GotoStatementAST::firstToken() const
+{
+ return goto_token;
+}
+
+unsigned GotoStatementAST::lastToken() const
+{
+ if (semicolon_token)
+ return semicolon_token + 1;
+ else if (identifier_token)
+ return identifier_token + 1;
+ else if (goto_token)
+ return goto_token + 1;
+ return 0;
+}
+
+IfStatementAST *IfStatementAST::clone(MemoryPool *pool) const
+{
+ IfStatementAST *ast = new (pool) IfStatementAST;
+ ast->if_token = if_token;
+ ast->lparen_token = lparen_token;
+ if (condition)
+ ast->condition = condition->clone(pool);
+ ast->rparen_token = rparen_token;
+ if (statement)
+ ast->statement = statement->clone(pool);
+ ast->else_token = else_token;
+ if (else_statement)
+ ast->else_statement = else_statement->clone(pool);
+ return ast;
+}
+
+void IfStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(condition, visitor);
+ accept(statement, visitor);
+ accept(else_statement, visitor);
+ }
+}
+
+unsigned IfStatementAST::firstToken() const
+{
+ return if_token;
+}
+
+unsigned IfStatementAST::lastToken() const
+{
+ if (else_statement)
+ return else_statement->lastToken();
+ else if (else_token)
+ return else_token + 1;
+ else if (statement)
+ return statement->lastToken();
+ else if (rparen_token)
+ return rparen_token + 1;
+ else if (condition)
+ return condition->lastToken();
+ else if (lparen_token)
+ return lparen_token + 1;
+ return if_token + 1;
+}
+
+LabeledStatementAST *LabeledStatementAST::clone(MemoryPool *pool) const
+{
+ LabeledStatementAST *ast = new (pool) LabeledStatementAST;
+ ast->label_token = label_token;
+ ast->colon_token = colon_token;
+ if (statement)
+ ast->statement = statement->clone(pool);
+ return ast;
+}
+
+void LabeledStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+}
+
+unsigned LabeledStatementAST::firstToken() const
+{
+ return label_token;
+}
+
+unsigned LabeledStatementAST::lastToken() const
+{
+ if (statement)
+ return statement->lastToken();
+ else if (colon_token)
+ return colon_token + 1;
+ return label_token + 1;
+}
+
+LinkageBodyAST *LinkageBodyAST::clone(MemoryPool *pool) const
+{
+ LinkageBodyAST *ast = new (pool) LinkageBodyAST;
+ ast->lbrace_token = lbrace_token;
+ if (declarations)
+ ast->declarations = declarations->clone(pool);
+ ast->rbrace_token = rbrace_token;
+ return ast;
+}
+
+void LinkageBodyAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (DeclarationAST *decl = declarations; decl;
+ decl = decl->next)
+ accept(decl, visitor);
+ }
+}
+
+unsigned LinkageBodyAST::firstToken() const
+{
+ return lbrace_token;
+}
+
+unsigned LinkageBodyAST::lastToken() const
+{
+ if (rbrace_token)
+ return rbrace_token + 1;
+
+ for (DeclarationAST *it = declarations; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ return lbrace_token + 1;
+}
+
+LinkageSpecificationAST *LinkageSpecificationAST::clone(MemoryPool *pool) const
+{
+ LinkageSpecificationAST *ast = new (pool) LinkageSpecificationAST;
+ ast->extern_token = extern_token;
+ ast->extern_type = extern_type;
+ if (declaration)
+ ast->declaration = declaration->clone(pool);
+ return ast;
+}
+
+void LinkageSpecificationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declaration, visitor);
+ }
+}
+
+unsigned LinkageSpecificationAST::firstToken() const
+{
+ return extern_token;
+}
+
+unsigned LinkageSpecificationAST::lastToken() const
+{
+ if (declaration)
+ return declaration->lastToken();
+ else if (extern_type)
+ return extern_type + 1;
+ return extern_token + 1;
+}
+
+MemInitializerAST *MemInitializerAST::clone(MemoryPool *pool) const
+{
+ MemInitializerAST *ast = new (pool) MemInitializerAST;
+ if (name)
+ ast->name = name->clone(pool);
+ ast->lparen_token = lparen_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ ast->rparen_token = rparen_token;
+ if (next)
+ ast->next = next->clone(pool);
+ return ast;
+}
+
+void MemInitializerAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned MemInitializerAST::firstToken() const
+{
+ return name->firstToken();
+}
+
+unsigned MemInitializerAST::lastToken() const
+{
+ if (rparen_token)
+ return rparen_token + 1;
+ else if (expression)
+ return expression->lastToken();
+ else if (lparen_token)
+ return lparen_token + 1;
+ return name->lastToken();
+}
+
+MemberAccessAST *MemberAccessAST::clone(MemoryPool *pool) const
+{
+ MemberAccessAST *ast = new (pool) MemberAccessAST;
+ ast->access_token = access_token;
+ ast->template_token = template_token;
+ if (member_name)
+ ast->member_name = member_name->clone(pool);
+ return ast;
+}
+
+void MemberAccessAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(member_name, visitor);
+ }
+}
+
+unsigned MemberAccessAST::firstToken() const
+{
+ return access_token;
+}
+
+unsigned MemberAccessAST::lastToken() const
+{
+ if (member_name)
+ return member_name->lastToken();
+ else if (template_token)
+ return template_token + 1;
+ return access_token + 1;
+}
+
+NamedTypeSpecifierAST *NamedTypeSpecifierAST::clone(MemoryPool *pool) const
+{
+ NamedTypeSpecifierAST *ast = new (pool) NamedTypeSpecifierAST;
+ if (name)
+ ast->name = name->clone(pool);
+ return ast;
+}
+
+void NamedTypeSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ }
+}
+
+unsigned NamedTypeSpecifierAST::firstToken() const
+{
+ return name->firstToken();
+}
+
+unsigned NamedTypeSpecifierAST::lastToken() const
+{
+ return name->lastToken();
+}
+
+NamespaceAST *NamespaceAST::clone(MemoryPool *pool) const
+{
+ NamespaceAST *ast = new (pool) NamespaceAST;
+ ast->namespace_token = namespace_token;
+ ast->identifier_token = identifier_token;
+ if (attributes)
+ ast->attributes = attributes->clone(pool);
+ if (linkage_body)
+ ast->linkage_body = linkage_body->clone(pool);
+ return ast;
+}
+
+void NamespaceAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *attr = attributes; attr; attr = attr->next) {
+ accept(attr, visitor);
+ }
+ accept(linkage_body, visitor);
+ }
+}
+
+unsigned NamespaceAST::firstToken() const
+{
+ return namespace_token;
+}
+
+unsigned NamespaceAST::lastToken() const
+{
+ if (linkage_body)
+ return linkage_body->lastToken();
+
+ for (SpecifierAST *it = attributes; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ if (identifier_token)
+ return identifier_token + 1;
+
+ return namespace_token + 1;
+}
+
+NamespaceAliasDefinitionAST *NamespaceAliasDefinitionAST::clone(MemoryPool *pool) const
+{
+ NamespaceAliasDefinitionAST *ast = new (pool) NamespaceAliasDefinitionAST;
+ ast->namespace_token = namespace_token;
+ ast->namespace_name = namespace_name;
+ ast->equal_token = equal_token;
+ if (name)
+ ast->name = name->clone(pool);
+ ast->semicolon_token = semicolon_token;
+ return ast;
+}
+
+void NamespaceAliasDefinitionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ }
+}
+
+unsigned NamespaceAliasDefinitionAST::firstToken() const
+{
+ return namespace_token;
+}
+
+unsigned NamespaceAliasDefinitionAST::lastToken() const
+{
+ if (semicolon_token)
+ return semicolon_token + 1;
+ else if (name)
+ return name->lastToken();
+ else if (equal_token)
+ return equal_token + 1;
+ else if (namespace_name)
+ return namespace_name + 1;
+ return namespace_token + 1;
+}
+
+NestedDeclaratorAST *NestedDeclaratorAST::clone(MemoryPool *pool) const
+{
+ NestedDeclaratorAST *ast = new (pool) NestedDeclaratorAST;
+ ast->lparen_token = lparen_token;
+ if (declarator)
+ ast->declarator = declarator->clone(pool);
+ ast->rparen_token = rparen_token;
+ return ast;
+}
+
+void NestedDeclaratorAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declarator, visitor);
+ }
+}
+
+unsigned NestedDeclaratorAST::firstToken() const
+{
+ return lparen_token;
+}
+
+unsigned NestedDeclaratorAST::lastToken() const
+{
+ if (rparen_token)
+ return rparen_token + 1;
+ else if (declarator)
+ return declarator->lastToken();
+ return lparen_token + 1;
+}
+
+NestedExpressionAST *NestedExpressionAST::clone(MemoryPool *pool) const
+{
+ NestedExpressionAST *ast = new (pool) NestedExpressionAST;
+ ast->lparen_token = lparen_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ ast->rparen_token = rparen_token;
+ return ast;
+}
+
+void NestedExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned NestedExpressionAST::firstToken() const
+{
+ return lparen_token;
+}
+
+unsigned NestedExpressionAST::lastToken() const
+{
+ if (rparen_token)
+ return rparen_token + 1;
+ else if (expression)
+ return expression->lastToken();
+ return lparen_token + 1;
+}
+
+NestedNameSpecifierAST *NestedNameSpecifierAST::clone(MemoryPool *pool) const
+{
+ NestedNameSpecifierAST *ast = new (pool) NestedNameSpecifierAST;
+ if (class_or_namespace_name)
+ ast->class_or_namespace_name = class_or_namespace_name->clone(pool);
+ ast->scope_token = scope_token;
+ if (next)
+ ast->next = next->clone(pool);
+ return ast;
+}
+
+void NestedNameSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(class_or_namespace_name, visitor);
+ accept(next, visitor); // ### I'm not 100% sure about this.
+ }
+}
+
+unsigned NestedNameSpecifierAST::firstToken() const
+{
+ return class_or_namespace_name->firstToken();
+}
+
+unsigned NestedNameSpecifierAST::lastToken() const
+{
+ if (scope_token)
+ return scope_token + 1;
+ return class_or_namespace_name->lastToken();
+}
+
+NewDeclaratorAST *NewDeclaratorAST::clone(MemoryPool *pool) const
+{
+ NewDeclaratorAST *ast = new (pool) NewDeclaratorAST;
+ if (ptr_operators)
+ ast->ptr_operators = ptr_operators->clone(pool);
+ if (declarator)
+ ast->declarator = declarator->clone(pool);
+ return ast;
+}
+
+void NewDeclaratorAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (PtrOperatorAST *ptr_op = ptr_operators; ptr_op;
+ ptr_op = static_cast<PtrOperatorAST *>(ptr_op->next)) {
+ accept(ptr_op, visitor);
+ }
+
+ accept(declarator, visitor);
+ }
+}
+
+unsigned NewDeclaratorAST::firstToken() const
+{
+ return ptr_operators->firstToken();
+}
+
+unsigned NewDeclaratorAST::lastToken() const
+{
+ if (declarator)
+ return declarator->lastToken();
+
+ for (PtrOperatorAST *it = ptr_operators; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ return 0;
+}
+
+NewExpressionAST *NewExpressionAST::clone(MemoryPool *pool) const
+{
+ NewExpressionAST *ast = new (pool) NewExpressionAST;
+ ast->scope_token = scope_token;
+ ast->new_token = new_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ if (type_id)
+ ast->type_id = type_id->clone(pool);
+ if (new_type_id)
+ ast->new_type_id = new_type_id->clone(pool);
+ if (new_initializer)
+ ast->new_initializer = new_initializer->clone(pool);
+ return ast;
+}
+
+void NewExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(type_id, visitor);
+ accept(new_type_id, visitor);
+ accept(new_initializer, visitor);
+ }
+}
+
+unsigned NewExpressionAST::firstToken() const
+{
+ if (scope_token)
+ return scope_token;
+ return new_token;
+}
+
+unsigned NewExpressionAST::lastToken() const
+{
+ if (new_initializer)
+ return new_initializer->lastToken();
+ else if (new_type_id)
+ return new_type_id->lastToken();
+ else if (type_id)
+ return type_id->lastToken();
+ else if (expression)
+ return expression->lastToken();
+ else if (new_token)
+ return new_token + 1;
+ else if (scope_token)
+ return scope_token + 1;
+ // ### assert?
+ return 0;
+}
+
+NewInitializerAST *NewInitializerAST::clone(MemoryPool *pool) const
+{
+ NewInitializerAST *ast = new (pool) NewInitializerAST;
+ ast->lparen_token = lparen_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ ast->rparen_token = rparen_token;
+ return ast;
+}
+
+void NewInitializerAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned NewInitializerAST::firstToken() const
+{
+ return lparen_token;
+}
+
+unsigned NewInitializerAST::lastToken() const
+{
+ if (rparen_token)
+ return rparen_token + 1;
+ else if (expression)
+ return expression->lastToken();
+ return lparen_token + 1;
+}
+
+TypeIdAST *TypeIdAST::clone(MemoryPool *pool) const
+{
+ TypeIdAST *ast = new (pool) TypeIdAST;
+ if (type_specifier)
+ ast->type_specifier = type_specifier->clone(pool);
+ if (declarator)
+ ast->declarator = declarator->clone(pool);
+ return ast;
+}
+
+NewTypeIdAST *NewTypeIdAST::clone(MemoryPool *pool) const
+{
+ NewTypeIdAST *ast = new (pool) NewTypeIdAST;
+ if (type_specifier)
+ ast->type_specifier = type_specifier->clone(pool);
+ if (new_initializer)
+ ast->new_initializer = new_initializer->clone(pool);
+ if (new_declarator)
+ ast->new_declarator = new_declarator->clone(pool);
+ return ast;
+}
+
+void NewTypeIdAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = type_specifier; spec; spec = spec->next)
+ accept(spec, visitor);
+ accept(new_initializer, visitor);
+ accept(new_declarator, visitor);
+ }
+}
+
+unsigned NewTypeIdAST::firstToken() const
+{
+ return type_specifier->firstToken();
+}
+
+unsigned NewTypeIdAST::lastToken() const
+{
+ if (new_declarator)
+ return new_declarator->lastToken();
+ else if (new_initializer)
+ return new_initializer->lastToken();
+ for (SpecifierAST *it = type_specifier; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ // ### assert?
+ return 0;
+}
+
+NumericLiteralAST *NumericLiteralAST::clone(MemoryPool *pool) const
+{
+ NumericLiteralAST *ast = new (pool) NumericLiteralAST;
+ ast->token = token;
+ return ast;
+}
+
+void NumericLiteralAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned NumericLiteralAST::firstToken() const
+{
+ return token;
+}
+
+unsigned NumericLiteralAST::lastToken() const
+{
+ return token + 1;
+}
+
+OperatorAST *OperatorAST::clone(MemoryPool *pool) const
+{
+ OperatorAST *ast = new (pool) OperatorAST;
+ ast->op_token = op_token;
+ ast->open_token = open_token;
+ ast->close_token = close_token;
+ return ast;
+}
+
+void OperatorAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned OperatorAST::firstToken() const
+{
+ return op_token;
+}
+
+unsigned OperatorAST::lastToken() const
+{
+ if (close_token)
+ return close_token + 1;
+ else if (open_token)
+ return open_token + 1;
+ return op_token + 1;
+}
+
+OperatorFunctionIdAST *OperatorFunctionIdAST::clone(MemoryPool *pool) const
+{
+ OperatorFunctionIdAST *ast = new (pool) OperatorFunctionIdAST;
+ ast->operator_token = operator_token;
+ if (op)
+ ast->op = op->clone(pool);
+ return ast;
+}
+
+void OperatorFunctionIdAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(op, visitor);
+ }
+}
+
+unsigned OperatorFunctionIdAST::firstToken() const
+{
+ return operator_token;
+}
+
+unsigned OperatorFunctionIdAST::lastToken() const
+{
+ if (op)
+ return op->lastToken();
+ return operator_token + 1;
+}
+
+ParameterDeclarationAST *ParameterDeclarationAST::clone(MemoryPool *pool) const
+{
+ ParameterDeclarationAST *ast = new (pool) ParameterDeclarationAST;
+ if (type_specifier)
+ ast->type_specifier = type_specifier->clone(pool);
+ if (declarator)
+ ast->declarator = declarator->clone(pool);
+ ast->equal_token = equal_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ return ast;
+}
+
+void ParameterDeclarationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = type_specifier; spec; spec = spec->next)
+ accept(spec, visitor);
+ accept(declarator, visitor);
+ accept(expression, visitor);
+ }
+}
+
+unsigned ParameterDeclarationAST::firstToken() const
+{
+ return type_specifier->firstToken();
+}
+
+unsigned ParameterDeclarationAST::lastToken() const
+{
+ if (expression)
+ return expression->lastToken();
+ else if (equal_token)
+ return equal_token + 1;
+ else if (declarator)
+ return declarator->lastToken();
+ for (SpecifierAST *it = type_specifier; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ // ### assert?
+ return 0;
+}
+
+ParameterDeclarationClauseAST *ParameterDeclarationClauseAST::clone(MemoryPool *pool) const
+{
+ ParameterDeclarationClauseAST *ast = new (pool) ParameterDeclarationClauseAST;
+ if (parameter_declarations)
+ ast->parameter_declarations = parameter_declarations;
+ ast->dot_dot_dot_token = dot_dot_dot_token;
+ return ast;
+}
+
+void ParameterDeclarationClauseAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (DeclarationAST *param = parameter_declarations; param;
+ param = param->next)
+ accept(param, visitor);
+ }
+}
+
+unsigned ParameterDeclarationClauseAST::firstToken() const
+{
+ if (parameter_declarations)
+ return parameter_declarations->firstToken();
+ return dot_dot_dot_token;
+}
+
+unsigned ParameterDeclarationClauseAST::lastToken() const
+{
+ if (dot_dot_dot_token)
+ return dot_dot_dot_token + 1;
+ return parameter_declarations->lastToken();
+}
+
+PointerAST *PointerAST::clone(MemoryPool *pool) const
+{
+ PointerAST *ast = new (pool) PointerAST;
+ ast->star_token = star_token;
+ if (cv_qualifier_seq)
+ ast->cv_qualifier_seq = cv_qualifier_seq->clone(pool);
+ return ast;
+}
+
+void PointerAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = cv_qualifier_seq; spec;
+ spec = spec->next)
+ accept(spec, visitor);
+ }
+}
+
+unsigned PointerAST::firstToken() const
+{
+ return star_token;
+}
+
+unsigned PointerAST::lastToken() const
+{
+ for (SpecifierAST *it = cv_qualifier_seq; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ return star_token + 1;
+}
+
+PointerToMemberAST *PointerToMemberAST::clone(MemoryPool *pool) const
+{
+ PointerToMemberAST *ast = new (pool) PointerToMemberAST;
+ ast->global_scope_token = global_scope_token;
+ if (nested_name_specifier)
+ ast->nested_name_specifier = nested_name_specifier->clone(pool);
+ ast->star_token = star_token;
+ if (cv_qualifier_seq)
+ ast->cv_qualifier_seq = cv_qualifier_seq->clone(pool);
+ return ast;
+}
+
+void PointerToMemberAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(nested_name_specifier, visitor);
+ for (SpecifierAST *spec = cv_qualifier_seq; spec;
+ spec = spec->next)
+ accept(spec, visitor);
+ }
+}
+
+unsigned PointerToMemberAST::firstToken() const
+{
+ if (global_scope_token)
+ return global_scope_token;
+ else if (nested_name_specifier)
+ return nested_name_specifier->firstToken();
+ return star_token;
+}
+
+unsigned PointerToMemberAST::lastToken() const
+{
+ for (SpecifierAST *it = cv_qualifier_seq; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ if (star_token)
+ return star_token + 1;
+
+ for (NestedNameSpecifierAST *it = nested_name_specifier; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ if (global_scope_token)
+ return global_scope_token + 1;
+
+ return 0;
+}
+
+PostIncrDecrAST *PostIncrDecrAST::clone(MemoryPool *pool) const
+{
+ PostIncrDecrAST *ast = new (pool) PostIncrDecrAST;
+ ast->incr_decr_token = incr_decr_token;
+ return ast;
+}
+
+void PostIncrDecrAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned PostIncrDecrAST::firstToken() const
+{
+ return incr_decr_token;
+}
+
+unsigned PostIncrDecrAST::lastToken() const
+{
+ return incr_decr_token + 1;
+}
+
+PostfixExpressionAST *PostfixExpressionAST::clone(MemoryPool *pool) const
+{
+ PostfixExpressionAST *ast = new (pool) PostfixExpressionAST;
+ if (base_expression)
+ ast->base_expression = base_expression->clone(pool);
+ if (postfix_expressions)
+ ast->postfix_expressions = postfix_expressions->clone(pool);
+ return ast;
+}
+
+void PostfixExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base_expression, visitor);
+ for (PostfixAST *fx = postfix_expressions; fx; fx = fx->next)
+ accept(fx, visitor);
+ }
+}
+
+unsigned PostfixExpressionAST::firstToken() const
+{
+ return base_expression->firstToken();
+}
+
+unsigned PostfixExpressionAST::lastToken() const
+{
+ for (PostfixAST *it = postfix_expressions; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ return base_expression->lastToken();
+}
+
+QualifiedNameAST *QualifiedNameAST::clone(MemoryPool *pool) const
+{
+ QualifiedNameAST *ast = new (pool) QualifiedNameAST;
+ ast->global_scope_token = global_scope_token;
+ if (nested_name_specifier)
+ ast->nested_name_specifier = nested_name_specifier->clone(pool);
+ if (unqualified_name)
+ ast->unqualified_name = unqualified_name->clone(pool);
+ return ast;
+}
+
+void QualifiedNameAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(nested_name_specifier, visitor);
+ accept(unqualified_name, visitor);
+ }
+}
+
+unsigned QualifiedNameAST::firstToken() const
+{
+ if (global_scope_token)
+ return global_scope_token;
+ else if (nested_name_specifier)
+ return nested_name_specifier->firstToken();
+ return unqualified_name->firstToken();
+}
+
+unsigned QualifiedNameAST::lastToken() const
+{
+ if (unqualified_name)
+ return unqualified_name->lastToken();
+
+ for (NestedNameSpecifierAST *it = nested_name_specifier; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ if (global_scope_token)
+ return global_scope_token + 1;
+
+ return 0;
+}
+
+ReferenceAST *ReferenceAST::clone(MemoryPool *pool) const
+{
+ ReferenceAST *ast = new (pool) ReferenceAST;
+ ast->amp_token = amp_token;
+ return ast;
+}
+
+void ReferenceAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned ReferenceAST::firstToken() const
+{
+ return amp_token;
+}
+
+unsigned ReferenceAST::lastToken() const
+{
+ return amp_token + 1;
+}
+
+ReturnStatementAST *ReturnStatementAST::clone(MemoryPool *pool) const
+{
+ ReturnStatementAST *ast = new (pool) ReturnStatementAST;
+ ast->return_token = return_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ ast->semicolon_token = semicolon_token;
+ return ast;
+}
+
+void ReturnStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned ReturnStatementAST::firstToken() const
+{
+ return return_token;
+}
+
+unsigned ReturnStatementAST::lastToken() const
+{
+ if (semicolon_token)
+ return semicolon_token + 1;
+ else if (expression)
+ return expression->lastToken();
+ return return_token + 1;
+}
+
+SimpleDeclarationAST *SimpleDeclarationAST::clone(MemoryPool *pool) const
+{
+ SimpleDeclarationAST *ast = new (pool) SimpleDeclarationAST;
+ if (decl_specifier_seq)
+ ast->decl_specifier_seq = decl_specifier_seq->clone(pool);
+ if (declarators)
+ ast->declarators = declarators->clone(pool);
+ ast->semicolon_token = semicolon_token;
+ return ast;
+}
+
+void SimpleDeclarationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = decl_specifier_seq; spec;
+ spec = spec->next)
+ accept(spec, visitor);
+ accept(declarators, visitor);
+ }
+}
+
+unsigned SimpleDeclarationAST::firstToken() const
+{
+ if (decl_specifier_seq)
+ return decl_specifier_seq->firstToken();
+ else if (declarators)
+ return declarators->firstToken();
+ return semicolon_token;
+}
+
+unsigned SimpleDeclarationAST::lastToken() const
+{
+ if (semicolon_token)
+ return semicolon_token + 1;
+
+ for (DeclaratorListAST *it = declarators; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ for (SpecifierAST *it = decl_specifier_seq; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ return 0;
+}
+
+SimpleNameAST *SimpleNameAST::clone(MemoryPool *pool) const
+{
+ SimpleNameAST *ast = new (pool) SimpleNameAST;
+ ast->identifier_token = identifier_token;
+ return ast;
+}
+
+void SimpleNameAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned SimpleNameAST::firstToken() const
+{
+ return identifier_token;
+}
+
+unsigned SimpleNameAST::lastToken() const
+{
+ return identifier_token + 1;
+}
+
+void SimpleSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+SimpleSpecifierAST *SimpleSpecifierAST::clone(MemoryPool *pool) const
+{
+ SimpleSpecifierAST *ast = new (pool) SimpleSpecifierAST;
+ ast->specifier_token = specifier_token;
+ if (next)
+ ast->next = next->clone(pool);
+ return ast;
+}
+
+unsigned SimpleSpecifierAST::firstToken() const
+{
+ return specifier_token;
+}
+
+unsigned SimpleSpecifierAST::lastToken() const
+{
+ return specifier_token + 1;
+}
+
+TypeofSpecifierAST *TypeofSpecifierAST::clone(MemoryPool *pool) const
+{
+ TypeofSpecifierAST *ast = new (pool) TypeofSpecifierAST;
+ ast->typeof_token = typeof_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ if (next)
+ ast->next = next->clone(pool);
+ return ast;
+}
+
+void TypeofSpecifierAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned TypeofSpecifierAST::firstToken() const
+{
+ return typeof_token;
+}
+
+unsigned TypeofSpecifierAST::lastToken() const
+{
+ if (expression)
+ return expression->lastToken();
+ return typeof_token + 1;
+}
+
+SizeofExpressionAST *SizeofExpressionAST::clone(MemoryPool *pool) const
+{
+ SizeofExpressionAST *ast = new (pool) SizeofExpressionAST;
+ ast->sizeof_token = sizeof_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ return ast;
+}
+
+void SizeofExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned SizeofExpressionAST::firstToken() const
+{
+ return sizeof_token;
+}
+
+unsigned SizeofExpressionAST::lastToken() const
+{
+ if (expression)
+ return expression->lastToken();
+ return sizeof_token + 1;
+}
+
+StringLiteralAST *StringLiteralAST::clone(MemoryPool *pool) const
+{
+ StringLiteralAST *ast = new (pool) StringLiteralAST;
+ ast->token = token;
+ if (next)
+ ast->next = next->clone(pool);
+ return ast;
+}
+
+void StringLiteralAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(next, visitor);
+ }
+}
+
+unsigned StringLiteralAST::firstToken() const
+{
+ return token;
+}
+
+unsigned StringLiteralAST::lastToken() const
+{
+ if (next)
+ return next->lastToken();
+ return token + 1;
+}
+
+SwitchStatementAST *SwitchStatementAST::clone(MemoryPool *pool) const
+{
+ SwitchStatementAST *ast = new (pool) SwitchStatementAST;
+ ast->switch_token = switch_token;
+ ast->lparen_token = lparen_token;
+ if (condition)
+ ast->condition = condition->clone(pool);
+ ast->rparen_token = rparen_token;
+ if (statement)
+ ast->statement = statement->clone(pool);
+ return ast;
+}
+
+void SwitchStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(condition, visitor);
+ accept(statement, visitor);
+ }
+}
+
+unsigned SwitchStatementAST::firstToken() const
+{
+ return switch_token;
+}
+
+unsigned SwitchStatementAST::lastToken() const
+{
+ if (statement)
+ return statement->lastToken();
+ else if (rparen_token)
+ return rparen_token + 1;
+ else if (condition)
+ return condition->lastToken();
+ else if (lparen_token)
+ return lparen_token + 1;
+ return switch_token + 1;
+}
+
+TemplateArgumentListAST *TemplateArgumentListAST::clone(MemoryPool *pool) const
+{
+ TemplateArgumentListAST *ast = new (pool) TemplateArgumentListAST;
+ if (template_argument)
+ ast->template_argument = template_argument->clone(pool);
+ if (next)
+ ast->next = next->clone(pool);
+ return ast;
+}
+
+void TemplateArgumentListAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(template_argument, visitor);
+ accept(next, visitor);
+ }
+}
+
+unsigned TemplateArgumentListAST::firstToken() const
+{
+ return template_argument->firstToken();
+}
+
+unsigned TemplateArgumentListAST::lastToken() const
+{
+ for (const TemplateArgumentListAST *it = this; it; it = it->next) {
+ if (! it->next && it->template_argument)
+ return it->template_argument->lastToken();
+ }
+ return 0;
+}
+
+TemplateDeclarationAST *TemplateDeclarationAST::clone(MemoryPool *pool) const
+{
+ TemplateDeclarationAST *ast = new (pool) TemplateDeclarationAST;
+ ast->export_token = export_token;
+ ast->template_token = template_token;
+ ast->less_token = less_token;
+ if (template_parameters)
+ ast->template_parameters = template_parameters->clone(pool);
+ ast->greater_token = greater_token;
+ if (declaration)
+ ast->declaration = declaration->clone(pool);
+ return ast;
+}
+
+void TemplateDeclarationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (DeclarationAST *param = template_parameters; param;
+ param = param->next)
+ accept(param, visitor);
+ accept(declaration, visitor);
+ }
+}
+
+unsigned TemplateDeclarationAST::firstToken() const
+{
+ if (export_token)
+ return export_token;
+ return template_token;
+}
+
+unsigned TemplateDeclarationAST::lastToken() const
+{
+ if (declaration)
+ return declaration->lastToken();
+ else if (greater_token)
+ return greater_token + 1;
+
+ for (DeclarationAST *it = template_parameters; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ if (less_token)
+ return less_token + 1;
+ else if (template_token)
+ return template_token + 1;
+ else if (export_token)
+ return export_token + 1;
+
+ return 0;
+}
+
+TemplateIdAST *TemplateIdAST::clone(MemoryPool *pool) const
+{
+ TemplateIdAST *ast = new (pool) TemplateIdAST;
+ ast->identifier_token = identifier_token;
+ ast->less_token = less_token;
+ if (template_arguments)
+ ast->template_arguments = template_arguments->clone(pool);
+ ast->greater_token = greater_token;
+ return ast;
+}
+
+void TemplateIdAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (TemplateArgumentListAST *it = template_arguments; it; it = it->next) {
+ accept(it, visitor);
+ }
+ }
+}
+
+unsigned TemplateIdAST::firstToken() const
+{
+ return identifier_token;
+}
+
+unsigned TemplateIdAST::lastToken() const
+{
+ if (greater_token)
+ return greater_token + 1;
+
+ for (TemplateArgumentListAST *it = template_arguments; it; it = it->next) {
+ if (! it->next && it->template_argument)
+ return it->template_argument->lastToken();
+ }
+
+ if (less_token)
+ return less_token + 1;
+
+ return identifier_token + 1;
+}
+
+TemplateTypeParameterAST *TemplateTypeParameterAST::clone(MemoryPool *pool) const
+{
+ TemplateTypeParameterAST *ast = new (pool) TemplateTypeParameterAST;
+ ast->template_token = template_token;
+ ast->less_token = less_token;
+ if (template_parameters)
+ ast->template_parameters = template_parameters->clone(pool);
+ ast->greater_token = greater_token;
+ ast->class_token = class_token;
+ if (name)
+ ast->name = name->clone(pool);
+ ast->equal_token = equal_token;
+ if (type_id)
+ ast->type_id = type_id->clone(pool);
+ return ast;
+}
+
+void TemplateTypeParameterAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned TemplateTypeParameterAST::firstToken() const
+{
+ return template_token;
+}
+
+unsigned TemplateTypeParameterAST::lastToken() const
+{
+ if (type_id)
+ return type_id->lastToken();
+ else if (equal_token)
+ return equal_token + 1;
+ else if (name)
+ return name->lastToken();
+ else if (class_token)
+ return class_token + 1;
+ else if (greater_token)
+ return greater_token + 1;
+
+ for (DeclarationAST *it = template_parameters; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ if (less_token)
+ return less_token + 1;
+
+ return template_token + 1;
+}
+
+ThisExpressionAST *ThisExpressionAST::clone(MemoryPool *pool) const
+{
+ ThisExpressionAST *ast = new (pool) ThisExpressionAST;
+ ast->this_token = this_token;
+ return ast;
+}
+
+void ThisExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned ThisExpressionAST::firstToken() const
+{
+ return this_token;
+}
+
+unsigned ThisExpressionAST::lastToken() const
+{
+ return this_token + 1;
+}
+
+ThrowExpressionAST *ThrowExpressionAST::clone(MemoryPool *pool) const
+{
+ ThrowExpressionAST *ast = new (pool) ThrowExpressionAST;
+ ast->throw_token = throw_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ return ast;
+}
+
+void ThrowExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned ThrowExpressionAST::firstToken() const
+{
+ return throw_token;
+}
+
+unsigned ThrowExpressionAST::lastToken() const
+{
+ if (expression)
+ return expression->lastToken();
+ return throw_token + 1;
+}
+
+TranslationUnitAST *TranslationUnitAST::clone(MemoryPool *pool) const
+{
+ TranslationUnitAST *ast = new (pool) TranslationUnitAST;
+ if (declarations)
+ ast->declarations = declarations->clone(pool);
+ return ast;
+}
+
+void TranslationUnitAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (DeclarationAST *decl = declarations; decl;
+ decl = decl->next)
+ accept(decl, visitor);
+ }
+}
+
+unsigned TranslationUnitAST::firstToken() const
+{
+ return declarations->firstToken();
+}
+
+unsigned TranslationUnitAST::lastToken() const
+{
+ for (DeclarationAST *it = declarations; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+ return 0;
+}
+
+TryBlockStatementAST *TryBlockStatementAST::clone(MemoryPool *pool) const
+{
+ TryBlockStatementAST *ast = new (pool) TryBlockStatementAST;
+ ast->try_token = try_token;
+ if (statement)
+ ast->statement = statement->clone(pool);
+ if (catch_clause_seq)
+ ast->catch_clause_seq = catch_clause_seq->clone(pool);
+ return ast;
+}
+
+void TryBlockStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ accept(catch_clause_seq, visitor);
+ }
+}
+
+unsigned TryBlockStatementAST::firstToken() const
+{
+ return try_token;
+}
+
+unsigned TryBlockStatementAST::lastToken() const
+{
+ for (CatchClauseAST *it = catch_clause_seq; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ if (statement)
+ return statement->lastToken();
+
+ return try_token + 1;
+}
+
+TypeConstructorCallAST *TypeConstructorCallAST::clone(MemoryPool *pool) const
+{
+ TypeConstructorCallAST *ast = new (pool) TypeConstructorCallAST;
+ if (type_specifier)
+ ast->type_specifier = type_specifier->clone(pool);
+ ast->lparen_token = lparen_token;
+ if (expression_list)
+ ast->expression_list = expression_list;
+ ast->rparen_token = rparen_token;
+ return ast;
+}
+
+void TypeConstructorCallAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = type_specifier; spec; spec = spec->next)
+ accept(spec, visitor);
+ for (ExpressionListAST *expr = expression_list;expr;
+ expr = expr->next)
+ accept(expr->expression, visitor);
+ }
+}
+
+unsigned TypeConstructorCallAST::firstToken() const
+{
+ return type_specifier->firstToken();
+}
+
+unsigned TypeConstructorCallAST::lastToken() const
+{
+ if (rparen_token)
+ return rparen_token + 1;
+
+ for (ExpressionListAST *it = expression_list; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ if (lparen_token)
+ return lparen_token + 1;
+
+
+ for (SpecifierAST *it = type_specifier; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ return 0;
+}
+
+void TypeIdAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *spec = type_specifier; spec; spec = spec->next)
+ accept(spec, visitor);
+ accept(declarator, visitor);
+ }
+}
+
+unsigned TypeIdAST::firstToken() const
+{
+ return type_specifier->firstToken();
+}
+
+unsigned TypeIdAST::lastToken() const
+{
+ if (declarator)
+ return declarator->lastToken();
+
+ for (SpecifierAST *it = type_specifier; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ return 0;
+}
+
+TypeidExpressionAST *TypeidExpressionAST::clone(MemoryPool *pool) const
+{
+ TypeidExpressionAST *ast = new (pool) TypeidExpressionAST;
+ ast->typeid_token = typeid_token;
+ ast->lparen_token = lparen_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ ast->rparen_token = rparen_token;
+ return ast;
+}
+
+void TypeidExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned TypeidExpressionAST::firstToken() const
+{
+ return typeid_token;
+}
+
+unsigned TypeidExpressionAST::lastToken() const
+{
+ if (rparen_token)
+ return rparen_token + 1;
+ else if (expression)
+ return expression->lastToken();
+ else if (lparen_token)
+ return lparen_token + 1;
+
+ return typeid_token + 1;
+}
+
+TypenameCallExpressionAST *TypenameCallExpressionAST::clone(MemoryPool *pool) const
+{
+ TypenameCallExpressionAST *ast = new (pool) TypenameCallExpressionAST;
+ ast->typename_token = typename_token;
+ if (name)
+ ast->name = name->clone(pool);
+ ast->lparen_token = lparen_token;
+ if (expression_list)
+ ast->expression_list = expression_list;
+ ast->rparen_token = rparen_token;
+ return ast;
+}
+
+void TypenameCallExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ for (ExpressionListAST *expr = expression_list;expr;
+ expr = expr->next)
+ accept(expr->expression, visitor);
+ }
+}
+
+unsigned TypenameCallExpressionAST::firstToken() const
+{
+ return typename_token;
+}
+
+unsigned TypenameCallExpressionAST::lastToken() const
+{
+ if (rparen_token)
+ return rparen_token + 1;
+
+ for (ExpressionListAST *it = expression_list; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ if (lparen_token)
+ return lparen_token + 1;
+ else if (name)
+ return name->lastToken();
+
+ return typename_token + 1;
+}
+
+TypenameTypeParameterAST *TypenameTypeParameterAST::clone(MemoryPool *pool) const
+{
+ TypenameTypeParameterAST *ast = new (pool) TypenameTypeParameterAST;
+ ast->classkey_token = classkey_token;
+ if (name)
+ ast->name = name->clone(pool);
+ ast->equal_token = equal_token;
+ if (type_id)
+ ast->type_id = type_id->clone(pool);
+ return ast;
+}
+
+void TypenameTypeParameterAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ accept(type_id, visitor);
+ }
+}
+
+unsigned TypenameTypeParameterAST::firstToken() const
+{
+ return classkey_token;
+}
+
+unsigned TypenameTypeParameterAST::lastToken() const
+{
+ if (type_id)
+ return type_id->lastToken();
+ else if (equal_token)
+ return equal_token + 1;
+ else if (name)
+ return name->lastToken();
+ return classkey_token + 1;
+}
+
+UnaryExpressionAST *UnaryExpressionAST::clone(MemoryPool *pool) const
+{
+ UnaryExpressionAST *ast = new (pool) UnaryExpressionAST;
+ ast->unary_op_token = unary_op_token;
+ if (expression)
+ ast->expression = expression->clone(pool);
+ return ast;
+}
+
+void UnaryExpressionAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+}
+
+unsigned UnaryExpressionAST::firstToken() const
+{
+ return unary_op_token;
+}
+
+unsigned UnaryExpressionAST::lastToken() const
+{
+ if (expression)
+ return expression->lastToken();
+ return unary_op_token + 1;
+}
+
+UsingAST *UsingAST::clone(MemoryPool *pool) const
+{
+ UsingAST *ast = new (pool) UsingAST;
+ ast->using_token = using_token;
+ ast->typename_token = typename_token;
+ if (name)
+ ast->name = name->clone(pool);
+ ast->semicolon_token = semicolon_token;
+ return ast;
+}
+
+void UsingAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ }
+}
+
+unsigned UsingAST::firstToken() const
+{
+ return using_token;
+}
+
+unsigned UsingAST::lastToken() const
+{
+ if (semicolon_token)
+ return semicolon_token + 1;
+ else if (name)
+ return name->lastToken();
+ else if (typename_token)
+ return typename_token + 1;
+ return using_token + 1;
+}
+
+UsingDirectiveAST *UsingDirectiveAST::clone(MemoryPool *pool) const
+{
+ UsingDirectiveAST *ast = new (pool) UsingDirectiveAST;
+ ast->using_token = using_token;
+ ast->namespace_token = namespace_token;
+ if (name)
+ ast->name = name->clone(pool);
+ ast->semicolon_token = semicolon_token;
+ return ast;
+}
+
+void UsingDirectiveAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ }
+}
+
+unsigned UsingDirectiveAST::firstToken() const
+{
+ return using_token;
+}
+
+unsigned UsingDirectiveAST::lastToken() const
+{
+ if (semicolon_token)
+ return semicolon_token + 1;
+ else if (name)
+ return name->lastToken();
+ else if (namespace_token)
+ return namespace_token + 1;
+ return using_token + 1;
+}
+
+WhileStatementAST *WhileStatementAST::clone(MemoryPool *pool) const
+{
+ WhileStatementAST *ast = new (pool) WhileStatementAST;
+ ast->while_token = while_token;
+ ast->lparen_token = lparen_token;
+ if (condition)
+ ast->condition = condition->clone(pool);
+ ast->rparen_token = rparen_token;
+ if (statement)
+ ast->statement = statement->clone(pool);
+ return ast;
+}
+
+void WhileStatementAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(condition, visitor);
+ accept(statement, visitor);
+ }
+}
+
+unsigned WhileStatementAST::firstToken() const
+{
+ return while_token;
+}
+
+unsigned WhileStatementAST::lastToken() const
+{
+ if (statement)
+ return statement->lastToken();
+ else if (rparen_token)
+ return rparen_token + 1;
+ else if (condition)
+ return condition->lastToken();
+ else if (lparen_token)
+ return lparen_token + 1;
+ return while_token + 1;
+}
+
+// ObjC++
+unsigned IdentifierListAST::firstToken() const
+{
+ return identifier_token;
+}
+
+unsigned IdentifierListAST::lastToken() const
+{
+ for (const IdentifierListAST *it = this; it; it = it->next) {
+ if (! it->next && it->identifier_token) {
+ return it->identifier_token + 1;
+ }
+ }
+ // ### assert?
+ return 0;
+}
+
+IdentifierListAST *IdentifierListAST::clone(MemoryPool *pool) const
+{
+ IdentifierListAST *ast = new (pool) IdentifierListAST;
+ ast->identifier_token = identifier_token;
+ if (next)
+ ast->next = next->clone(pool);
+ return ast;
+}
+
+void IdentifierListAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+}
+
+unsigned ObjCClassDeclarationAST::firstToken() const
+{
+ if (attributes)
+ return attributes->firstToken();
+ return class_token;
+}
+
+unsigned ObjCClassDeclarationAST::lastToken() const
+{
+ if (semicolon_token)
+ return semicolon_token + 1;
+
+ for (IdentifierListAST *it = identifier_list; it; it = it->next) {
+ if (! it->next && it->identifier_token)
+ return it->identifier_token + 1;
+ }
+
+ for (SpecifierAST *it = attributes; it; it = it->next) {
+ if (! it->next)
+ return it->lastToken();
+ }
+
+ return class_token + 1;
+}
+
+ObjCClassDeclarationAST *ObjCClassDeclarationAST::clone(MemoryPool *pool) const
+{
+ ObjCClassDeclarationAST *ast = new (pool) ObjCClassDeclarationAST;
+ if (attributes)
+ ast->attributes = attributes->clone(pool);
+ ast->class_token = class_token;
+ if (identifier_list)
+ ast->identifier_list = identifier_list->clone(pool);
+ ast->semicolon_token = semicolon_token;
+ return ast;
+}
+
+void ObjCClassDeclarationAST::accept0(ASTVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SpecifierAST *it = attributes; it; it = it->next) {
+ accept(it, visitor);
+ }
+ }
+}
+
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/AST.h b/src/shared/cplusplus/AST.h
new file mode 100644
index 0000000000..d7f346c5b0
--- /dev/null
+++ b/src/shared/cplusplus/AST.h
@@ -0,0 +1,1989 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_AST_H
+#define CPLUSPLUS_AST_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "ASTfwd.h"
+#include "MemoryPool.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT AST: public Managed
+{
+ AST(const AST &other);
+ void operator =(const AST &other);
+
+public:
+ AST();
+ virtual ~AST();
+
+ void accept(ASTVisitor *visitor);
+
+ static void accept(AST *ast, ASTVisitor *visitor)
+ { if (ast) ast->accept(visitor); }
+
+ virtual unsigned firstToken() const = 0;
+ virtual unsigned lastToken() const = 0;
+
+ AccessDeclarationAST *asAccessDeclaration();
+ ArrayAccessAST *asArrayAccess();
+ ArrayDeclaratorAST *asArrayDeclarator();
+ ArrayInitializerAST *asArrayInitializer();
+ AsmDefinitionAST *asAsmDefinition();
+ AttributeAST *asAttribute();
+ AttributeSpecifierAST *asAttributeSpecifier();
+ BaseSpecifierAST *asBaseSpecifier();
+ QtMethodAST *asQtMethod();
+ BinaryExpressionAST *asBinaryExpression();
+ BoolLiteralAST *asBoolLiteral();
+ BreakStatementAST *asBreakStatement();
+ CallAST *asCall();
+ CaseStatementAST *asCaseStatement();
+ CastExpressionAST *asCastExpression();
+ CatchClauseAST *asCatchClause();
+ ClassSpecifierAST *asClassSpecifier();
+ CompoundLiteralAST *asCompoundLiteral();
+ CompoundStatementAST *asCompoundStatement();
+ ConditionAST *asCondition();
+ ConditionalExpressionAST *asConditionalExpression();
+ ContinueStatementAST *asContinueStatement();
+ ConversionFunctionIdAST *asConversionFunctionId();
+ CoreDeclaratorAST *asCoreDeclarator();
+ CppCastExpressionAST *asCppCastExpression();
+ CtorInitializerAST *asCtorInitializer();
+ DeclarationAST *asDeclaration();
+ DeclarationStatementAST *asDeclarationStatement();
+ DeclaratorAST *asDeclarator();
+ DeclaratorIdAST *asDeclaratorId();
+ DeclaratorListAST *asDeclaratorList();
+ DeleteExpressionAST *asDeleteExpression();
+ DestructorNameAST *asDestructorName();
+ DoStatementAST *asDoStatement();
+ ElaboratedTypeSpecifierAST *asElaboratedTypeSpecifier();
+ EmptyDeclarationAST *asEmptyDeclaration();
+ EnumSpecifierAST *asEnumSpecifier();
+ EnumeratorAST *asEnumerator();
+ ExceptionDeclarationAST *asExceptionDeclaration();
+ ExceptionSpecificationAST *asExceptionSpecification();
+ ExpressionAST *asExpression();
+ ExpressionListAST *asExpressionList();
+ ExpressionOrDeclarationStatementAST *asExpressionOrDeclarationStatement();
+ ExpressionStatementAST *asExpressionStatement();
+ ForStatementAST *asForStatement();
+ FunctionDeclaratorAST *asFunctionDeclarator();
+ FunctionDefinitionAST *asFunctionDefinition();
+ GotoStatementAST *asGotoStatement();
+ IfStatementAST *asIfStatement();
+ LabeledStatementAST *asLabeledStatement();
+ LinkageBodyAST *asLinkageBody();
+ LinkageSpecificationAST *asLinkageSpecification();
+ MemInitializerAST *asMemInitializer();
+ MemberAccessAST *asMemberAccess();
+ NameAST *asName();
+ NamedTypeSpecifierAST *asNamedTypeSpecifier();
+ NamespaceAST *asNamespace();
+ NamespaceAliasDefinitionAST *asNamespaceAliasDefinition();
+ NestedDeclaratorAST *asNestedDeclarator();
+ NestedExpressionAST *asNestedExpression();
+ NestedNameSpecifierAST *asNestedNameSpecifier();
+ NewDeclaratorAST *asNewDeclarator();
+ NewExpressionAST *asNewExpression();
+ NewInitializerAST *asNewInitializer();
+ NewTypeIdAST *asNewTypeId();
+ NumericLiteralAST *asNumericLiteral();
+ OperatorAST *asOperator();
+ OperatorFunctionIdAST *asOperatorFunctionId();
+ ParameterDeclarationAST *asParameterDeclaration();
+ ParameterDeclarationClauseAST *asParameterDeclarationClause();
+ PointerAST *asPointer();
+ PointerToMemberAST *asPointerToMember();
+ PostIncrDecrAST *asPostIncrDecr();
+ PostfixAST *asPostfix();
+ PostfixDeclaratorAST *asPostfixDeclarator();
+ PostfixExpressionAST *asPostfixExpression();
+ PtrOperatorAST *asPtrOperator();
+ QualifiedNameAST *asQualifiedName();
+ ReferenceAST *asReference();
+ ReturnStatementAST *asReturnStatement();
+ SimpleDeclarationAST *asSimpleDeclaration();
+ SimpleNameAST *asSimpleName();
+ SimpleSpecifierAST *asSimpleSpecifier();
+ SizeofExpressionAST *asSizeofExpression();
+ SpecifierAST *asSpecifier();
+ StatementAST *asStatement();
+ StringLiteralAST *asStringLiteral();
+ SwitchStatementAST *asSwitchStatement();
+ TemplateArgumentListAST *asTemplateArgumentList();
+ TemplateDeclarationAST *asTemplateDeclaration();
+ TemplateIdAST *asTemplateId();
+ TemplateTypeParameterAST *asTemplateTypeParameter();
+ ThisExpressionAST *asThisExpression();
+ ThrowExpressionAST *asThrowExpression();
+ TranslationUnitAST *asTranslationUnit();
+ TryBlockStatementAST *asTryBlockStatement();
+ TypeConstructorCallAST *asTypeConstructorCall();
+ TypeIdAST *asTypeId();
+ TypeidExpressionAST *asTypeidExpression();
+ TypenameCallExpressionAST *asTypenameCallExpression();
+ TypenameTypeParameterAST *asTypenameTypeParameter();
+ TypeofSpecifierAST *asTypeofSpecifier();
+ UnaryExpressionAST *asUnaryExpression();
+ UsingAST *asUsing();
+ UsingDirectiveAST *asUsingDirective();
+ WhileStatementAST *asWhileStatement();
+
+ virtual AST *clone(MemoryPool *pool) const = 0;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor) = 0;
+};
+
+class CPLUSPLUS_EXPORT SpecifierAST: public AST
+{
+public:
+ SpecifierAST *next;
+
+public:
+ virtual SpecifierAST *clone(MemoryPool *pool) const = 0;
+};
+
+class CPLUSPLUS_EXPORT SimpleSpecifierAST: public SpecifierAST
+{
+public:
+ unsigned specifier_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual SimpleSpecifierAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT AttributeSpecifierAST: public SpecifierAST
+{
+public:
+ unsigned attribute_token;
+ unsigned first_lparen_token;
+ unsigned second_lparen_token;
+ AttributeAST *attributes;
+ unsigned first_rparen_token;
+ unsigned second_rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual AttributeSpecifierAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT AttributeAST: public AST
+{
+public:
+ unsigned identifier_token;
+ unsigned lparen_token;
+ unsigned tag_token;
+ ExpressionListAST *expression_list;
+ unsigned rparen_token;
+ AttributeAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual AttributeAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TypeofSpecifierAST: public SpecifierAST
+{
+public:
+ unsigned typeof_token;
+ ExpressionAST *expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual TypeofSpecifierAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT StatementAST: public AST
+{
+public:
+ StatementAST *next;
+
+public:
+ virtual StatementAST *clone(MemoryPool *pool) const = 0;
+};
+
+class CPLUSPLUS_EXPORT ExpressionAST: public AST
+{
+public:
+ virtual ExpressionAST *clone(MemoryPool *pool) const = 0;
+};
+
+class CPLUSPLUS_EXPORT DeclarationAST: public AST
+{
+public:
+ DeclarationAST *next;
+
+public:
+ virtual DeclarationAST *clone(MemoryPool *pool) const = 0;
+};
+
+class CPLUSPLUS_EXPORT CoreDeclaratorAST: public AST
+{
+public:
+ virtual CoreDeclaratorAST *clone(MemoryPool *pool) const = 0;
+};
+
+class CPLUSPLUS_EXPORT PostfixDeclaratorAST: public AST
+{
+public:
+ PostfixDeclaratorAST *next;
+
+public:
+ virtual PostfixDeclaratorAST *clone(MemoryPool *pool) const = 0;
+};
+
+class CPLUSPLUS_EXPORT DeclaratorAST: public AST
+{
+public:
+ PtrOperatorAST *ptr_operators;
+ CoreDeclaratorAST *core_declarator;
+ PostfixDeclaratorAST *postfix_declarators;
+ SpecifierAST *attributes;
+ ExpressionAST *initializer;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual DeclaratorAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ExpressionListAST: public ExpressionAST
+{
+public:
+ ExpressionAST *expression;
+ ExpressionListAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ExpressionListAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT SimpleDeclarationAST: public DeclarationAST
+{
+public:
+ SpecifierAST *decl_specifier_seq;
+ DeclaratorListAST *declarators;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual SimpleDeclarationAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT EmptyDeclarationAST: public DeclarationAST
+{
+public:
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual EmptyDeclarationAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT AccessDeclarationAST: public DeclarationAST
+{
+public:
+ unsigned access_specifier_token;
+ unsigned slots_token;
+ unsigned colon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual AccessDeclarationAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT AsmDefinitionAST: public DeclarationAST
+{
+public:
+ unsigned asm_token;
+ SpecifierAST *cv_qualifier_seq;
+ unsigned lparen_token;
+ unsigned rparen_token;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual AsmDefinitionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT BaseSpecifierAST: public AST
+{
+public:
+ unsigned token_virtual;
+ unsigned token_access_specifier;
+ NameAST *name;
+ BaseSpecifierAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual BaseSpecifierAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT CompoundLiteralAST: public ExpressionAST
+{
+public:
+ unsigned lparen_token;
+ ExpressionAST *type_id;
+ unsigned rparen_token;
+ ExpressionAST *initializer;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual CompoundLiteralAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT QtMethodAST: public ExpressionAST
+{
+public:
+ unsigned method_token;
+ unsigned lparen_token;
+ DeclaratorAST *declarator;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual QtMethodAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT BinaryExpressionAST: public ExpressionAST
+{
+public:
+ ExpressionAST *left_expression;
+ unsigned binary_op_token;
+ ExpressionAST *right_expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual BinaryExpressionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT CastExpressionAST: public ExpressionAST
+{
+public:
+ unsigned lparen_token;
+ ExpressionAST *type_id;
+ unsigned rparen_token;
+ ExpressionAST *expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual CastExpressionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ClassSpecifierAST: public SpecifierAST
+{
+public:
+ unsigned classkey_token;
+ SpecifierAST *attributes;
+ NameAST *name;
+ unsigned colon_token;
+ BaseSpecifierAST *base_clause;
+ unsigned lbrace_token;
+ DeclarationAST *member_specifiers;
+ unsigned rbrace_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ClassSpecifierAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT CaseStatementAST: public StatementAST
+{
+public:
+ unsigned case_token;
+ ExpressionAST *expression;
+ unsigned colon_token;
+ StatementAST *statement;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual CaseStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT CompoundStatementAST: public StatementAST
+{
+public:
+ unsigned lbrace_token;
+ StatementAST *statements;
+ unsigned rbrace_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual CompoundStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ConditionAST: public ExpressionAST
+{
+public:
+ SpecifierAST *type_specifier;
+ DeclaratorAST *declarator;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ConditionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ConditionalExpressionAST: public ExpressionAST
+{
+public:
+ ExpressionAST *condition;
+ unsigned question_token;
+ ExpressionAST *left_expression;
+ unsigned colon_token;
+ ExpressionAST *right_expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ConditionalExpressionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT CppCastExpressionAST: public ExpressionAST
+{
+public:
+ unsigned cast_token;
+ unsigned less_token;
+ ExpressionAST *type_id;
+ unsigned greater_token;
+ unsigned lparen_token;
+ ExpressionAST *expression;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual CppCastExpressionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT CtorInitializerAST: public AST
+{
+public:
+ unsigned colon_token;
+ MemInitializerAST *member_initializers;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual CtorInitializerAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT DeclarationStatementAST: public StatementAST
+{
+public:
+ DeclarationAST *declaration;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual DeclarationStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT DeclaratorIdAST: public CoreDeclaratorAST
+{
+public:
+ NameAST *name;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual DeclaratorIdAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NestedDeclaratorAST: public CoreDeclaratorAST
+{
+public:
+ unsigned lparen_token;
+ DeclaratorAST *declarator;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual NestedDeclaratorAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT FunctionDeclaratorAST: public PostfixDeclaratorAST
+{
+public:
+ unsigned lparen_token;
+ ParameterDeclarationClauseAST *parameters;
+ unsigned rparen_token;
+ SpecifierAST *cv_qualifier_seq;
+ ExceptionSpecificationAST *exception_specification;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual FunctionDeclaratorAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ArrayDeclaratorAST: public PostfixDeclaratorAST
+{
+public:
+ unsigned lbracket_token;
+ ExpressionAST *expression;
+ unsigned rbracket_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ArrayDeclaratorAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT DeclaratorListAST: public AST
+{
+public:
+ DeclaratorAST *declarator;
+ DeclaratorListAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual DeclaratorListAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT DeleteExpressionAST: public ExpressionAST
+{
+public:
+ unsigned scope_token;
+ unsigned delete_token;
+ unsigned lbracket_token;
+ unsigned rbracket_token;
+ ExpressionAST *expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual DeleteExpressionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT DoStatementAST: public StatementAST
+{
+public:
+ unsigned do_token;
+ StatementAST *statement;
+ unsigned while_token;
+ unsigned lparen_token;
+ ExpressionAST *expression;
+ unsigned rparen_token;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual DoStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NamedTypeSpecifierAST: public SpecifierAST
+{
+public:
+ NameAST *name;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual NamedTypeSpecifierAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ElaboratedTypeSpecifierAST: public SpecifierAST
+{
+public:
+ unsigned classkey_token;
+ NameAST *name;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ElaboratedTypeSpecifierAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT EnumSpecifierAST: public SpecifierAST
+{
+public:
+ unsigned enum_token;
+ NameAST *name;
+ unsigned lbrace_token;
+ EnumeratorAST *enumerators;
+ unsigned rbrace_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual EnumSpecifierAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT EnumeratorAST: public AST
+{
+public:
+ unsigned identifier_token;
+ unsigned equal_token;
+ ExpressionAST *expression;
+ EnumeratorAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual EnumeratorAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ExceptionDeclarationAST: public DeclarationAST
+{
+public:
+ SpecifierAST *type_specifier;
+ DeclaratorAST *declarator;
+ unsigned dot_dot_dot_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ExceptionDeclarationAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ExceptionSpecificationAST: public AST
+{
+public:
+ unsigned throw_token;
+ unsigned lparen_token;
+ unsigned dot_dot_dot_token;
+ ExpressionListAST *type_ids;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ExceptionSpecificationAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ExpressionOrDeclarationStatementAST: public StatementAST
+{
+public:
+ StatementAST *expression;
+ StatementAST *declaration;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ExpressionOrDeclarationStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ExpressionStatementAST: public StatementAST
+{
+public:
+ ExpressionAST *expression;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ExpressionStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT FunctionDefinitionAST: public DeclarationAST
+{
+public:
+ SpecifierAST *decl_specifier_seq;
+ DeclaratorAST *declarator;
+ CtorInitializerAST *ctor_initializer;
+ StatementAST *function_body;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual FunctionDefinitionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ForStatementAST: public StatementAST
+{
+public:
+ unsigned for_token;
+ unsigned lparen_token;
+ StatementAST *initializer;
+ ExpressionAST *condition;
+ unsigned semicolon_token;
+ ExpressionAST *expression;
+ unsigned rparen_token;
+ StatementAST *statement;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ForStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT IfStatementAST: public StatementAST
+{
+public:
+ unsigned if_token;
+ unsigned lparen_token;
+ ExpressionAST *condition;
+ unsigned rparen_token;
+ StatementAST *statement;
+ unsigned else_token;
+ StatementAST *else_statement;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual IfStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ArrayInitializerAST: public ExpressionAST
+{
+public:
+ unsigned lbrace_token;
+ ExpressionListAST *expression_list;
+ unsigned rbrace_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ArrayInitializerAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT LabeledStatementAST: public StatementAST
+{
+public:
+ unsigned label_token;
+ unsigned colon_token;
+ StatementAST *statement;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual LabeledStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT LinkageBodyAST: public DeclarationAST
+{
+public:
+ unsigned lbrace_token;
+ DeclarationAST *declarations;
+ unsigned rbrace_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual LinkageBodyAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT LinkageSpecificationAST: public DeclarationAST
+{
+public:
+ unsigned extern_token;
+ unsigned extern_type;
+ DeclarationAST *declaration;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual LinkageSpecificationAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT MemInitializerAST: public AST
+{
+public:
+ NameAST *name;
+ unsigned lparen_token;
+ ExpressionAST *expression;
+ unsigned rparen_token;
+ MemInitializerAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual MemInitializerAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NameAST: public ExpressionAST
+{
+public:
+ virtual NameAST *clone(MemoryPool *pool) const = 0;
+};
+
+class CPLUSPLUS_EXPORT NestedNameSpecifierAST: public AST
+{
+public:
+ NameAST *class_or_namespace_name;
+ unsigned scope_token;
+ NestedNameSpecifierAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual NestedNameSpecifierAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT QualifiedNameAST: public NameAST
+{
+public:
+ unsigned global_scope_token;
+ NestedNameSpecifierAST *nested_name_specifier;
+ NameAST *unqualified_name;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual QualifiedNameAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT OperatorFunctionIdAST: public NameAST
+{
+public:
+ unsigned operator_token;
+ OperatorAST *op;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual OperatorFunctionIdAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ConversionFunctionIdAST: public NameAST
+{
+public:
+ unsigned operator_token;
+ SpecifierAST *type_specifier;
+ PtrOperatorAST *ptr_operators;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ConversionFunctionIdAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT SimpleNameAST: public NameAST
+{
+public:
+ unsigned identifier_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual SimpleNameAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT DestructorNameAST: public NameAST
+{
+public:
+ unsigned tilde_token;
+ unsigned identifier_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual DestructorNameAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TemplateIdAST: public NameAST
+{
+public:
+ unsigned identifier_token;
+ unsigned less_token;
+ TemplateArgumentListAST *template_arguments;
+ unsigned greater_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual TemplateIdAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NamespaceAST: public DeclarationAST
+{
+public:
+ unsigned namespace_token;
+ unsigned identifier_token;
+ SpecifierAST *attributes;
+ DeclarationAST *linkage_body;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual NamespaceAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NamespaceAliasDefinitionAST: public DeclarationAST
+{
+public:
+ unsigned namespace_token;
+ unsigned namespace_name;
+ unsigned equal_token;
+ NameAST *name;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual NamespaceAliasDefinitionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NewDeclaratorAST: public AST
+{
+public:
+ PtrOperatorAST *ptr_operators;
+ NewDeclaratorAST *declarator;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual NewDeclaratorAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NewExpressionAST: public ExpressionAST
+{
+public:
+ unsigned scope_token;
+ unsigned new_token;
+ ExpressionAST *expression;
+ ExpressionAST *type_id;
+ NewTypeIdAST *new_type_id;
+ NewInitializerAST *new_initializer;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual NewExpressionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NewInitializerAST: public AST
+{
+public:
+ unsigned lparen_token;
+ ExpressionAST *expression;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual NewInitializerAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NewTypeIdAST: public AST
+{
+public:
+ SpecifierAST *type_specifier;
+ NewInitializerAST *new_initializer;
+ NewDeclaratorAST *new_declarator;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual NewTypeIdAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT OperatorAST: public AST
+{
+public:
+ unsigned op_token;
+ unsigned open_token;
+ unsigned close_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual OperatorAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ParameterDeclarationAST: public DeclarationAST
+{
+public:
+ SpecifierAST *type_specifier;
+ DeclaratorAST *declarator;
+ unsigned equal_token;
+ ExpressionAST *expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ParameterDeclarationAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ParameterDeclarationClauseAST: public AST
+{
+public:
+ DeclarationAST *parameter_declarations;
+ unsigned dot_dot_dot_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ParameterDeclarationClauseAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT PostfixAST: public AST
+{
+public:
+ PostfixAST *next;
+
+public:
+ virtual PostfixAST *clone(MemoryPool *pool) const = 0;
+};
+
+class CPLUSPLUS_EXPORT CallAST: public PostfixAST
+{
+public:
+ unsigned lparen_token;
+ ExpressionListAST *expression_list;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual CallAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ArrayAccessAST: public PostfixAST
+{
+public:
+ unsigned lbracket_token;
+ ExpressionAST *expression;
+ unsigned rbracket_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ArrayAccessAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT PostIncrDecrAST: public PostfixAST
+{
+public:
+ unsigned incr_decr_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual PostIncrDecrAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT MemberAccessAST: public PostfixAST
+{
+public:
+ unsigned access_token;
+ unsigned template_token;
+ NameAST *member_name;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual MemberAccessAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TypeidExpressionAST: public ExpressionAST
+{
+public:
+ unsigned typeid_token;
+ unsigned lparen_token;
+ ExpressionAST *expression;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual TypeidExpressionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TypenameCallExpressionAST: public ExpressionAST
+{
+public:
+ unsigned typename_token;
+ NameAST *name;
+ unsigned lparen_token;
+ ExpressionListAST *expression_list;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual TypenameCallExpressionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TypeConstructorCallAST: public ExpressionAST
+{
+public:
+ SpecifierAST *type_specifier;
+ unsigned lparen_token;
+ ExpressionListAST *expression_list;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual TypeConstructorCallAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT PostfixExpressionAST: public ExpressionAST
+{
+public:
+ ExpressionAST *base_expression;
+ PostfixAST *postfix_expressions;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual PostfixExpressionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT PtrOperatorAST: public AST
+{
+public:
+ PtrOperatorAST *next;
+
+public:
+ virtual PtrOperatorAST *clone(MemoryPool *pool) const = 0;
+};
+
+class CPLUSPLUS_EXPORT PointerToMemberAST: public PtrOperatorAST
+{
+public:
+ unsigned global_scope_token;
+ NestedNameSpecifierAST *nested_name_specifier;
+ unsigned star_token;
+ SpecifierAST *cv_qualifier_seq;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual PointerToMemberAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT PointerAST: public PtrOperatorAST
+{
+public:
+ unsigned star_token;
+ SpecifierAST *cv_qualifier_seq;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual PointerAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ReferenceAST: public PtrOperatorAST
+{
+public:
+ unsigned amp_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ReferenceAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT BreakStatementAST: public StatementAST
+{
+public:
+ unsigned break_token;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual BreakStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ContinueStatementAST: public StatementAST
+{
+public:
+ unsigned continue_token;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ContinueStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT GotoStatementAST: public StatementAST
+{
+public:
+ unsigned goto_token;
+ unsigned identifier_token;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual GotoStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ReturnStatementAST: public StatementAST
+{
+public:
+ unsigned return_token;
+ ExpressionAST *expression;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ReturnStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT SizeofExpressionAST: public ExpressionAST
+{
+public:
+ unsigned sizeof_token;
+ ExpressionAST *expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual SizeofExpressionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NumericLiteralAST: public ExpressionAST
+{
+public:
+ unsigned token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual NumericLiteralAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT BoolLiteralAST: public ExpressionAST
+{
+public:
+ unsigned token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual BoolLiteralAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ThisExpressionAST: public ExpressionAST
+{
+public:
+ unsigned this_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ThisExpressionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NestedExpressionAST: public ExpressionAST
+{
+public:
+ unsigned lparen_token;
+ ExpressionAST *expression;
+ unsigned rparen_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual NestedExpressionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT StringLiteralAST: public ExpressionAST
+{
+public:
+ unsigned token;
+ StringLiteralAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual StringLiteralAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT SwitchStatementAST: public StatementAST
+{
+public:
+ unsigned switch_token;
+ unsigned lparen_token;
+ ExpressionAST *condition;
+ unsigned rparen_token;
+ StatementAST *statement;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual SwitchStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TemplateArgumentListAST: public AST
+{
+public:
+ ExpressionAST *template_argument;
+ TemplateArgumentListAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual TemplateArgumentListAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TemplateDeclarationAST: public DeclarationAST
+{
+public:
+ unsigned export_token;
+ unsigned template_token;
+ unsigned less_token;
+ DeclarationAST *template_parameters;
+ unsigned greater_token;
+ DeclarationAST *declaration;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual TemplateDeclarationAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ThrowExpressionAST: public ExpressionAST
+{
+public:
+ unsigned throw_token;
+ ExpressionAST *expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ThrowExpressionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TranslationUnitAST: public AST
+{
+public:
+ DeclarationAST *declarations;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual TranslationUnitAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TryBlockStatementAST: public StatementAST
+{
+public:
+ unsigned try_token;
+ StatementAST *statement;
+ CatchClauseAST *catch_clause_seq;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual TryBlockStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT CatchClauseAST: public StatementAST
+{
+public:
+ unsigned catch_token;
+ unsigned lparen_token;
+ ExceptionDeclarationAST *exception_declaration;
+ unsigned rparen_token;
+ StatementAST *statement;
+ CatchClauseAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual CatchClauseAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TypeIdAST: public ExpressionAST
+{
+public:
+ SpecifierAST *type_specifier;
+ DeclaratorAST *declarator;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual TypeIdAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TypenameTypeParameterAST: public DeclarationAST
+{
+public:
+ unsigned classkey_token;
+ NameAST *name;
+ unsigned equal_token;
+ ExpressionAST *type_id;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual TypenameTypeParameterAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT TemplateTypeParameterAST: public DeclarationAST
+{
+public:
+ unsigned template_token;
+ unsigned less_token;
+ DeclarationAST *template_parameters;
+ unsigned greater_token;
+ unsigned class_token;
+ NameAST *name;
+ unsigned equal_token;
+ ExpressionAST *type_id;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual TemplateTypeParameterAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT UnaryExpressionAST: public ExpressionAST
+{
+public:
+ unsigned unary_op_token;
+ ExpressionAST *expression;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual UnaryExpressionAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT UsingAST: public DeclarationAST
+{
+public:
+ unsigned using_token;
+ unsigned typename_token;
+ NameAST *name;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual UsingAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT UsingDirectiveAST: public DeclarationAST
+{
+public:
+ unsigned using_token;
+ unsigned namespace_token;
+ NameAST *name;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual UsingDirectiveAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT WhileStatementAST: public StatementAST
+{
+public:
+ unsigned while_token;
+ unsigned lparen_token;
+ ExpressionAST *condition;
+ unsigned rparen_token;
+ StatementAST *statement;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual WhileStatementAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+
+// ObjC++
+class CPLUSPLUS_EXPORT IdentifierListAST: public AST
+{
+public:
+ unsigned identifier_token;
+ IdentifierListAST *next;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual IdentifierListAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT ObjCClassDeclarationAST: public DeclarationAST
+{
+public:
+ SpecifierAST *attributes;
+ unsigned class_token;
+ IdentifierListAST *identifier_list;
+ unsigned semicolon_token;
+
+public:
+ virtual unsigned firstToken() const;
+ virtual unsigned lastToken() const;
+
+ virtual ObjCClassDeclarationAST *clone(MemoryPool *pool) const;
+
+protected:
+ virtual void accept0(ASTVisitor *visitor);
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_AST_H
diff --git a/src/shared/cplusplus/ASTVisitor.cpp b/src/shared/cplusplus/ASTVisitor.cpp
new file mode 100644
index 0000000000..7b9ca1ed7f
--- /dev/null
+++ b/src/shared/cplusplus/ASTVisitor.cpp
@@ -0,0 +1,105 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "ASTVisitor.h"
+#include "AST.h"
+#include "TranslationUnit.h"
+#include "Control.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+ASTVisitor::ASTVisitor(Control *control)
+ : _control(control)
+{ }
+
+ASTVisitor::~ASTVisitor()
+{ }
+
+void ASTVisitor::accept(AST *ast)
+{ AST::accept(ast, this); }
+
+Control *ASTVisitor::control() const
+{ return _control; }
+
+TranslationUnit *ASTVisitor::translationUnit() const
+{ return _control->translationUnit(); }
+
+int ASTVisitor::tokenKind(unsigned index) const
+{ return translationUnit()->tokenKind(index); }
+
+const char *ASTVisitor::spell(unsigned index) const
+{
+ if (! index)
+ return 0;
+
+ return translationUnit()->tokenAt(index).spell();
+}
+
+Identifier *ASTVisitor::identifier(unsigned index) const
+{ return translationUnit()->identifier(index); }
+
+Literal *ASTVisitor::literal(unsigned index) const
+{ return translationUnit()->literal(index); }
+
+NumericLiteral *ASTVisitor::numericLiteral(unsigned index) const
+{ return translationUnit()->numericLiteral(index); }
+
+StringLiteral *ASTVisitor::stringLiteral(unsigned index) const
+{ return translationUnit()->stringLiteral(index); }
+
+void ASTVisitor::getTokenPosition(unsigned index,
+ unsigned *line,
+ unsigned *column,
+ StringLiteral **fileName) const
+{ translationUnit()->getTokenPosition(index, line, column, fileName); }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/ASTVisitor.h b/src/shared/cplusplus/ASTVisitor.h
new file mode 100644
index 0000000000..f8d2d6790e
--- /dev/null
+++ b/src/shared/cplusplus/ASTVisitor.h
@@ -0,0 +1,200 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_ASTVISITOR_H
+#define CPLUSPLUS_ASTVISITOR_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "ASTfwd.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT ASTVisitor
+{
+ ASTVisitor(const ASTVisitor &other);
+ void operator =(const ASTVisitor &other);
+
+public:
+ ASTVisitor(Control *control);
+ virtual ~ASTVisitor();
+
+ Control *control() const;
+ TranslationUnit *translationUnit() const;
+
+ int tokenKind(unsigned index) const;
+ const char *spell(unsigned index) const;
+ Identifier *identifier(unsigned index) const;
+ Literal *literal(unsigned index) const;
+ NumericLiteral *numericLiteral(unsigned index) const;
+ StringLiteral *stringLiteral(unsigned index) const;
+
+ void getTokenPosition(unsigned index,
+ unsigned *line,
+ unsigned *column = 0,
+ StringLiteral **fileName = 0) const;
+
+ void accept(AST *ast);
+
+ virtual bool preVisit(AST *) { return true; }
+ virtual void postVisit(AST *) {}
+
+ virtual bool visit(AccessDeclarationAST *) { return true; }
+ virtual bool visit(ArrayAccessAST *) { return true; }
+ virtual bool visit(ArrayDeclaratorAST *) { return true; }
+ virtual bool visit(ArrayInitializerAST *) { return true; }
+ virtual bool visit(AsmDefinitionAST *) { return true; }
+ virtual bool visit(AttributeSpecifierAST *) { return true; }
+ virtual bool visit(AttributeAST *) { return true; }
+ virtual bool visit(BaseSpecifierAST *) { return true; }
+ virtual bool visit(BinaryExpressionAST *) { return true; }
+ virtual bool visit(BoolLiteralAST *) { return true; }
+ virtual bool visit(BreakStatementAST *) { return true; }
+ virtual bool visit(CallAST *) { return true; }
+ virtual bool visit(CaseStatementAST *) { return true; }
+ virtual bool visit(CastExpressionAST *) { return true; }
+ virtual bool visit(CatchClauseAST *) { return true; }
+ virtual bool visit(ClassSpecifierAST *) { return true; }
+ virtual bool visit(CompoundLiteralAST *) { return true; }
+ virtual bool visit(CompoundStatementAST *) { return true; }
+ virtual bool visit(ConditionAST *) { return true; }
+ virtual bool visit(ConditionalExpressionAST *) { return true; }
+ virtual bool visit(ContinueStatementAST *) { return true; }
+ virtual bool visit(ConversionFunctionIdAST *) { return true; }
+ virtual bool visit(CppCastExpressionAST *) { return true; }
+ virtual bool visit(CtorInitializerAST *) { return true; }
+ virtual bool visit(DeclaratorAST *) { return true; }
+ virtual bool visit(DeclarationStatementAST *) { return true; }
+ virtual bool visit(DeclaratorIdAST *) { return true; }
+ virtual bool visit(DeclaratorListAST *) { return true; }
+ virtual bool visit(DeleteExpressionAST *) { return true; }
+ virtual bool visit(DestructorNameAST *) { return true; }
+ virtual bool visit(DoStatementAST *) { return true; }
+ virtual bool visit(ElaboratedTypeSpecifierAST *) { return true; }
+ virtual bool visit(EmptyDeclarationAST *) { return true; }
+ virtual bool visit(EnumSpecifierAST *) { return true; }
+ virtual bool visit(EnumeratorAST *) { return true; }
+ virtual bool visit(ExceptionDeclarationAST *) { return true; }
+ virtual bool visit(ExceptionSpecificationAST *) { return true; }
+ virtual bool visit(ExpressionListAST *) { return true; }
+ virtual bool visit(ExpressionOrDeclarationStatementAST *) { return true; }
+ virtual bool visit(ExpressionStatementAST *) { return true; }
+ virtual bool visit(ForStatementAST *) { return true; }
+ virtual bool visit(FunctionDeclaratorAST *) { return true; }
+ virtual bool visit(FunctionDefinitionAST *) { return true; }
+ virtual bool visit(GotoStatementAST *) { return true; }
+ virtual bool visit(IfStatementAST *) { return true; }
+ virtual bool visit(LabeledStatementAST *) { return true; }
+ virtual bool visit(LinkageBodyAST *) { return true; }
+ virtual bool visit(LinkageSpecificationAST *) { return true; }
+ virtual bool visit(MemInitializerAST *) { return true; }
+ virtual bool visit(MemberAccessAST *) { return true; }
+ virtual bool visit(NamedTypeSpecifierAST *) { return true; }
+ virtual bool visit(NamespaceAST *) { return true; }
+ virtual bool visit(NamespaceAliasDefinitionAST *) { return true; }
+ virtual bool visit(NestedDeclaratorAST *) { return true; }
+ virtual bool visit(NestedExpressionAST *) { return true; }
+ virtual bool visit(NestedNameSpecifierAST *) { return true; }
+ virtual bool visit(NewDeclaratorAST *) { return true; }
+ virtual bool visit(NewExpressionAST *) { return true; }
+ virtual bool visit(NewInitializerAST *) { return true; }
+ virtual bool visit(NewTypeIdAST *) { return true; }
+ virtual bool visit(NumericLiteralAST *) { return true; }
+ virtual bool visit(OperatorAST *) { return true; }
+ virtual bool visit(OperatorFunctionIdAST *) { return true; }
+ virtual bool visit(ParameterDeclarationAST *) { return true; }
+ virtual bool visit(ParameterDeclarationClauseAST *) { return true; }
+ virtual bool visit(PointerAST *) { return true; }
+ virtual bool visit(PointerToMemberAST *) { return true; }
+ virtual bool visit(PostIncrDecrAST *) { return true; }
+ virtual bool visit(PostfixExpressionAST *) { return true; }
+ virtual bool visit(QualifiedNameAST *) { return true; }
+ virtual bool visit(ReferenceAST *) { return true; }
+ virtual bool visit(ReturnStatementAST *) { return true; }
+ virtual bool visit(SimpleDeclarationAST *) { return true; }
+ virtual bool visit(SimpleNameAST *) { return true; }
+ virtual bool visit(SimpleSpecifierAST *) { return true; }
+ virtual bool visit(SizeofExpressionAST *) { return true; }
+ virtual bool visit(StringLiteralAST *) { return true; }
+ virtual bool visit(SwitchStatementAST *) { return true; }
+ virtual bool visit(TemplateArgumentListAST *) { return true; }
+ virtual bool visit(TemplateDeclarationAST *) { return true; }
+ virtual bool visit(TemplateIdAST *) { return true; }
+ virtual bool visit(TemplateTypeParameterAST *) { return true; }
+ virtual bool visit(ThisExpressionAST *) { return true; }
+ virtual bool visit(ThrowExpressionAST *) { return true; }
+ virtual bool visit(TranslationUnitAST *) { return true; }
+ virtual bool visit(TryBlockStatementAST *) { return true; }
+ virtual bool visit(TypeConstructorCallAST *) { return true; }
+ virtual bool visit(TypeIdAST *) { return true; }
+ virtual bool visit(TypeidExpressionAST *) { return true; }
+ virtual bool visit(TypeofSpecifierAST *) { return true; }
+ virtual bool visit(TypenameCallExpressionAST *) { return true; }
+ virtual bool visit(TypenameTypeParameterAST *) { return true; }
+ virtual bool visit(UnaryExpressionAST *) { return true; }
+ virtual bool visit(UsingAST *) { return true; }
+ virtual bool visit(UsingDirectiveAST *) { return true; }
+ virtual bool visit(WhileStatementAST *) { return true; }
+ virtual bool visit(QtMethodAST *) { return true; }
+
+ // ObjC++
+ virtual bool visit(IdentifierListAST *) { return true; }
+ virtual bool visit(ObjCClassDeclarationAST *) { return true; }
+
+private:
+ Control *_control;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_ASTVISITOR_H
diff --git a/src/shared/cplusplus/ASTfwd.h b/src/shared/cplusplus/ASTfwd.h
new file mode 100644
index 0000000000..b4f5283a74
--- /dev/null
+++ b/src/shared/cplusplus/ASTfwd.h
@@ -0,0 +1,178 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_ASTFWD_H
+#define CPLUSPLUS_ASTFWD_H
+
+#include <CPlusPlusForwardDeclarations.h>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class AST;
+class ASTVisitor;
+
+class AccessDeclarationAST;
+class ArrayAccessAST;
+class ArrayDeclaratorAST;
+class ArrayInitializerAST;
+class AsmDefinitionAST;
+class AttributeAST;
+class AttributeSpecifierAST;
+class BaseSpecifierAST;
+class BinaryExpressionAST;
+class BoolLiteralAST;
+class BreakStatementAST;
+class CallAST;
+class CaseStatementAST;
+class CastExpressionAST;
+class CatchClauseAST;
+class ClassSpecifierAST;
+class CompoundLiteralAST;
+class CompoundStatementAST;
+class ConditionAST;
+class ConditionalExpressionAST;
+class ContinueStatementAST;
+class ConversionFunctionIdAST;
+class CoreDeclaratorAST;
+class CppCastExpressionAST;
+class CtorInitializerAST;
+class DeclarationAST;
+class DeclarationStatementAST;
+class DeclaratorAST;
+class DeclaratorIdAST;
+class DeclaratorListAST;
+class DeleteExpressionAST;
+class DestructorNameAST;
+class DoStatementAST;
+class ElaboratedTypeSpecifierAST;
+class EmptyDeclarationAST;
+class EnumSpecifierAST;
+class EnumeratorAST;
+class ExceptionDeclarationAST;
+class ExceptionSpecificationAST;
+class ExpressionAST;
+class ExpressionListAST;
+class ExpressionOrDeclarationStatementAST;
+class ExpressionStatementAST;
+class ForStatementAST;
+class FunctionDeclaratorAST;
+class FunctionDefinitionAST;
+class GotoStatementAST;
+class IfStatementAST;
+class LabeledStatementAST;
+class LinkageBodyAST;
+class LinkageSpecificationAST;
+class MemInitializerAST;
+class MemberAccessAST;
+class NameAST;
+class NamedTypeSpecifierAST;
+class NamespaceAST;
+class NamespaceAliasDefinitionAST;
+class NestedDeclaratorAST;
+class NestedExpressionAST;
+class NestedNameSpecifierAST;
+class NewDeclaratorAST;
+class NewExpressionAST;
+class NewInitializerAST;
+class NewTypeIdAST;
+class NumericLiteralAST;
+class OperatorAST;
+class OperatorFunctionIdAST;
+class ParameterDeclarationAST;
+class ParameterDeclarationClauseAST;
+class PointerAST;
+class PointerToMemberAST;
+class PostIncrDecrAST;
+class PostfixAST;
+class PostfixDeclaratorAST;
+class PostfixExpressionAST;
+class PtrOperatorAST;
+class QualifiedNameAST;
+class ReferenceAST;
+class ReturnStatementAST;
+class SimpleDeclarationAST;
+class SimpleNameAST;
+class SimpleSpecifierAST;
+class SizeofExpressionAST;
+class SpecifierAST;
+class StatementAST;
+class StringLiteralAST;
+class SwitchStatementAST;
+class TemplateArgumentListAST;
+class TemplateDeclarationAST;
+class TemplateIdAST;
+class TemplateTypeParameterAST;
+class ThisExpressionAST;
+class ThrowExpressionAST;
+class TranslationUnitAST;
+class TryBlockStatementAST;
+class TypeConstructorCallAST;
+class TypeIdAST;
+class TypeidExpressionAST;
+class TypenameCallExpressionAST;
+class TypenameTypeParameterAST;
+class TypeofSpecifierAST;
+class UnaryExpressionAST;
+class UsingAST;
+class UsingDirectiveAST;
+class WhileStatementAST;
+class QtMethodAST;
+
+// ObjC++
+class IdentifierListAST;
+class ObjCClassDeclarationAST;
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_ASTFWD_H
diff --git a/src/shared/cplusplus/Array.cpp b/src/shared/cplusplus/Array.cpp
new file mode 100644
index 0000000000..7159008fd4
--- /dev/null
+++ b/src/shared/cplusplus/Array.cpp
@@ -0,0 +1,34 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "Array.h"
diff --git a/src/shared/cplusplus/Array.h b/src/shared/cplusplus/Array.h
new file mode 100644
index 0000000000..c639affc89
--- /dev/null
+++ b/src/shared/cplusplus/Array.h
@@ -0,0 +1,135 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_ARRAY_H
+#define CPLUSPLUS_ARRAY_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include <new>
+#include <cstdlib>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+template <typename _Tp, int SEGMENT_SHIFT = 4>
+class Array
+{
+ Array(const Array &other);
+ void operator =(const Array &other);
+
+public:
+ Array()
+ : _segments(0),
+ _allocatedSegments(0),
+ _segmentCount(-1),
+ _allocatedElements(0),
+ _count(-1)
+ { }
+
+ ~Array()
+ {
+ if (_segments) {
+ for (int index = 0; index <= _segmentCount; ++index) {
+ delete[] (_segments[index] + (index << SEGMENT_SHIFT));
+ }
+ free(_segments);
+ }
+ }
+
+ inline unsigned size() const
+ { return _count + 1; }
+
+ inline unsigned count() const
+ { return _count + 1; }
+
+ inline const _Tp &at(unsigned index) const
+ { return _segments[index >> SEGMENT_SHIFT][index]; }
+
+ inline const _Tp &operator[](unsigned index) const
+ { return _segments[index >> SEGMENT_SHIFT][index]; }
+
+ inline _Tp &operator[](unsigned index)
+ { return _segments[index >> SEGMENT_SHIFT][index]; }
+
+ void push_back(const _Tp &value)
+ {
+ if (++_count == _allocatedElements) {
+ if (++_segmentCount == _allocatedSegments) {
+ _allocatedSegments += 4;
+ _segments = (_Tp **) realloc(_segments, _allocatedSegments * sizeof(_Tp *));
+ }
+
+ _Tp *segment = new _Tp[SEGMENT_SIZE];
+ _segments[_segmentCount] = segment - (_segmentCount << SEGMENT_SHIFT);
+ _allocatedElements += SEGMENT_SIZE;
+ }
+
+ _segments[_count >> SEGMENT_SHIFT][_count] = value;
+ }
+
+private:
+ enum {
+ SEGMENT_SIZE = 1 << SEGMENT_SHIFT
+ };
+
+ _Tp **_segments;
+ int _allocatedSegments;
+ int _segmentCount;
+
+ int _allocatedElements;
+ int _count;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_ARRAY_H
diff --git a/src/shared/cplusplus/CPlusPlusForwardDeclarations.h b/src/shared/cplusplus/CPlusPlusForwardDeclarations.h
new file mode 100644
index 0000000000..31b01bfd81
--- /dev/null
+++ b/src/shared/cplusplus/CPlusPlusForwardDeclarations.h
@@ -0,0 +1,140 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H
+#define CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H
+
+#ifdef HAVE_QT
+# include <QtCore/qglobal.h>
+# define CPLUSPLUS_BEGIN_HEADER
+# define CPLUSPLUS_END_HEADER
+# if defined(CPLUSPLUS_BUILD_LIB)
+# define CPLUSPLUS_EXPORT Q_DECL_EXPORT
+# else
+# define CPLUSPLUS_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define CPLUSPLUS_BEGIN_HEADER
+# define CPLUSPLUS_END_HEADER
+# define CPLUSPLUS_EXPORT
+#endif
+
+#ifdef CPLUSPLUS_WITH_NAMESPACE
+# define CPLUSPLUS_BEGIN_NAMESPACE namespace CPlusPlus {
+# define CPLUSPLUS_END_NAMESPACE } // end of namespace CPlusPLus
+# define CPLUSPLUS_USE_NAMESPACE using namespace CPlusPlus;
+#else
+# define CPLUSPLUS_BEGIN_NAMESPACE
+# define CPLUSPLUS_END_NAMESPACE
+# define CPLUSPLUS_USE_NAMESPACE ;
+#endif
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class TranslationUnit;
+class Semantic;
+class Control;
+class MemoryPool;
+class DiagnosticClient;
+
+class Identifier;
+class Literal;
+class StringLiteral;
+class NumericLiteral;
+
+class Scope;
+
+// names
+class NameVisitor;
+class Name;
+class NameId;
+class TemplateNameId;
+class DestructorNameId;
+class OperatorNameId;
+class ConversionNameId;
+class QualifiedNameId;
+
+// types
+class FullySpecifiedType;
+class TypeVisitor;
+class Type;
+class VoidType;
+class IntegerType;
+class FloatType;
+class PointerToMemberType;
+class PointerType;
+class ReferenceType;
+class ArrayType;
+class NamedType;
+
+// symbols
+class SymbolVisitor;
+class Symbol;
+class ScopedSymbol;
+class UsingNamespaceDirective;
+class UsingDeclaration;
+class Declaration;
+class Argument;
+class Function;
+class Namespace;
+class BaseClass;
+class Block;
+class Class;
+class Enum;
+
+class Use;
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H
diff --git a/src/shared/cplusplus/CheckDeclaration.cpp b/src/shared/cplusplus/CheckDeclaration.cpp
new file mode 100644
index 0000000000..610d57626f
--- /dev/null
+++ b/src/shared/cplusplus/CheckDeclaration.cpp
@@ -0,0 +1,374 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "CheckDeclaration.h"
+#include "Semantic.h"
+#include "AST.h"
+#include "TranslationUnit.h"
+#include "Scope.h"
+#include "Names.h"
+#include "CoreTypes.h"
+#include "Symbols.h"
+#include "Control.h"
+#include <cassert>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+CheckDeclaration::CheckDeclaration(Semantic *semantic)
+ : SemanticCheck(semantic),
+ _declaration(0),
+ _scope(0),
+ _templateParameters(0),
+ _checkAnonymousArguments(false)
+{ }
+
+CheckDeclaration::~CheckDeclaration()
+{ }
+
+void CheckDeclaration::check(DeclarationAST *declaration,
+ Scope *scope, Scope *templateParameters)
+{
+ Scope *previousScope = switchScope(scope);
+ Scope *previousTemplateParameters = switchTemplateParameters(templateParameters);
+ DeclarationAST *previousDeclaration = switchDeclaration(declaration);
+ accept(declaration);
+ (void) switchDeclaration(previousDeclaration);
+ (void) switchTemplateParameters(previousTemplateParameters);
+ (void) switchScope(previousScope);
+}
+
+DeclarationAST *CheckDeclaration::switchDeclaration(DeclarationAST *declaration)
+{
+ DeclarationAST *previousDeclaration = _declaration;
+ _declaration = declaration;
+ return previousDeclaration;
+}
+
+Scope *CheckDeclaration::switchScope(Scope *scope)
+{
+ Scope *previousScope = _scope;
+ _scope = scope;
+ return previousScope;
+}
+
+Scope *CheckDeclaration::switchTemplateParameters(Scope *templateParameters)
+{
+ Scope *previousTemplateParameters = _templateParameters;
+ _templateParameters = templateParameters;
+ return previousTemplateParameters;
+}
+
+void CheckDeclaration::checkFunctionArguments(Function *fun)
+{
+ if (! _checkAnonymousArguments)
+ return;
+
+ if (_scope->isClassScope() && fun->isPublic()) {
+ for (unsigned argc = 0; argc < fun->argumentCount(); ++argc) {
+ Argument *arg = fun->argumentAt(argc)->asArgument();
+ assert(arg != 0);
+
+ if (! arg->name()) {
+ translationUnit()->warning(arg->sourceLocation(),
+ "anonymous argument");
+ }
+ }
+ }
+}
+
+bool CheckDeclaration::visit(SimpleDeclarationAST *ast)
+{
+ FullySpecifiedType ty = semantic()->check(ast->decl_specifier_seq, _scope);
+ FullySpecifiedType qualTy = ty.qualifiedType();
+
+ if (_templateParameters) {
+ if (Class *klass = ty->asClass()) {
+ klass->setTemplateParameters(_templateParameters);
+ }
+ }
+
+ for (DeclaratorListAST *it = ast->declarators; it; it = it->next) {
+ Name *name = 0;
+ FullySpecifiedType declTy = semantic()->check(it->declarator, qualTy,
+ _scope, &name);
+
+ if (Function *fun = declTy->asFunction()) {
+ fun->setScope(_scope);
+ fun->setName(name);
+ fun->setMethodKey(semantic()->currentMethodKey());
+ fun->setVisibility(semantic()->currentVisibility());
+ } else if (semantic()->currentMethodKey() != Function::NormalMethod) {
+ translationUnit()->warning(ast->firstToken(),
+ "expected a function declaration");
+ }
+
+ unsigned location = 0;
+ if (it->declarator)
+ location = it->declarator->firstToken();
+ else
+ location = ast->firstToken();
+
+ Declaration *symbol = control()->newDeclaration(location, name);
+ symbol->setType(control()->integerType(IntegerType::Int));
+ symbol->setType(declTy);
+
+ if (_templateParameters && it == ast->declarators && ! ty->asClass())
+ symbol->setTemplateParameters(_templateParameters);
+
+ symbol->setVisibility(semantic()->currentVisibility());
+
+ if (ty.isFriend())
+ symbol->setStorage(Symbol::Friend);
+ else if (ty.isRegister())
+ symbol->setStorage(Symbol::Register);
+ else if (ty.isStatic())
+ symbol->setStorage(Symbol::Static);
+ else if (ty.isExtern())
+ symbol->setStorage(Symbol::Extern);
+ else if (ty.isMutable())
+ symbol->setStorage(Symbol::Mutable);
+ else if (ty.isTypedef())
+ symbol->setStorage(Symbol::Typedef);
+
+ _scope->enterSymbol(symbol);
+ }
+ return false;
+}
+
+bool CheckDeclaration::visit(EmptyDeclarationAST *)
+{
+ return false;
+}
+
+bool CheckDeclaration::visit(AccessDeclarationAST *ast)
+{
+ int accessSpecifier = tokenKind(ast->access_specifier_token);
+ int visibility = semantic()->visibilityForAccessSpecifier(accessSpecifier);
+ semantic()->switchVisibility(visibility);
+ if (ast->slots_token)
+ semantic()->switchMethodKey(Function::SlotMethod);
+ else if (accessSpecifier == T_SIGNALS)
+ semantic()->switchMethodKey(Function::SignalMethod);
+ else
+ semantic()->switchMethodKey(Function::NormalMethod);
+ return false;
+}
+
+bool CheckDeclaration::visit(AsmDefinitionAST *)
+{
+ return false;
+}
+
+bool CheckDeclaration::visit(ExceptionDeclarationAST *)
+{
+ return false;
+}
+
+bool CheckDeclaration::visit(FunctionDefinitionAST *ast)
+{
+ FullySpecifiedType ty = semantic()->check(ast->decl_specifier_seq, _scope);
+ FullySpecifiedType qualTy = ty.qualifiedType();
+ Name *name = 0;
+ FullySpecifiedType funTy = semantic()->check(ast->declarator, qualTy,
+ _scope, &name);
+ Function *fun = funTy->asFunction();
+ if (! fun) {
+ translationUnit()->error(ast->firstToken(),
+ "expected a function prototype");
+ return false;
+ }
+
+ fun->setName(name);
+ fun->setTemplateParameters(_templateParameters);
+ fun->setVisibility(semantic()->currentVisibility());
+ fun->setMethodKey(semantic()->currentMethodKey());
+
+ checkFunctionArguments(fun);
+
+ _scope->enterSymbol(fun);
+
+ if (ast->ctor_initializer) {
+ bool looksLikeCtor = false;
+ if (ty.isValid() || ! fun->identity())
+ looksLikeCtor = false;
+ else if (fun->identity()->isNameId() || fun->identity()->isTemplateNameId())
+ looksLikeCtor = true;
+
+ if (! looksLikeCtor) {
+ translationUnit()->error(ast->ctor_initializer->firstToken(),
+ "only constructors take base initializers");
+ }
+ }
+
+ const int previousVisibility = semantic()->switchVisibility(Symbol::Public);
+ const int previousMethodKey = semantic()->switchMethodKey(Function::NormalMethod);
+
+ semantic()->check(ast->function_body, fun->members());
+
+ semantic()->switchMethodKey(previousMethodKey);
+ semantic()->switchVisibility(previousVisibility);
+
+ if (ast->next && ast->next->asEmptyDeclaration()) {
+ translationUnit()->warning(ast->next->firstToken(),
+ "unnecessary semicolon after function block");
+ }
+
+ return false;
+}
+
+bool CheckDeclaration::visit(LinkageBodyAST *ast)
+{
+ for (DeclarationAST *decl = ast->declarations; decl; decl = decl->next) {
+ semantic()->check(decl, _scope);
+ }
+ return false;
+}
+
+bool CheckDeclaration::visit(LinkageSpecificationAST *ast)
+{
+ for (DeclarationAST *decl = ast->declaration; decl; decl = decl->next) {
+ semantic()->check(decl, _scope);
+ }
+ return false;
+}
+
+bool CheckDeclaration::visit(NamespaceAST *ast)
+{
+ Identifier *id = identifier(ast->identifier_token);
+ Name *namespaceName = control()->nameId(id);
+ Namespace *ns = control()->newNamespace(ast->firstToken(), namespaceName);
+ _scope->enterSymbol(ns);
+ semantic()->check(ast->linkage_body, ns->members()); // ### we'll do the merge later.
+
+ if (ast->next && ast->next->asEmptyDeclaration()) {
+ translationUnit()->warning(ast->next->firstToken(),
+ "unnecessary semicolon after namespace");
+ }
+
+ return false;
+}
+
+bool CheckDeclaration::visit(NamespaceAliasDefinitionAST *)
+{
+ return false;
+}
+
+bool CheckDeclaration::visit(ParameterDeclarationAST *ast)
+{
+ Name *argName = 0;
+ FullySpecifiedType ty = semantic()->check(ast->type_specifier, _scope);
+ FullySpecifiedType argTy = semantic()->check(ast->declarator, ty.qualifiedType(),
+ _scope, &argName);
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ Argument *arg = control()->newArgument(ast->firstToken(), argName);
+ if (ast->expression)
+ arg->setInitializer(true);
+ arg->setType(argTy);
+ _scope->enterSymbol(arg);
+ return false;
+}
+
+bool CheckDeclaration::visit(TemplateDeclarationAST *ast)
+{
+/*
+ Template *templ = control()->newTemplate(ast->firstToken());
+
+ for (DeclarationAST *param = ast->template_parameters; param;
+ param = param->next) {
+ semantic()->check(param, templ->members());
+ }
+*/
+
+ Scope *previousScope = switchScope(new Scope(_scope->owner()));
+ for (DeclarationAST *param = ast->template_parameters; param;
+ param = param->next) {
+ semantic()->check(param, _scope);
+ }
+
+ Scope *templateParameters = switchScope(previousScope);
+ semantic()->check(ast->declaration, _scope, templateParameters);
+ return false;
+}
+
+bool CheckDeclaration::visit(TypenameTypeParameterAST *ast)
+{
+ Name *name = semantic()->check(ast->name, _scope);
+ Argument *arg = control()->newArgument(ast->firstToken(), name); // ### new template type
+ _scope->enterSymbol(arg);
+ return false;
+}
+
+bool CheckDeclaration::visit(TemplateTypeParameterAST *ast)
+{
+ Name *name = semantic()->check(ast->name, _scope);
+ Argument *arg = control()->newArgument(ast->firstToken(), name); // ### new template type
+ _scope->enterSymbol(arg);
+ return false;
+}
+
+bool CheckDeclaration::visit(UsingAST *ast)
+{
+ Name *name = semantic()->check(ast->name, _scope);
+ UsingDeclaration *u = control()->newUsingDeclaration(ast->firstToken(), name);
+ _scope->enterSymbol(u);
+ return false;
+}
+
+bool CheckDeclaration::visit(UsingDirectiveAST *ast)
+{
+ Name *name = semantic()->check(ast->name, _scope);
+ UsingNamespaceDirective *u = control()->newUsingNamespaceDirective(ast->firstToken(), name);
+ _scope->enterSymbol(u);
+ return false;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/CheckDeclaration.h b/src/shared/cplusplus/CheckDeclaration.h
new file mode 100644
index 0000000000..6e82678fa0
--- /dev/null
+++ b/src/shared/cplusplus/CheckDeclaration.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CHECKDECLARATION_H
+#define CPLUSPLUS_CHECKDECLARATION_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "SemanticCheck.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT CheckDeclaration: public SemanticCheck
+{
+public:
+ CheckDeclaration(Semantic *semantic);
+ virtual ~CheckDeclaration();
+
+ void check(DeclarationAST *declaration, Scope *scope, Scope *templateParameters);
+
+protected:
+ DeclarationAST *switchDeclaration(DeclarationAST *declaration);
+ Scope *switchScope(Scope *scope);
+ Scope *switchTemplateParameters(Scope *templateParameters);
+
+ void checkFunctionArguments(Function *fun);
+
+ using ASTVisitor::visit;
+
+ virtual bool visit(SimpleDeclarationAST *ast);
+ virtual bool visit(EmptyDeclarationAST *ast);
+ virtual bool visit(AccessDeclarationAST *ast);
+ virtual bool visit(AsmDefinitionAST *ast);
+ virtual bool visit(ExceptionDeclarationAST *ast);
+ virtual bool visit(FunctionDefinitionAST *ast);
+ virtual bool visit(LinkageBodyAST *ast);
+ virtual bool visit(LinkageSpecificationAST *ast);
+ virtual bool visit(NamespaceAST *ast);
+ virtual bool visit(NamespaceAliasDefinitionAST *ast);
+ virtual bool visit(ParameterDeclarationAST *ast);
+ virtual bool visit(TemplateDeclarationAST *ast);
+ virtual bool visit(TypenameTypeParameterAST *ast);
+ virtual bool visit(TemplateTypeParameterAST *ast);
+ virtual bool visit(UsingAST *ast);
+ virtual bool visit(UsingDirectiveAST *ast);
+
+private:
+ DeclarationAST *_declaration;
+ Scope *_scope;
+ Scope *_templateParameters;
+ bool _checkAnonymousArguments: 1;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CHECKDECLARATION_H
diff --git a/src/shared/cplusplus/CheckDeclarator.cpp b/src/shared/cplusplus/CheckDeclarator.cpp
new file mode 100644
index 0000000000..13120fec58
--- /dev/null
+++ b/src/shared/cplusplus/CheckDeclarator.cpp
@@ -0,0 +1,258 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "CheckDeclarator.h"
+#include "Semantic.h"
+#include "AST.h"
+#include "Control.h"
+#include "TranslationUnit.h"
+#include "Literals.h"
+#include "CoreTypes.h"
+#include "Symbols.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+CheckDeclarator::CheckDeclarator(Semantic *semantic)
+ : SemanticCheck(semantic),
+ _declarator(0),
+ _scope(0),
+ _name(0)
+{ }
+
+CheckDeclarator::~CheckDeclarator()
+{ }
+
+FullySpecifiedType CheckDeclarator::check(DeclaratorAST *declarator,
+ FullySpecifiedType type,
+ Scope *scope,
+ Name **name)
+{
+ FullySpecifiedType previousType = switchFullySpecifiedType(type);
+ Scope *previousScope = switchScope(scope);
+ DeclaratorAST *previousDeclarator = switchDeclarator(declarator);
+ Name **previousName = switchName(name);
+ accept(declarator);
+ (void) switchName(previousName);
+ (void) switchDeclarator(previousDeclarator);
+ (void) switchScope(previousScope);
+ return switchFullySpecifiedType(previousType);
+}
+
+FullySpecifiedType CheckDeclarator::check(PtrOperatorAST *ptrOperators,
+ FullySpecifiedType type,
+ Scope *scope)
+{
+ FullySpecifiedType previousType = switchFullySpecifiedType(type);
+ Scope *previousScope = switchScope(scope);
+ accept(ptrOperators);
+ (void) switchScope(previousScope);
+ return switchFullySpecifiedType(previousType);
+}
+
+DeclaratorAST *CheckDeclarator::switchDeclarator(DeclaratorAST *declarator)
+{
+ DeclaratorAST *previousDeclarator = _declarator;
+ _declarator = declarator;
+ return previousDeclarator;
+}
+
+FullySpecifiedType CheckDeclarator::switchFullySpecifiedType(FullySpecifiedType type)
+{
+ FullySpecifiedType previousType = _fullySpecifiedType;
+ _fullySpecifiedType = type;
+ return previousType;
+}
+
+Scope *CheckDeclarator::switchScope(Scope *scope)
+{
+ Scope *previousScope = _scope;
+ _scope = scope;
+ return previousScope;
+}
+
+Name **CheckDeclarator::switchName(Name **name)
+{
+ Name **previousName = _name;
+ _name = name;
+ return previousName;
+}
+
+bool CheckDeclarator::visit(DeclaratorAST *ast)
+{
+ accept(ast->ptr_operators);
+ accept(ast->postfix_declarators);
+ accept(ast->core_declarator);
+
+ // ### check the initializer
+ // FullySpecifiedType exprTy = semantic()->check(ast->initializer, _scope);
+
+ if (ast->initializer && _fullySpecifiedType->isFunction()) {
+ _fullySpecifiedType->asFunction()->setPureVirtual(true);
+ }
+ return false;
+}
+
+bool CheckDeclarator::visit(DeclaratorIdAST *ast)
+{
+ Name *name = semantic()->check(ast->name, _scope);
+ if (_name)
+ *_name = name;
+ return false;
+}
+
+bool CheckDeclarator::visit(NestedDeclaratorAST *ast)
+{
+ accept(ast->declarator);
+ return false;
+}
+
+bool CheckDeclarator::visit(FunctionDeclaratorAST *ast)
+{
+ Function *fun = control()->newFunction(ast->firstToken());
+ fun->setReturnType(_fullySpecifiedType);
+
+ if (ast->parameters) {
+ DeclarationAST *parameter_declarations = ast->parameters->parameter_declarations;
+ for (DeclarationAST *decl = parameter_declarations; decl; decl = decl->next) {
+ semantic()->check(decl, fun->arguments());
+ }
+
+ if (ast->parameters->dot_dot_dot_token)
+ fun->setVariadic(true);
+ }
+
+ // check the arguments
+ bool hasDefaultArguments = false;
+ for (unsigned i = 0; i < fun->argumentCount(); ++i) {
+ Argument *arg = fun->argumentAt(i)->asArgument();
+ if (hasDefaultArguments && ! arg->hasInitializer()) {
+ translationUnit()->error(ast->firstToken(),
+ "default argument missing for parameter at position %d", i + 1);
+ } else if (! hasDefaultArguments) {
+ hasDefaultArguments = arg->hasInitializer();
+ }
+ }
+
+ FullySpecifiedType funTy(fun);
+ _fullySpecifiedType = funTy;
+
+ for (SpecifierAST *it = ast->cv_qualifier_seq; it; it = it->next) {
+ SimpleSpecifierAST *cv = static_cast<SimpleSpecifierAST *>(it);
+ int k = tokenKind(cv->specifier_token);
+ if (k == T_CONST)
+ fun->setConst(true);
+ else if (k == T_VOLATILE)
+ fun->setVolatile(true);
+ }
+
+ accept(ast->next);
+ return false;
+}
+
+bool CheckDeclarator::visit(ArrayDeclaratorAST *ast)
+{
+ ArrayType *ty = control()->arrayType(_fullySpecifiedType); // ### set the dimension
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ FullySpecifiedType arrTy(ty);
+ _fullySpecifiedType = ty;
+ accept(ast->next);
+ return false;
+}
+
+bool CheckDeclarator::visit(PointerToMemberAST *ast)
+{
+ Name *memberName = semantic()->check(ast->nested_name_specifier, _scope);
+ PointerToMemberType *ptrTy = control()->pointerToMemberType(memberName, _fullySpecifiedType);
+ FullySpecifiedType ty(ptrTy);
+ _fullySpecifiedType = ty;
+ applyCvQualifiers(ast->cv_qualifier_seq);
+ accept(ast->next);
+ return false;
+}
+
+bool CheckDeclarator::visit(PointerAST *ast)
+{
+ PointerType *ptrTy = control()->pointerType(_fullySpecifiedType);
+ FullySpecifiedType ty(ptrTy);
+ _fullySpecifiedType = ty;
+ applyCvQualifiers(ast->cv_qualifier_seq);
+ accept(ast->next);
+ return false;
+}
+
+bool CheckDeclarator::visit(ReferenceAST *ast)
+{
+ ReferenceType *refTy = control()->referenceType(_fullySpecifiedType);
+ FullySpecifiedType ty(refTy);
+ _fullySpecifiedType = ty;
+ accept(ast->next);
+ return false;
+}
+
+void CheckDeclarator::applyCvQualifiers(SpecifierAST *cv)
+{
+ for (; cv; cv = cv->next) {
+ SimpleSpecifierAST *spec = static_cast<SimpleSpecifierAST *>(cv);
+ switch (translationUnit()->tokenKind(spec->specifier_token)) {
+ case T_VOLATILE:
+ _fullySpecifiedType.setVolatile(true);
+ break;
+ case T_CONST:
+ _fullySpecifiedType.setConst(true);
+ break;
+ default:
+ break;
+ } // switch
+ }
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/CheckDeclarator.h b/src/shared/cplusplus/CheckDeclarator.h
new file mode 100644
index 0000000000..b1de623b00
--- /dev/null
+++ b/src/shared/cplusplus/CheckDeclarator.h
@@ -0,0 +1,110 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CHECKDECLARATOR_H
+#define CPLUSPLUS_CHECKDECLARATOR_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "SemanticCheck.h"
+#include "FullySpecifiedType.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT CheckDeclarator: public SemanticCheck
+{
+public:
+ CheckDeclarator(Semantic *semantic);
+ virtual ~CheckDeclarator();
+
+ FullySpecifiedType check(DeclaratorAST *declarator,
+ FullySpecifiedType type,
+ Scope *scope,
+ Name **name);
+
+ FullySpecifiedType check(PtrOperatorAST *ptrOperators,
+ FullySpecifiedType type,
+ Scope *scope);
+
+protected:
+ DeclaratorAST *switchDeclarator(DeclaratorAST *declarator);
+ FullySpecifiedType switchFullySpecifiedType(FullySpecifiedType type);
+ Scope *switchScope(Scope *scope);
+ Name **switchName(Name **name);
+
+ using ASTVisitor::visit;
+
+ virtual bool visit(DeclaratorAST *ast);
+ // ptr operators
+ virtual bool visit(PointerToMemberAST *ast);
+ virtual bool visit(PointerAST *ast);
+ virtual bool visit(ReferenceAST *ast);
+ // core declarators
+ virtual bool visit(DeclaratorIdAST *ast);
+ virtual bool visit(NestedDeclaratorAST *ast);
+ // postfix declarators
+ virtual bool visit(FunctionDeclaratorAST *ast);
+ virtual bool visit(ArrayDeclaratorAST *ast);
+
+ void applyCvQualifiers(SpecifierAST *cv);
+
+private:
+ DeclaratorAST *_declarator;
+ Scope *_scope;
+ Name **_name;
+ FullySpecifiedType _fullySpecifiedType;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CHECKDECLARATOR_H
diff --git a/src/shared/cplusplus/CheckExpression.cpp b/src/shared/cplusplus/CheckExpression.cpp
new file mode 100644
index 0000000000..e546a99a53
--- /dev/null
+++ b/src/shared/cplusplus/CheckExpression.cpp
@@ -0,0 +1,369 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "CheckExpression.h"
+#include "Semantic.h"
+#include "TranslationUnit.h"
+#include "AST.h"
+#include "Scope.h"
+#include "Literals.h"
+#include "CoreTypes.h"
+#include "Symbols.h"
+#include "Control.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+CheckExpression::CheckExpression(Semantic *semantic)
+ : SemanticCheck(semantic),
+ _expression(0),
+ _scope(0),
+ _checkOldStyleCasts(false)
+{ }
+
+CheckExpression::~CheckExpression()
+{ }
+
+FullySpecifiedType CheckExpression::check(ExpressionAST *expression, Scope *scope)
+{
+ FullySpecifiedType previousType = switchFullySpecifiedType(FullySpecifiedType());
+ Scope *previousScope = switchScope(scope);
+ ExpressionAST *previousExpression = switchExpression(expression);
+ accept(expression);
+ (void) switchExpression(previousExpression);
+ (void) switchScope(previousScope);
+ return switchFullySpecifiedType(previousType);
+}
+
+ExpressionAST *CheckExpression::switchExpression(ExpressionAST *expression)
+{
+ ExpressionAST *previousExpression = _expression;
+ _expression = expression;
+ return previousExpression;
+}
+
+FullySpecifiedType CheckExpression::switchFullySpecifiedType(FullySpecifiedType type)
+{
+ FullySpecifiedType previousType = _fullySpecifiedType;
+ _fullySpecifiedType = type;
+ return previousType;
+}
+
+Scope *CheckExpression::switchScope(Scope *scope)
+{
+ Scope *previousScope = _scope;
+ _scope = scope;
+ return previousScope;
+}
+
+bool CheckExpression::visit(ExpressionListAST *ast)
+{
+ for (ExpressionListAST *it = ast; it; it = it->next) {
+ FullySpecifiedType exprTy = semantic()->check(it->expression, _scope);
+ }
+ return false;
+}
+
+bool CheckExpression::visit(BinaryExpressionAST *ast)
+{
+ FullySpecifiedType leftExprTy = semantic()->check(ast->left_expression, _scope);
+ FullySpecifiedType rightExprTy = semantic()->check(ast->right_expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(CastExpressionAST *ast)
+{
+ FullySpecifiedType castTy = semantic()->check(ast->type_id, _scope);
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ if (_checkOldStyleCasts && ! castTy->isVoidType())
+ translationUnit()->warning(ast->firstToken(),
+ "ugly old style cast");
+ return false;
+}
+
+bool CheckExpression::visit(ConditionAST *ast)
+{
+ FullySpecifiedType typeSpecTy = semantic()->check(ast->type_specifier, _scope);
+ Name *name = 0;
+ FullySpecifiedType declTy = semantic()->check(ast->declarator, typeSpecTy.qualifiedType(),
+ _scope, &name);
+ Declaration *decl = control()->newDeclaration(ast->declarator->firstToken(), name);
+ decl->setType(declTy);
+ _scope->enterSymbol(decl);
+ return false;
+}
+
+bool CheckExpression::visit(ConditionalExpressionAST *ast)
+{
+ FullySpecifiedType condTy = semantic()->check(ast->condition, _scope);
+ FullySpecifiedType leftExprTy = semantic()->check(ast->left_expression, _scope);
+ FullySpecifiedType rightExprTy = semantic()->check(ast->right_expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(CppCastExpressionAST *ast)
+{
+ FullySpecifiedType typeIdTy = semantic()->check(ast->type_id, _scope);
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(DeleteExpressionAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(ArrayInitializerAST *ast)
+{
+ for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
+ FullySpecifiedType exprTy = semantic()->check(it->expression, _scope);
+ }
+ return false;
+}
+
+bool CheckExpression::visit(QualifiedNameAST *ast)
+{
+ Name *name = semantic()->check(ast, _scope);
+ _scope->addUse(ast->firstToken(), name);
+ return false;
+}
+
+bool CheckExpression::visit(OperatorFunctionIdAST *ast)
+{
+ Name *name = semantic()->check(ast, _scope);
+ _scope->addUse(ast->firstToken(), name);
+ return false;
+}
+
+bool CheckExpression::visit(ConversionFunctionIdAST *ast)
+{
+ Name *name = semantic()->check(ast, _scope);
+ _scope->addUse(ast->firstToken(), name);
+ return false;
+}
+
+bool CheckExpression::visit(SimpleNameAST *ast)
+{
+ Name *name = semantic()->check(ast, _scope);
+ _scope->addUse(ast->firstToken(), name);
+ return false;
+}
+
+bool CheckExpression::visit(DestructorNameAST *ast)
+{
+ Name *name = semantic()->check(ast, _scope);
+ _scope->addUse(ast->firstToken(), name);
+ return false;
+}
+
+bool CheckExpression::visit(TemplateIdAST *ast)
+{
+ Name *name = semantic()->check(ast, _scope);
+ _scope->addUse(ast->firstToken(), name);
+ return false;
+}
+
+bool CheckExpression::visit(NewExpressionAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ FullySpecifiedType typeIdTy = semantic()->check(ast->type_id, _scope);
+ // ### process new-typeid
+ // ### process new-initializer
+ return false;
+}
+
+bool CheckExpression::visit(TypeidExpressionAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(TypenameCallExpressionAST *ast)
+{
+ if (Name *name = semantic()->check(ast->name, _scope)) {
+ _scope->addUse(ast->name->firstToken(), name);
+ }
+ for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
+ FullySpecifiedType exprTy = semantic()->check(it->expression, _scope);
+ }
+ return false;
+}
+
+bool CheckExpression::visit(TypeConstructorCallAST *ast)
+{
+ FullySpecifiedType typeSpecTy = semantic()->check(ast->type_specifier, _scope);
+ for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
+ FullySpecifiedType exprTy = semantic()->check(it->expression, _scope);
+ }
+ return false;
+}
+
+bool CheckExpression::visit(PostfixExpressionAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->base_expression, _scope);
+ for (PostfixAST *fx = ast->postfix_expressions; fx; fx = fx->next) {
+ accept(fx); // ### not exactly.
+ }
+ return false;
+}
+
+bool CheckExpression::visit(SizeofExpressionAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(NumericLiteralAST *)
+{
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::Int));
+ return false;
+}
+
+bool CheckExpression::visit(BoolLiteralAST *)
+{
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::Bool));
+ return false;
+}
+
+bool CheckExpression::visit(StringLiteralAST *)
+{
+ IntegerType *charTy = control()->integerType(IntegerType::Char);
+ _fullySpecifiedType.setType(control()->pointerType(charTy));
+ return false;
+}
+
+bool CheckExpression::visit(ThisExpressionAST *)
+{
+ return false;
+}
+
+bool CheckExpression::visit(NestedExpressionAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(ThrowExpressionAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(TypeIdAST *ast)
+{
+ FullySpecifiedType typeSpecTy = semantic()->check(ast->type_specifier, _scope);
+ FullySpecifiedType declTy = semantic()->check(ast->declarator, typeSpecTy.qualifiedType(),
+ _scope);
+ _fullySpecifiedType = declTy;
+ return false;
+}
+
+bool CheckExpression::visit(UnaryExpressionAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(QtMethodAST *ast)
+{
+ Name *name = 0;
+ Scope dummy;
+ FullySpecifiedType methTy = semantic()->check(ast->declarator, FullySpecifiedType(),
+ &dummy, &name);
+ Function *fty = methTy->asFunction();
+ if (! fty)
+ translationUnit()->warning(ast->firstToken(), "expected a function declarator");
+ else {
+ for (unsigned i = 0; i < fty->argumentCount(); ++i) {
+ Symbol *arg = fty->argumentAt(i);
+ if (arg->name())
+ translationUnit()->warning(arg->sourceLocation(),
+ "argument should be anonymous");
+ }
+ }
+ return false;
+}
+
+bool CheckExpression::visit(CompoundLiteralAST *ast)
+{
+ /*FullySpecifiedType exprTy = */ semantic()->check(ast->type_id, _scope);
+ /*FullySpecifiedType initTy = */ semantic()->check(ast->initializer, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(CallAST *ast)
+{
+ for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
+ FullySpecifiedType exprTy = semantic()->check(it->expression, _scope);
+ }
+ return false;
+}
+
+bool CheckExpression::visit(ArrayAccessAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckExpression::visit(PostIncrDecrAST *)
+{
+ return false;
+}
+
+bool CheckExpression::visit(MemberAccessAST *ast)
+{
+ if (Name *name = semantic()->check(ast->member_name, _scope))
+ _scope->addUse(ast->member_name->firstToken(), name);
+ return false;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/CheckExpression.h b/src/shared/cplusplus/CheckExpression.h
new file mode 100644
index 0000000000..5b5ae884b7
--- /dev/null
+++ b/src/shared/cplusplus/CheckExpression.h
@@ -0,0 +1,127 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CHECKEXPRESSION_H
+#define CPLUSPLUS_CHECKEXPRESSION_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "SemanticCheck.h"
+#include "FullySpecifiedType.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT CheckExpression: public SemanticCheck
+{
+public:
+ CheckExpression(Semantic *semantic);
+ virtual ~CheckExpression();
+
+ FullySpecifiedType check(ExpressionAST *expression, Scope *scope);
+
+protected:
+ ExpressionAST *switchExpression(ExpressionAST *expression);
+ FullySpecifiedType switchFullySpecifiedType(FullySpecifiedType type);
+ Scope *switchScope(Scope *scope);
+
+ using ASTVisitor::visit;
+
+ virtual bool visit(ExpressionListAST *ast);
+ virtual bool visit(BinaryExpressionAST *ast);
+ virtual bool visit(CastExpressionAST *ast);
+ virtual bool visit(ConditionAST *ast);
+ virtual bool visit(ConditionalExpressionAST *ast);
+ virtual bool visit(CppCastExpressionAST *ast);
+ virtual bool visit(DeleteExpressionAST *ast);
+ virtual bool visit(ArrayInitializerAST *ast);
+ virtual bool visit(NewExpressionAST *ast);
+ virtual bool visit(TypeidExpressionAST *ast);
+ virtual bool visit(TypenameCallExpressionAST *ast);
+ virtual bool visit(TypeConstructorCallAST *ast);
+ virtual bool visit(PostfixExpressionAST *ast);
+ virtual bool visit(SizeofExpressionAST *ast);
+ virtual bool visit(NumericLiteralAST *ast);
+ virtual bool visit(BoolLiteralAST *ast);
+ virtual bool visit(ThisExpressionAST *ast);
+ virtual bool visit(NestedExpressionAST *ast);
+ virtual bool visit(StringLiteralAST *ast);
+ virtual bool visit(ThrowExpressionAST *ast);
+ virtual bool visit(TypeIdAST *ast);
+ virtual bool visit(UnaryExpressionAST *ast);
+ virtual bool visit(QtMethodAST *ast);
+ virtual bool visit(CompoundLiteralAST *ast);
+
+ //names
+ virtual bool visit(QualifiedNameAST *ast);
+ virtual bool visit(OperatorFunctionIdAST *ast);
+ virtual bool visit(ConversionFunctionIdAST *ast);
+ virtual bool visit(SimpleNameAST *ast);
+ virtual bool visit(DestructorNameAST *ast);
+ virtual bool visit(TemplateIdAST *ast);
+
+ // postfix expressions
+ virtual bool visit(CallAST *ast);
+ virtual bool visit(ArrayAccessAST *ast);
+ virtual bool visit(PostIncrDecrAST *ast);
+ virtual bool visit(MemberAccessAST *ast);
+
+private:
+ ExpressionAST *_expression;
+ FullySpecifiedType _fullySpecifiedType;
+ Scope *_scope;
+ bool _checkOldStyleCasts: 1;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CHECKEXPRESSION_H
diff --git a/src/shared/cplusplus/CheckName.cpp b/src/shared/cplusplus/CheckName.cpp
new file mode 100644
index 0000000000..09b90f3cb8
--- /dev/null
+++ b/src/shared/cplusplus/CheckName.cpp
@@ -0,0 +1,348 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "CheckName.h"
+#include "Semantic.h"
+#include "AST.h"
+#include "Control.h"
+#include "TranslationUnit.h"
+#include "Literals.h"
+#include "Names.h"
+#include "CoreTypes.h"
+#include "Symbols.h"
+#include <cassert>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+CheckName::CheckName(Semantic *semantic)
+ : SemanticCheck(semantic),
+ _name(0),
+ _scope(0)
+{ }
+
+CheckName::~CheckName()
+{ }
+
+Name *CheckName::check(NameAST *name, Scope *scope)
+{
+ Name *previousName = switchName(0);
+ Scope *previousScope = switchScope(scope);
+ accept(name);
+ (void) switchScope(previousScope);
+ return switchName(previousName);
+}
+
+Name *CheckName::check(NestedNameSpecifierAST *nested_name_specifier, Scope *scope)
+{
+ Name *previousName = switchName(0);
+ Scope *previousScope = switchScope(scope);
+
+ std::vector<Name *> names;
+ for (NestedNameSpecifierAST *it = nested_name_specifier;
+ it; it = it->next) {
+ names.push_back(semantic()->check(it->class_or_namespace_name, _scope));
+ }
+ _name = control()->qualifiedNameId(&names[0], names.size());
+
+ (void) switchScope(previousScope);
+ return switchName(previousName);
+}
+
+Name *CheckName::switchName(Name *name)
+{
+ Name *previousName = _name;
+ _name = name;
+ return previousName;
+}
+
+Scope *CheckName::switchScope(Scope *scope)
+{
+ Scope *previousScope = _scope;
+ _scope = scope;
+ return previousScope;
+}
+
+bool CheckName::visit(QualifiedNameAST *ast)
+{
+ std::vector<Name *> names;
+ for (NestedNameSpecifierAST *it = ast->nested_name_specifier;
+ it; it = it->next) {
+ names.push_back(semantic()->check(it->class_or_namespace_name, _scope));
+ }
+ names.push_back(semantic()->check(ast->unqualified_name, _scope));
+ _name = control()->qualifiedNameId(&names[0], names.size(),
+ ast->global_scope_token != 0);
+ return false;
+}
+
+bool CheckName::visit(OperatorFunctionIdAST *ast)
+{
+ assert(ast->op != 0);
+
+ OperatorNameId::Kind kind = OperatorNameId::InvalidOp;
+
+ switch (tokenKind(ast->op->op_token)) {
+ case T_NEW:
+ if (ast->op->open_token)
+ kind = OperatorNameId::NewArrayOp;
+ else
+ kind = OperatorNameId::NewOp;
+ break;
+
+ case T_DELETE:
+ if (ast->op->open_token)
+ kind = OperatorNameId::DeleteArrayOp;
+ else
+ kind = OperatorNameId::DeleteOp;
+ break;
+
+ case T_PLUS:
+ kind = OperatorNameId::PlusOp;
+ break;
+
+ case T_MINUS:
+ kind = OperatorNameId::MinusOp;
+ break;
+
+ case T_STAR:
+ kind = OperatorNameId::StarOp;
+ break;
+
+ case T_SLASH:
+ kind = OperatorNameId::SlashOp;
+ break;
+
+ case T_PERCENT:
+ kind = OperatorNameId::PercentOp;
+ break;
+
+ case T_CARET:
+ kind = OperatorNameId::CaretOp;
+ break;
+
+ case T_AMPER:
+ kind = OperatorNameId::AmpOp;
+ break;
+
+ case T_PIPE:
+ kind = OperatorNameId::PipeOp;
+ break;
+
+ case T_TILDE:
+ kind = OperatorNameId::TildeOp;
+ break;
+
+ case T_EXCLAIM:
+ kind = OperatorNameId::ExclaimOp;
+ break;
+
+ case T_EQUAL:
+ kind = OperatorNameId::EqualOp;
+ break;
+
+ case T_LESS:
+ kind = OperatorNameId::LessOp;
+ break;
+
+ case T_GREATER:
+ kind = OperatorNameId::GreaterOp;
+ break;
+
+ case T_PLUS_EQUAL:
+ kind = OperatorNameId::PlusEqualOp;
+ break;
+
+ case T_MINUS_EQUAL:
+ kind = OperatorNameId::MinusEqualOp;
+ break;
+
+ case T_STAR_EQUAL:
+ kind = OperatorNameId::StarEqualOp;
+ break;
+
+ case T_SLASH_EQUAL:
+ kind = OperatorNameId::SlashEqualOp;
+ break;
+
+ case T_PERCENT_EQUAL:
+ kind = OperatorNameId::PercentEqualOp;
+ break;
+
+ case T_CARET_EQUAL:
+ kind = OperatorNameId::CaretEqualOp;
+ break;
+
+ case T_AMPER_EQUAL:
+ kind = OperatorNameId::AmpEqualOp;
+ break;
+
+ case T_PIPE_EQUAL:
+ kind = OperatorNameId::PipeEqualOp;
+ break;
+
+ case T_LESS_LESS:
+ kind = OperatorNameId::LessLessOp;
+ break;
+
+ case T_GREATER_GREATER:
+ kind = OperatorNameId::GreaterGreaterOp;
+ break;
+
+ case T_LESS_LESS_EQUAL:
+ kind = OperatorNameId::LessLessEqualOp;
+ break;
+
+ case T_GREATER_GREATER_EQUAL:
+ kind = OperatorNameId::GreaterGreaterEqualOp;
+ break;
+
+ case T_EQUAL_EQUAL:
+ kind = OperatorNameId::EqualEqualOp;
+ break;
+
+ case T_EXCLAIM_EQUAL:
+ kind = OperatorNameId::ExclaimEqualOp;
+ break;
+
+ case T_LESS_EQUAL:
+ kind = OperatorNameId::LessEqualOp;
+ break;
+
+ case T_GREATER_EQUAL:
+ kind = OperatorNameId::GreaterEqualOp;
+ break;
+
+ case T_AMPER_AMPER:
+ kind = OperatorNameId::AmpAmpOp;
+ break;
+
+ case T_PIPE_PIPE:
+ kind = OperatorNameId::PipePipeOp;
+ break;
+
+ case T_PLUS_PLUS:
+ kind = OperatorNameId::PlusPlusOp;
+ break;
+
+ case T_MINUS_MINUS:
+ kind = OperatorNameId::MinusMinusOp;
+ break;
+
+ case T_COMMA:
+ kind = OperatorNameId::CommaOp;
+ break;
+
+ case T_ARROW_STAR:
+ kind = OperatorNameId::ArrowStarOp;
+ break;
+
+ case T_ARROW:
+ kind = OperatorNameId::ArrowOp;
+ break;
+
+ case T_LPAREN:
+ kind = OperatorNameId::FunctionCallOp;
+ break;
+
+ case T_LBRACKET:
+ kind = OperatorNameId::ArrayAccessOp;
+ break;
+
+ default:
+ kind = OperatorNameId::InvalidOp;
+ } // switch
+
+ _name = control()->operatorNameId(kind);
+ return false;
+}
+
+bool CheckName::visit(ConversionFunctionIdAST *ast)
+{
+ FullySpecifiedType ty = semantic()->check(ast->type_specifier, _scope);
+ ty = semantic()->check(ast->ptr_operators, ty, _scope);
+ _name = control()->conversionNameId(ty);
+ return false;
+}
+
+bool CheckName::visit(SimpleNameAST *ast)
+{
+ Identifier *id = identifier(ast->identifier_token);
+ _name = control()->nameId(id);
+ return false;
+}
+
+bool CheckName::visit(DestructorNameAST *ast)
+{
+ Identifier *id = identifier(ast->identifier_token);
+ _name = control()->destructorNameId(id);
+ return false;
+}
+
+bool CheckName::visit(TemplateIdAST *ast)
+{
+ Identifier *id = identifier(ast->identifier_token);
+ std::vector<FullySpecifiedType> templateArguments;
+ for (TemplateArgumentListAST *it = ast->template_arguments; it;
+ it = it->next) {
+ ExpressionAST *arg = it->template_argument;
+ FullySpecifiedType exprTy = semantic()->check(arg, _scope);
+ templateArguments.push_back(exprTy);
+ }
+ if (templateArguments.empty())
+ _name = control()->templateNameId(id);
+ else
+ _name = control()->templateNameId(id, &templateArguments[0],
+ templateArguments.size());
+ return false;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/CheckName.h b/src/shared/cplusplus/CheckName.h
new file mode 100644
index 0000000000..4b0631b002
--- /dev/null
+++ b/src/shared/cplusplus/CheckName.h
@@ -0,0 +1,92 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CHECKNAME_H
+#define CPLUSPLUS_CHECKNAME_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "SemanticCheck.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT CheckName: public SemanticCheck
+{
+public:
+ CheckName(Semantic *semantic);
+ virtual ~CheckName();
+
+ Name *check(NameAST *name, Scope *scope);
+ Name *check(NestedNameSpecifierAST *name, Scope *scope);
+
+protected:
+ Name *switchName(Name *name);
+ Scope *switchScope(Scope *scope);
+
+ using ASTVisitor::visit;
+
+ virtual bool visit(QualifiedNameAST *ast);
+ virtual bool visit(OperatorFunctionIdAST *ast);
+ virtual bool visit(ConversionFunctionIdAST *ast);
+ virtual bool visit(SimpleNameAST *ast);
+ virtual bool visit(DestructorNameAST *ast);
+ virtual bool visit(TemplateIdAST *ast);
+
+private:
+ Name *_name;
+ Scope *_scope;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CHECKNAME_H
diff --git a/src/shared/cplusplus/CheckSpecifier.cpp b/src/shared/cplusplus/CheckSpecifier.cpp
new file mode 100644
index 0000000000..eeb59eebcc
--- /dev/null
+++ b/src/shared/cplusplus/CheckSpecifier.cpp
@@ -0,0 +1,392 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "CheckSpecifier.h"
+#include "Semantic.h"
+#include "AST.h"
+#include "Token.h"
+#include "TranslationUnit.h"
+#include "Literals.h"
+#include "Names.h"
+#include "CoreTypes.h"
+#include "Symbols.h"
+#include "Control.h"
+#include "Scope.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+CheckSpecifier::CheckSpecifier(Semantic *semantic)
+ : SemanticCheck(semantic),
+ _specifier(0),
+ _scope(0)
+{ }
+
+CheckSpecifier::~CheckSpecifier()
+{ }
+
+FullySpecifiedType CheckSpecifier::check(SpecifierAST *specifier, Scope *scope)
+{
+ FullySpecifiedType previousType = switchFullySpecifiedType(FullySpecifiedType());
+ Scope *previousScope = switchScope(scope);
+ SpecifierAST *previousSpecifier = switchSpecifier(specifier);
+ accept(specifier);
+ (void) switchSpecifier(previousSpecifier);
+ (void) switchScope(previousScope);
+ return switchFullySpecifiedType(previousType);
+}
+
+SpecifierAST *CheckSpecifier::switchSpecifier(SpecifierAST *specifier)
+{
+ SpecifierAST *previousSpecifier = _specifier;
+ _specifier = specifier;
+ return previousSpecifier;
+}
+
+FullySpecifiedType CheckSpecifier::switchFullySpecifiedType(FullySpecifiedType type)
+{
+ FullySpecifiedType previousType = _fullySpecifiedType;
+ _fullySpecifiedType = type;
+ return previousType;
+}
+
+Scope *CheckSpecifier::switchScope(Scope *scope)
+{
+ Scope *previousScope = _scope;
+ _scope = scope;
+ return previousScope;
+}
+
+bool CheckSpecifier::visit(SimpleSpecifierAST *ast)
+{
+ switch (tokenKind(ast->specifier_token)) {
+ case T_CONST:
+ if (_fullySpecifiedType.isConst())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setConst(true);
+ break;
+
+ case T_VOLATILE:
+ if (_fullySpecifiedType.isVolatile())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setVolatile(true);
+ break;
+
+ case T_FRIEND:
+ if (_fullySpecifiedType.isFriend())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setFriend(true);
+ break;
+
+ case T_REGISTER:
+ if (_fullySpecifiedType.isRegister())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setRegister(true);
+ break;
+
+ case T_STATIC:
+ if (_fullySpecifiedType.isStatic())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setStatic(true);
+ break;
+
+ case T_EXTERN:
+ if (_fullySpecifiedType.isExtern())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setExtern(true);
+ break;
+
+ case T_MUTABLE:
+ if (_fullySpecifiedType.isMutable())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setMutable(true);
+ break;
+
+ case T_TYPEDEF:
+ if (_fullySpecifiedType.isTypedef())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setTypedef(true);
+ break;
+
+ case T_INLINE:
+ if (_fullySpecifiedType.isInline())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setInline(true);
+ break;
+
+ case T_VIRTUAL:
+ if (_fullySpecifiedType.isVirtual())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setVirtual(true);
+ break;
+
+ case T_EXPLICIT:
+ if (_fullySpecifiedType.isExplicit())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setExplicit(true);
+ break;
+
+ case T_SIGNED:
+ if (_fullySpecifiedType.isSigned())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setSigned(true);
+ break;
+
+ case T_UNSIGNED:
+ if (_fullySpecifiedType.isUnsigned())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate `%s'", spell(ast->specifier_token));
+ _fullySpecifiedType.setUnsigned(true);
+ break;
+
+ case T_CHAR:
+ if (_fullySpecifiedType.type())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::Char));
+ break;
+
+ case T_WCHAR_T:
+ if (_fullySpecifiedType.type())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::WideChar));
+ break;
+
+ case T_BOOL:
+ if (_fullySpecifiedType.type())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::Bool));
+ break;
+
+ case T_SHORT:
+ if (Type *tp = _fullySpecifiedType.type()) {
+ IntegerType *intType = control()->integerType(IntegerType::Int);
+ if (tp != intType)
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ }
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::Short));
+ break;
+
+ case T_INT:
+ if (Type *tp = _fullySpecifiedType.type()) {
+ IntegerType *shortType = control()->integerType(IntegerType::Short);
+ IntegerType *longType = control()->integerType(IntegerType::Long);
+ IntegerType *longLongType = control()->integerType(IntegerType::LongLong);
+ if (tp == shortType || tp == longType || tp == longLongType)
+ break;
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ }
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::Int));
+ break;
+
+ case T_LONG:
+ if (Type *tp = _fullySpecifiedType.type()) {
+ IntegerType *intType = control()->integerType(IntegerType::Int);
+ IntegerType *longType = control()->integerType(IntegerType::Long);
+ FloatType *doubleType = control()->floatType(FloatType::Double);
+ if (tp == longType) {
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::LongLong));
+ break;
+ } else if (tp == doubleType) {
+ _fullySpecifiedType.setType(control()->floatType(FloatType::LongDouble));
+ break;
+ } else if (tp != intType) {
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ }
+ }
+ _fullySpecifiedType.setType(control()->integerType(IntegerType::Long));
+ break;
+
+ case T_FLOAT:
+ if (_fullySpecifiedType.type())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ _fullySpecifiedType.setType(control()->floatType(FloatType::Float));
+ break;
+
+ case T_DOUBLE:
+ if (Type *tp = _fullySpecifiedType.type()) {
+ IntegerType *longType = control()->integerType(IntegerType::Long);
+ if (tp == longType) {
+ _fullySpecifiedType.setType(control()->floatType(FloatType::LongDouble));
+ break;
+ }
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ }
+ _fullySpecifiedType.setType(control()->floatType(FloatType::Double));
+ break;
+
+ case T_VOID:
+ if (_fullySpecifiedType.type())
+ translationUnit()->error(ast->specifier_token,
+ "duplicate data type in declaration");
+ _fullySpecifiedType.setType(control()->voidType());
+ break;
+
+ default:
+ break;
+ } // switch
+ accept(ast->next);
+ return false;
+}
+
+bool CheckSpecifier::visit(ClassSpecifierAST *ast)
+{
+ Name *className = semantic()->check(ast->name, _scope);
+ Class *klass = control()->newClass(ast->firstToken(), className);
+ unsigned classKey = tokenKind(ast->classkey_token);
+ if (classKey == T_CLASS)
+ klass->setClassKey(Class::ClassKey);
+ else if (classKey == T_STRUCT)
+ klass->setClassKey(Class::StructKey);
+ else if (classKey == T_UNION)
+ klass->setClassKey(Class::UnionKey);
+ klass->setVisibility(semantic()->currentVisibility());
+ _scope->enterSymbol(klass);
+ _fullySpecifiedType.setType(klass);
+
+ for (BaseSpecifierAST *base = ast->base_clause; base; base = base->next) {
+ Name *baseClassName = semantic()->check(base->name, _scope);
+ BaseClass *baseClass = control()->newBaseClass(ast->firstToken(), baseClassName);
+ if (base->token_virtual)
+ baseClass->setVirtual(true);
+ if (base->token_access_specifier) {
+ int accessSpecifier = tokenKind(base->token_access_specifier);
+ int visibility = semantic()->visibilityForAccessSpecifier(accessSpecifier);
+ baseClass->setVisibility(visibility);
+ }
+ klass->addBaseClass(baseClass);
+ }
+
+ int visibility = semantic()->visibilityForClassKey(classKey);
+ int previousVisibility = semantic()->switchVisibility(visibility);
+ int previousMethodKey = semantic()->switchMethodKey(Function::NormalMethod);
+
+ for (DeclarationAST *member = ast->member_specifiers;
+ member; member = member->next) {
+ semantic()->check(member, klass->members());
+ }
+
+ (void) semantic()->switchMethodKey(previousMethodKey);
+ (void) semantic()->switchVisibility(previousVisibility);
+
+ accept(ast->next);
+ return false;
+}
+
+bool CheckSpecifier::visit(NamedTypeSpecifierAST *ast)
+{
+ Name *name = semantic()->check(ast->name, _scope);
+ _fullySpecifiedType.setType(control()->namedType(name));
+ accept(ast->next);
+ return false;
+}
+
+bool CheckSpecifier::visit(ElaboratedTypeSpecifierAST *ast)
+{
+ Name *name = semantic()->check(ast->name, _scope);
+ _fullySpecifiedType.setType(control()->namedType(name));
+ accept(ast->next);
+ return false;
+}
+
+bool CheckSpecifier::visit(EnumSpecifierAST *ast)
+{
+ Name *name = semantic()->check(ast->name, _scope);
+ Enum *e = control()->newEnum(ast->firstToken(), name);
+ e->setVisibility(semantic()->currentVisibility());
+ _scope->enterSymbol(e);
+ _fullySpecifiedType.setType(e);
+ for (EnumeratorAST *enumerator = ast->enumerators; enumerator;
+ enumerator = enumerator->next) {
+ Identifier *id = identifier(enumerator->identifier_token);
+ if (! id)
+ continue;
+ NameId *enumeratorName = control()->nameId(id);
+ Declaration *decl = control()->newDeclaration(enumerator->firstToken(),
+ enumeratorName);
+ e->addMember(decl);
+ }
+ accept(ast->next);
+ return false;
+}
+
+bool CheckSpecifier::visit(TypeofSpecifierAST *ast)
+{
+ semantic()->check(ast->expression, _scope);
+ accept(ast->next);
+ return false;
+}
+
+bool CheckSpecifier::visit(AttributeSpecifierAST *)
+{
+ return false;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/CheckSpecifier.h b/src/shared/cplusplus/CheckSpecifier.h
new file mode 100644
index 0000000000..3e6ddc57ba
--- /dev/null
+++ b/src/shared/cplusplus/CheckSpecifier.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CHECKSPECIFIER_H
+#define CPLUSPLUS_CHECKSPECIFIER_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "SemanticCheck.h"
+#include "FullySpecifiedType.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT CheckSpecifier: public SemanticCheck
+{
+public:
+ CheckSpecifier(Semantic *semantic);
+ virtual ~CheckSpecifier();
+
+ FullySpecifiedType check(SpecifierAST *specifier, Scope *scope);
+
+protected:
+ SpecifierAST *switchSpecifier(SpecifierAST *specifier);
+ FullySpecifiedType switchFullySpecifiedType(FullySpecifiedType type);
+ Scope *switchScope(Scope *scope);
+
+ using ASTVisitor::visit;
+
+ virtual bool visit(SimpleSpecifierAST *ast);
+ virtual bool visit(ClassSpecifierAST *ast);
+ virtual bool visit(NamedTypeSpecifierAST *ast);
+ virtual bool visit(ElaboratedTypeSpecifierAST *ast);
+ virtual bool visit(EnumSpecifierAST *ast);
+ virtual bool visit(TypeofSpecifierAST *ast);
+ virtual bool visit(AttributeSpecifierAST *ast);
+
+private:
+ SpecifierAST *_specifier;
+ FullySpecifiedType _fullySpecifiedType;
+ Scope *_scope;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CHECKSPECIFIER_H
diff --git a/src/shared/cplusplus/CheckStatement.cpp b/src/shared/cplusplus/CheckStatement.cpp
new file mode 100644
index 0000000000..67902ff252
--- /dev/null
+++ b/src/shared/cplusplus/CheckStatement.cpp
@@ -0,0 +1,239 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "CheckStatement.h"
+#include "Semantic.h"
+#include "AST.h"
+#include "TranslationUnit.h"
+#include "Scope.h"
+#include "CoreTypes.h"
+#include "Control.h"
+#include "Symbols.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+CheckStatement::CheckStatement(Semantic *semantic)
+ : SemanticCheck(semantic),
+ _statement(0),
+ _scope(0)
+{ }
+
+CheckStatement::~CheckStatement()
+{ }
+
+void CheckStatement::check(StatementAST *statement, Scope *scope)
+{
+ Scope *previousScope = switchScope(scope);
+ StatementAST *previousStatement = switchStatement(statement);
+ accept(statement);
+ (void) switchStatement(previousStatement);
+ (void) switchScope(previousScope);
+}
+
+StatementAST *CheckStatement::switchStatement(StatementAST *statement)
+{
+ StatementAST *previousStatement = _statement;
+ _statement = statement;
+ return previousStatement;
+}
+
+Scope *CheckStatement::switchScope(Scope *scope)
+{
+ Scope *previousScope = _scope;
+ _scope = scope;
+ return previousScope;
+}
+
+bool CheckStatement::visit(CaseStatementAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ semantic()->check(ast->statement, _scope);
+ return false;
+}
+
+bool CheckStatement::visit(CompoundStatementAST *ast)
+{
+ Block *block = control()->newBlock(ast->lbrace_token);
+ _scope->enterSymbol(block);
+ Scope *previousScope = switchScope(block->members());
+ for (StatementAST *it = ast->statements; it; it = it->next) {
+ semantic()->check(it, _scope);
+ }
+ (void) switchScope(previousScope);
+ return false;
+}
+
+bool CheckStatement::visit(DeclarationStatementAST *ast)
+{
+ semantic()->check(ast->declaration, _scope);
+ return false;
+}
+
+bool CheckStatement::visit(DoStatementAST *ast)
+{
+ semantic()->check(ast->statement, _scope);
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckStatement::visit(ExpressionOrDeclarationStatementAST *ast)
+{
+// translationUnit()->warning(ast->firstToken(),
+// "ambiguous expression or declaration statement");
+ if (ast->declaration)
+ semantic()->check(ast->declaration, _scope);
+ else
+ semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckStatement::visit(ExpressionStatementAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckStatement::visit(ForStatementAST *ast)
+{
+ Block *block = control()->newBlock(ast->for_token);
+ _scope->enterSymbol(block);
+ Scope *previousScope = switchScope(block->members());
+ semantic()->check(ast->initializer, _scope);
+ FullySpecifiedType condTy = semantic()->check(ast->condition, _scope);
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ semantic()->check(ast->statement, _scope);
+ (void) switchScope(previousScope);
+ return false;
+}
+
+bool CheckStatement::visit(IfStatementAST *ast)
+{
+ Block *block = control()->newBlock(ast->if_token);
+ _scope->enterSymbol(block);
+ Scope *previousScope = switchScope(block->members());
+ FullySpecifiedType exprTy = semantic()->check(ast->condition, _scope);
+ semantic()->check(ast->statement, _scope);
+ semantic()->check(ast->else_statement, _scope);
+ (void) switchScope(previousScope);
+ return false;
+}
+
+bool CheckStatement::visit(LabeledStatementAST *ast)
+{
+ semantic()->check(ast->statement, _scope);
+ return false;
+}
+
+bool CheckStatement::visit(BreakStatementAST *)
+{
+ return false;
+}
+
+bool CheckStatement::visit(ContinueStatementAST *)
+{
+ return false;
+}
+
+bool CheckStatement::visit(GotoStatementAST *)
+{
+ return false;
+}
+
+bool CheckStatement::visit(ReturnStatementAST *ast)
+{
+ FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+ return false;
+}
+
+bool CheckStatement::visit(SwitchStatementAST *ast)
+{
+ Block *block = control()->newBlock(ast->switch_token);
+ _scope->enterSymbol(block);
+ Scope *previousScope = switchScope(block->members());
+ FullySpecifiedType condTy = semantic()->check(ast->condition, _scope);
+ semantic()->check(ast->statement, _scope);
+ (void) switchScope(previousScope);
+ return false;
+}
+
+bool CheckStatement::visit(TryBlockStatementAST *ast)
+{
+ semantic()->check(ast->statement, _scope);
+ for (CatchClauseAST *c = ast->catch_clause_seq; c; c = c->next) {
+ semantic()->check(c, _scope);
+ }
+ return false;
+}
+
+bool CheckStatement::visit(CatchClauseAST *ast)
+{
+ Block *block = control()->newBlock(ast->catch_token);
+ _scope->enterSymbol(block);
+ Scope *previousScope = switchScope(block->members());
+ semantic()->check(ast->exception_declaration, _scope);
+ semantic()->check(ast->statement, _scope);
+ (void) switchScope(previousScope);
+ return false;
+}
+
+bool CheckStatement::visit(WhileStatementAST *ast)
+{
+ Block *block = control()->newBlock(ast->while_token);
+ _scope->enterSymbol(block);
+ Scope *previousScope = switchScope(block->members());
+ FullySpecifiedType condTy = semantic()->check(ast->condition, _scope);
+ semantic()->check(ast->statement, _scope);
+ (void) switchScope(previousScope);
+ return false;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/CheckStatement.h b/src/shared/cplusplus/CheckStatement.h
new file mode 100644
index 0000000000..856f64be8f
--- /dev/null
+++ b/src/shared/cplusplus/CheckStatement.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CHECKSTATEMENT_H
+#define CPLUSPLUS_CHECKSTATEMENT_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "SemanticCheck.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT CheckStatement: public SemanticCheck
+{
+public:
+ CheckStatement(Semantic *semantic);
+ virtual ~CheckStatement();
+
+ void check(StatementAST *statement, Scope *scope);
+
+protected:
+ StatementAST *switchStatement(StatementAST *statement);
+ Scope *switchScope(Scope *scope);
+
+ using ASTVisitor::visit;
+
+ virtual bool visit(CaseStatementAST *ast);
+ virtual bool visit(CompoundStatementAST *ast);
+ virtual bool visit(DeclarationStatementAST *ast);
+ virtual bool visit(DoStatementAST *ast);
+ virtual bool visit(ExpressionOrDeclarationStatementAST *ast);
+ virtual bool visit(ExpressionStatementAST *ast);
+ virtual bool visit(ForStatementAST *ast);
+ virtual bool visit(IfStatementAST *ast);
+ virtual bool visit(LabeledStatementAST *ast);
+ virtual bool visit(BreakStatementAST *ast);
+ virtual bool visit(ContinueStatementAST *ast);
+ virtual bool visit(GotoStatementAST *ast);
+ virtual bool visit(ReturnStatementAST *ast);
+ virtual bool visit(SwitchStatementAST *ast);
+ virtual bool visit(TryBlockStatementAST *ast);
+ virtual bool visit(CatchClauseAST *ast);
+ virtual bool visit(WhileStatementAST *ast);
+
+private:
+ StatementAST *_statement;
+ Scope *_scope;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CHECKSTATEMENT_H
diff --git a/src/shared/cplusplus/Control.cpp b/src/shared/cplusplus/Control.cpp
new file mode 100644
index 0000000000..e44d84a1ae
--- /dev/null
+++ b/src/shared/cplusplus/Control.cpp
@@ -0,0 +1,636 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Control.h"
+#include "MemoryPool.h"
+#include "Literals.h"
+#include "LiteralTable.h"
+#include "TranslationUnit.h"
+#include "CoreTypes.h"
+#include "Symbols.h"
+#include "Names.h"
+#include "Array.h"
+#include <map> // ### replace me with LiteralTable
+#include <string>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+template <typename _Iterator>
+static void delete_map_entries(_Iterator first, _Iterator last)
+{
+ for (; first != last; ++first)
+ delete first->second;
+}
+
+template <typename _Map>
+static void delete_map_entries(const _Map &m)
+{ delete_map_entries(m.begin(), m.end()); }
+
+template <typename _Iterator>
+static void delete_array_entries(_Iterator first, _Iterator last)
+{
+ for (; first != last; ++first)
+ delete *first;
+}
+
+template <typename _Array>
+static void delete_array_entries(const _Array &a)
+{ delete_array_entries(a.begin(), a.end()); }
+
+class Control::Data
+{
+public:
+ Data(Control *control)
+ : control(control),
+ translationUnit(0),
+ diagnosticClient(0)
+ { }
+
+ ~Data()
+ {
+ // names
+ delete_map_entries(nameIds);
+ delete_map_entries(destructorNameIds);
+ delete_map_entries(operatorNameIds);
+ delete_map_entries(conversionNameIds);
+ delete_map_entries(qualifiedNameIds);
+ delete_map_entries(templateNameIds);
+
+ // types
+ delete_map_entries(integerTypes);
+ delete_map_entries(floatTypes);
+ delete_map_entries(pointerToMemberTypes);
+ delete_map_entries(pointerTypes);
+ delete_map_entries(referenceTypes);
+ delete_map_entries(arrayTypes);
+ delete_map_entries(namedTypes);
+
+ // symbols
+ delete_array_entries(declarations);
+ delete_array_entries(arguments);
+ delete_array_entries(functions);
+ delete_array_entries(baseClasses);
+ delete_array_entries(blocks);
+ delete_array_entries(classes);
+ delete_array_entries(namespaces);
+ delete_array_entries(usingNamespaceDirectives);
+ delete_array_entries(enums);
+ delete_array_entries(usingDeclarations);
+ }
+
+ NameId *findOrInsertNameId(Identifier *id)
+ {
+ if (! id)
+ return 0;
+ std::map<Identifier *, NameId *>::iterator it = nameIds.lower_bound(id);
+ if (it == nameIds.end() || it->first != id)
+ it = nameIds.insert(it, std::make_pair(id, new NameId(id)));
+ return it->second;
+ }
+
+ TemplateNameId *findOrInsertTemplateNameId(Identifier *id,
+ const std::vector<FullySpecifiedType> &templateArguments)
+ {
+ if (! id)
+ return 0;
+ const TemplateNameIdKey key(id, templateArguments);
+ std::map<TemplateNameIdKey, TemplateNameId *>::iterator it =
+ templateNameIds.lower_bound(key);
+ if (it == templateNameIds.end() || it->first != key) {
+ const FullySpecifiedType *args = 0;
+ if (templateArguments.size())
+ args = &templateArguments[0];
+ TemplateNameId *templ = new TemplateNameId(id, args,
+ templateArguments.size());
+ it = templateNameIds.insert(it, std::make_pair(key, templ));
+ }
+ return it->second;
+ }
+
+ DestructorNameId *findOrInsertDestructorNameId(Identifier *id)
+ {
+ if (! id)
+ return 0;
+ std::map<Identifier *, DestructorNameId *>::iterator it = destructorNameIds.lower_bound(id);
+ if (it == destructorNameIds.end() || it->first != id)
+ it = destructorNameIds.insert(it, std::make_pair(id, new DestructorNameId(id)));
+ return it->second;
+ }
+
+ OperatorNameId *findOrInsertOperatorNameId(int kind)
+ {
+ const int key(kind);
+ std::map<int, OperatorNameId *>::iterator it = operatorNameIds.lower_bound(key);
+ if (it == operatorNameIds.end() || it->first != key)
+ it = operatorNameIds.insert(it, std::make_pair(key, new OperatorNameId(kind)));
+ return it->second;
+ }
+
+ ConversionNameId *findOrInsertConversionNameId(FullySpecifiedType type)
+ {
+ std::map<FullySpecifiedType, ConversionNameId *>::iterator it =
+ conversionNameIds.lower_bound(type);
+ if (it == conversionNameIds.end() || it->first != type)
+ it = conversionNameIds.insert(it, std::make_pair(type, new ConversionNameId(type)));
+ return it->second;
+ }
+
+ QualifiedNameId *findOrInsertQualifiedNameId(const std::vector<Name *> &names, bool isGlobal)
+ {
+ const QualifiedNameIdKey key(names, isGlobal);
+ std::map<QualifiedNameIdKey, QualifiedNameId *>::iterator it =
+ qualifiedNameIds.lower_bound(key);
+ if (it == qualifiedNameIds.end() || it->first != key) {
+ QualifiedNameId *name = new QualifiedNameId(&names[0], names.size(), isGlobal);
+ it = qualifiedNameIds.insert(it, std::make_pair(key, name));
+ }
+ return it->second;
+ }
+
+ IntegerType *findOrInsertIntegerType(int kind)
+ {
+ const int key = int(kind);
+ std::map<int, IntegerType *>::iterator it = integerTypes.lower_bound(key);
+ if (it == integerTypes.end() || it->first != key)
+ it = integerTypes.insert(it, std::make_pair(key, new IntegerType(kind)));
+ return it->second;
+ }
+
+ FloatType *findOrInsertFloatType(int kind)
+ {
+ const int key = int(kind);
+ std::map<int, FloatType *>::iterator it = floatTypes.lower_bound(key);
+ if (it == floatTypes.end() || it->first != key)
+ it = floatTypes.insert(it, std::make_pair(key, new FloatType(kind)));
+ return it->second;
+ }
+
+ PointerToMemberType *findOrInsertPointerToMemberType(Name *memberName, FullySpecifiedType elementType)
+ {
+ const PointerToMemberTypeKey key(memberName, elementType);
+ std::map<PointerToMemberTypeKey, PointerToMemberType *>::iterator it =
+ pointerToMemberTypes.lower_bound(key);
+ if (it == pointerToMemberTypes.end() || it->first != key)
+ it = pointerToMemberTypes.insert(it, std::make_pair(key, new PointerToMemberType(memberName, elementType)));
+ return it->second;
+ }
+
+ PointerType *findOrInsertPointerType(FullySpecifiedType elementType)
+ {
+ std::map<FullySpecifiedType, PointerType *>::iterator it =
+ pointerTypes.lower_bound(elementType);
+ if (it == pointerTypes.end() || it->first != elementType)
+ it = pointerTypes.insert(it, std::make_pair(elementType, new PointerType(elementType)));
+ return it->second;
+ }
+
+ ReferenceType *findOrInsertReferenceType(FullySpecifiedType elementType)
+ {
+ std::map<FullySpecifiedType, ReferenceType *>::iterator it =
+ referenceTypes.lower_bound(elementType);
+ if (it == referenceTypes.end() || it->first != elementType)
+ it = referenceTypes.insert(it, std::make_pair(elementType, new ReferenceType(elementType)));
+ return it->second;
+ }
+
+ ArrayType *findOrInsertArrayType(FullySpecifiedType elementType, size_t size)
+ {
+ const ArrayKey key(elementType, size);
+ std::map<ArrayKey, ArrayType *>::iterator it =
+ arrayTypes.lower_bound(key);
+ if (it == arrayTypes.end() || it->first != key)
+ it = arrayTypes.insert(it, std::make_pair(key, new ArrayType(elementType, size)));
+ return it->second;
+ }
+
+ NamedType *findOrInsertNamedType(Name *name)
+ {
+ std::map<Name *, NamedType *>::iterator it = namedTypes.lower_bound(name);
+ if (it == namedTypes.end() || it->first != name)
+ it = namedTypes.insert(it, std::make_pair(name, new NamedType(name)));
+ return it->second;
+ }
+
+ Declaration *newDeclaration(unsigned sourceLocation, Name *name)
+ {
+ Declaration *declaration = new Declaration(translationUnit,
+ sourceLocation, name);
+ declarations.push_back(declaration);
+ return declaration;
+ }
+
+ Argument *newArgument(unsigned sourceLocation, Name *name)
+ {
+ Argument *argument = new Argument(translationUnit,
+ sourceLocation, name);
+ arguments.push_back(argument);
+ return argument;
+ }
+
+ Function *newFunction(unsigned sourceLocation, Name *name)
+ {
+ Function *function = new Function(translationUnit,
+ sourceLocation, name);
+ functions.push_back(function);
+ return function;
+ }
+
+ BaseClass *newBaseClass(unsigned sourceLocation, Name *name)
+ {
+ BaseClass *baseClass = new BaseClass(translationUnit,
+ sourceLocation, name);
+ baseClasses.push_back(baseClass);
+ return baseClass;
+ }
+
+ Block *newBlock(unsigned sourceLocation)
+ {
+ Block *block = new Block(translationUnit, sourceLocation);
+ blocks.push_back(block);
+ return block;
+ }
+
+ Class *newClass(unsigned sourceLocation, Name *name)
+ {
+ Class *klass = new Class(translationUnit,
+ sourceLocation, name);
+ classes.push_back(klass);
+ return klass;
+ }
+
+ Namespace *newNamespace(unsigned sourceLocation, Name *name)
+ {
+ Namespace *ns = new Namespace(translationUnit,
+ sourceLocation, name);
+ namespaces.push_back(ns);
+ return ns;
+ }
+
+ UsingNamespaceDirective *newUsingNamespaceDirective(unsigned sourceLocation, Name *name)
+ {
+ UsingNamespaceDirective *u = new UsingNamespaceDirective(translationUnit,
+ sourceLocation, name);
+ usingNamespaceDirectives.push_back(u);
+ return u;
+ }
+
+ Enum *newEnum(unsigned sourceLocation, Name *name)
+ {
+ Enum *e = new Enum(translationUnit,
+ sourceLocation, name);
+ enums.push_back(e);
+ return e;
+ }
+
+ UsingDeclaration *newUsingDeclaration(unsigned sourceLocation, Name *name)
+ {
+ UsingDeclaration *u = new UsingDeclaration(translationUnit,
+ sourceLocation, name);
+ usingDeclarations.push_back(u);
+ return u;
+ }
+
+ struct TemplateNameIdKey {
+ Identifier *id;
+ std::vector<FullySpecifiedType> templateArguments;
+
+ TemplateNameIdKey(Identifier *id, const std::vector<FullySpecifiedType> &templateArguments)
+ : id(id), templateArguments(templateArguments)
+ { }
+
+ bool operator == (const TemplateNameIdKey &other) const
+ { return id == other.id && templateArguments == other.templateArguments; }
+
+ bool operator != (const TemplateNameIdKey &other) const
+ { return ! operator==(other); }
+
+ bool operator < (const TemplateNameIdKey &other) const
+ {
+ if (id == other.id)
+ return std::lexicographical_compare(templateArguments.begin(),
+ templateArguments.end(),
+ other.templateArguments.begin(),
+ other.templateArguments.end());
+ return id < other.id;
+ }
+ };
+
+ struct QualifiedNameIdKey {
+ std::vector<Name *> names;
+ bool isGlobal;
+
+ QualifiedNameIdKey(const std::vector<Name *> &names, bool isGlobal) :
+ names(names), isGlobal(isGlobal)
+ { }
+
+ bool operator == (const QualifiedNameIdKey &other) const
+ { return isGlobal == other.isGlobal && names == other.names; }
+
+ bool operator != (const QualifiedNameIdKey &other) const
+ { return ! operator==(other); }
+
+ bool operator < (const QualifiedNameIdKey &other) const
+ {
+ if (isGlobal == other.isGlobal)
+ return std::lexicographical_compare(names.begin(), names.end(),
+ other.names.begin(), other.names.end());
+ return isGlobal < other.isGlobal;
+ }
+ };
+
+ struct ArrayKey {
+ FullySpecifiedType type;
+ size_t size;
+
+ ArrayKey() :
+ size(0)
+ { }
+
+ ArrayKey(FullySpecifiedType type, size_t size) :
+ type(type), size(size)
+ { }
+
+ bool operator == (const ArrayKey &other) const
+ { return type == other.type && size == other.size; }
+
+ bool operator != (const ArrayKey &other) const
+ { return ! operator==(other); }
+
+ bool operator < (const ArrayKey &other) const
+ {
+ if (type == other.type)
+ return size < other.size;
+ return type < other.type;
+ }
+ };
+
+ struct PointerToMemberTypeKey {
+ Name *memberName;
+ FullySpecifiedType type;
+
+ PointerToMemberTypeKey()
+ : memberName(0)
+ { }
+
+ PointerToMemberTypeKey(Name *memberName, FullySpecifiedType type)
+ : memberName(memberName), type(type)
+ { }
+
+ bool operator == (const PointerToMemberTypeKey &other) const
+ { return memberName == other.memberName && type == other.type; }
+
+ bool operator != (const PointerToMemberTypeKey &other) const
+ { return ! operator==(other); }
+
+ bool operator < (const PointerToMemberTypeKey &other) const
+ {
+ if (memberName == other.memberName)
+ return type < other.type;
+ return memberName < other.memberName;
+ }
+ };
+
+ Control *control;
+ TranslationUnit *translationUnit;
+ DiagnosticClient *diagnosticClient;
+ LiteralTable<Identifier> identifiers;
+ LiteralTable<StringLiteral> stringLiterals;
+ LiteralTable<NumericLiteral> numericLiterals;
+ LiteralTable<StringLiteral> fileNames;
+
+ // ### replace std::map with lookup tables. ASAP!
+
+ // names
+ std::map<Identifier *, NameId *> nameIds;
+ std::map<Identifier *, DestructorNameId *> destructorNameIds;
+ std::map<int, OperatorNameId *> operatorNameIds;
+ std::map<FullySpecifiedType, ConversionNameId *> conversionNameIds;
+ std::map<TemplateNameIdKey, TemplateNameId *> templateNameIds;
+ std::map<QualifiedNameIdKey, QualifiedNameId *> qualifiedNameIds;
+
+ // types
+ VoidType voidType;
+ std::map<int, IntegerType *> integerTypes;
+ std::map<int, FloatType *> floatTypes;
+ std::map<PointerToMemberTypeKey, PointerToMemberType *> pointerToMemberTypes;
+ std::map<FullySpecifiedType, PointerType *> pointerTypes;
+ std::map<FullySpecifiedType, ReferenceType *> referenceTypes;
+ std::map<ArrayKey, ArrayType *> arrayTypes;
+ std::map<Name *, NamedType *> namedTypes;
+
+ // symbols
+ std::vector<Declaration *> declarations;
+ std::vector<Argument *> arguments;
+ std::vector<Function *> functions;
+ std::vector<BaseClass *> baseClasses;
+ std::vector<Block *> blocks;
+ std::vector<Class *> classes;
+ std::vector<Namespace *> namespaces;
+ std::vector<UsingNamespaceDirective *> usingNamespaceDirectives;
+ std::vector<Enum *> enums;
+ std::vector<UsingDeclaration *> usingDeclarations;
+};
+
+Control::Control()
+{ d = new Data(this); }
+
+Control::~Control()
+{ delete d; }
+
+TranslationUnit *Control::translationUnit() const
+{ return d->translationUnit; }
+
+TranslationUnit *Control::switchTranslationUnit(TranslationUnit *unit)
+{
+ TranslationUnit *previousTranslationUnit = d->translationUnit;
+ d->translationUnit = unit;
+ return previousTranslationUnit;
+}
+
+DiagnosticClient *Control::diagnosticClient() const
+{ return d->diagnosticClient; }
+
+void Control::setDiagnosticClient(DiagnosticClient *diagnosticClient)
+{ d->diagnosticClient = diagnosticClient; }
+
+Identifier *Control::findOrInsertIdentifier(const char *chars, unsigned size)
+{ return d->identifiers.findOrInsertLiteral(chars, size); }
+
+Identifier *Control::findOrInsertIdentifier(const char *chars)
+{
+ unsigned length = std::char_traits<char>::length(chars);
+ return findOrInsertIdentifier(chars, length);
+}
+
+Control::IdentifierIterator Control::firstIdentifier() const
+{ return d->identifiers.begin(); }
+
+Control::IdentifierIterator Control::lastIdentifier() const
+{ return d->identifiers.end(); }
+
+StringLiteral *Control::findOrInsertStringLiteral(const char *chars, unsigned size)
+{ return d->stringLiterals.findOrInsertLiteral(chars, size); }
+
+StringLiteral *Control::findOrInsertStringLiteral(const char *chars)
+{
+ unsigned length = std::char_traits<char>::length(chars);
+ return findOrInsertStringLiteral(chars, length);
+}
+
+NumericLiteral *Control::findOrInsertNumericLiteral(const char *chars, unsigned size)
+{ return d->numericLiterals.findOrInsertLiteral(chars, size); }
+
+NumericLiteral *Control::findOrInsertNumericLiteral(const char *chars)
+{
+ unsigned length = std::char_traits<char>::length(chars);
+ return findOrInsertNumericLiteral(chars, length);
+}
+
+unsigned Control::fileNameCount() const
+{ return d->fileNames.size(); }
+
+StringLiteral *Control::fileNameAt(unsigned index) const
+{ return d->fileNames.at(index); }
+
+StringLiteral *Control::findOrInsertFileName(const char *chars, unsigned size)
+{ return d->fileNames.findOrInsertLiteral(chars, size); }
+
+StringLiteral *Control::findOrInsertFileName(const char *chars)
+{
+ unsigned length = std::char_traits<char>::length(chars);
+ return findOrInsertFileName(chars, length);
+}
+
+NameId *Control::nameId(Identifier *id)
+{ return d->findOrInsertNameId(id); }
+
+TemplateNameId *Control::templateNameId(Identifier *id,
+ FullySpecifiedType *const args,
+ unsigned argv)
+{
+ std::vector<FullySpecifiedType> templateArguments(args, args + argv);
+ return d->findOrInsertTemplateNameId(id, templateArguments);
+}
+
+DestructorNameId *Control::destructorNameId(Identifier *id)
+{ return d->findOrInsertDestructorNameId(id); }
+
+OperatorNameId *Control::operatorNameId(int kind)
+{ return d->findOrInsertOperatorNameId(kind); }
+
+ConversionNameId *Control::conversionNameId(FullySpecifiedType type)
+{ return d->findOrInsertConversionNameId(type); }
+
+QualifiedNameId *Control::qualifiedNameId(Name *const *names,
+ unsigned nameCount,
+ bool isGlobal)
+{
+ std::vector<Name *> classOrNamespaceNames(names, names + nameCount);
+ return d->findOrInsertQualifiedNameId(classOrNamespaceNames, isGlobal);
+}
+
+VoidType *Control::voidType()
+{ return &d->voidType; }
+
+IntegerType *Control::integerType(int kind)
+{ return d->findOrInsertIntegerType(kind); }
+
+FloatType *Control::floatType(int kind)
+{ return d->findOrInsertFloatType(kind); }
+
+PointerToMemberType *Control::pointerToMemberType(Name *memberName, FullySpecifiedType elementType)
+{ return d->findOrInsertPointerToMemberType(memberName, elementType); }
+
+PointerType *Control::pointerType(FullySpecifiedType elementType)
+{ return d->findOrInsertPointerType(elementType); }
+
+ReferenceType *Control::referenceType(FullySpecifiedType elementType)
+{ return d->findOrInsertReferenceType(elementType); }
+
+ArrayType *Control::arrayType(FullySpecifiedType elementType, size_t size)
+{ return d->findOrInsertArrayType(elementType, size); }
+
+NamedType *Control::namedType(Name *name)
+{ return d->findOrInsertNamedType(name); }
+
+Argument *Control::newArgument(unsigned sourceLocation, Name *name)
+{ return d->newArgument(sourceLocation, name); }
+
+Function *Control::newFunction(unsigned sourceLocation, Name *name)
+{ return d->newFunction(sourceLocation, name); }
+
+Namespace *Control::newNamespace(unsigned sourceLocation, Name *name)
+{ return d->newNamespace(sourceLocation, name); }
+
+BaseClass *Control::newBaseClass(unsigned sourceLocation, Name *name)
+{ return d->newBaseClass(sourceLocation, name); }
+
+Class *Control::newClass(unsigned sourceLocation, Name *name)
+{ return d->newClass(sourceLocation, name); }
+
+Enum *Control::newEnum(unsigned sourceLocation, Name *name)
+{ return d->newEnum(sourceLocation, name); }
+
+Block *Control::newBlock(unsigned sourceLocation)
+{ return d->newBlock(sourceLocation); }
+
+Declaration *Control::newDeclaration(unsigned sourceLocation, Name *name)
+{ return d->newDeclaration(sourceLocation, name); }
+
+UsingNamespaceDirective *Control::newUsingNamespaceDirective(unsigned sourceLocation,
+ Name *name)
+{ return d->newUsingNamespaceDirective(sourceLocation, name); }
+
+UsingDeclaration *Control::newUsingDeclaration(unsigned sourceLocation, Name *name)
+{ return d->newUsingDeclaration(sourceLocation, name); }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Control.h b/src/shared/cplusplus/Control.h
new file mode 100644
index 0000000000..98c1bacdd2
--- /dev/null
+++ b/src/shared/cplusplus/Control.h
@@ -0,0 +1,180 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CONTROL_H
+#define CPLUSPLUS_CONTROL_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include <cstddef>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Control
+{
+public:
+ Control();
+ ~Control();
+
+ TranslationUnit *translationUnit() const;
+ TranslationUnit *switchTranslationUnit(TranslationUnit *unit);
+
+ DiagnosticClient *diagnosticClient() const;
+ void setDiagnosticClient(DiagnosticClient *diagnosticClient);
+
+ /// Returns the canonical name id.
+ NameId *nameId(Identifier *id);
+
+ /// Returns the canonical template name id.
+ TemplateNameId *templateNameId(Identifier *id,
+ FullySpecifiedType *const args = 0,
+ unsigned argc = 0);
+
+ /// Returns the canonical destructor name id.
+ DestructorNameId *destructorNameId(Identifier *id);
+
+ /// Returns the canonical operator name id.
+ OperatorNameId *operatorNameId(int operatorId);
+
+ /// Returns the canonical conversion name id.
+ ConversionNameId *conversionNameId(FullySpecifiedType type);
+
+ /// Returns the canonical qualified name id.
+ QualifiedNameId *qualifiedNameId(Name *const *names,
+ unsigned nameCount,
+ bool isGlobal = false);
+
+ /// Returns a Type object of type VoidType.
+ VoidType *voidType();
+
+ /// Returns a Type object of type IntegerType.
+ IntegerType *integerType(int integerId);
+
+ /// Returns a Type object of type FloatType.
+ FloatType *floatType(int floatId);
+
+ /// Returns a Type object of type PointertoMemberType.
+ PointerToMemberType *pointerToMemberType(Name *memberName,
+ FullySpecifiedType elementType);
+
+ /// Returns a Type object of type PointerType.
+ PointerType *pointerType(FullySpecifiedType elementType);
+
+ /// Returns a Type object of type ReferenceType.
+ ReferenceType *referenceType(FullySpecifiedType elementType);
+
+ /// Retruns a Type object of type ArrayType.
+ ArrayType *arrayType(FullySpecifiedType elementType, size_t size = 0);
+
+ /// Returns a Type object of type NamedType.
+ NamedType *namedType(Name *name);
+
+ /// Creates a new Declaration symbol.
+ Declaration *newDeclaration(unsigned sourceLocation, Name *name = 0);
+
+ /// Creates a new Argument symbol.
+ Argument *newArgument(unsigned sourceLocation, Name *name = 0);
+
+ /// Creates a new Function symbol.
+ Function *newFunction(unsigned sourceLocation, Name *name = 0);
+
+ /// Creates a new Namespace symbol.
+ Namespace *newNamespace(unsigned sourceLocation, Name *name = 0);
+
+ /// Creates a new BaseClass symbol.
+ BaseClass *newBaseClass(unsigned sourceLocation, Name *name = 0);
+
+ /// Creates a new Class symbol.
+ Class *newClass(unsigned sourceLocation, Name *name = 0);
+
+ /// Creates a new Enum symbol.
+ Enum *newEnum(unsigned sourceLocation, Name *name = 0);
+
+ /// Creates a new Block symbol.
+ Block *newBlock(unsigned sourceLocation);
+
+ /// Creates a new UsingNamespaceDirective symbol.
+ UsingNamespaceDirective *newUsingNamespaceDirective(unsigned sourceLocation, Name *name = 0);
+
+ /// Creates a new UsingDeclaration symbol.
+ UsingDeclaration *newUsingDeclaration(unsigned sourceLocation, Name *name = 0);
+
+ Identifier *findOrInsertIdentifier(const char *chars, unsigned size);
+ Identifier *findOrInsertIdentifier(const char *chars);
+
+ typedef const Identifier *const *IdentifierIterator;
+
+ IdentifierIterator firstIdentifier() const;
+ IdentifierIterator lastIdentifier() const;
+
+ StringLiteral *findOrInsertStringLiteral(const char *chars, unsigned size);
+ StringLiteral *findOrInsertStringLiteral(const char *chars);
+
+ NumericLiteral *findOrInsertNumericLiteral(const char *chars, unsigned size);
+ NumericLiteral *findOrInsertNumericLiteral(const char *chars);
+
+ StringLiteral *findOrInsertFileName(const char *chars, unsigned size);
+ StringLiteral *findOrInsertFileName(const char *chars);
+
+ unsigned fileNameCount() const;
+ StringLiteral *fileNameAt(unsigned index) const;
+
+private:
+ class Data;
+ friend class Data;
+ Data *d;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CONTROL_H
diff --git a/src/shared/cplusplus/CoreTypes.cpp b/src/shared/cplusplus/CoreTypes.cpp
new file mode 100644
index 0000000000..cf5a3ca4fb
--- /dev/null
+++ b/src/shared/cplusplus/CoreTypes.cpp
@@ -0,0 +1,237 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "CoreTypes.h"
+#include "TypeVisitor.h"
+#include "Names.h"
+#include <algorithm>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+
+bool VoidType::isEqualTo(const Type *other) const
+{
+ const VoidType *o = other->asVoidType();
+ return o != 0;
+}
+
+void VoidType::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+PointerToMemberType::PointerToMemberType(Name *memberName, FullySpecifiedType elementType)
+ : _memberName(memberName),
+ _elementType(elementType)
+{ }
+
+PointerToMemberType::~PointerToMemberType()
+{ }
+
+Name *PointerToMemberType::memberName() const
+{ return _memberName; }
+
+FullySpecifiedType PointerToMemberType::elementType() const
+{ return _elementType; }
+
+bool PointerToMemberType::isEqualTo(const Type *other) const
+{
+ const PointerToMemberType *o = other->asPointerToMemberType();
+ if (! o)
+ return false;
+ else if (! _memberName->isEqualTo(o->_memberName))
+ return false;
+ return _elementType.isEqualTo(o->_elementType);
+}
+
+void PointerToMemberType::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+PointerType::PointerType(FullySpecifiedType elementType)
+ : _elementType(elementType)
+{ }
+
+PointerType::~PointerType()
+{ }
+
+bool PointerType::isEqualTo(const Type *other) const
+{
+ const PointerType *o = other->asPointerType();
+ if (! o)
+ return false;
+ return _elementType.isEqualTo(o->_elementType);
+}
+
+void PointerType::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+FullySpecifiedType PointerType::elementType() const
+{ return _elementType; }
+
+ReferenceType::ReferenceType(FullySpecifiedType elementType)
+ : _elementType(elementType)
+{ }
+
+ReferenceType::~ReferenceType()
+{ }
+
+bool ReferenceType::isEqualTo(const Type *other) const
+{
+ const ReferenceType *o = other->asReferenceType();
+ if (! o)
+ return false;
+ return _elementType.isEqualTo(o->_elementType);
+}
+
+void ReferenceType::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+FullySpecifiedType ReferenceType::elementType() const
+{ return _elementType; }
+
+IntegerType::IntegerType(int kind)
+ : _kind(kind)
+{ }
+
+IntegerType::~IntegerType()
+{ }
+
+bool IntegerType::isEqualTo(const Type *other) const
+{
+ const IntegerType *o = other->asIntegerType();
+ if (! o)
+ return false;
+ return _kind == o->_kind;
+}
+
+void IntegerType::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+int IntegerType::kind() const
+{ return _kind; }
+
+FloatType::FloatType(int kind)
+ : _kind(kind)
+{ }
+
+FloatType::~FloatType()
+{ }
+
+void FloatType::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+int FloatType::kind() const
+{ return _kind; }
+
+bool FloatType::isEqualTo(const Type *other) const
+{
+ const FloatType *o = other->asFloatType();
+ if (! o)
+ return false;
+ return _kind == o->_kind;
+}
+
+ArrayType::ArrayType(FullySpecifiedType elementType, size_t size)
+ : _elementType(elementType), _size(size)
+{ }
+
+ArrayType::~ArrayType()
+{ }
+
+bool ArrayType::isEqualTo(const Type *other) const
+{
+ const ArrayType *o = other->asArrayType();
+ if (! o)
+ return false;
+ else if (_size != o->_size)
+ return false;
+ return _elementType.isEqualTo(o->_elementType);
+}
+
+void ArrayType::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+FullySpecifiedType ArrayType::elementType() const
+{ return _elementType; }
+
+size_t ArrayType::size() const
+{ return _size; }
+
+NamedType::NamedType(Name *name)
+ : _name(name)
+{ }
+
+NamedType::~NamedType()
+{ }
+
+Name *NamedType::name() const
+{ return _name; }
+
+bool NamedType::isEqualTo(const Type *other) const
+{
+ const NamedType *o = other->asNamedType();
+ if (! o)
+ return false;
+
+ Name *name = _name;
+ if (QualifiedNameId *q = name->asQualifiedNameId())
+ name = q->unqualifiedNameId();
+
+ Name *otherName = o->name();
+ if (QualifiedNameId *q = otherName->asQualifiedNameId())
+ otherName = q->unqualifiedNameId();
+
+ return name->isEqualTo(otherName);
+}
+
+void NamedType::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/CoreTypes.h b/src/shared/cplusplus/CoreTypes.h
new file mode 100644
index 0000000000..c3c0461838
--- /dev/null
+++ b/src/shared/cplusplus/CoreTypes.h
@@ -0,0 +1,217 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_CORETYPES_H
+#define CPLUSPLUS_CORETYPES_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "Type.h"
+#include "FullySpecifiedType.h"
+#include <cstddef>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT VoidType: public Type
+{
+public:
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT IntegerType: public Type
+{
+public:
+ enum Kind {
+ Char,
+ WideChar,
+ Bool,
+ Short,
+ Int,
+ Long,
+ LongLong
+ };
+
+public:
+ IntegerType(int kind);
+ virtual ~IntegerType();
+
+ int kind() const;
+
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ int _kind;
+};
+
+class CPLUSPLUS_EXPORT FloatType: public Type
+{
+public:
+ enum Kind {
+ Float,
+ Double,
+ LongDouble
+ };
+
+public:
+ FloatType(int kind);
+ virtual ~FloatType();
+
+ int kind() const;
+
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ int _kind;
+};
+
+class CPLUSPLUS_EXPORT PointerType: public Type
+{
+public:
+ PointerType(FullySpecifiedType elementType);
+ virtual ~PointerType();
+
+ FullySpecifiedType elementType() const;
+
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ FullySpecifiedType _elementType;
+};
+
+class CPLUSPLUS_EXPORT PointerToMemberType: public Type
+{
+public:
+ PointerToMemberType(Name *memberName, FullySpecifiedType elementType);
+ virtual ~PointerToMemberType();
+
+ Name *memberName() const;
+ FullySpecifiedType elementType() const;
+
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ Name *_memberName;
+ FullySpecifiedType _elementType;
+};
+
+class CPLUSPLUS_EXPORT ReferenceType: public Type
+{
+public:
+ ReferenceType(FullySpecifiedType elementType);
+ virtual ~ReferenceType();
+
+ FullySpecifiedType elementType() const;
+
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ FullySpecifiedType _elementType;
+};
+
+class CPLUSPLUS_EXPORT ArrayType: public Type
+{
+public:
+ ArrayType(FullySpecifiedType elementType, size_t size);
+ virtual ~ArrayType();
+
+ FullySpecifiedType elementType() const;
+ size_t size() const;
+
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ FullySpecifiedType _elementType;
+ size_t _size;
+};
+
+class CPLUSPLUS_EXPORT NamedType: public Type
+{
+public:
+ NamedType(Name *name);
+ virtual ~NamedType();
+
+ Name *name() const;
+
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ Name *_name;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_CORETYPES_H
diff --git a/src/shared/cplusplus/DiagnosticClient.cpp b/src/shared/cplusplus/DiagnosticClient.cpp
new file mode 100644
index 0000000000..12670adef9
--- /dev/null
+++ b/src/shared/cplusplus/DiagnosticClient.cpp
@@ -0,0 +1,63 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "DiagnosticClient.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+DiagnosticClient::DiagnosticClient()
+{ }
+
+DiagnosticClient::~DiagnosticClient()
+{ }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/DiagnosticClient.h b/src/shared/cplusplus/DiagnosticClient.h
new file mode 100644
index 0000000000..6fa06887c6
--- /dev/null
+++ b/src/shared/cplusplus/DiagnosticClient.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_DIAGNOSTICCLIENT_H
+#define CPLUSPLUS_DIAGNOSTICCLIENT_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include <cstdarg>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT DiagnosticClient
+{
+ DiagnosticClient(const DiagnosticClient &other);
+ void operator =(const DiagnosticClient &other);
+
+public:
+ enum Level {
+ Warning,
+ Error,
+ Fatal
+ };
+
+ DiagnosticClient();
+ virtual ~DiagnosticClient();
+
+ virtual void report(int level,
+ StringLiteral *fileName,
+ unsigned line, unsigned column,
+ const char *format, va_list ap) = 0;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_DIAGNOSTICCLIENT_H
diff --git a/src/shared/cplusplus/FullySpecifiedType.cpp b/src/shared/cplusplus/FullySpecifiedType.cpp
new file mode 100644
index 0000000000..71dec2934b
--- /dev/null
+++ b/src/shared/cplusplus/FullySpecifiedType.cpp
@@ -0,0 +1,204 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "FullySpecifiedType.h"
+#include "Type.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+FullySpecifiedType::FullySpecifiedType(Type *type) :
+ _type(type), _flags(0)
+{ }
+
+FullySpecifiedType::~FullySpecifiedType()
+{ }
+
+bool FullySpecifiedType::isValid() const
+{ return _type != 0; }
+
+Type *FullySpecifiedType::type() const
+{ return _type; }
+
+void FullySpecifiedType::setType(Type *type)
+{ _type = type; }
+
+FullySpecifiedType FullySpecifiedType::qualifiedType() const
+{
+ FullySpecifiedType ty = *this;
+ ty.setFriend(false);
+ ty.setRegister(false);
+ ty.setStatic(false);
+ ty.setExtern(false);
+ ty.setMutable(false);
+ ty.setTypedef(false);
+ return ty;
+}
+
+bool FullySpecifiedType::isConst() const
+{ return _isConst; }
+
+void FullySpecifiedType::setConst(bool isConst)
+{ _isConst = isConst; }
+
+bool FullySpecifiedType::isVolatile() const
+{ return _isVolatile; }
+
+void FullySpecifiedType::setVolatile(bool isVolatile)
+{ _isVolatile = isVolatile; }
+
+bool FullySpecifiedType::isSigned() const
+{ return _isSigned; }
+
+void FullySpecifiedType::setSigned(bool isSigned)
+{ _isSigned = isSigned; }
+
+bool FullySpecifiedType::isUnsigned() const
+{ return _isUnsigned; }
+
+void FullySpecifiedType::setUnsigned(bool isUnsigned)
+{ _isUnsigned = isUnsigned; }
+
+bool FullySpecifiedType::isFriend() const
+{ return _isFriend; }
+
+void FullySpecifiedType::setFriend(bool isFriend)
+{ _isFriend = isFriend; }
+
+bool FullySpecifiedType::isRegister() const
+{ return _isRegister; }
+
+void FullySpecifiedType::setRegister(bool isRegister)
+{ _isRegister = isRegister; }
+
+bool FullySpecifiedType::isStatic() const
+{ return _isStatic; }
+
+void FullySpecifiedType::setStatic(bool isStatic)
+{ _isStatic = isStatic; }
+
+bool FullySpecifiedType::isExtern() const
+{ return _isExtern; }
+
+void FullySpecifiedType::setExtern(bool isExtern)
+{ _isExtern = isExtern; }
+
+bool FullySpecifiedType::isMutable() const
+{ return _isMutable; }
+
+void FullySpecifiedType::setMutable(bool isMutable)
+{ _isMutable = isMutable; }
+
+bool FullySpecifiedType::isTypedef() const
+{ return _isTypedef; }
+
+void FullySpecifiedType::setTypedef(bool isTypedef)
+{ _isTypedef = isTypedef; }
+
+bool FullySpecifiedType::isInline() const
+{ return _isInline; }
+
+void FullySpecifiedType::setInline(bool isInline)
+{ _isInline = isInline; }
+
+bool FullySpecifiedType::isVirtual() const
+{ return _isVirtual; }
+
+void FullySpecifiedType::setVirtual(bool isVirtual)
+{ _isVirtual = isVirtual; }
+
+bool FullySpecifiedType::isExplicit() const
+{ return _isExplicit; }
+
+void FullySpecifiedType::setExplicit(bool isExplicit)
+{ _isExplicit = isExplicit; }
+
+bool FullySpecifiedType::isEqualTo(const FullySpecifiedType &other) const
+{
+ if (_flags != other._flags)
+ return false;
+ if (_type == other._type)
+ return true;
+ else if (! _type)
+ return false;
+ else
+ return _type->isEqualTo(other._type);
+}
+
+Type &FullySpecifiedType::operator*()
+{ return *_type; }
+
+FullySpecifiedType::operator bool() const
+{ return _type != 0; }
+
+const Type &FullySpecifiedType::operator*() const
+{ return *_type; }
+
+Type *FullySpecifiedType::operator->()
+{ return _type; }
+
+const Type *FullySpecifiedType::operator->() const
+{ return _type; }
+
+bool FullySpecifiedType::operator == (const FullySpecifiedType &other) const
+{ return _type == other._type && _flags == other._flags; }
+
+bool FullySpecifiedType::operator != (const FullySpecifiedType &other) const
+{ return ! operator ==(other); }
+
+bool FullySpecifiedType::operator < (const FullySpecifiedType &other) const
+{
+ if (_type == other._type)
+ return _flags < other._flags;
+ return _type < other._type;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/FullySpecifiedType.h b/src/shared/cplusplus/FullySpecifiedType.h
new file mode 100644
index 0000000000..d156fff5ab
--- /dev/null
+++ b/src/shared/cplusplus/FullySpecifiedType.h
@@ -0,0 +1,158 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_FULLYSPECIFIEDTYPE_H
+#define CPLUSPLUS_FULLYSPECIFIEDTYPE_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT FullySpecifiedType
+{
+public:
+ FullySpecifiedType(Type *type = 0);
+ ~FullySpecifiedType();
+
+ bool isValid() const;
+ operator bool() const;
+
+ Type *type() const;
+ void setType(Type *type);
+
+ FullySpecifiedType qualifiedType() const;
+
+ bool isConst() const;
+ void setConst(bool isConst);
+
+ bool isVolatile() const;
+ void setVolatile(bool isVolatile);
+
+ bool isSigned() const;
+ void setSigned(bool isSigned);
+
+ bool isUnsigned() const;
+ void setUnsigned(bool isUnsigned);
+
+ bool isFriend() const;
+ void setFriend(bool isFriend);
+
+ bool isRegister() const;
+ void setRegister(bool isRegister);
+
+ bool isStatic() const;
+ void setStatic(bool isStatic);
+
+ bool isExtern() const;
+ void setExtern(bool isExtern);
+
+ bool isMutable() const;
+ void setMutable(bool isMutable);
+
+ bool isTypedef() const;
+ void setTypedef(bool isTypedef);
+
+ bool isInline() const;
+ void setInline(bool isInline);
+
+ bool isVirtual() const;
+ void setVirtual(bool isVirtual);
+
+ bool isExplicit() const;
+ void setExplicit(bool isExplicit);
+
+ bool isEqualTo(const FullySpecifiedType &other) const;
+
+ Type &operator*();
+ const Type &operator*() const;
+
+ Type *operator->();
+ const Type *operator->() const;
+
+ bool operator == (const FullySpecifiedType &other) const;
+ bool operator != (const FullySpecifiedType &other) const;
+ bool operator < (const FullySpecifiedType &other) const;
+
+private:
+ Type *_type;
+ union {
+ unsigned _flags;
+ struct {
+ // cv qualifiers
+ unsigned _isConst: 1;
+ unsigned _isVolatile: 1;
+
+ // sign
+ unsigned _isSigned: 1;
+ unsigned _isUnsigned: 1;
+
+ // storage class specifiers
+ unsigned _isFriend: 1;
+ unsigned _isRegister: 1;
+ unsigned _isStatic: 1;
+ unsigned _isExtern: 1;
+ unsigned _isMutable: 1;
+ unsigned _isTypedef: 1;
+
+ // function specifiers
+ unsigned _isInline: 1;
+ unsigned _isVirtual: 1;
+ unsigned _isExplicit: 1;
+ };
+ };
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_FULLYSPECIFIEDTYPE_H
diff --git a/src/shared/cplusplus/Keywords.cpp b/src/shared/cplusplus/Keywords.cpp
new file mode 100644
index 0000000000..180feb341d
--- /dev/null
+++ b/src/shared/cplusplus/Keywords.cpp
@@ -0,0 +1,1348 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Lexer.h"
+#include "Token.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+static inline int classify2(const char *s, bool) {
+ if (s[0] == 'd') {
+ if (s[1] == 'o') {
+ return T_DO;
+ }
+ }
+ else if (s[0] == 'i') {
+ if (s[1] == 'f') {
+ return T_IF;
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify3(const char *s, bool) {
+ if (s[0] == 'a') {
+ if (s[1] == 's') {
+ if (s[2] == 'm') {
+ return T_ASM;
+ }
+ }
+ }
+ else if (s[0] == 'f') {
+ if (s[1] == 'o') {
+ if (s[2] == 'r') {
+ return T_FOR;
+ }
+ }
+ }
+ else if (s[0] == 'i') {
+ if (s[1] == 'n') {
+ if (s[2] == 't') {
+ return T_INT;
+ }
+ }
+ }
+ else if (s[0] == 'n') {
+ if (s[1] == 'e') {
+ if (s[2] == 'w') {
+ return T_NEW;
+ }
+ }
+ }
+ else if (s[0] == 't') {
+ if (s[1] == 'r') {
+ if (s[2] == 'y') {
+ return T_TRY;
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify4(const char *s, bool q) {
+ if (s[0] == 'a') {
+ if (s[1] == 'u') {
+ if (s[2] == 't') {
+ if (s[3] == 'o') {
+ return T_AUTO;
+ }
+ }
+ }
+ }
+ else if (s[0] == 'b') {
+ if (s[1] == 'o') {
+ if (s[2] == 'o') {
+ if (s[3] == 'l') {
+ return T_BOOL;
+ }
+ }
+ }
+ }
+ else if (s[0] == 'c') {
+ if (s[1] == 'a') {
+ if (s[2] == 's') {
+ if (s[3] == 'e') {
+ return T_CASE;
+ }
+ }
+ }
+ else if (s[1] == 'h') {
+ if (s[2] == 'a') {
+ if (s[3] == 'r') {
+ return T_CHAR;
+ }
+ }
+ }
+ }
+ else if (s[0] == 'e') {
+ if (s[1] == 'l') {
+ if (s[2] == 's') {
+ if (s[3] == 'e') {
+ return T_ELSE;
+ }
+ }
+ }
+ else if (s[1] == 'n') {
+ if (s[2] == 'u') {
+ if (s[3] == 'm') {
+ return T_ENUM;
+ }
+ }
+ }
+ }
+ else if (s[0] == 'g') {
+ if (s[1] == 'o') {
+ if (s[2] == 't') {
+ if (s[3] == 'o') {
+ return T_GOTO;
+ }
+ }
+ }
+ }
+ else if (s[0] == 'l') {
+ if (s[1] == 'o') {
+ if (s[2] == 'n') {
+ if (s[3] == 'g') {
+ return T_LONG;
+ }
+ }
+ }
+ }
+ else if (s[0] == 't') {
+ if (s[1] == 'h') {
+ if (s[2] == 'i') {
+ if (s[3] == 's') {
+ return T_THIS;
+ }
+ }
+ }
+ else if (s[1] == 'r') {
+ if (s[2] == 'u') {
+ if (s[3] == 'e') {
+ return T_TRUE;
+ }
+ }
+ }
+ }
+ else if (s[0] == 'v') {
+ if (s[1] == 'o') {
+ if (s[2] == 'i') {
+ if (s[3] == 'd') {
+ return T_VOID;
+ }
+ }
+ }
+ }
+ else if (q && s[0] == 'S') {
+ if (s[1] == 'L') {
+ if (s[2] == 'O') {
+ if (s[3] == 'T') {
+ return T_SLOT;
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify5(const char *s, bool q) {
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'a') {
+ if (s[3] == 's') {
+ if (s[4] == 'm') {
+ return T___ASM;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'b') {
+ if (s[1] == 'r') {
+ if (s[2] == 'e') {
+ if (s[3] == 'a') {
+ if (s[4] == 'k') {
+ return T_BREAK;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'c') {
+ if (s[1] == 'a') {
+ if (s[2] == 't') {
+ if (s[3] == 'c') {
+ if (s[4] == 'h') {
+ return T_CATCH;
+ }
+ }
+ }
+ }
+ else if (s[1] == 'l') {
+ if (s[2] == 'a') {
+ if (s[3] == 's') {
+ if (s[4] == 's') {
+ return T_CLASS;
+ }
+ }
+ }
+ }
+ else if (s[1] == 'o') {
+ if (s[2] == 'n') {
+ if (s[3] == 's') {
+ if (s[4] == 't') {
+ return T_CONST;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'f') {
+ if (s[1] == 'a') {
+ if (s[2] == 'l') {
+ if (s[3] == 's') {
+ if (s[4] == 'e') {
+ return T_FALSE;
+ }
+ }
+ }
+ }
+ else if (s[1] == 'l') {
+ if (s[2] == 'o') {
+ if (s[3] == 'a') {
+ if (s[4] == 't') {
+ return T_FLOAT;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 's') {
+ if (s[1] == 'h') {
+ if (s[2] == 'o') {
+ if (s[3] == 'r') {
+ if (s[4] == 't') {
+ return T_SHORT;
+ }
+ }
+ }
+ }
+ else if (q) {
+ if (s[1] == 'l') {
+ if (s[2] == 'o') {
+ if (s[3] == 't') {
+ if (s[4] == 's') {
+ return T_SLOTS;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 't') {
+ if (s[1] == 'h') {
+ if (s[2] == 'r') {
+ if (s[3] == 'o') {
+ if (s[4] == 'w') {
+ return T_THROW;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'u') {
+ if (s[1] == 'n') {
+ if (s[2] == 'i') {
+ if (s[3] == 'o') {
+ if (s[4] == 'n') {
+ return T_UNION;
+ }
+ }
+ }
+ }
+ else if (s[1] == 's') {
+ if (s[2] == 'i') {
+ if (s[3] == 'n') {
+ if (s[4] == 'g') {
+ return T_USING;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'w') {
+ if (s[1] == 'h') {
+ if (s[2] == 'i') {
+ if (s[3] == 'l') {
+ if (s[4] == 'e') {
+ return T_WHILE;
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify6(const char *s, bool q) {
+ if (s[0] == 'd') {
+ if (s[1] == 'e') {
+ if (s[2] == 'l') {
+ if (s[3] == 'e') {
+ if (s[4] == 't') {
+ if (s[5] == 'e') {
+ return T_DELETE;
+ }
+ }
+ }
+ }
+ }
+ else if (s[1] == 'o') {
+ if (s[2] == 'u') {
+ if (s[3] == 'b') {
+ if (s[4] == 'l') {
+ if (s[5] == 'e') {
+ return T_DOUBLE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'e') {
+ if (s[1] == 'x') {
+ if (s[2] == 'p') {
+ if (s[3] == 'o') {
+ if (s[4] == 'r') {
+ if (s[5] == 't') {
+ return T_EXPORT;
+ }
+ }
+ }
+ }
+ else if (s[2] == 't') {
+ if (s[3] == 'e') {
+ if (s[4] == 'r') {
+ if (s[5] == 'n') {
+ return T_EXTERN;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'f') {
+ if (s[1] == 'r') {
+ if (s[2] == 'i') {
+ if (s[3] == 'e') {
+ if (s[4] == 'n') {
+ if (s[5] == 'd') {
+ return T_FRIEND;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'i') {
+ if (s[1] == 'n') {
+ if (s[2] == 'l') {
+ if (s[3] == 'i') {
+ if (s[4] == 'n') {
+ if (s[5] == 'e') {
+ return T_INLINE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'p') {
+ if (s[1] == 'u') {
+ if (s[2] == 'b') {
+ if (s[3] == 'l') {
+ if (s[4] == 'i') {
+ if (s[5] == 'c') {
+ return T_PUBLIC;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'r') {
+ if (s[1] == 'e') {
+ if (s[2] == 't') {
+ if (s[3] == 'u') {
+ if (s[4] == 'r') {
+ if (s[5] == 'n') {
+ return T_RETURN;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 's') {
+ if (s[1] == 'i') {
+ if (s[2] == 'g') {
+ if (s[3] == 'n') {
+ if (s[4] == 'e') {
+ if (s[5] == 'd') {
+ return T_SIGNED;
+ }
+ }
+ }
+ }
+ else if (s[2] == 'z') {
+ if (s[3] == 'e') {
+ if (s[4] == 'o') {
+ if (s[5] == 'f') {
+ return T_SIZEOF;
+ }
+ }
+ }
+ }
+ }
+ else if (s[1] == 't') {
+ if (s[2] == 'a') {
+ if (s[3] == 't') {
+ if (s[4] == 'i') {
+ if (s[5] == 'c') {
+ return T_STATIC;
+ }
+ }
+ }
+ }
+ else if (s[2] == 'r') {
+ if (s[3] == 'u') {
+ if (s[4] == 'c') {
+ if (s[5] == 't') {
+ return T_STRUCT;
+ }
+ }
+ }
+ }
+ }
+ else if (s[1] == 'w') {
+ if (s[2] == 'i') {
+ if (s[3] == 't') {
+ if (s[4] == 'c') {
+ if (s[5] == 'h') {
+ return T_SWITCH;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 't') {
+ if (s[1] == 'y') {
+ if (s[2] == 'p') {
+ if (s[3] == 'e') {
+ if (s[4] == 'i') {
+ if (s[5] == 'd') {
+ return T_TYPEID;
+ }
+ }
+ else if (s[4] == 'o') {
+ if (s[5] == 'f') {
+ return T_TYPEOF;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (q && s[0] == 'S') {
+ if (s[1] == 'I') {
+ if (s[2] == 'G') {
+ if (s[3] == 'N') {
+ if (s[4] == 'A') {
+ if (s[5] == 'L') {
+ return T_SIGNAL;
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify7(const char *s, bool q) {
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'a') {
+ if (s[3] == 's') {
+ if (s[4] == 'm') {
+ if (s[5] == '_') {
+ if (s[6] == '_') {
+ return T___ASM__;
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 'c') {
+ if (s[3] == 'o') {
+ if (s[4] == 'n') {
+ if (s[5] == 's') {
+ if (s[6] == 't') {
+ return T___CONST;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'd') {
+ if (s[1] == 'e') {
+ if (s[2] == 'f') {
+ if (s[3] == 'a') {
+ if (s[4] == 'u') {
+ if (s[5] == 'l') {
+ if (s[6] == 't') {
+ return T_DEFAULT;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'm') {
+ if (s[1] == 'u') {
+ if (s[2] == 't') {
+ if (s[3] == 'a') {
+ if (s[4] == 'b') {
+ if (s[5] == 'l') {
+ if (s[6] == 'e') {
+ return T_MUTABLE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'p') {
+ if (s[1] == 'r') {
+ if (s[2] == 'i') {
+ if (s[3] == 'v') {
+ if (s[4] == 'a') {
+ if (s[5] == 't') {
+ if (s[6] == 'e') {
+ return T_PRIVATE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (q && s[0] == 's') {
+ if (s[1] == 'i') {
+ if (s[2] == 'g') {
+ if (s[3] == 'n') {
+ if (s[4] == 'a') {
+ if (s[5] == 'l') {
+ if (s[6] == 's') {
+ return T_SIGNALS;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 't') {
+ if (s[1] == 'y') {
+ if (s[2] == 'p') {
+ if (s[3] == 'e') {
+ if (s[4] == 'd') {
+ if (s[5] == 'e') {
+ if (s[6] == 'f') {
+ return T_TYPEDEF;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'v') {
+ if (s[1] == 'i') {
+ if (s[2] == 'r') {
+ if (s[3] == 't') {
+ if (s[4] == 'u') {
+ if (s[5] == 'a') {
+ if (s[6] == 'l') {
+ return T_VIRTUAL;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'w') {
+ if (s[1] == 'c') {
+ if (s[2] == 'h') {
+ if (s[3] == 'a') {
+ if (s[4] == 'r') {
+ if (s[5] == '_') {
+ if (s[6] == 't') {
+ return T_WCHAR_T;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (q && s[0] == 'Q') {
+ if (s[1] == '_') {
+ if (s[2] == 'S') {
+ if (s[3] == 'L') {
+ if (s[4] == 'O') {
+ if (s[5] == 'T') {
+ if (s[6] == 'S') {
+ return T_SLOTS;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify8(const char *s, bool) {
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'i') {
+ if (s[3] == 'n') {
+ if (s[4] == 'l') {
+ if (s[5] == 'i') {
+ if (s[6] == 'n') {
+ if (s[7] == 'e') {
+ return T___INLINE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 't') {
+ if (s[3] == 'y') {
+ if (s[4] == 'p') {
+ if (s[5] == 'e') {
+ if (s[6] == 'o') {
+ if (s[7] == 'f') {
+ return T___TYPEOF;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'c') {
+ if (s[1] == 'o') {
+ if (s[2] == 'n') {
+ if (s[3] == 't') {
+ if (s[4] == 'i') {
+ if (s[5] == 'n') {
+ if (s[6] == 'u') {
+ if (s[7] == 'e') {
+ return T_CONTINUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'e') {
+ if (s[1] == 'x') {
+ if (s[2] == 'p') {
+ if (s[3] == 'l') {
+ if (s[4] == 'i') {
+ if (s[5] == 'c') {
+ if (s[6] == 'i') {
+ if (s[7] == 't') {
+ return T_EXPLICIT;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'o') {
+ if (s[1] == 'p') {
+ if (s[2] == 'e') {
+ if (s[3] == 'r') {
+ if (s[4] == 'a') {
+ if (s[5] == 't') {
+ if (s[6] == 'o') {
+ if (s[7] == 'r') {
+ return T_OPERATOR;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'r') {
+ if (s[1] == 'e') {
+ if (s[2] == 'g') {
+ if (s[3] == 'i') {
+ if (s[4] == 's') {
+ if (s[5] == 't') {
+ if (s[6] == 'e') {
+ if (s[7] == 'r') {
+ return T_REGISTER;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 't') {
+ if (s[1] == 'e') {
+ if (s[2] == 'm') {
+ if (s[3] == 'p') {
+ if (s[4] == 'l') {
+ if (s[5] == 'a') {
+ if (s[6] == 't') {
+ if (s[7] == 'e') {
+ return T_TEMPLATE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[1] == 'y') {
+ if (s[2] == 'p') {
+ if (s[3] == 'e') {
+ if (s[4] == 'n') {
+ if (s[5] == 'a') {
+ if (s[6] == 'm') {
+ if (s[7] == 'e') {
+ return T_TYPENAME;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'u') {
+ if (s[1] == 'n') {
+ if (s[2] == 's') {
+ if (s[3] == 'i') {
+ if (s[4] == 'g') {
+ if (s[5] == 'n') {
+ if (s[6] == 'e') {
+ if (s[7] == 'd') {
+ return T_UNSIGNED;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'v') {
+ if (s[1] == 'o') {
+ if (s[2] == 'l') {
+ if (s[3] == 'a') {
+ if (s[4] == 't') {
+ if (s[5] == 'i') {
+ if (s[6] == 'l') {
+ if (s[7] == 'e') {
+ return T_VOLATILE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify9(const char *s, bool q) {
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'c') {
+ if (s[3] == 'o') {
+ if (s[4] == 'n') {
+ if (s[5] == 's') {
+ if (s[6] == 't') {
+ if (s[7] == '_') {
+ if (s[8] == '_') {
+ return T___CONST__;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'n') {
+ if (s[1] == 'a') {
+ if (s[2] == 'm') {
+ if (s[3] == 'e') {
+ if (s[4] == 's') {
+ if (s[5] == 'p') {
+ if (s[6] == 'a') {
+ if (s[7] == 'c') {
+ if (s[8] == 'e') {
+ return T_NAMESPACE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'p') {
+ if (s[1] == 'r') {
+ if (s[2] == 'o') {
+ if (s[3] == 't') {
+ if (s[4] == 'e') {
+ if (s[5] == 'c') {
+ if (s[6] == 't') {
+ if (s[7] == 'e') {
+ if (s[8] == 'd') {
+ return T_PROTECTED;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (q && s[0] == 'Q') {
+ if (s[1] == '_') {
+ if (s[2] == 'S') {
+ if (s[3] == 'I') {
+ if (s[4] == 'G') {
+ if (s[5] == 'N') {
+ if (s[6] == 'A') {
+ if (s[7] == 'L') {
+ if (s[8] == 'S') {
+ return T_SIGNALS;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify10(const char *s, bool) {
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'i') {
+ if (s[3] == 'n') {
+ if (s[4] == 'l') {
+ if (s[5] == 'i') {
+ if (s[6] == 'n') {
+ if (s[7] == 'e') {
+ if (s[8] == '_') {
+ if (s[9] == '_') {
+ return T___INLINE__;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 't') {
+ if (s[3] == 'y') {
+ if (s[4] == 'p') {
+ if (s[5] == 'e') {
+ if (s[6] == 'o') {
+ if (s[7] == 'f') {
+ if (s[8] == '_') {
+ if (s[9] == '_') {
+ return T___TYPEOF__;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 'v') {
+ if (s[3] == 'o') {
+ if (s[4] == 'l') {
+ if (s[5] == 'a') {
+ if (s[6] == 't') {
+ if (s[7] == 'i') {
+ if (s[8] == 'l') {
+ if (s[9] == 'e') {
+ return T___VOLATILE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'c') {
+ if (s[1] == 'o') {
+ if (s[2] == 'n') {
+ if (s[3] == 's') {
+ if (s[4] == 't') {
+ if (s[5] == '_') {
+ if (s[6] == 'c') {
+ if (s[7] == 'a') {
+ if (s[8] == 's') {
+ if (s[9] == 't') {
+ return T_CONST_CAST;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify11(const char *s, bool) {
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'a') {
+ if (s[3] == 't') {
+ if (s[4] == 't') {
+ if (s[5] == 'r') {
+ if (s[6] == 'i') {
+ if (s[7] == 'b') {
+ if (s[8] == 'u') {
+ if (s[9] == 't') {
+ if (s[10] == 'e') {
+ return T___ATTRIBUTE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 's') {
+ if (s[1] == 't') {
+ if (s[2] == 'a') {
+ if (s[3] == 't') {
+ if (s[4] == 'i') {
+ if (s[5] == 'c') {
+ if (s[6] == '_') {
+ if (s[7] == 'c') {
+ if (s[8] == 'a') {
+ if (s[9] == 's') {
+ if (s[10] == 't') {
+ return T_STATIC_CAST;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify12(const char *s, bool) {
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'v') {
+ if (s[3] == 'o') {
+ if (s[4] == 'l') {
+ if (s[5] == 'a') {
+ if (s[6] == 't') {
+ if (s[7] == 'i') {
+ if (s[8] == 'l') {
+ if (s[9] == 'e') {
+ if (s[10] == '_') {
+ if (s[11] == '_') {
+ return T___VOLATILE__;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'd') {
+ if (s[1] == 'y') {
+ if (s[2] == 'n') {
+ if (s[3] == 'a') {
+ if (s[4] == 'm') {
+ if (s[5] == 'i') {
+ if (s[6] == 'c') {
+ if (s[7] == '_') {
+ if (s[8] == 'c') {
+ if (s[9] == 'a') {
+ if (s[10] == 's') {
+ if (s[11] == 't') {
+ return T_DYNAMIC_CAST;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify13(const char *s, bool) {
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'a') {
+ if (s[3] == 't') {
+ if (s[4] == 't') {
+ if (s[5] == 'r') {
+ if (s[6] == 'i') {
+ if (s[7] == 'b') {
+ if (s[8] == 'u') {
+ if (s[9] == 't') {
+ if (s[10] == 'e') {
+ if (s[11] == '_') {
+ if (s[12] == '_') {
+ return T___ATTRIBUTE__;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classify16(const char *s, bool) {
+ if (s[0] == 'r') {
+ if (s[1] == 'e') {
+ if (s[2] == 'i') {
+ if (s[3] == 'n') {
+ if (s[4] == 't') {
+ if (s[5] == 'e') {
+ if (s[6] == 'r') {
+ if (s[7] == 'p') {
+ if (s[8] == 'r') {
+ if (s[9] == 'e') {
+ if (s[10] == 't') {
+ if (s[11] == '_') {
+ if (s[12] == 'c') {
+ if (s[13] == 'a') {
+ if (s[14] == 's') {
+ if (s[15] == 't') {
+ return T_REINTERPRET_CAST;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+int Lexer::classify(const char *s, int n, bool q) {
+ switch (n) {
+ case 2: return classify2(s, q);
+ case 3: return classify3(s, q);
+ case 4: return classify4(s, q);
+ case 5: return classify5(s, q);
+ case 6: return classify6(s, q);
+ case 7: return classify7(s, q);
+ case 8: return classify8(s, q);
+ case 9: return classify9(s, q);
+ case 10: return classify10(s, q);
+ case 11: return classify11(s, q);
+ case 12: return classify12(s, q);
+ case 13: return classify13(s, q);
+ case 16: return classify16(s, q);
+ default: return T_IDENTIFIER;
+ } // switch
+}
+
+static inline int classifyOperator2(const char *s) {
+ if (s[0] == 'o') {
+ if (s[1] == 'r') {
+ return T_OR;
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classifyOperator3(const char *s) {
+ if (s[0] == 'a') {
+ if (s[1] == 'n') {
+ if (s[2] == 'd') {
+ return T_AND;
+ }
+ }
+ }
+ else if (s[0] == 'n') {
+ if (s[1] == 'o') {
+ if (s[2] == 't') {
+ return T_NOT;
+ }
+ }
+ }
+ else if (s[0] == 'x') {
+ if (s[1] == 'o') {
+ if (s[2] == 'r') {
+ return T_XOR;
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classifyOperator5(const char *s) {
+ if (s[0] == 'b') {
+ if (s[1] == 'i') {
+ if (s[2] == 't') {
+ if (s[3] == 'o') {
+ if (s[4] == 'r') {
+ return T_BITOR;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'c') {
+ if (s[1] == 'o') {
+ if (s[2] == 'm') {
+ if (s[3] == 'p') {
+ if (s[4] == 'l') {
+ return T_COMPL;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'o') {
+ if (s[1] == 'r') {
+ if (s[2] == '_') {
+ if (s[3] == 'e') {
+ if (s[4] == 'q') {
+ return T_OR_EQ;
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+static inline int classifyOperator6(const char *s) {
+ if (s[0] == 'a') {
+ if (s[1] == 'n') {
+ if (s[2] == 'd') {
+ if (s[3] == '_') {
+ if (s[4] == 'e') {
+ if (s[5] == 'q') {
+ return T_AND_EQ;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'b') {
+ if (s[1] == 'i') {
+ if (s[2] == 't') {
+ if (s[3] == 'a') {
+ if (s[4] == 'n') {
+ if (s[5] == 'd') {
+ return T_BITAND;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'n') {
+ if (s[1] == 'o') {
+ if (s[2] == 't') {
+ if (s[3] == '_') {
+ if (s[4] == 'e') {
+ if (s[5] == 'q') {
+ return T_NOT_EQ;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'x') {
+ if (s[1] == 'o') {
+ if (s[2] == 'r') {
+ if (s[3] == '_') {
+ if (s[4] == 'e') {
+ if (s[5] == 'q') {
+ return T_XOR_EQ;
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_IDENTIFIER;
+}
+
+int Lexer::classifyOperator(const char *s, int n) {
+ switch (n) {
+ case 2: return classifyOperator2(s);
+ case 3: return classifyOperator3(s);
+ case 5: return classifyOperator5(s);
+ case 6: return classifyOperator6(s);
+ default: return T_IDENTIFIER;
+ } // switch
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Keywords.kwgen b/src/shared/cplusplus/Keywords.kwgen
new file mode 100644
index 0000000000..f23b3b7cea
--- /dev/null
+++ b/src/shared/cplusplus/Keywords.kwgen
@@ -0,0 +1,86 @@
+
+#include "Lexer.h"
+#include "Token.h"
+
+%token-prefix=T_
+%toupper
+%no-enums
+%namespace=Lexer
+
+%%
+__asm
+__asm__
+__attribute
+__attribute__
+__const
+__const__
+__inline
+__inline__
+__typeof
+__typeof__
+__volatile
+__volatile__
+asm
+auto
+bool
+break
+case
+catch
+char
+class
+const
+const_cast
+continue
+default
+delete
+do
+double
+dynamic_cast
+else
+enum
+explicit
+export
+extern
+false
+float
+for
+friend
+goto
+if
+inline
+int
+long
+mutable
+namespace
+new
+operator
+private
+protected
+public
+register
+reinterpret_cast
+return
+short
+signed
+sizeof
+static
+static_cast
+struct
+switch
+template
+this
+throw
+true
+try
+typedef
+typeid
+typename
+typeof
+union
+unsigned
+using
+virtual
+void
+volatile
+wchar_t
+while
diff --git a/src/shared/cplusplus/Lexer.cpp b/src/shared/cplusplus/Lexer.cpp
new file mode 100644
index 0000000000..73c12524d7
--- /dev/null
+++ b/src/shared/cplusplus/Lexer.cpp
@@ -0,0 +1,680 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Lexer.h"
+#include "Control.h"
+#include "TranslationUnit.h"
+#include <cctype>
+#include <cassert>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+Lexer::Lexer(TranslationUnit *unit)
+ : _translationUnit(unit),
+ _state(Lexer::DefaultState),
+ _flags(0),
+ _currentLine(1)
+{
+ _scanKeywords = true;
+ setSource(_translationUnit->firstSourceChar(),
+ _translationUnit->lastSourceChar());
+}
+
+Lexer::Lexer(const char *firstChar, const char *lastChar)
+ : _translationUnit(0),
+ _state(Lexer::DefaultState),
+ _flags(0),
+ _currentLine(1)
+{
+ _scanKeywords = true;
+ setSource(firstChar, lastChar);
+}
+
+Lexer::~Lexer()
+{ }
+
+TranslationUnit *Lexer::translationUnit() const
+{ return _translationUnit; }
+
+Control *Lexer::control() const
+{
+ if (_translationUnit)
+ return _translationUnit->control();
+
+ return 0;
+}
+
+void Lexer::setSource(const char *firstChar, const char *lastChar)
+{
+ _firstChar = firstChar;
+ _lastChar = lastChar;
+ _currentChar = _firstChar - 1;
+ _tokenStart = _currentChar;
+ _yychar = '\n';
+}
+
+void Lexer::setStartWithNewline(bool enabled)
+{
+ if (enabled)
+ _yychar = '\n';
+ else
+ _yychar = ' ';
+}
+
+int Lexer::state() const
+{ return _state; }
+
+void Lexer::setState(int state)
+{ _state = state; }
+
+bool Lexer::qtMocRunEnabled() const
+{ return _qtMocRunEnabled; }
+
+void Lexer::setQtMocRunEnabled(bool onoff)
+{ _qtMocRunEnabled = onoff; }
+
+bool Lexer::objCEnabled() const
+{ return _objCEnabled; }
+
+void Lexer::setObjCEnabled(bool onoff)
+{ _objCEnabled = onoff; }
+
+bool Lexer::isIncremental() const
+{ return _isIncremental; }
+
+void Lexer::setIncremental(bool isIncremental)
+{ _isIncremental = isIncremental; }
+
+bool Lexer::scanCommentTokens() const
+{ return _scanCommentTokens; }
+
+void Lexer::setScanCommentTokens(bool onoff)
+{ _scanCommentTokens = onoff; }
+
+bool Lexer::scanKeywords() const
+{ return _scanKeywords; }
+
+void Lexer::setScanKeywords(bool onoff)
+{ _scanKeywords = onoff; }
+
+void Lexer::setScanAngleStringLiteralTokens(bool onoff)
+{ _scanAngleStringLiteralTokens = onoff; }
+
+void Lexer::pushLineStartOffset()
+{
+ ++_currentLine;
+
+ if (_translationUnit)
+ _translationUnit->pushLineOffset(_currentChar - _firstChar);
+}
+
+unsigned Lexer::tokenOffset() const
+{ return _tokenStart - _firstChar; }
+
+unsigned Lexer::tokenLength() const
+{ return _currentChar - _tokenStart; }
+
+const char *Lexer::tokenBegin() const
+{ return _tokenStart; }
+
+const char *Lexer::tokenEnd() const
+{ return _currentChar; }
+
+unsigned Lexer::currentLine() const
+{ return _currentLine; }
+
+void Lexer::scan(Token *tok)
+{
+ tok->reset();
+ scan_helper(tok);
+ tok->length = _currentChar - _tokenStart;
+}
+
+void Lexer::scan_helper(Token *tok)
+{
+ _Lagain:
+ while (_yychar && std::isspace(_yychar)) {
+ if (_yychar == '\n')
+ tok->newline = true;
+ else
+ tok->whitespace = true;
+ yyinp();
+ }
+
+ if (! _translationUnit)
+ tok->lineno = _currentLine;
+
+ _tokenStart = _currentChar;
+ tok->offset = _currentChar - _firstChar;
+
+ if (_state == MultiLineCommentState) {
+ if (! _yychar) {
+ tok->kind = T_EOF_SYMBOL;
+ return;
+ }
+
+ while (_yychar) {
+ if (_yychar != '*')
+ yyinp();
+ else {
+ yyinp();
+ if (_yychar == '/') {
+ yyinp();
+ _state = DefaultState;
+ break;
+ }
+ }
+ }
+
+ if (! _scanCommentTokens)
+ goto _Lagain;
+
+ tok->kind = T_COMMENT;
+ return; // done
+ }
+
+ if (! _yychar) {
+ tok->kind = T_EOF_SYMBOL;
+ return;
+ }
+
+ unsigned char ch = _yychar;
+ yyinp();
+
+ switch (ch) {
+ case '\\':
+ while (_yychar != '\n' && std::isspace(_yychar))
+ yyinp();
+ // ### assert(! _yychar || _yychar == '\n');
+ if (_yychar == '\n') {
+ tok->joined = true;
+ tok->newline = false;
+ yyinp();
+ }
+ goto _Lagain;
+
+ case '"': case '\'': {
+ const char quote = ch;
+
+ tok->kind = quote == '"'
+ ? T_STRING_LITERAL
+ : T_CHAR_LITERAL;
+
+ const char *yytext = _currentChar;
+
+ while (_yychar && _yychar != quote) {
+ if (_yychar != '\\')
+ yyinp();
+ else {
+ yyinp(); // skip `\\'
+
+ if (_yychar)
+ yyinp();
+ }
+ }
+ // assert(_yychar == quote);
+
+ int yylen = _currentChar - yytext;
+
+ if (_yychar == quote)
+ yyinp();
+
+ if (control())
+ tok->string = control()->findOrInsertStringLiteral(yytext, yylen);
+ } break;
+
+ case '{':
+ tok->kind = T_LBRACE;
+ break;
+
+ case '}':
+ tok->kind = T_RBRACE;
+ break;
+
+ case '[':
+ tok->kind = T_LBRACKET;
+ break;
+
+ case ']':
+ tok->kind = T_RBRACKET;
+ break;
+
+ case '#':
+ if (_yychar == '#') {
+ tok->kind = T_POUND_POUND;
+ yyinp();
+ } else {
+ tok->kind = T_POUND;
+ }
+ break;
+
+ case '(':
+ tok->kind = T_LPAREN;
+ break;
+
+ case ')':
+ tok->kind = T_RPAREN;
+ break;
+
+ case ';':
+ tok->kind = T_SEMICOLON;
+ break;
+
+ case ':':
+ if (_yychar == ':') {
+ yyinp();
+ tok->kind = T_COLON_COLON;
+ } else {
+ tok->kind = T_COLON;
+ }
+ break;
+
+ case '.':
+ if (_yychar == '*') {
+ yyinp();
+ tok->kind = T_DOT_STAR;
+ } else if (_yychar == '.') {
+ yyinp();
+ // ### assert(_yychar);
+ if (_yychar == '.') {
+ yyinp();
+ tok->kind = T_DOT_DOT_DOT;
+ } else {
+ tok->kind = T_ERROR;
+ }
+ } else if (std::isdigit(_yychar)) {
+ const char *yytext = _currentChar - 2;
+ do {
+ if (_yychar == 'e' || _yychar == 'E') {
+ yyinp();
+ if (_yychar == '-' || _yychar == '+') {
+ yyinp();
+ // ### assert(std::isdigit(_yychar));
+ }
+ } else if (std::isalnum(_yychar) || _yychar == '.') {
+ yyinp();
+ } else {
+ break;
+ }
+ } while (_yychar);
+ int yylen = _currentChar - yytext;
+ tok->kind = T_INT_LITERAL;
+ if (control())
+ tok->number = control()->findOrInsertNumericLiteral(yytext, yylen);
+ } else {
+ tok->kind = T_DOT;
+ }
+ break;
+
+ case '?':
+ tok->kind = T_QUESTION;
+ break;
+
+ case '+':
+ if (_yychar == '+') {
+ yyinp();
+ tok->kind = T_PLUS_PLUS;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_PLUS_EQUAL;
+ } else {
+ tok->kind = T_PLUS;
+ }
+ break;
+
+ case '-':
+ if (_yychar == '-') {
+ yyinp();
+ tok->kind = T_MINUS_MINUS;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_MINUS_EQUAL;
+ } else if (_yychar == '>') {
+ yyinp();
+ if (_yychar == '*') {
+ yyinp();
+ tok->kind = T_ARROW_STAR;
+ } else {
+ tok->kind = T_ARROW;
+ }
+ } else {
+ tok->kind = T_MINUS;
+ }
+ break;
+
+ case '*':
+ if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_STAR_EQUAL;
+ } else {
+ tok->kind = T_STAR;
+ }
+ break;
+
+ case '/':
+ if (_yychar == '/') {
+ do {
+ yyinp();
+ } while (_yychar && _yychar != '\n');
+ if (! _scanCommentTokens)
+ goto _Lagain;
+ tok->kind = T_COMMENT;
+ } else if (_yychar == '*') {
+ yyinp();
+ while (_yychar) {
+ if (_yychar != '*') {
+ yyinp();
+ } else {
+ yyinp();
+ if (_yychar == '/')
+ break;
+ }
+ }
+
+ if (_yychar)
+ yyinp();
+ else
+ _state = MultiLineCommentState;
+
+ if (! _scanCommentTokens)
+ goto _Lagain;
+ tok->kind = T_COMMENT;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_SLASH_EQUAL;
+ } else {
+ tok->kind = T_SLASH;
+ }
+ break;
+
+ case '%':
+ if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_PERCENT_EQUAL;
+ } else {
+ tok->kind = T_PERCENT;
+ }
+ break;
+
+ case '^':
+ if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_CARET_EQUAL;
+ } else {
+ tok->kind = T_CARET;
+ }
+ break;
+
+ case '&':
+ if (_yychar == '&') {
+ yyinp();
+ tok->kind = T_AMPER_AMPER;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_AMPER_EQUAL;
+ } else {
+ tok->kind = T_AMPER;
+ }
+ break;
+
+ case '|':
+ if (_yychar == '|') {
+ yyinp();
+ tok->kind = T_PIPE_PIPE;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_PIPE_EQUAL;
+ } else {
+ tok->kind = T_PIPE;
+ }
+ break;
+
+ case '~':
+ if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_TILDE_EQUAL;
+ } else {
+ tok->kind = T_TILDE;
+ }
+ break;
+
+ case '!':
+ if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_EXCLAIM_EQUAL;
+ } else {
+ tok->kind = T_EXCLAIM;
+ }
+ break;
+
+ case '=':
+ if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_EQUAL_EQUAL;
+ } else {
+ tok->kind = T_EQUAL;
+ }
+ break;
+
+ case '<':
+ if (_scanAngleStringLiteralTokens) {
+ const char *yytext = _currentChar;
+ while (_yychar && _yychar != '>')
+ yyinp();
+ int yylen = _currentChar - yytext;
+ // ### assert(_yychar == '>');
+ if (_yychar == '>')
+ yyinp();
+ if (control())
+ tok->string = control()->findOrInsertStringLiteral(yytext, yylen);
+ tok->kind = T_ANGLE_STRING_LITERAL;
+ } else if (_yychar == '<') {
+ yyinp();
+ if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_LESS_LESS_EQUAL;
+ } else
+ tok->kind = T_LESS_LESS;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_LESS_EQUAL;
+ } else {
+ tok->kind = T_LESS;
+ }
+ break;
+
+ case '>':
+ if (_yychar == '>') {
+ yyinp();
+ if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_GREATER_GREATER_EQUAL;
+ } else
+ tok->kind = T_LESS_LESS;
+ tok->kind = T_GREATER_GREATER;
+ } else if (_yychar == '=') {
+ yyinp();
+ tok->kind = T_GREATER_EQUAL;
+ } else {
+ tok->kind = T_GREATER;
+ }
+ break;
+
+ case ',':
+ tok->kind = T_COMMA;
+ break;
+
+ default: {
+ if (_objCEnabled) {
+ if (ch == '@' && _yychar >= 'a' && _yychar <= 'z') {
+ const char *yytext = _currentChar;
+
+ do {
+ yyinp();
+ if (! isalnum(_yychar))
+ break;
+ } while (_yychar);
+
+ const int yylen = _currentChar - yytext;
+ tok->kind = classifyObjCAtKeyword(yytext, yylen);
+ break;
+ } else if (ch == '@' && _yychar == '"') {
+ // objc @string literals
+ ch = _yychar;
+ yyinp();
+ tok->kind = T_AT_STRING_LITERAL;
+
+ const char *yytext = _currentChar;
+
+ while (_yychar && _yychar != '"') {
+ if (_yychar != '\\')
+ yyinp();
+ else {
+ yyinp(); // skip `\\'
+
+ if (_yychar)
+ yyinp();
+ }
+ }
+ // assert(_yychar == '"');
+
+ int yylen = _currentChar - yytext;
+
+ if (_yychar == '"')
+ yyinp();
+
+ if (control())
+ tok->string = control()->findOrInsertStringLiteral(yytext, yylen);
+
+ break;
+ }
+ }
+
+ if (ch == 'L' && (_yychar == '"' || _yychar == '\'')) {
+ // wide char/string literals
+ ch = _yychar;
+ yyinp();
+
+ const char quote = ch;
+
+ tok->kind = quote == '"'
+ ? T_WIDE_STRING_LITERAL
+ : T_WIDE_CHAR_LITERAL;
+
+ const char *yytext = _currentChar;
+
+ while (_yychar && _yychar != quote) {
+ if (_yychar != '\\')
+ yyinp();
+ else {
+ yyinp(); // skip `\\'
+
+ if (_yychar)
+ yyinp();
+ }
+ }
+ // assert(_yychar == quote);
+
+ int yylen = _currentChar - yytext;
+
+ if (_yychar == quote)
+ yyinp();
+
+ if (control())
+ tok->string = control()->findOrInsertStringLiteral(yytext, yylen);
+ } else if (std::isalpha(ch) || ch == '_') {
+ const char *yytext = _currentChar - 1;
+ while (std::isalnum(_yychar) || _yychar == '_')
+ yyinp();
+ int yylen = _currentChar - yytext;
+ if (_scanKeywords)
+ tok->kind = classify(yytext, yylen, _qtMocRunEnabled);
+ else
+ tok->kind = T_IDENTIFIER;
+
+ if (tok->kind == T_IDENTIFIER) {
+ tok->kind = classifyOperator(yytext, yylen);
+
+ if (control())
+ tok->identifier = control()->findOrInsertIdentifier(yytext, yylen);
+ }
+ break;
+ } else if (std::isdigit(ch)) {
+ const char *yytext = _currentChar - 1;
+ while (_yychar) {
+ if (_yychar == 'e' || _yychar == 'E') {
+ yyinp();
+ if (_yychar == '-' || _yychar == '+') {
+ yyinp();
+ // ### assert(std::isdigit(_yychar));
+ }
+ } else if (std::isalnum(_yychar) || _yychar == '.') {
+ yyinp();
+ } else {
+ break;
+ }
+ }
+ int yylen = _currentChar - yytext;
+ tok->kind = T_INT_LITERAL;
+ if (control())
+ tok->number = control()->findOrInsertNumericLiteral(yytext, yylen);
+ break;
+ } else {
+ tok->kind = T_ERROR;
+ break;
+ }
+ } // default
+
+ } // switch
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Lexer.h b/src/shared/cplusplus/Lexer.h
new file mode 100644
index 0000000000..4cb62493db
--- /dev/null
+++ b/src/shared/cplusplus/Lexer.h
@@ -0,0 +1,159 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_LEXER_H
+#define CPLUSPLUS_LEXER_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "Token.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Lexer
+{
+ Lexer(const Lexer &other);
+ void operator =(const Lexer &other);
+
+public:
+ enum State {
+ DefaultState,
+ MultiLineCommentState
+ };
+
+ Lexer(TranslationUnit *unit);
+ Lexer(const char *firstChar, const char *lastChar);
+ ~Lexer();
+
+ Control *control() const;
+ TranslationUnit *translationUnit() const;
+
+ bool qtMocRunEnabled() const;
+ void setQtMocRunEnabled(bool onoff);
+
+ bool objCEnabled() const;
+ void setObjCEnabled(bool onoff);
+
+ void scan(Token *tok);
+
+ inline void operator()(Token *tok)
+ { scan(tok); }
+
+ unsigned tokenOffset() const;
+ unsigned tokenLength() const;
+ const char *tokenBegin() const;
+ const char *tokenEnd() const;
+ unsigned currentLine() const;
+
+ bool scanCommentTokens() const;
+ void setScanCommentTokens(bool onoff);
+
+ bool scanKeywords() const;
+ void setScanKeywords(bool onoff);
+
+ bool scanAngleStringLiteralTokens() const;
+ void setScanAngleStringLiteralTokens(bool onoff);
+
+ void setStartWithNewline(bool enabled);
+
+ int state() const;
+ void setState(int state);
+
+ bool isIncremental() const;
+ void setIncremental(bool isIncremental);
+
+private:
+ void scan_helper(Token *tok);
+ void setSource(const char *firstChar, const char *lastChar);
+ static int classify(const char *string, int length, bool q);
+ static int classifyObjCAtKeyword(const char *s, int n);
+ static int classifyOperator(const char *string, int length);
+
+ inline void yyinp()
+ {
+ if (++_currentChar == _lastChar)
+ _yychar = 0;
+ else {
+ _yychar = *_currentChar;
+ if (_yychar == '\n')
+ pushLineStartOffset();
+ }
+ }
+
+ void pushLineStartOffset();
+
+private:
+ TranslationUnit *_translationUnit;
+ const char *_firstChar;
+ const char *_currentChar;
+ const char *_lastChar;
+ const char *_tokenStart;
+ unsigned char _yychar;
+ int _state;
+ union {
+ unsigned _flags;
+ struct {
+ unsigned _isIncremental: 1;
+ unsigned _scanCommentTokens: 1;
+ unsigned _scanKeywords: 1;
+ unsigned _scanAngleStringLiteralTokens: 1;
+ unsigned _qtMocRunEnabled: 1;
+ unsigned _objCEnabled: 1;
+ };
+ };
+ unsigned _currentLine;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_LEXER_H
diff --git a/src/shared/cplusplus/LiteralTable.cpp b/src/shared/cplusplus/LiteralTable.cpp
new file mode 100644
index 0000000000..21e3b2d8dd
--- /dev/null
+++ b/src/shared/cplusplus/LiteralTable.cpp
@@ -0,0 +1,34 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "LiteralTable.h"
diff --git a/src/shared/cplusplus/LiteralTable.h b/src/shared/cplusplus/LiteralTable.h
new file mode 100644
index 0000000000..35744fe360
--- /dev/null
+++ b/src/shared/cplusplus/LiteralTable.h
@@ -0,0 +1,181 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_LITERALTABLE_H
+#define CPLUSPLUS_LITERALTABLE_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include <cstring>
+#include <cstdlib>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+template <typename _Literal>
+class LiteralTable
+{
+ LiteralTable(const LiteralTable &other);
+ void operator =(const LiteralTable &other);
+
+public:
+ typedef _Literal **iterator;
+
+public:
+ LiteralTable()
+ : _literals(0),
+ _allocatedLiterals(0),
+ _literalCount(-1),
+ _buckets(0),
+ _allocatedBuckets(0)
+ { }
+
+ ~LiteralTable()
+ {
+ if (_literals) {
+ _Literal **lastLiteral = _literals + _literalCount + 1;
+ for (_Literal **it = _literals; it != lastLiteral; ++it)
+ delete *it;
+ free(_literals);
+ }
+ if (_buckets)
+ free(_buckets);
+ }
+
+ bool empty() const
+ { return _literalCount == -1; }
+
+ unsigned size() const
+ { return _literalCount + 1; }
+
+ _Literal *at(unsigned index) const
+ { return _literals[index]; }
+
+ iterator begin() const
+ { return _literals; }
+
+ iterator end() const
+ { return _literals + _literalCount + 1; }
+
+ _Literal *findOrInsertLiteral(const char *chars, unsigned size)
+ {
+ if (_buckets) {
+ unsigned h = _Literal::hashCode(chars, size);
+ _Literal *literal = _buckets[h % _allocatedBuckets];
+ for (; literal; literal = static_cast<_Literal *>(literal->_next)) {
+ if (literal->size() == size && ! strncmp(literal->chars(), chars, size))
+ return literal;
+ }
+ }
+
+ _Literal *literal = new _Literal(chars, size);
+
+ if (++_literalCount == _allocatedLiterals) {
+ _allocatedLiterals <<= 1;
+
+ if (! _allocatedLiterals)
+ _allocatedLiterals = 256;
+
+ _literals = (_Literal **) realloc(_literals, sizeof(_Literal *) * _allocatedLiterals);
+ }
+
+ _literals[_literalCount] = literal;
+
+ if (! _buckets || _literalCount >= _allocatedBuckets * .6)
+ rehash();
+ else {
+ unsigned h = literal->hashCode() % _allocatedBuckets;
+ literal->_next = _buckets[h];
+ _buckets[h] = literal;
+ }
+
+ return literal;
+ }
+
+protected:
+ void rehash()
+ {
+ if (_buckets)
+ free(_buckets);
+
+ _allocatedBuckets <<= 1;
+
+ if (! _allocatedBuckets)
+ _allocatedBuckets = 256;
+
+ _buckets = (_Literal **) calloc(_allocatedBuckets, sizeof(_Literal *));
+
+ _Literal **lastLiteral = _literals + (_literalCount + 1);
+
+ for (_Literal **it = _literals; it != lastLiteral; ++it) {
+ _Literal *literal = *it;
+ unsigned h = literal->hashCode() % _allocatedBuckets;
+
+ literal->_next = _buckets[h];
+ _buckets[h] = literal;
+ }
+ }
+
+protected:
+ MemoryPool *_pool;
+
+ _Literal **_literals;
+ int _allocatedLiterals;
+ int _literalCount;
+
+ _Literal **_buckets;
+ int _allocatedBuckets;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_LITERALTABLE_H
diff --git a/src/shared/cplusplus/Literals.cpp b/src/shared/cplusplus/Literals.cpp
new file mode 100644
index 0000000000..f7ac69f568
--- /dev/null
+++ b/src/shared/cplusplus/Literals.cpp
@@ -0,0 +1,138 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Literals.h"
+#include <cstring>
+#include <algorithm>
+#include <iostream>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+////////////////////////////////////////////////////////////////////////////////
+Literal::Literal(const char *chars, unsigned size)
+ : _index(0), _next(0)
+{
+ _chars = new char[size + 1];
+
+ strncpy(_chars, chars, size);
+ _chars[size] = '\0';
+
+ _size = size;
+
+ _hashCode = hashCode(_chars, _size);
+}
+
+Literal::~Literal()
+{ delete[] _chars; }
+
+Literal::iterator Literal::begin() const
+{ return _chars; }
+
+Literal::iterator Literal::end() const
+{ return _chars + _size; }
+
+const char *Literal::chars() const
+{ return _chars; }
+
+char Literal::at(unsigned index) const
+{ return _chars[index]; }
+
+unsigned Literal::size() const
+{ return _size; }
+
+unsigned Literal::hashCode() const
+{ return _hashCode; }
+
+unsigned Literal::hashCode(const char *chars, unsigned size)
+{
+ unsigned h = 0;
+ for (unsigned i = 0; i < size; ++i)
+ h = (h >> 5) - h + chars[i];
+ return h;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+StringLiteral::StringLiteral(const char *chars, unsigned size)
+ : Literal(chars, size)
+{ }
+
+StringLiteral::~StringLiteral()
+{ }
+
+////////////////////////////////////////////////////////////////////////////////
+NumericLiteral::NumericLiteral(const char *chars, unsigned size)
+ : Literal(chars, size)
+{ }
+
+NumericLiteral::~NumericLiteral()
+{ }
+
+////////////////////////////////////////////////////////////////////////////////
+Identifier::Identifier(const char *chars, unsigned size)
+ : Literal(chars, size)
+{ }
+
+Identifier::~Identifier()
+{ }
+
+bool Identifier::isEqualTo(const Identifier *other) const
+{
+ if (this == other)
+ return true;
+ else if (hashCode() != other->hashCode())
+ return false;
+ else if (size() != other->size())
+ return false;
+ return ! strcmp(chars(), other->chars());
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Literals.h b/src/shared/cplusplus/Literals.h
new file mode 100644
index 0000000000..f55978b270
--- /dev/null
+++ b/src/shared/cplusplus/Literals.h
@@ -0,0 +1,122 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_LITERALS_H
+#define CPLUSPLUS_LITERALS_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "Token.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Literal
+{
+ Literal(const Literal &other);
+ void operator =(const Literal &other);
+
+public:
+ typedef const char *iterator;
+ typedef iterator const_iterator;
+
+public:
+ Literal(const char *chars, unsigned size);
+ virtual ~Literal();
+
+ iterator begin() const;
+ iterator end() const;
+
+ char at(unsigned index) const;
+ const char *chars() const;
+ unsigned size() const;
+
+ unsigned hashCode() const;
+ static unsigned hashCode(const char *chars, unsigned size);
+
+private:
+ char *_chars;
+ unsigned _size;
+ unsigned _hashCode;
+
+public:
+ // ### private
+ unsigned _index;
+ Literal *_next;
+};
+
+class CPLUSPLUS_EXPORT StringLiteral: public Literal
+{
+public:
+ StringLiteral(const char *chars, unsigned size);
+ virtual ~StringLiteral();
+};
+
+class CPLUSPLUS_EXPORT NumericLiteral: public Literal
+{
+public:
+ NumericLiteral(const char *chars, unsigned size);
+ virtual ~NumericLiteral();
+};
+
+class CPLUSPLUS_EXPORT Identifier: public Literal
+{
+public:
+ Identifier(const char *chars, unsigned size);
+ virtual ~Identifier();
+
+ bool isEqualTo(const Identifier *other) const;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_LITERALS_H
diff --git a/src/shared/cplusplus/MemoryPool.cpp b/src/shared/cplusplus/MemoryPool.cpp
new file mode 100644
index 0000000000..880c6bb884
--- /dev/null
+++ b/src/shared/cplusplus/MemoryPool.cpp
@@ -0,0 +1,130 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "MemoryPool.h"
+#include <cstdlib>
+#include <cstring>
+#include <cassert>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+MemoryPool::MemoryPool()
+ : _initializeAllocatedMemory(true),
+ _blocks(0),
+ _allocatedBlocks(0),
+ _blockCount(-1),
+ ptr(0),
+ end(0)
+{ }
+
+MemoryPool::~MemoryPool()
+{
+ if (_blockCount != -1) {
+ for (int i = 0; i < _blockCount + 1; ++i) {
+ free(_blocks[i]);
+ }
+ }
+
+ if (_blocks)
+ free(_blocks);
+}
+
+bool MemoryPool::initializeAllocatedMemory() const
+{ return _initializeAllocatedMemory; }
+
+void MemoryPool::setInitializeAllocatedMemory(bool initializeAllocatedMemory)
+{ _initializeAllocatedMemory = initializeAllocatedMemory; }
+
+void *MemoryPool::allocate_helper(size_t size)
+{
+ assert(size < BLOCK_SIZE);
+
+ if (++_blockCount == _allocatedBlocks) {
+ if (! _allocatedBlocks)
+ _allocatedBlocks = 8;
+ else
+ _allocatedBlocks *= 2;
+
+ _blocks = (char **) realloc(_blocks, sizeof(char *) * _allocatedBlocks);
+ }
+
+ char *&block = _blocks[_blockCount];
+
+ if (_initializeAllocatedMemory)
+ block = (char *) calloc(1, BLOCK_SIZE);
+ else
+ block = (char *) malloc(BLOCK_SIZE);
+
+ ptr = block;
+ end = ptr + BLOCK_SIZE;
+
+ void *addr = ptr;
+ ptr += size;
+ return addr;
+}
+
+Managed::Managed()
+{ }
+
+Managed::~Managed()
+{ }
+
+void *Managed::operator new(size_t size, MemoryPool *pool)
+{ return pool->allocate(size); }
+
+void Managed::operator delete(void *)
+{ }
+
+void Managed::operator delete(void *, MemoryPool *)
+{ }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/MemoryPool.h b/src/shared/cplusplus/MemoryPool.h
new file mode 100644
index 0000000000..13c61c9d24
--- /dev/null
+++ b/src/shared/cplusplus/MemoryPool.h
@@ -0,0 +1,120 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_MEMORYPOOL_H
+#define CPLUSPLUS_MEMORYPOOL_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include <cstddef>
+#include <new>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT MemoryPool
+{
+ MemoryPool(const MemoryPool &other);
+ void operator =(const MemoryPool &other);
+
+public:
+ MemoryPool();
+ ~MemoryPool();
+
+ bool initializeAllocatedMemory() const;
+ void setInitializeAllocatedMemory(bool initializeAllocatedMemory);
+
+ inline void *allocate(size_t size)
+ {
+ size = (size + 7) & ~7;
+ if (ptr && (ptr + size < end)) {
+ void *addr = ptr;
+ ptr += size;
+ return addr;
+ }
+ return allocate_helper(size);
+ }
+
+private:
+ void *allocate_helper(size_t size);
+
+private:
+ bool _initializeAllocatedMemory;
+ char **_blocks;
+ int _allocatedBlocks;
+ int _blockCount;
+ char *ptr, *end;
+
+ enum
+ {
+ BLOCK_SIZE = 8 * 1024,
+ DEFAULT_BLOCK_COUNT = 8
+ };
+};
+
+class CPLUSPLUS_EXPORT Managed
+{
+ Managed(const Managed &other);
+ void operator = (const Managed &other);
+
+public:
+ Managed();
+ virtual ~Managed();
+
+ void *operator new(size_t size, MemoryPool *pool);
+ void operator delete(void *);
+ void operator delete(void *, MemoryPool *);
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_MEMORYPOOL_H
diff --git a/src/shared/cplusplus/Name.cpp b/src/shared/cplusplus/Name.cpp
new file mode 100644
index 0000000000..89e875a93c
--- /dev/null
+++ b/src/shared/cplusplus/Name.cpp
@@ -0,0 +1,133 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Name.h"
+#include "Names.h"
+#include "NameVisitor.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+Name::Name()
+{ }
+
+Name::~Name()
+{ }
+
+bool Name::isNameId() const
+{ return dynamic_cast<const NameId *>(this) != 0; }
+
+bool Name::isTemplateNameId() const
+{ return dynamic_cast<const TemplateNameId *>(this) != 0; }
+
+bool Name::isDestructorNameId() const
+{ return dynamic_cast<const DestructorNameId *>(this) != 0; }
+
+bool Name::isOperatorNameId() const
+{ return dynamic_cast<const OperatorNameId *>(this) != 0; }
+
+bool Name::isConversionNameId() const
+{ return dynamic_cast<const ConversionNameId *>(this) != 0; }
+
+bool Name::isQualifiedNameId() const
+{ return dynamic_cast<const QualifiedNameId *>(this) != 0; }
+
+const NameId *Name::asNameId() const
+{ return dynamic_cast<const NameId *>(this); }
+
+const TemplateNameId *Name::asTemplateNameId() const
+{ return dynamic_cast<const TemplateNameId *>(this); }
+
+const DestructorNameId *Name::asDestructorNameId() const
+{ return dynamic_cast<const DestructorNameId *>(this); }
+
+const OperatorNameId *Name::asOperatorNameId() const
+{ return dynamic_cast<const OperatorNameId *>(this); }
+
+const ConversionNameId *Name::asConversionNameId() const
+{ return dynamic_cast<const ConversionNameId *>(this); }
+
+const QualifiedNameId *Name::asQualifiedNameId() const
+{ return dynamic_cast<const QualifiedNameId *>(this); }
+
+NameId *Name::asNameId()
+{ return dynamic_cast<NameId *>(this); }
+
+TemplateNameId *Name::asTemplateNameId()
+{ return dynamic_cast<TemplateNameId *>(this); }
+
+DestructorNameId *Name::asDestructorNameId()
+{ return dynamic_cast<DestructorNameId *>(this); }
+
+OperatorNameId *Name::asOperatorNameId()
+{ return dynamic_cast<OperatorNameId *>(this); }
+
+ConversionNameId *Name::asConversionNameId()
+{ return dynamic_cast<ConversionNameId *>(this); }
+
+QualifiedNameId *Name::asQualifiedNameId()
+{ return dynamic_cast<QualifiedNameId *>(this); }
+
+void Name::accept(NameVisitor *visitor)
+{
+ if (visitor->preVisit(this))
+ accept0(visitor);
+ visitor->postVisit(this);
+}
+
+void Name::accept(Name *name, NameVisitor *visitor)
+{
+ if (! name)
+ return;
+ name->accept(visitor);
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Name.h b/src/shared/cplusplus/Name.h
new file mode 100644
index 0000000000..1f30a28516
--- /dev/null
+++ b/src/shared/cplusplus/Name.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_NAME_H
+#define CPLUSPLUS_NAME_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Name
+{
+ Name(const Name &other);
+ void operator =(const Name &other);
+
+public:
+ Name();
+ virtual ~Name();
+
+ bool isNameId() const;
+ bool isTemplateNameId() const;
+ bool isDestructorNameId() const;
+ bool isOperatorNameId() const;
+ bool isConversionNameId() const;
+ bool isQualifiedNameId() const;
+
+ const NameId *asNameId() const;
+ const TemplateNameId *asTemplateNameId() const;
+ const DestructorNameId *asDestructorNameId() const;
+ const OperatorNameId *asOperatorNameId() const;
+ const ConversionNameId *asConversionNameId() const;
+ const QualifiedNameId *asQualifiedNameId() const;
+
+ NameId *asNameId();
+ TemplateNameId *asTemplateNameId();
+ DestructorNameId *asDestructorNameId();
+ OperatorNameId *asOperatorNameId();
+ ConversionNameId *asConversionNameId();
+ QualifiedNameId *asQualifiedNameId();
+
+ virtual bool isEqualTo(const Name *other) const = 0;
+
+ void accept(NameVisitor *visitor);
+ static void accept(Name *name, NameVisitor *visitor);
+
+protected:
+ virtual void accept0(NameVisitor *visitor) = 0;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_NAME_H
diff --git a/src/shared/cplusplus/NameVisitor.cpp b/src/shared/cplusplus/NameVisitor.cpp
new file mode 100644
index 0000000000..d4f1af6575
--- /dev/null
+++ b/src/shared/cplusplus/NameVisitor.cpp
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "NameVisitor.h"
+#include "Names.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+NameVisitor::NameVisitor()
+{ }
+
+NameVisitor::~NameVisitor()
+{ }
+
+void NameVisitor::accept(Name *name)
+{ Name::accept(name, this); }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/NameVisitor.h b/src/shared/cplusplus/NameVisitor.h
new file mode 100644
index 0000000000..5cea38b9f8
--- /dev/null
+++ b/src/shared/cplusplus/NameVisitor.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_NAMEVISITOR_H
+#define CPLUSPLUS_NAMEVISITOR_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT NameVisitor
+{
+ NameVisitor(const NameVisitor &other);
+ void operator =(const NameVisitor &other);
+
+public:
+ NameVisitor();
+ virtual ~NameVisitor();
+
+ void accept(Name *name);
+
+ virtual bool preVisit(Name *) { return true; }
+ virtual void postVisit(Name *) {}
+
+ virtual void visit(NameId *) {}
+ virtual void visit(TemplateNameId *) {}
+ virtual void visit(DestructorNameId *) {}
+ virtual void visit(OperatorNameId *) {}
+ virtual void visit(ConversionNameId *) {}
+ virtual void visit(QualifiedNameId *) {}
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_NAMEVISITOR_H
diff --git a/src/shared/cplusplus/Names.cpp b/src/shared/cplusplus/Names.cpp
new file mode 100644
index 0000000000..35bb84b44c
--- /dev/null
+++ b/src/shared/cplusplus/Names.cpp
@@ -0,0 +1,262 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Names.h"
+#include "NameVisitor.h"
+#include "Literals.h"
+#include <cstring>
+#include <algorithm>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+QualifiedNameId::QualifiedNameId(Name *const names[],
+ unsigned nameCount,
+ bool isGlobal)
+ : _names(0),
+ _nameCount(nameCount),
+ _isGlobal(isGlobal)
+{
+ if (_nameCount) {
+ _names = new Name *[_nameCount];
+ std::copy(&names[0], &names[nameCount], _names);
+ }
+}
+
+QualifiedNameId::~QualifiedNameId()
+{ delete[] _names; }
+
+void QualifiedNameId::accept0(NameVisitor *visitor)
+{ visitor->visit(this); }
+
+unsigned QualifiedNameId::nameCount() const
+{ return _nameCount; }
+
+Name *QualifiedNameId::nameAt(unsigned index) const
+{ return _names[index]; }
+
+Name *const *QualifiedNameId::names() const
+{ return _names; }
+
+bool QualifiedNameId::isGlobal() const
+{ return _isGlobal; }
+
+Name *QualifiedNameId::unqualifiedNameId() const
+{
+ if (! _nameCount)
+ return 0;
+
+ return _names[_nameCount - 1];
+}
+
+bool QualifiedNameId::isEqualTo(const Name *other) const
+{
+ const QualifiedNameId *q = other->asQualifiedNameId();
+ if (! q)
+ return false;
+ else if (isGlobal() != q->isGlobal())
+ return false;
+ else {
+ const unsigned count = nameCount();
+ if (count != q->nameCount())
+ return false;
+ for (unsigned i = 0; i < count; ++i) {
+ Name *l = nameAt(i);
+ Name *r = q->nameAt(i);
+ if (! l->isEqualTo(r))
+ return false;
+ }
+ }
+ return true;
+}
+
+NameId::NameId(Identifier *identifier)
+ : _identifier(identifier)
+{ }
+
+NameId::~NameId()
+{ }
+
+void NameId::accept0(NameVisitor *visitor)
+{ visitor->visit(this); }
+
+Identifier *NameId::identifier() const
+{ return _identifier; }
+
+bool NameId::isEqualTo(const Name *other) const
+{
+ const NameId *nameId = other->asNameId();
+ if (! nameId)
+ return false;
+ Identifier *l = identifier();
+ Identifier *r = nameId->identifier();
+ return l->isEqualTo(r);
+}
+
+DestructorNameId::DestructorNameId(Identifier *identifier)
+ : _identifier(identifier)
+{ }
+
+DestructorNameId::~DestructorNameId()
+{ }
+
+void DestructorNameId::accept0(NameVisitor *visitor)
+{ visitor->visit(this); }
+
+Identifier *DestructorNameId::identifier() const
+{ return _identifier; }
+
+bool DestructorNameId::isEqualTo(const Name *other) const
+{
+ const DestructorNameId *d = other->asDestructorNameId();
+ if (! d)
+ return false;
+ Identifier *l = identifier();
+ Identifier *r = d->identifier();
+ return l->isEqualTo(r);
+}
+
+TemplateNameId::TemplateNameId(Identifier *identifier,
+ const FullySpecifiedType templateArguments[],
+ unsigned templateArgumentCount)
+ : _identifier(identifier),
+ _templateArguments(0),
+ _templateArgumentCount(templateArgumentCount)
+{
+ if (_templateArgumentCount) {
+ _templateArguments = new FullySpecifiedType[_templateArgumentCount];
+ std::copy(&templateArguments[0], &templateArguments[_templateArgumentCount],
+ _templateArguments);
+ }
+}
+
+TemplateNameId::~TemplateNameId()
+{ delete[] _templateArguments; }
+
+void TemplateNameId::accept0(NameVisitor *visitor)
+{ visitor->visit(this); }
+
+Identifier *TemplateNameId::identifier() const
+{ return _identifier; }
+
+unsigned TemplateNameId::templateArgumentCount() const
+{ return _templateArgumentCount; }
+
+const FullySpecifiedType &TemplateNameId::templateArgumentAt(unsigned index) const
+{ return _templateArguments[index]; }
+
+const FullySpecifiedType *TemplateNameId::templateArguments() const
+{ return _templateArguments; }
+
+bool TemplateNameId::isEqualTo(const Name *other) const
+{
+ const TemplateNameId *t = other->asTemplateNameId();
+ if (! t)
+ return false;
+ Identifier *l = identifier();
+ Identifier *r = t->identifier();
+ if (! l->isEqualTo(r))
+ return false;
+ if (_templateArgumentCount != t->_templateArgumentCount)
+ return false;
+ for (unsigned i = 0; i < _templateArgumentCount; ++i) {
+ const FullySpecifiedType &l = _templateArguments[i];
+ const FullySpecifiedType &r = t->_templateArguments[i];
+ if (! l.isEqualTo(r))
+ return false;
+ }
+ return true;
+}
+
+OperatorNameId::OperatorNameId(int kind)
+ : _kind(kind)
+{ }
+
+OperatorNameId::~OperatorNameId()
+{ }
+
+void OperatorNameId::accept0(NameVisitor *visitor)
+{ visitor->visit(this); }
+
+int OperatorNameId::kind() const
+{ return _kind; }
+
+bool OperatorNameId::isEqualTo(const Name *other) const
+{
+ const OperatorNameId *o = other->asOperatorNameId();
+ if (! o)
+ return false;
+ return _kind == o->kind();
+}
+
+ConversionNameId::ConversionNameId(FullySpecifiedType type)
+ : _type(type)
+{ }
+
+ConversionNameId::~ConversionNameId()
+{ }
+
+void ConversionNameId::accept0(NameVisitor *visitor)
+{ visitor->visit(this); }
+
+FullySpecifiedType ConversionNameId::type() const
+{ return _type; }
+
+bool ConversionNameId::isEqualTo(const Name *other) const
+{
+ const ConversionNameId *c = other->asConversionNameId();
+ if (! c)
+ return false;
+ return _type.isEqualTo(c->type());
+}
+
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Names.h b/src/shared/cplusplus/Names.h
new file mode 100644
index 0000000000..86e6813c6c
--- /dev/null
+++ b/src/shared/cplusplus/Names.h
@@ -0,0 +1,241 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_NAMES_H
+#define CPLUSPLUS_NAMES_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "Name.h"
+#include "FullySpecifiedType.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT QualifiedNameId: public Name
+{
+public:
+ QualifiedNameId(Name *const names[],
+ unsigned nameCount,
+ bool isGlobal = false);
+ virtual ~QualifiedNameId();
+
+ unsigned nameCount() const;
+ Name *nameAt(unsigned index) const;
+ Name *const *names() const;
+ Name *unqualifiedNameId() const;
+
+ bool isGlobal() const;
+
+ virtual bool isEqualTo(const Name *other) const;
+
+protected:
+ virtual void accept0(NameVisitor *visitor);
+
+private:
+ Name **_names;
+ unsigned _nameCount;
+ bool _isGlobal;
+};
+
+class CPLUSPLUS_EXPORT NameId: public Name
+{
+public:
+ NameId(Identifier *identifier);
+ virtual ~NameId();
+
+ Identifier *identifier() const;
+
+ virtual bool isEqualTo(const Name *other) const;
+
+protected:
+ virtual void accept0(NameVisitor *visitor);
+
+private:
+ Identifier *_identifier;
+};
+
+class CPLUSPLUS_EXPORT DestructorNameId: public Name
+{
+public:
+ DestructorNameId(Identifier *identifier);
+ virtual ~DestructorNameId();
+
+ Identifier *identifier() const;
+
+ virtual bool isEqualTo(const Name *other) const;
+
+protected:
+ virtual void accept0(NameVisitor *visitor);
+
+private:
+ Identifier *_identifier;
+};
+
+class CPLUSPLUS_EXPORT TemplateNameId: public Name
+{
+public:
+ TemplateNameId(Identifier *identifier,
+ const FullySpecifiedType templateArguments[],
+ unsigned templateArgumentCount);
+ virtual ~TemplateNameId();
+
+ Identifier *identifier() const;
+
+ // ### find a better name
+ unsigned templateArgumentCount() const;
+ const FullySpecifiedType &templateArgumentAt(unsigned index) const;
+ const FullySpecifiedType *templateArguments() const;
+
+ virtual bool isEqualTo(const Name *other) const;
+
+protected:
+ virtual void accept0(NameVisitor *visitor);
+
+private:
+ Identifier *_identifier;
+ FullySpecifiedType *_templateArguments;
+ unsigned _templateArgumentCount;
+};
+
+class CPLUSPLUS_EXPORT OperatorNameId: public Name
+{
+public:
+ /*
+ new delete new[] delete[]
+ + - * / % ^ & | ~
+ ! = < > += -= *= /= %=
+ ^= &= |= << >> >>= <<= == !=
+ <= >= && || ++ -- , ->* ->
+ () []
+ */
+ enum Kind {
+ InvalidOp,
+ NewOp,
+ DeleteOp,
+ NewArrayOp,
+ DeleteArrayOp,
+ PlusOp,
+ MinusOp,
+ StarOp,
+ SlashOp,
+ PercentOp,
+ CaretOp,
+ AmpOp,
+ PipeOp,
+ TildeOp,
+ ExclaimOp,
+ EqualOp,
+ LessOp,
+ GreaterOp,
+ PlusEqualOp,
+ MinusEqualOp,
+ StarEqualOp,
+ SlashEqualOp,
+ PercentEqualOp,
+ CaretEqualOp,
+ AmpEqualOp,
+ PipeEqualOp,
+ LessLessOp,
+ GreaterGreaterOp,
+ LessLessEqualOp,
+ GreaterGreaterEqualOp,
+ EqualEqualOp,
+ ExclaimEqualOp,
+ LessEqualOp,
+ GreaterEqualOp,
+ AmpAmpOp,
+ PipePipeOp,
+ PlusPlusOp,
+ MinusMinusOp,
+ CommaOp,
+ ArrowStarOp,
+ ArrowOp,
+ FunctionCallOp,
+ ArrayAccessOp
+ };
+
+public:
+ OperatorNameId(int kind);
+ virtual ~OperatorNameId();
+
+ int kind() const;
+
+ virtual bool isEqualTo(const Name *other) const;
+
+protected:
+ virtual void accept0(NameVisitor *visitor);
+
+private:
+ int _kind;
+};
+
+class CPLUSPLUS_EXPORT ConversionNameId: public Name
+{
+public:
+ ConversionNameId(FullySpecifiedType type);
+ virtual ~ConversionNameId();
+
+ FullySpecifiedType type() const;
+
+ virtual bool isEqualTo(const Name *other) const;
+
+protected:
+ virtual void accept0(NameVisitor *visitor);
+
+private:
+ FullySpecifiedType _type;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_NAMES_H
diff --git a/src/shared/cplusplus/ObjectiveCAtKeywords.cpp b/src/shared/cplusplus/ObjectiveCAtKeywords.cpp
new file mode 100644
index 0000000000..3f8fc7c396
--- /dev/null
+++ b/src/shared/cplusplus/ObjectiveCAtKeywords.cpp
@@ -0,0 +1,464 @@
+#include "Lexer.h"
+#include "Token.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+static inline int classify3(const char *s) {
+ if (s[0] == 'e') {
+ if (s[1] == 'n') {
+ if (s[2] == 'd') {
+ return T_AT_END;
+ }
+ }
+ }
+ else if (s[0] == 't') {
+ if (s[1] == 'r') {
+ if (s[2] == 'y') {
+ return T_AT_TRY;
+ }
+ }
+ }
+ return T_ERROR;
+}
+
+static inline int classify4(const char *s) {
+ if (s[0] == 'd') {
+ if (s[1] == 'e') {
+ if (s[2] == 'f') {
+ if (s[3] == 's') {
+ return T_AT_DEFS;
+ }
+ }
+ }
+ }
+ return T_ERROR;
+}
+
+static inline int classify5(const char *s) {
+ if (s[0] == 'c') {
+ if (s[1] == 'a') {
+ if (s[2] == 't') {
+ if (s[3] == 'c') {
+ if (s[4] == 'h') {
+ return T_AT_CATCH;
+ }
+ }
+ }
+ }
+ else if (s[1] == 'l') {
+ if (s[2] == 'a') {
+ if (s[3] == 's') {
+ if (s[4] == 's') {
+ return T_AT_CLASS;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 't') {
+ if (s[1] == 'h') {
+ if (s[2] == 'r') {
+ if (s[3] == 'o') {
+ if (s[4] == 'w') {
+ return T_AT_THROW;
+ }
+ }
+ }
+ }
+ }
+ return T_ERROR;
+}
+
+static inline int classify6(const char *s) {
+ if (s[0] == 'e') {
+ if (s[1] == 'n') {
+ if (s[2] == 'c') {
+ if (s[3] == 'o') {
+ if (s[4] == 'd') {
+ if (s[5] == 'e') {
+ return T_AT_ENCODE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'p') {
+ if (s[1] == 'u') {
+ if (s[2] == 'b') {
+ if (s[3] == 'l') {
+ if (s[4] == 'i') {
+ if (s[5] == 'c') {
+ return T_AT_PUBLIC;
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_ERROR;
+}
+
+static inline int classify7(const char *s) {
+ if (s[0] == 'd') {
+ if (s[1] == 'y') {
+ if (s[2] == 'n') {
+ if (s[3] == 'a') {
+ if (s[4] == 'm') {
+ if (s[5] == 'i') {
+ if (s[6] == 'c') {
+ return T_AT_DYNAMIC;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'f') {
+ if (s[1] == 'i') {
+ if (s[2] == 'n') {
+ if (s[3] == 'a') {
+ if (s[4] == 'l') {
+ if (s[5] == 'l') {
+ if (s[6] == 'y') {
+ return T_AT_FINALLY;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'p') {
+ if (s[1] == 'a') {
+ if (s[2] == 'c') {
+ if (s[3] == 'k') {
+ if (s[4] == 'a') {
+ if (s[5] == 'g') {
+ if (s[6] == 'e') {
+ return T_AT_PACKAGE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[1] == 'r') {
+ if (s[2] == 'i') {
+ if (s[3] == 'v') {
+ if (s[4] == 'a') {
+ if (s[5] == 't') {
+ if (s[6] == 'e') {
+ return T_AT_PRIVATE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_ERROR;
+}
+
+static inline int classify8(const char *s) {
+ if (s[0] == 'o') {
+ if (s[1] == 'p') {
+ if (s[2] == 't') {
+ if (s[3] == 'i') {
+ if (s[4] == 'o') {
+ if (s[5] == 'n') {
+ if (s[6] == 'a') {
+ if (s[7] == 'l') {
+ return T_AT_OPTIONAL;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'p') {
+ if (s[1] == 'r') {
+ if (s[2] == 'o') {
+ if (s[3] == 'p') {
+ if (s[4] == 'e') {
+ if (s[5] == 'r') {
+ if (s[6] == 't') {
+ if (s[7] == 'y') {
+ return T_AT_PROPERTY;
+ }
+ }
+ }
+ }
+ }
+ else if (s[3] == 't') {
+ if (s[4] == 'o') {
+ if (s[5] == 'c') {
+ if (s[6] == 'o') {
+ if (s[7] == 'l') {
+ return T_AT_PROTOCOL;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'r') {
+ if (s[1] == 'e') {
+ if (s[2] == 'q') {
+ if (s[3] == 'u') {
+ if (s[4] == 'i') {
+ if (s[5] == 'r') {
+ if (s[6] == 'e') {
+ if (s[7] == 'd') {
+ return T_AT_REQUIRED;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 's') {
+ if (s[1] == 'e') {
+ if (s[2] == 'l') {
+ if (s[3] == 'e') {
+ if (s[4] == 'c') {
+ if (s[5] == 't') {
+ if (s[6] == 'o') {
+ if (s[7] == 'r') {
+ return T_AT_SELECTOR;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_ERROR;
+}
+
+static inline int classify9(const char *s) {
+ if (s[0] == 'i') {
+ if (s[1] == 'n') {
+ if (s[2] == 't') {
+ if (s[3] == 'e') {
+ if (s[4] == 'r') {
+ if (s[5] == 'f') {
+ if (s[6] == 'a') {
+ if (s[7] == 'c') {
+ if (s[8] == 'e') {
+ return T_AT_INTERFACE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0] == 'p') {
+ if (s[1] == 'r') {
+ if (s[2] == 'o') {
+ if (s[3] == 't') {
+ if (s[4] == 'e') {
+ if (s[5] == 'c') {
+ if (s[6] == 't') {
+ if (s[7] == 'e') {
+ if (s[8] == 'd') {
+ return T_AT_PROTECTED;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_ERROR;
+}
+
+static inline int classify10(const char *s) {
+ if (s[0] == 's') {
+ if (s[1] == 'y') {
+ if (s[2] == 'n') {
+ if (s[3] == 't') {
+ if (s[4] == 'h') {
+ if (s[5] == 'e') {
+ if (s[6] == 's') {
+ if (s[7] == 'i') {
+ if (s[8] == 'z') {
+ if (s[9] == 'e') {
+ return T_AT_SYNTHESIZE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_ERROR;
+}
+
+static inline int classify11(const char *s) {
+ if (s[0] == 'n') {
+ if (s[1] == 'o') {
+ if (s[2] == 't') {
+ if (s[3] == '_') {
+ if (s[4] == 'k') {
+ if (s[5] == 'e') {
+ if (s[6] == 'y') {
+ if (s[7] == 'w') {
+ if (s[8] == 'o') {
+ if (s[9] == 'r') {
+ if (s[10] == 'd') {
+ return T_AT_NOT_KEYWORD;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_ERROR;
+}
+
+static inline int classify12(const char *s) {
+ if (s[0] == 's') {
+ if (s[1] == 'y') {
+ if (s[2] == 'n') {
+ if (s[3] == 'c') {
+ if (s[4] == 'h') {
+ if (s[5] == 'r') {
+ if (s[6] == 'o') {
+ if (s[7] == 'n') {
+ if (s[8] == 'i') {
+ if (s[9] == 'z') {
+ if (s[10] == 'e') {
+ if (s[11] == 'd') {
+ return T_AT_SYNCHRONIZED;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_ERROR;
+}
+
+static inline int classify14(const char *s) {
+ if (s[0] == 'i') {
+ if (s[1] == 'm') {
+ if (s[2] == 'p') {
+ if (s[3] == 'l') {
+ if (s[4] == 'e') {
+ if (s[5] == 'm') {
+ if (s[6] == 'e') {
+ if (s[7] == 'n') {
+ if (s[8] == 't') {
+ if (s[9] == 'a') {
+ if (s[10] == 't') {
+ if (s[11] == 'i') {
+ if (s[12] == 'o') {
+ if (s[13] == 'n') {
+ return T_AT_IMPLEMENTATION;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_ERROR;
+}
+
+static inline int classify19(const char *s) {
+ if (s[0] == 'c') {
+ if (s[1] == 'o') {
+ if (s[2] == 'm') {
+ if (s[3] == 'p') {
+ if (s[4] == 'a') {
+ if (s[5] == 't') {
+ if (s[6] == 'i') {
+ if (s[7] == 'b') {
+ if (s[8] == 'i') {
+ if (s[9] == 'l') {
+ if (s[10] == 'i') {
+ if (s[11] == 't') {
+ if (s[12] == 'y') {
+ if (s[13] == '_') {
+ if (s[14] == 'a') {
+ if (s[15] == 'l') {
+ if (s[16] == 'i') {
+ if (s[17] == 'a') {
+ if (s[18] == 's') {
+ return T_AT_COMPATIBILITY_ALIAS;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return T_ERROR;
+}
+
+int Lexer::classifyObjCAtKeyword(const char *s, int n) {
+ switch (n) {
+ case 3: return classify3(s);
+ case 4: return classify4(s);
+ case 5: return classify5(s);
+ case 6: return classify6(s);
+ case 7: return classify7(s);
+ case 8: return classify8(s);
+ case 9: return classify9(s);
+ case 10: return classify10(s);
+ case 11: return classify11(s);
+ case 12: return classify12(s);
+ case 14: return classify14(s);
+ case 19: return classify19(s);
+ default: return T_ERROR;
+ } // switch
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Parser.cpp b/src/shared/cplusplus/Parser.cpp
new file mode 100644
index 0000000000..085c8cb54e
--- /dev/null
+++ b/src/shared/cplusplus/Parser.cpp
@@ -0,0 +1,3810 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Parser.h"
+#include "Token.h"
+#include "Lexer.h"
+#include "Control.h"
+#include "AST.h"
+#include "Literals.h"
+#include <cstdlib>
+#include <cstring>
+#include <cassert>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+Parser::Parser(TranslationUnit *unit)
+ : _translationUnit(unit),
+ _control(_translationUnit->control()),
+ _pool(_translationUnit->memoryPool()),
+ _tokenIndex(1),
+ _templateArguments(0),
+ _qtMocRunEnabled(false),
+ _objCEnabled(false),
+ _inFunctionBody(false),
+ _inObjCImplementationContext(false)
+{ }
+
+Parser::~Parser()
+{ }
+
+bool Parser::qtMocRunEnabled() const
+{ return _qtMocRunEnabled; }
+
+void Parser::setQtMocRunEnabled(bool onoff)
+{ _qtMocRunEnabled = onoff; }
+
+bool Parser::objCEnabled() const
+{ return _objCEnabled; }
+
+void Parser::setObjCEnabled(bool onoff)
+{ _objCEnabled = onoff; }
+
+bool Parser::switchTemplateArguments(bool templateArguments)
+{
+ bool previousTemplateArguments = _templateArguments;
+ _templateArguments = templateArguments;
+ return previousTemplateArguments;
+}
+
+bool Parser::blockErrors(bool block)
+{ return _translationUnit->blockErrors(block); }
+
+bool Parser::skipUntil(int token)
+{
+ while (int tk = LA()) {
+ if (tk == token)
+ return true;
+
+ consumeToken();
+ }
+
+ return false;
+}
+
+bool Parser::skipUntilDeclaration()
+{
+ while (int tk = LA()) {
+ switch (tk) {
+ case T_SEMICOLON:
+ case T_TILDE:
+ case T_COLON_COLON:
+ case T_IDENTIFIER:
+ case T_OPERATOR:
+ case T_CHAR:
+ case T_WCHAR_T:
+ case T_BOOL:
+ case T_SHORT:
+ case T_INT:
+ case T_LONG:
+ case T_SIGNED:
+ case T_UNSIGNED:
+ case T_FLOAT:
+ case T_DOUBLE:
+ case T_VOID:
+ case T_EXTERN:
+ case T_NAMESPACE:
+ case T_USING:
+ case T_TYPEDEF:
+ case T_ASM:
+ case T_TEMPLATE:
+ case T_EXPORT:
+ case T_CONST:
+ case T_VOLATILE:
+ case T_PUBLIC:
+ case T_PROTECTED:
+ case T_PRIVATE:
+ return true;
+
+ default:
+ consumeToken();
+ }
+ }
+
+ return false;
+}
+
+bool Parser::skipUntilStatement()
+{
+ while (int tk = LA()) {
+ switch (tk) {
+ case T_SEMICOLON:
+ case T_LBRACE:
+ case T_RBRACE:
+ case T_CONST:
+ case T_VOLATILE:
+ case T_IDENTIFIER:
+ case T_CASE:
+ case T_DEFAULT:
+ case T_IF:
+ case T_SWITCH:
+ case T_WHILE:
+ case T_DO:
+ case T_FOR:
+ case T_BREAK:
+ case T_CONTINUE:
+ case T_RETURN:
+ case T_GOTO:
+ case T_TRY:
+ case T_CATCH:
+ case T_THROW:
+ case T_CHAR:
+ case T_WCHAR_T:
+ case T_BOOL:
+ case T_SHORT:
+ case T_INT:
+ case T_LONG:
+ case T_SIGNED:
+ case T_UNSIGNED:
+ case T_FLOAT:
+ case T_DOUBLE:
+ case T_VOID:
+ case T_CLASS:
+ case T_STRUCT:
+ case T_UNION:
+ case T_ENUM:
+ case T_COLON_COLON:
+ case T_TEMPLATE:
+ case T_USING:
+ return true;
+
+ default:
+ consumeToken();
+ }
+ }
+
+ return false;
+}
+
+bool Parser::skip(int l, int r)
+{
+ int count = 0;
+
+ while (int tk = LA()) {
+ if (tk == l)
+ ++count;
+ else if (tk == r)
+ --count;
+ else if (l != T_LBRACE && (tk == T_LBRACE ||
+ tk == T_RBRACE ||
+ tk == T_SEMICOLON))
+ return false;
+
+ if (count == 0)
+ return true;
+
+ consumeToken();
+ }
+
+ return false;
+}
+
+void Parser::match(int kind, unsigned *token)
+{
+ if (LA() == kind)
+ *token = consumeToken();
+ else {
+ *token = 0;
+ _translationUnit->error(_tokenIndex, "expected token `%s' got `%s'",
+ Token::name(kind), tok().spell());
+ }
+}
+
+bool Parser::parseClassOrNamespaceName(NameAST *&node)
+{
+ if (LA() == T_IDENTIFIER) {
+ unsigned identifier_token = cursor();
+
+ if (LA(2) == T_LESS && parseTemplateId(node) && LA() == T_COLON_COLON)
+ return true;
+
+ rewind(identifier_token);
+
+ if (LA(2) == T_COLON_COLON) {
+ SimpleNameAST *ast = new (_pool) SimpleNameAST;
+ ast->identifier_token = consumeToken();
+ node = ast;
+ return true;
+ }
+ } else if (LA() == T_TEMPLATE) {
+ unsigned template_token = consumeToken();
+ if (parseTemplateId(node))
+ return true;
+ rewind(template_token);
+ }
+ return false;
+}
+
+bool Parser::parseTemplateId(NameAST *&node)
+{
+ if (LA() == T_IDENTIFIER && LA(2) == T_LESS) {
+ TemplateIdAST *ast = new (_pool) TemplateIdAST;
+ ast->identifier_token = consumeToken();
+ ast->less_token = consumeToken();
+ if (LA() == T_GREATER || parseTemplateArgumentList(
+ ast->template_arguments)) {
+ if (LA() == T_GREATER) {
+ ast->greater_token = consumeToken();
+ node = ast;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool Parser::parseNestedNameSpecifier(NestedNameSpecifierAST *&node,
+ bool /*acceptTemplateId*/)
+{
+ NestedNameSpecifierAST **nested_name_specifier = &node;
+ NameAST *class_or_namespace_name = 0;
+ if (parseClassOrNamespaceName(class_or_namespace_name) &&
+ LA() == T_COLON_COLON) {
+ unsigned scope_token = consumeToken();
+ *nested_name_specifier = new (_pool) NestedNameSpecifierAST;
+ (*nested_name_specifier)->class_or_namespace_name
+ = class_or_namespace_name;
+ (*nested_name_specifier)->scope_token = scope_token;
+
+ nested_name_specifier = &(*nested_name_specifier)->next;
+
+ while (parseClassOrNamespaceName(class_or_namespace_name) &&
+ LA() == T_COLON_COLON) {
+ scope_token = consumeToken();
+ *nested_name_specifier = new (_pool) NestedNameSpecifierAST;
+ (*nested_name_specifier)->class_or_namespace_name = class_or_namespace_name;
+ (*nested_name_specifier)->scope_token = scope_token;
+ nested_name_specifier = &(*nested_name_specifier)->next;
+ }
+
+ // ### ugly hack
+ rewind(scope_token);
+ consumeToken();
+ return true;
+ }
+
+ return false;
+}
+
+bool Parser::parseNestedNameSpecifierOpt(NestedNameSpecifierAST *&name,
+ bool acceptTemplateId)
+{
+ unsigned start = cursor();
+ if (! parseNestedNameSpecifier(name, acceptTemplateId))
+ rewind(start);
+ return true;
+}
+
+bool Parser::parseName(NameAST *&node, bool acceptTemplateId)
+{
+ unsigned global_scope_token = 0;
+ if (LA() == T_COLON_COLON)
+ global_scope_token = consumeToken();
+
+ NestedNameSpecifierAST *nested_name_specifier = 0;
+ parseNestedNameSpecifierOpt(nested_name_specifier,
+ /*acceptTemplateId=*/ true);
+
+ NameAST *unqualified_name = 0;
+ if (parseUnqualifiedName(unqualified_name,
+ /*acceptTemplateId=*/ acceptTemplateId || nested_name_specifier != 0)) {
+ if (! global_scope_token && ! nested_name_specifier) {
+ node = unqualified_name;
+ return true;
+ }
+
+ QualifiedNameAST *ast = new (_pool) QualifiedNameAST;
+ ast->global_scope_token = global_scope_token;
+ ast->nested_name_specifier = nested_name_specifier;
+ ast->unqualified_name = unqualified_name;
+ node = ast;
+ return true;
+ }
+
+ return false;
+}
+
+bool Parser::parseTranslationUnit(TranslationUnitAST *&node)
+{
+ TranslationUnitAST *ast = new (_pool) TranslationUnitAST;
+ DeclarationAST **decl = &ast->declarations;
+
+ while (LA()) {
+ unsigned start_declaration = cursor();
+
+ if (parseDeclaration(*decl)) {
+ if (*decl)
+ decl = &(*decl)->next;
+ } else {
+ rewind(start_declaration + 1);
+ skipUntilDeclaration();
+ }
+ }
+
+ node = ast;
+ return true;
+}
+
+bool Parser::parseEmptyDeclaration(DeclarationAST *&node)
+{
+ if (LA() == T_SEMICOLON) {
+ EmptyDeclarationAST *ast = new (_pool) EmptyDeclarationAST;
+ ast->semicolon_token = consumeToken();
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseDeclaration(DeclarationAST *&node)
+{
+ switch (LA()) {
+ case T_SEMICOLON:
+ return parseEmptyDeclaration(node);
+
+ case T_NAMESPACE:
+ return parseNamespace(node);
+
+ case T_USING:
+ return parseUsing(node);
+
+ case T_ASM:
+ return parseAsmDefinition(node);
+
+ case T_TEMPLATE:
+ case T_EXPORT:
+ return parseTemplateDeclaration(node);
+
+ // ObjcC++
+ case T_AT_CLASS:
+ return parseObjCClassDeclaration(node);
+
+ case T_AT_INTERFACE:
+ return parseObjCInterface(node);
+
+ case T_AT_PROTOCOL:
+ return parseObjCProtocol(node);
+
+ case T_AT_IMPLEMENTATION:
+ return parseObjCImplementation(node);
+
+ case T_AT_END:
+ return parseObjCEnd(node);
+
+ default: {
+ if (_objCEnabled && LA() == T___ATTRIBUTE__) {
+ const unsigned start = cursor();
+ SpecifierAST *attributes = 0, **attr = &attributes;
+ while (parseAttributeSpecifier(*attr))
+ attr = &(*attr)->next;
+ if (LA() == T_AT_INTERFACE)
+ return parseObjCInterface(node, attributes);
+ else if (LA() == T_AT_PROTOCOL)
+ return parseObjCProtocol(node, attributes);
+ else if (LA() == T_AT_PROPERTY)
+ return parseObjCPropertyDeclaration(node, attributes);
+ rewind(start);
+ }
+
+ if (LA() == T_EXTERN && LA(2) == T_TEMPLATE)
+ return parseTemplateDeclaration(node);
+ else if (LA() == T_EXTERN && LA(2) == T_STRING_LITERAL)
+ return parseLinkageSpecification(node);
+ else
+ return parseSimpleDeclaration(node);
+ } break; // default
+
+ } // end switch
+
+ return false;
+}
+
+bool Parser::parseLinkageSpecification(DeclarationAST *&node)
+{
+ if (LA() == T_EXTERN && LA(2) == T_STRING_LITERAL) {
+ LinkageSpecificationAST *ast = new (_pool) LinkageSpecificationAST;
+ ast->extern_token = consumeToken();
+ ast->extern_type = consumeToken();
+
+ if (LA() == T_LBRACE)
+ parseLinkageBody(ast->declaration);
+ else
+ parseDeclaration(ast->declaration);
+
+ node = ast;
+ return true;
+ }
+
+ return false;
+}
+
+bool Parser::parseLinkageBody(DeclarationAST *&node)
+{
+ if (LA() == T_LBRACE) {
+ LinkageBodyAST *ast = new (_pool) LinkageBodyAST;
+ ast->lbrace_token = consumeToken();
+ DeclarationAST **declaration_ptr = &ast->declarations;
+
+ while (int tk = LA()) {
+ if (tk == T_RBRACE)
+ break;
+
+ unsigned start_declaration = cursor();
+ if (parseDeclaration(*declaration_ptr)) {
+ if (*declaration_ptr) // ### remove me
+ declaration_ptr = &(*declaration_ptr)->next;
+ } else {
+ rewind(start_declaration + 1);
+ skipUntilDeclaration();
+ }
+ }
+ match(T_RBRACE, &ast->rbrace_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+// ### rename parseNamespaceAliarOrDeclaration?
+bool Parser::parseNamespace(DeclarationAST *&node)
+{
+ if (LA() != T_NAMESPACE)
+ return false;
+
+ unsigned namespace_token = consumeToken();
+
+ if (LA() == T_IDENTIFIER && LA(2) == T_EQUAL) {
+ NamespaceAliasDefinitionAST *ast =
+ new (_pool) NamespaceAliasDefinitionAST;
+ ast->namespace_token = namespace_token;
+ ast->namespace_name = consumeToken();
+ ast->equal_token = consumeToken();
+ parseName(ast->name);
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+
+ NamespaceAST *ast = new (_pool) NamespaceAST;
+ ast->namespace_token = namespace_token;
+ if (LA() == T_IDENTIFIER)
+ ast->identifier_token = consumeToken();
+ SpecifierAST **attr_ptr = &ast->attributes;
+ while (LA() == T___ATTRIBUTE__) {
+ parseAttributeSpecifier(*attr_ptr);
+ attr_ptr = &(*attr_ptr)->next;
+ }
+ if (LA() == T_LBRACE)
+ parseLinkageBody(ast->linkage_body);
+ node = ast;
+ return true;
+}
+
+bool Parser::parseUsing(DeclarationAST *&node)
+{
+ if (LA() != T_USING)
+ return false;
+
+ if (LA(2) == T_NAMESPACE)
+ return parseUsingDirective(node);
+
+ UsingAST *ast = new (_pool) UsingAST;
+ ast->using_token = consumeToken();
+
+ if (LA() == T_TYPENAME)
+ ast->typename_token = consumeToken();
+
+ parseName(ast->name);
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+}
+
+bool Parser::parseUsingDirective(DeclarationAST *&node)
+{
+ if (LA() == T_USING && LA(2) == T_NAMESPACE) {
+ UsingDirectiveAST *ast = new (_pool) UsingDirectiveAST;
+ ast->using_token = consumeToken();
+ ast->namespace_token = consumeToken();
+ if (! parseName(ast->name))
+ _translationUnit->warning(cursor(), "expected `namespace name' before `%s'",
+ tok().spell());
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseConversionFunctionId(NameAST *&node)
+{
+ if (LA() != T_OPERATOR)
+ return false;
+ unsigned operator_token = consumeToken();
+ SpecifierAST *type_specifier = 0;
+ if (! parseTypeSpecifier(type_specifier)) {
+ return false;
+ }
+ PtrOperatorAST *ptr_operators = 0, **ptr_operators_tail = &ptr_operators;
+ while (parsePtrOperator(*ptr_operators_tail))
+ ptr_operators_tail = &(*ptr_operators_tail)->next;
+
+ ConversionFunctionIdAST *ast = new (_pool) ConversionFunctionIdAST;
+ ast->operator_token = operator_token;
+ ast->type_specifier = type_specifier;
+ ast->ptr_operators = ptr_operators;
+ node = ast;
+ return true;
+}
+
+bool Parser::parseOperatorFunctionId(NameAST *&node)
+{
+ if (LA() != T_OPERATOR)
+ return false;
+ unsigned operator_token = consumeToken();
+
+ OperatorAST *op = 0;
+ if (! parseOperator(op))
+ return false;
+
+ OperatorFunctionIdAST *ast = new (_pool) OperatorFunctionIdAST;
+ ast->operator_token = operator_token;
+ ast->op = op;
+ node = ast;
+ return true;
+}
+
+bool Parser::parseTemplateArgumentList(TemplateArgumentListAST *&node)
+{
+ TemplateArgumentListAST **template_argument_ptr = &node;
+ ExpressionAST *template_argument = 0;
+ if (parseTemplateArgument(template_argument)) {
+ *template_argument_ptr = new (_pool) TemplateArgumentListAST;
+ (*template_argument_ptr)->template_argument = template_argument;
+ template_argument_ptr = &(*template_argument_ptr)->next;
+ while (LA() == T_COMMA) {
+ consumeToken();
+
+ if (parseTemplateArgument(template_argument)) {
+ *template_argument_ptr = new (_pool) TemplateArgumentListAST;
+ (*template_argument_ptr)->template_argument = template_argument;
+ template_argument_ptr = &(*template_argument_ptr)->next;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseAsmDefinition(DeclarationAST *&node)
+{
+ if (LA() == T_ASM) {
+ AsmDefinitionAST *ast = new (_pool) AsmDefinitionAST;
+ ast->asm_token = consumeToken();
+ parseCvQualifiers(ast->cv_qualifier_seq);
+ if (LA() == T_LPAREN) {
+ ast->lparen_token = cursor();
+ if (skip(T_LPAREN, T_RPAREN))
+ ast->rparen_token = consumeToken();
+ }
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseTemplateDeclaration(DeclarationAST *&node)
+{
+ if (! (LA(1) == T_TEMPLATE || ((LA(1) == T_EXPORT || LA(1) == T_EXTERN)
+ && LA(2) == T_TEMPLATE)))
+ return false;
+
+ TemplateDeclarationAST *ast = new (_pool) TemplateDeclarationAST;
+
+ if (LA() == T_EXPORT || LA() == T_EXPORT)
+ ast->export_token = consumeToken();
+
+ ast->template_token = consumeToken();
+
+ if (LA() == T_LESS) {
+ ast->less_token = consumeToken();
+ if (LA() == T_GREATER || parseTemplateParameterList(ast->template_parameters))
+ match(T_GREATER, &ast->greater_token);
+ }
+
+ parseDeclaration(ast->declaration);
+ node = ast;
+ return true;
+}
+
+bool Parser::parseOperator(OperatorAST *&node) // ### FIXME
+{
+ OperatorAST *ast = new (_pool) OperatorAST;
+
+ switch (LA()) {
+ case T_NEW:
+ case T_DELETE: {
+ ast->op_token = consumeToken();
+ if (LA() == T_LBRACKET) {
+ ast->open_token = consumeToken();
+ match(T_RBRACKET, &ast->close_token);
+ }
+ } break;
+
+ case T_PLUS:
+ case T_MINUS:
+ case T_STAR:
+ case T_SLASH:
+ case T_PERCENT:
+ case T_CARET:
+ case T_AMPER:
+ case T_PIPE:
+ case T_TILDE:
+ case T_EXCLAIM:
+ case T_LESS:
+ case T_GREATER:
+ case T_COMMA:
+ case T_AMPER_EQUAL:
+ case T_CARET_EQUAL:
+ case T_SLASH_EQUAL:
+ case T_EQUAL:
+ case T_EQUAL_EQUAL:
+ case T_EXCLAIM_EQUAL:
+ case T_GREATER_EQUAL:
+ case T_GREATER_GREATER_EQUAL:
+ case T_LESS_EQUAL:
+ case T_LESS_LESS_EQUAL:
+ case T_MINUS_EQUAL:
+ case T_PERCENT_EQUAL:
+ case T_PIPE_EQUAL:
+ case T_PLUS_EQUAL:
+ case T_STAR_EQUAL:
+ case T_TILDE_EQUAL:
+ case T_LESS_LESS:
+ case T_GREATER_GREATER:
+ case T_AMPER_AMPER:
+ case T_PIPE_PIPE:
+ case T_PLUS_PLUS:
+ case T_MINUS_MINUS:
+ case T_ARROW_STAR:
+ case T_DOT_STAR:
+ case T_ARROW:
+ ast->op_token = consumeToken();
+ break;
+
+ default:
+ if (LA() == T_LPAREN && LA(2) == T_RPAREN) {
+ ast->op_token = ast->open_token = consumeToken();
+ ast->close_token = consumeToken();
+ } else if (LA() == T_LBRACKET && LA(2) == T_RBRACKET) {
+ ast->op_token = ast->open_token = consumeToken();
+ ast->close_token = consumeToken();
+ } else {
+ return false;
+ }
+ }
+
+ node = ast;
+ return true;
+}
+
+bool Parser::parseCvQualifiers(SpecifierAST *&node)
+{
+ unsigned start = cursor();
+ SpecifierAST **ast = &node;
+ while (*ast)
+ ast = &(*ast)->next;
+
+ while (int tk = LA()) {
+ if (tk == T_CONST || tk == T_VOLATILE) {
+ SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
+ spec->specifier_token = consumeToken();
+ *ast = spec;
+ ast = &(*ast)->next;
+ } else if(LA() == T___ATTRIBUTE__) {
+ parseAttributeSpecifier(*ast);
+ ast = &(*ast)->next;
+ } else {
+ break;
+ }
+ }
+
+ return start != cursor();
+}
+
+bool Parser::parsePtrOperator(PtrOperatorAST *&node)
+{
+ if (LA() == T_AMPER) {
+ ReferenceAST *ast = new (_pool) ReferenceAST;
+ ast->amp_token = consumeToken();
+ node = ast;
+ return true;
+ } else if (LA() == T_STAR) {
+ PointerAST *ast = new (_pool) PointerAST;
+ ast->star_token = consumeToken();
+ parseCvQualifiers(ast->cv_qualifier_seq);
+ node = ast;
+ return true;
+ } else if (LA() == T_COLON_COLON || LA() == T_IDENTIFIER) {
+ unsigned scope_or_identifier_token = cursor();
+
+ unsigned global_scope_token = 0;
+ if (LA() == T_COLON_COLON)
+ global_scope_token = consumeToken();
+
+ NestedNameSpecifierAST *nested_name_specifier = 0;
+ bool has_nested_name_specifier = parseNestedNameSpecifier(
+ nested_name_specifier, true);
+ if (has_nested_name_specifier && LA() == T_STAR) {
+ PointerToMemberAST *ast = new (_pool) PointerToMemberAST;
+ ast->global_scope_token = global_scope_token;
+ ast->nested_name_specifier = nested_name_specifier;
+ ast->star_token = consumeToken();
+ parseCvQualifiers(ast->cv_qualifier_seq);
+ node = ast;
+ return true;
+ }
+ rewind(scope_or_identifier_token);
+ }
+ return false;
+}
+
+bool Parser::parseTemplateArgument(ExpressionAST *&node)
+{
+ unsigned start = cursor();
+ if (parseTypeId(node) && (LA() == T_COMMA || LA() == T_GREATER))
+ return true;
+
+ rewind(start);
+ bool previousTemplateArguments = switchTemplateArguments(true);
+ bool parsed = parseLogicalOrExpression(node);
+ (void) switchTemplateArguments(previousTemplateArguments);
+ return parsed;
+}
+
+bool Parser::parseDeclSpecifierSeq(SpecifierAST *&decl_specifier_seq,
+ bool onlyTypeSpecifiers,
+ bool simplified)
+{
+ bool has_type_specifier = false;
+ NameAST *named_type_specifier = 0;
+ SpecifierAST **decl_specifier_seq_ptr = &decl_specifier_seq;
+ for (;;) {
+ if (lookAtCVQualifier()) {
+ SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
+ spec->specifier_token = consumeToken();
+ *decl_specifier_seq_ptr = spec;
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ } else if (! onlyTypeSpecifiers && lookAtStorageClassSpecifier()) {
+ SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
+ spec->specifier_token = consumeToken();
+ *decl_specifier_seq_ptr = spec;
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ } else if (! named_type_specifier && lookAtBuiltinTypeSpecifier()) {
+ parseBuiltinTypeSpecifier(*decl_specifier_seq_ptr);
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ has_type_specifier = true;
+ } else if (! has_type_specifier && (LA() == T_COLON_COLON ||
+ LA() == T_IDENTIFIER)) {
+ if (! parseName(named_type_specifier))
+ return false;
+ NamedTypeSpecifierAST *spec = new (_pool) NamedTypeSpecifierAST;
+ spec->name = named_type_specifier;
+ *decl_specifier_seq_ptr = spec;
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ has_type_specifier = true;
+ } else if (! simplified && ! has_type_specifier && (LA() == T_TYPENAME ||
+ LA() == T_ENUM ||
+ lookAtClassKey())) {
+ unsigned startOfElaboratedTypeSpecifier = cursor();
+ if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr)) {
+ _translationUnit->error(startOfElaboratedTypeSpecifier,
+ "expected an elaborated type specifier");
+ break;
+ }
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ has_type_specifier = true;
+ } else
+ break;
+ }
+
+ return decl_specifier_seq != 0;
+}
+
+bool Parser::parseDeclaratorOrAbstractDeclarator(DeclaratorAST *&node)
+{
+ unsigned start = cursor();
+ bool blocked = blockErrors(true);
+ if (parseDeclarator(node)) {
+ blockErrors(blocked);
+ return true;
+ }
+ blockErrors(blocked);
+ rewind(start);
+ return parseAbstractDeclarator(node);
+}
+
+bool Parser::parseCoreDeclarator(DeclaratorAST *&node)
+{
+ PtrOperatorAST *ptr_operators = 0, **ptr_operators_tail = &ptr_operators;
+ while (parsePtrOperator(*ptr_operators_tail))
+ ptr_operators_tail = &(*ptr_operators_tail)->next;
+
+ if (LA() == T_COLON_COLON || LA() == T_IDENTIFIER || LA() == T_TILDE
+ || LA() == T_OPERATOR) {
+ NameAST *name = 0;
+ if (parseName(name)) {
+ DeclaratorIdAST *declarator_id = new (_pool) DeclaratorIdAST;
+ declarator_id->name = name;
+ DeclaratorAST *ast = new (_pool) DeclaratorAST;
+ ast->ptr_operators = ptr_operators;
+ ast->core_declarator = declarator_id;
+ node = ast;
+ return true;
+ }
+ } else if (LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+ DeclaratorAST *declarator = 0;
+ if (parseDeclarator(declarator) && LA() == T_RPAREN) {
+ NestedDeclaratorAST *nested_declarator = new (_pool) NestedDeclaratorAST;
+ nested_declarator->lparen_token = lparen_token;
+ nested_declarator->declarator = declarator;
+ nested_declarator->rparen_token = consumeToken();
+ DeclaratorAST *ast = new (_pool) DeclaratorAST;
+ ast->ptr_operators = ptr_operators;
+ ast->core_declarator = nested_declarator;
+ node = ast;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Parser::parseDeclarator(DeclaratorAST *&node)
+{
+ if (! parseCoreDeclarator(node))
+ return false;
+
+ PostfixDeclaratorAST **postfix_ptr = &node->postfix_declarators;
+
+ for (;;) {
+ unsigned startOfPostDeclarator = cursor();
+
+ if (LA() == T_LPAREN) {
+ FunctionDeclaratorAST *ast = new (_pool) FunctionDeclaratorAST;
+ ast->lparen_token = consumeToken();
+ parseParameterDeclarationClause(ast->parameters);
+ if (LA() != T_RPAREN) {
+ rewind(startOfPostDeclarator);
+ break;
+ }
+
+ ast->rparen_token = consumeToken();
+ parseCvQualifiers(ast->cv_qualifier_seq);
+ parseExceptionSpecification(ast->exception_specification);
+ *postfix_ptr = ast;
+ postfix_ptr = &(*postfix_ptr)->next;
+ } else if (LA() == T_LBRACKET) {
+ ArrayDeclaratorAST *ast = new (_pool) ArrayDeclaratorAST;
+ ast->lbracket_token = consumeToken();
+ if (LA() == T_RBRACKET || parseConstantExpression(ast->expression)) {
+ match(T_RBRACKET, &ast->rbracket_token);
+ }
+ *postfix_ptr = ast;
+ postfix_ptr = &(*postfix_ptr)->next;
+ } else
+ break;
+ }
+
+ SpecifierAST **spec_ptr = &node->attributes;
+ while (LA() == T___ATTRIBUTE__) {
+ parseAttributeSpecifier(*spec_ptr);
+ spec_ptr = &(*spec_ptr)->next;
+ }
+
+ return true;
+}
+
+bool Parser::parseAbstractCoreDeclarator(DeclaratorAST *&node)
+{
+ PtrOperatorAST *ptr_operators = 0, **ptr_operators_tail = &ptr_operators;
+ while (parsePtrOperator(*ptr_operators_tail))
+ ptr_operators_tail = &(*ptr_operators_tail)->next;
+
+ unsigned after_ptr_operators = cursor();
+
+ if (LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+ DeclaratorAST *declarator = 0;
+ if (parseAbstractDeclarator(declarator) && LA() == T_RPAREN) {
+ NestedDeclaratorAST *nested_declarator = new (_pool) NestedDeclaratorAST;
+ nested_declarator->lparen_token = lparen_token;
+ nested_declarator->declarator = declarator;
+ nested_declarator->rparen_token = consumeToken();
+ DeclaratorAST *ast = new (_pool) DeclaratorAST;
+ ast->ptr_operators = ptr_operators;
+ ast->core_declarator = nested_declarator;
+ node = ast;
+ return true;
+ }
+ }
+
+ rewind(after_ptr_operators);
+ if (ptr_operators) {
+ DeclaratorAST *ast = new (_pool) DeclaratorAST;
+ ast->ptr_operators = ptr_operators;
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseAbstractDeclarator(DeclaratorAST *&node)
+{
+ if (! parseAbstractCoreDeclarator(node))
+ return false;
+
+ PostfixDeclaratorAST *postfix_declarators = 0,
+ **postfix_ptr = &postfix_declarators;
+
+ for (;;) {
+ if (LA() == T_LPAREN) {
+ FunctionDeclaratorAST *ast = new (_pool) FunctionDeclaratorAST;
+ ast->lparen_token = consumeToken();
+ if (LA() == T_RPAREN || parseParameterDeclarationClause(ast->parameters)) {
+ if (LA() == T_RPAREN)
+ ast->rparen_token = consumeToken();
+ }
+ parseCvQualifiers(ast->cv_qualifier_seq);
+ parseExceptionSpecification(ast->exception_specification);
+ *postfix_ptr = ast;
+ postfix_ptr = &(*postfix_ptr)->next;
+ } else if (LA() == T_LBRACKET) {
+ ArrayDeclaratorAST *ast = new (_pool) ArrayDeclaratorAST;
+ ast->lbracket_token = consumeToken();
+ if (LA() == T_RBRACKET || parseConstantExpression(ast->expression)) {
+ if (LA() == T_RBRACKET)
+ ast->rbracket_token = consumeToken();
+ }
+ *postfix_ptr = ast;
+ postfix_ptr = &(*postfix_ptr)->next;
+ } else
+ break;
+ }
+
+ if (postfix_declarators) {
+ if (! node)
+ node = new (_pool) DeclaratorAST;
+
+ node->postfix_declarators = postfix_declarators;
+ }
+
+ return true;
+}
+
+bool Parser::parseEnumSpecifier(SpecifierAST *&node)
+{
+ if (LA() == T_ENUM) {
+ unsigned enum_token = consumeToken();
+ NameAST *name = 0;
+ parseName(name);
+ if (LA() == T_LBRACE) {
+ EnumSpecifierAST *ast = new (_pool) EnumSpecifierAST;
+ ast->enum_token = enum_token;
+ ast->name = name;
+ ast->lbrace_token = consumeToken();
+ EnumeratorAST **enumerator_ptr = &ast->enumerators;
+ while (int tk = LA()) {
+ if (tk == T_RBRACE)
+ break;
+
+ if (LA() != T_IDENTIFIER) {
+ _translationUnit->error(cursor(), "expected identifier before '%s'", tok().spell());
+ skipUntil(T_IDENTIFIER);
+ }
+
+ if (parseEnumerator(*enumerator_ptr))
+ enumerator_ptr = &(*enumerator_ptr)->next;
+
+ if (LA() != T_RBRACE) {
+ unsigned comma_token = 0;
+ match(T_COMMA, &comma_token);
+ }
+ }
+ match(T_RBRACE, &ast->rbrace_token);
+ node = ast;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Parser::parseTemplateParameterList(DeclarationAST *&node)
+{
+ DeclarationAST **template_parameter_ptr = &node;
+ if (parseTemplateParameter(*template_parameter_ptr)) {
+ template_parameter_ptr = &(*template_parameter_ptr)->next;
+ while (LA() == T_COMMA) {
+ consumeToken();
+
+ if (parseTemplateParameter(*template_parameter_ptr))
+ template_parameter_ptr = &(*template_parameter_ptr)->next;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseTemplateParameter(DeclarationAST *&node)
+{
+ if (parseTypeParameter(node))
+ return true;
+ bool previousTemplateArguments = switchTemplateArguments(true);
+ bool parsed = parseParameterDeclaration(node);
+ (void) switchTemplateArguments(previousTemplateArguments);
+ return parsed;
+}
+
+bool Parser::parseTypenameTypeParameter(DeclarationAST *&node)
+{
+ if (LA() == T_CLASS || LA() == T_TYPENAME) {
+ TypenameTypeParameterAST *ast = new (_pool) TypenameTypeParameterAST;
+ ast->classkey_token = consumeToken();
+ parseName(ast->name);
+ if (LA() == T_EQUAL) {
+ ast->equal_token = consumeToken();
+ parseTypeId(ast->type_id);
+ }
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseTemplateTypeParameter(DeclarationAST *&node)
+{
+ if (LA() == T_TEMPLATE) {
+ TemplateTypeParameterAST *ast = new (_pool) TemplateTypeParameterAST;
+ ast->template_token = consumeToken();
+ if (LA() == T_LESS)
+ ast->less_token = consumeToken();
+ parseTemplateParameterList(ast->template_parameters);
+ if (LA() == T_GREATER)
+ ast->greater_token = consumeToken();
+ if (LA() == T_CLASS)
+ ast->class_token = consumeToken();
+
+ // parse optional name
+ parseName(ast->name);
+
+ if (LA() == T_EQUAL) {
+ ast->equal_token = consumeToken();
+ parseTypeId(ast->type_id);
+ }
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseTypeParameter(DeclarationAST *&node)
+{
+ if (LA() == T_CLASS || LA() == T_TYPENAME)
+ return parseTypenameTypeParameter(node);
+ else if (LA() == T_TEMPLATE)
+ return parseTemplateTypeParameter(node);
+ else
+ return false;
+}
+
+bool Parser::parseTypeId(ExpressionAST *&node)
+{
+ SpecifierAST *type_specifier = 0;
+ if (parseTypeSpecifier(type_specifier)) {
+ TypeIdAST *ast = new (_pool) TypeIdAST;
+ ast->type_specifier = type_specifier;
+ parseAbstractDeclarator(ast->declarator);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseParameterDeclarationClause(ParameterDeclarationClauseAST *&node)
+{
+ DeclarationAST *parameter_declarations = 0;
+ if (LA() != T_DOT_DOT_DOT)
+ parseParameterDeclarationList(parameter_declarations);
+ unsigned dot_dot_dot_token = 0;
+ if (LA() == T_DOT_DOT_DOT || (LA() == T_COMMA && LA(2) == T_DOT_DOT_DOT)) {
+ if (LA() == T_COMMA)
+ consumeToken();
+ dot_dot_dot_token = consumeToken();
+ }
+ ParameterDeclarationClauseAST *ast = new (_pool) ParameterDeclarationClauseAST;
+ ast->parameter_declarations = parameter_declarations;
+ ast->dot_dot_dot_token = dot_dot_dot_token;
+ node = ast;
+ return true;
+}
+
+bool Parser::parseParameterDeclarationList(DeclarationAST *&node)
+{
+ DeclarationAST **parameter_declaration_ptr = &node;
+ if (parseParameterDeclaration(*parameter_declaration_ptr)) {
+ parameter_declaration_ptr = &(*parameter_declaration_ptr)->next;
+ while (LA() == T_COMMA) {
+ consumeToken();
+
+ if (LA() == T_DOT_DOT_DOT)
+ break;
+
+ if (parseParameterDeclaration(*parameter_declaration_ptr))
+ parameter_declaration_ptr = &(*parameter_declaration_ptr)->next;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseParameterDeclaration(DeclarationAST *&node)
+{
+ SpecifierAST *decl_specifier_seq = 0;
+ if (parseDeclSpecifierSeq(decl_specifier_seq)) {
+ ParameterDeclarationAST *ast = new (_pool) ParameterDeclarationAST;
+ ast->type_specifier = decl_specifier_seq;
+ parseDeclaratorOrAbstractDeclarator(ast->declarator);
+ if (LA() == T_EQUAL) {
+ ast->equal_token = consumeToken();
+ parseLogicalOrExpression(ast->expression);
+ }
+
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseClassSpecifier(SpecifierAST *&node)
+{
+ if (! lookAtClassKey())
+ return false;
+
+ unsigned classkey_token = consumeToken();
+
+ SpecifierAST *attributes = 0, **attr_ptr = &attributes;
+ while (LA() == T___ATTRIBUTE__) {
+ parseAttributeSpecifier(*attr_ptr);
+ attr_ptr = &(*attr_ptr)->next;
+ }
+
+ if (LA(1) == T_IDENTIFIER && LA(2) == T_IDENTIFIER) {
+ _translationUnit->warning(cursor(), "skip identifier `%s'",
+ tok().spell());
+ consumeToken();
+ }
+
+ NameAST *name = 0;
+ parseName(name);
+
+ bool parsed = false;
+
+ const bool previousInFunctionBody = _inFunctionBody;
+ _inFunctionBody = false;
+
+ unsigned colon_token = 0;
+
+ if (LA() == T_COLON || LA() == T_LBRACE) {
+ BaseSpecifierAST *base_clause = 0;
+ if (LA() == T_COLON) {
+ colon_token = cursor();
+ parseBaseClause(base_clause);
+ if (LA() != T_LBRACE) {
+ _translationUnit->error(cursor(), "expected `{' before `%s'", tok().spell());
+ unsigned saved = cursor();
+ for (int n = 0; n < 3 && LA() != T_EOF_SYMBOL; ++n, consumeToken()) {
+ if (LA() == T_LBRACE)
+ break;
+ }
+ if (LA() != T_LBRACE)
+ rewind(saved);
+ }
+ }
+
+ ClassSpecifierAST *ast = new (_pool) ClassSpecifierAST;
+ ast->classkey_token = classkey_token;
+ ast->attributes = attributes;
+ ast->name = name;
+ ast->colon_token = colon_token;
+ ast->base_clause = base_clause;
+
+ if (LA() == T_LBRACE)
+ ast->lbrace_token = consumeToken();
+
+ DeclarationAST **declaration_ptr = &ast->member_specifiers;
+ while (int tk = LA()) {
+ if (tk == T_RBRACE) {
+ ast->rbrace_token = consumeToken();
+ break;
+ }
+
+ unsigned start_declaration = cursor();
+ if (parseMemberSpecification(*declaration_ptr)) {
+ if (*declaration_ptr)
+ declaration_ptr = &(*declaration_ptr)->next;
+ } else {
+ rewind(start_declaration + 1);
+ skipUntilDeclaration();
+ }
+ }
+ node = ast;
+ parsed = true;
+ }
+
+ _inFunctionBody = previousInFunctionBody;
+
+ return parsed;
+}
+
+bool Parser::parseAccessSpecifier(SpecifierAST *&node)
+{
+ switch (LA()) {
+ case T_PUBLIC:
+ case T_PROTECTED:
+ case T_PRIVATE: {
+ SimpleSpecifierAST *ast = new (_pool) SimpleSpecifierAST;
+ ast->specifier_token = consumeToken();
+ node = ast;
+ return true;
+ }
+
+ default:
+ return false;
+ } // switch
+}
+
+bool Parser::parseAccessDeclaration(DeclarationAST *&node)
+{
+ if (LA() == T_PUBLIC || LA() == T_PROTECTED || LA() == T_PRIVATE || LA() == T_SIGNALS) {
+ bool isSignals = LA() == T_SIGNALS;
+ AccessDeclarationAST *ast = new (_pool) AccessDeclarationAST;
+ ast->access_specifier_token = consumeToken();
+ if (! isSignals && LA() == T_SLOTS)
+ ast->slots_token = consumeToken();
+ match(T_COLON, &ast->colon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseMemberSpecification(DeclarationAST *&node)
+{
+ switch (LA()) {
+ case T_SEMICOLON:
+ return parseEmptyDeclaration(node);
+
+ case T_USING:
+ return parseUsing(node);
+
+ case T_TEMPLATE:
+ return parseTemplateDeclaration(node);
+
+ case T_SIGNALS:
+ case T_PUBLIC:
+ case T_PROTECTED:
+ case T_PRIVATE:
+ return parseAccessDeclaration(node);
+
+ default:
+ return parseSimpleDeclaration(node, /*acceptStructDeclarator=*/true);
+ } // switch
+}
+
+bool Parser::parseCtorInitializer(CtorInitializerAST *&node)
+{
+ if (LA() == T_COLON) {
+ unsigned colon_token = consumeToken();
+
+ CtorInitializerAST *ast = new (_pool) CtorInitializerAST;
+ ast->colon_token = colon_token;
+
+ parseMemInitializerList(ast->member_initializers);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseElaboratedTypeSpecifier(SpecifierAST *&node)
+{
+ if (lookAtClassKey() || LA() == T_ENUM || LA() == T_TYPENAME) {
+ unsigned classkey_token = consumeToken();
+ NameAST *name = 0;
+ if (parseName(name)) {
+ ElaboratedTypeSpecifierAST *ast =
+ new (_pool) ElaboratedTypeSpecifierAST;
+
+ ast->classkey_token = classkey_token;
+ ast->name = name;
+ node = ast;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Parser::parseExceptionSpecification(ExceptionSpecificationAST *&node)
+{
+ if (LA() == T_THROW) {
+ ExceptionSpecificationAST *ast = new (_pool) ExceptionSpecificationAST;
+ ast->throw_token = consumeToken();
+ if (LA() == T_LPAREN)
+ ast->lparen_token = consumeToken();
+ if (LA() == T_DOT_DOT_DOT)
+ ast->dot_dot_dot_token = consumeToken();
+ else
+ parseTypeIdList(ast->type_ids);
+ if (LA() == T_RPAREN)
+ ast->rparen_token = consumeToken();
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseEnumerator(EnumeratorAST *&node)
+{
+ if (LA() == T_IDENTIFIER) {
+ EnumeratorAST *ast = new (_pool) EnumeratorAST;
+ ast->identifier_token = consumeToken();
+
+ if (LA() == T_EQUAL) {
+ ast->equal_token = consumeToken();
+ parseConstantExpression(ast->expression);
+ }
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseInitDeclarator(DeclaratorAST *&node,
+ bool acceptStructDeclarator)
+{
+ unsigned start = cursor();
+
+ if (acceptStructDeclarator && LA() == T_COLON) {
+ // anonymous bit-field declaration.
+ // ### TODO create the AST
+ } else if (! parseDeclarator(node)) {
+ return false;
+ }
+
+ if (LA() == T_ASM && LA(2) == T_LPAREN) { // ### FIXME
+ consumeToken();
+
+ if (skip(T_LPAREN, T_RPAREN))
+ consumeToken();
+ }
+
+ if (acceptStructDeclarator && node &&
+ ! node->postfix_declarators &&
+ node->core_declarator &&
+ node->core_declarator->asNestedDeclarator()) {
+ rewind(start);
+ return false;
+ }
+
+ if (acceptStructDeclarator && LA() == T_COLON
+ && (! node || ! node->postfix_declarators)) {
+ unsigned colon_token = consumeToken();
+ ExpressionAST *expression = 0;
+ if (parseConstantExpression(expression) && (LA() == T_COMMA ||
+ LA() == T_SEMICOLON)) {
+ // recognized a bitfielddeclarator.
+ // ### TODO create the AST
+ return true;
+ }
+ rewind(colon_token);
+ } else if (LA() == T_EQUAL || (! acceptStructDeclarator && LA() == T_LPAREN)) {
+ parseInitializer(node->initializer);
+ }
+ return true;
+}
+
+bool Parser::parseBaseClause(BaseSpecifierAST *&node)
+{
+ if (LA() == T_COLON) {
+ consumeToken();
+
+ BaseSpecifierAST **ast = &node;
+ if (parseBaseSpecifier(*ast)) {
+ ast = &(*ast)->next;
+
+ while (LA() == T_COMMA) {
+ consumeToken();
+
+ if (parseBaseSpecifier(*ast))
+ ast = &(*ast)->next;
+ }
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseInitializer(ExpressionAST *&node)
+{
+ if (LA() == T_LPAREN) {
+ return parsePrimaryExpression(node);
+ } else if (LA() == T_EQUAL) {
+ consumeToken();
+ return parseInitializerClause(node);
+ }
+ return false;
+}
+
+bool Parser::parseMemInitializerList(MemInitializerAST *&node)
+{
+ MemInitializerAST **initializer = &node;
+
+ if (parseMemInitializer(*initializer)) {
+ initializer = &(*initializer)->next;
+ while (LA() == T_COMMA) {
+ consumeToken();
+ if (parseMemInitializer(*initializer))
+ initializer = &(*initializer)->next;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseMemInitializer(MemInitializerAST *&node)
+{
+ NameAST *name = 0;
+ if (parseName(name) && LA() == T_LPAREN) {
+ MemInitializerAST *ast = new (_pool) MemInitializerAST;
+ ast->name = name;
+ ast->lparen_token = consumeToken();
+ parseExpression(ast->expression);
+ if (LA() == T_RPAREN)
+ ast->rparen_token = consumeToken();
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseTypeIdList(ExpressionListAST *&node)
+{
+ ExpressionListAST **expression_list_ptr = &node;
+ ExpressionAST *typeId = 0;
+ if (parseTypeId(typeId)) {
+ *expression_list_ptr = new (_pool) ExpressionListAST;
+ (*expression_list_ptr)->expression = typeId;
+ expression_list_ptr = &(*expression_list_ptr)->next;
+ while (LA() == T_COMMA) {
+ consumeToken();
+
+ if (parseTypeId(typeId)) {
+ *expression_list_ptr = new (_pool) ExpressionListAST;
+ (*expression_list_ptr)->expression = typeId;
+ expression_list_ptr = &(*expression_list_ptr)->next;
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool Parser::parseExpressionList(ExpressionListAST *&node)
+{
+ ExpressionListAST **expression_list_ptr = &node;
+ ExpressionAST *expression = 0;
+ if (parseAssignmentExpression(expression)) {
+ *expression_list_ptr = new (_pool) ExpressionListAST;
+ (*expression_list_ptr)->expression = expression;
+ expression_list_ptr = &(*expression_list_ptr)->next;
+ while (LA() == T_COMMA) {
+ consumeToken();
+
+ if (parseExpression(expression)) {
+ *expression_list_ptr = new (_pool) ExpressionListAST;
+ (*expression_list_ptr)->expression = expression;
+ expression_list_ptr = &(*expression_list_ptr)->next;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseBaseSpecifier(BaseSpecifierAST *&node)
+{
+ BaseSpecifierAST *ast = new (_pool) BaseSpecifierAST;
+
+ if (LA() == T_VIRTUAL) {
+ ast->token_virtual = consumeToken();
+
+ int tk = LA();
+ if (tk == T_PUBLIC || tk == T_PROTECTED || tk == T_PRIVATE)
+ ast->token_access_specifier = consumeToken();
+ } else {
+ int tk = LA();
+ if (tk == T_PUBLIC || tk == T_PROTECTED || tk == T_PRIVATE)
+ ast->token_access_specifier = consumeToken();
+
+ if (LA() == T_VIRTUAL)
+ ast->token_virtual = consumeToken();
+ }
+
+ parseName(ast->name);
+ if (! ast->name)
+ _translationUnit->error(cursor(), "expected class-name");
+ node = ast;
+ return true;
+}
+
+bool Parser::parseInitializerList(ExpressionListAST *&node)
+{
+ ExpressionListAST **initializer_ptr = &node;
+ ExpressionAST *initializer = 0;
+ if (parseInitializerClause(initializer)) {
+ *initializer_ptr = new (_pool) ExpressionListAST;
+ (*initializer_ptr)->expression = initializer;
+ initializer_ptr = &(*initializer_ptr)->next;
+ while (LA() == T_COMMA) {
+ consumeToken();
+ initializer = 0;
+ parseInitializerClause(initializer);
+ *initializer_ptr = new (_pool) ExpressionListAST;
+ (*initializer_ptr)->expression = initializer;
+ initializer_ptr = &(*initializer_ptr)->next;
+ }
+ }
+ return true;
+}
+
+bool Parser::parseInitializerClause(ExpressionAST *&node)
+{
+ if (LA() == T_LBRACE) {
+ ArrayInitializerAST *ast = new (_pool) ArrayInitializerAST;
+ ast->lbrace_token = consumeToken();
+ parseInitializerList(ast->expression_list);
+ match(T_RBRACE, &ast->rbrace_token);
+ node = ast;
+ return true;
+ }
+ return parseAssignmentExpression(node);
+}
+
+bool Parser::parseUnqualifiedName(NameAST *&node, bool acceptTemplateId)
+{
+ if (LA() == T_TILDE && LA(2) == T_IDENTIFIER) {
+ DestructorNameAST *ast = new (_pool) DestructorNameAST;
+ ast->tilde_token = consumeToken();
+ ast->identifier_token = consumeToken();
+ node = ast;
+ return true;
+ } else if (LA() == T_OPERATOR) {
+ unsigned operator_token = cursor();
+ if (parseOperatorFunctionId(node))
+ return true;
+ rewind(operator_token);
+ return parseConversionFunctionId(node);
+ } else if (LA() == T_IDENTIFIER) {
+ unsigned identifier_token = cursor();
+ if (acceptTemplateId && LA(2) == T_LESS && parseTemplateId(node)) {
+ if (! _templateArguments || (LA() == T_COMMA || LA() == T_GREATER ||
+ LA() == T_LPAREN || LA() == T_RPAREN ||
+ LA() == T_COLON_COLON))
+ return true;
+ }
+ rewind(identifier_token);
+ SimpleNameAST *ast = new (_pool) SimpleNameAST;
+ ast->identifier_token = consumeToken();
+ node = ast;
+ return true;
+ } else if (LA() == T_TEMPLATE) {
+ unsigned template_token = consumeToken();
+ if (parseTemplateId(node))
+ return true;
+ rewind(template_token);
+ }
+ return false;
+}
+
+bool Parser::parseStringLiteral(ExpressionAST *&node)
+{
+ if (! (LA() == T_STRING_LITERAL || LA() == T_WIDE_STRING_LITERAL))
+ return false;
+
+ StringLiteralAST **ast = reinterpret_cast<StringLiteralAST **> (&node);
+
+ while (LA() == T_STRING_LITERAL || LA() == T_WIDE_STRING_LITERAL) {
+ *ast = new (_pool) StringLiteralAST;
+ (*ast)->token = consumeToken();
+ ast = &(*ast)->next;
+ }
+ return true;
+}
+
+bool Parser::parseExpressionStatement(StatementAST *&node)
+{
+ ExpressionAST *expression = 0;
+ if (LA() == T_SEMICOLON || parseExpression(expression)) {
+ ExpressionStatementAST *ast = new (_pool) ExpressionStatementAST;
+ ast->expression = expression;
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseStatement(StatementAST *&node)
+{
+ switch (LA()) {
+ case T_WHILE:
+ return parseWhileStatement(node);
+
+ case T_DO:
+ return parseDoStatement(node);
+
+ case T_FOR:
+ return parseForStatement(node);
+
+ case T_IF:
+ return parseIfStatement(node);
+
+ case T_SWITCH:
+ return parseSwitchStatement(node);
+
+ case T_TRY:
+ return parseTryBlockStatement(node);
+
+ case T_CASE:
+ case T_DEFAULT:
+ return parseLabeledStatement(node);
+
+ case T_BREAK:
+ return parseBreakStatement(node);
+
+ case T_CONTINUE:
+ return parseContinueStatement(node);
+
+ case T_GOTO:
+ return parseGotoStatement(node);
+
+ case T_RETURN:
+ return parseReturnStatement(node);
+
+ case T_LBRACE:
+ return parseCompoundStatement(node);
+
+ case T_ASM:
+ case T_NAMESPACE:
+ case T_USING:
+ case T_TEMPLATE:
+ case T_CLASS: case T_STRUCT: case T_UNION:
+ return parseDeclarationStatement(node);
+
+ case T_SEMICOLON: {
+ ExpressionStatementAST *ast = new (_pool) ExpressionStatementAST;
+ ast->semicolon_token = consumeToken();
+ node = ast;
+ return true;
+ }
+
+ default:
+ if (LA() == T_IDENTIFIER && LA(2) == T_COLON)
+ return parseLabeledStatement(node);
+
+ return parseExpressionOrDeclarationStatement(node);
+ } // switch
+ return false;
+}
+
+bool Parser::parseBreakStatement(StatementAST *&node)
+{
+ if (LA() == T_BREAK) {
+ BreakStatementAST *ast = new (_pool) BreakStatementAST;
+ ast->break_token = consumeToken();
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseContinueStatement(StatementAST *&node)
+{
+ if (LA() == T_CONTINUE) {
+ ContinueStatementAST *ast = new (_pool) ContinueStatementAST;
+ ast->continue_token = consumeToken();
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseGotoStatement(StatementAST *&node)
+{
+ if (LA() == T_GOTO) {
+ GotoStatementAST *ast = new (_pool) GotoStatementAST;
+ ast->goto_token = consumeToken();
+ match(T_IDENTIFIER, &ast->identifier_token);
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseReturnStatement(StatementAST *&node)
+{
+ if (LA() == T_RETURN) {
+ ReturnStatementAST *ast = new (_pool) ReturnStatementAST;
+ ast->return_token = consumeToken();
+ parseExpression(ast->expression);
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::maybeFunctionCall(SimpleDeclarationAST *simpleDecl) const
+{
+ if (! simpleDecl)
+ return false;
+ else if (! simpleDecl->decl_specifier_seq)
+ return false;
+ else if (simpleDecl->decl_specifier_seq->next)
+ return false;
+
+ NamedTypeSpecifierAST *type_spec = simpleDecl->decl_specifier_seq->asNamedTypeSpecifier();
+ if (! type_spec)
+ return false;
+
+ DeclaratorListAST *first_declarator = simpleDecl->declarators;
+ if (! first_declarator)
+ return false;
+ else if (first_declarator->next)
+ return false;
+
+ DeclaratorAST *declarator = first_declarator->declarator;
+ if (! declarator)
+ return false;
+ else if (declarator->ptr_operators)
+ return false;
+ else if (declarator->postfix_declarators)
+ return false;
+ else if (declarator->initializer)
+ return false;
+ else if (! declarator->core_declarator)
+ return false;
+
+ NestedDeclaratorAST *nested_declarator = declarator->core_declarator->asNestedDeclarator();
+ if (! nested_declarator)
+ return false;
+
+ return true;
+}
+
+bool Parser::maybeSimpleExpression(SimpleDeclarationAST *simpleDecl) const
+{
+ if (! simpleDecl->declarators) {
+ SpecifierAST *spec = simpleDecl->decl_specifier_seq;
+ if (spec && ! spec->next && spec->asNamedTypeSpecifier()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Parser::parseExpressionOrDeclarationStatement(StatementAST *&node)
+{
+ if (LA() == T_SEMICOLON)
+ return parseExpressionStatement(node);
+
+ unsigned start = cursor();
+ bool blocked = blockErrors(true);
+ if (parseDeclarationStatement(node)) {
+ DeclarationStatementAST *stmt = static_cast<DeclarationStatementAST *>(node);
+ SimpleDeclarationAST *simpleDecl = 0;
+ if (stmt->declaration)
+ simpleDecl = stmt->declaration->asSimpleDeclaration();
+
+ if (simpleDecl && simpleDecl->decl_specifier_seq &&
+ ! maybeFunctionCall(simpleDecl) && ! maybeSimpleExpression(simpleDecl)) {
+ unsigned end_of_declaration_statement = cursor();
+ rewind(start);
+ StatementAST *expression = 0;
+ if (! parseExpressionStatement(expression) || cursor() != end_of_declaration_statement) {
+ rewind(end_of_declaration_statement);
+ } else {
+ ExpressionOrDeclarationStatementAST *ast =
+ new (_pool) ExpressionOrDeclarationStatementAST;
+ ast->declaration = node;
+ ast->expression = expression;
+ node = ast;
+ }
+ blockErrors(blocked);
+ return true;
+ }
+ }
+
+ blockErrors(blocked);
+ rewind(start);
+ return parseExpressionStatement(node);
+}
+
+bool Parser::parseCondition(ExpressionAST *&node)
+{
+ unsigned start = cursor();
+
+ bool blocked = blockErrors(true);
+ SpecifierAST *type_specifier = 0;
+ if (parseTypeSpecifier(type_specifier)) {
+ DeclaratorAST *declarator = 0;
+ if (parseInitDeclarator(declarator, /*acceptStructDeclarator=*/false)) {
+ if (declarator->initializer) {
+ ConditionAST *ast = new (_pool) ConditionAST;
+ ast->type_specifier = type_specifier;
+ ast->declarator = declarator;
+ node = ast;
+ blockErrors(blocked);
+ return true;
+ }
+ }
+ }
+
+ blockErrors(blocked);
+ rewind(start);
+ return parseExpression(node);
+}
+
+bool Parser::parseWhileStatement(StatementAST *&node)
+{
+ if (LA() == T_WHILE) {
+ WhileStatementAST *ast = new (_pool) WhileStatementAST;
+ ast->while_token = consumeToken();
+ match(T_LPAREN, &ast->lparen_token);
+ parseCondition(ast->condition);
+ match(T_RPAREN, &ast->rparen_token);
+ parseStatement(ast->statement);
+ node = ast;
+ return true;
+ }
+ return true;
+}
+
+bool Parser::parseDoStatement(StatementAST *&node)
+{
+ if (LA() == T_DO) {
+ DoStatementAST *ast = new (_pool) DoStatementAST;
+ ast->do_token = consumeToken();
+ parseStatement(ast->statement);
+ match(T_WHILE, &ast->while_token);
+ match(T_LPAREN, &ast->lparen_token);
+ parseExpression(ast->expression);
+ match(T_RPAREN, &ast->rparen_token);
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseForStatement(StatementAST *&node)
+{
+ if (LA() == T_FOR) {
+ ForStatementAST *ast = new (_pool) ForStatementAST;
+ ast->for_token = consumeToken();
+ match(T_LPAREN, &ast->lparen_token);
+ parseForInitStatement(ast->initializer);
+ parseExpression(ast->condition);
+ match(T_SEMICOLON, &ast->semicolon_token);
+ parseExpression(ast->expression);
+ match(T_RPAREN, &ast->rparen_token);
+ parseStatement(ast->statement);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseForInitStatement(StatementAST *&node)
+{
+ return parseExpressionOrDeclarationStatement(node);
+}
+
+bool Parser::parseCompoundStatement(StatementAST *&node)
+{
+ if (LA() == T_LBRACE) {
+ CompoundStatementAST *ast = new (_pool) CompoundStatementAST;
+ ast->lbrace_token = consumeToken();
+ StatementAST **statement_ptr = &ast->statements;
+ while (int tk = LA()) {
+ if (tk == T_RBRACE)
+ break;
+
+ unsigned start_statement = cursor();
+ if (! parseStatement(*statement_ptr)) {
+ rewind(start_statement + 1);
+ skipUntilStatement();
+ } else {
+ statement_ptr = &(*statement_ptr)->next;
+ }
+ }
+ match(T_RBRACE, &ast->rbrace_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseIfStatement(StatementAST *&node)
+{
+ if (LA() == T_IF) {
+ IfStatementAST *ast = new (_pool) IfStatementAST;
+ ast->if_token = consumeToken();
+ match(T_LPAREN, &ast->lparen_token);
+ parseCondition(ast->condition);
+ match(T_RPAREN, &ast->rparen_token);
+ if (! parseStatement(ast->statement))
+ _translationUnit->error(cursor(), "expected statement");
+ if (LA() == T_ELSE) {
+ ast->else_token = consumeToken();
+ if (! parseStatement(ast->else_statement))
+ _translationUnit->error(cursor(), "expected statement");
+ }
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseSwitchStatement(StatementAST *&node)
+{
+ if (LA() == T_SWITCH) {
+ SwitchStatementAST *ast = new (_pool) SwitchStatementAST;
+ ast->switch_token = consumeToken();
+ match(T_LPAREN, &ast->lparen_token);
+ parseCondition(ast->condition);
+ match(T_RPAREN, &ast->rparen_token);
+ parseStatement(ast->statement);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseLabeledStatement(StatementAST *&node)
+{
+ switch (LA()) {
+ case T_IDENTIFIER:
+ if (LA(2) == T_COLON) {
+ LabeledStatementAST *ast = new (_pool) LabeledStatementAST;
+ ast->label_token = consumeToken();
+ ast->colon_token = consumeToken();
+ parseStatement(ast->statement);
+ node = ast;
+ return true;
+ }
+ break;
+
+ case T_DEFAULT: {
+ LabeledStatementAST *ast = new (_pool) LabeledStatementAST;
+ ast->label_token = consumeToken();
+ match(T_COLON, &ast->colon_token);
+ parseStatement(ast->statement);
+ node = ast;
+ return true;
+ }
+
+ case T_CASE: {
+ CaseStatementAST *ast = new (_pool) CaseStatementAST;
+ ast->case_token = consumeToken();
+ parseConstantExpression(ast->expression);
+ match(T_COLON, &ast->colon_token);
+ parseStatement(ast->statement);
+ node = ast;
+ return true;
+ }
+
+ default:
+ break;
+ } // switch
+ return false;
+}
+
+bool Parser::parseBlockDeclaration(DeclarationAST *&node)
+{
+ switch (LA()) {
+ case T_USING:
+ return parseUsing(node);
+
+ case T_ASM:
+ return parseAsmDefinition(node);
+
+ case T_NAMESPACE:
+ return parseNamespaceAliasDefinition(node);
+
+ default:
+ return parseSimpleDeclaration(node);
+ } // switch
+
+}
+
+bool Parser::parseNamespaceAliasDefinition(DeclarationAST *&node)
+{
+ if (LA() == T_NAMESPACE && LA(2) == T_IDENTIFIER && LA(3) == T_EQUAL) {
+ NamespaceAliasDefinitionAST *ast = new (_pool) NamespaceAliasDefinitionAST;
+ ast->namespace_token = consumeToken();
+ ast->namespace_name = consumeToken();
+ ast->equal_token = consumeToken();
+ parseName(ast->name);
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseDeclarationStatement(StatementAST *&node)
+{
+ DeclarationAST *declaration = 0;
+ if (! parseBlockDeclaration(declaration))
+ return false;
+
+ DeclarationStatementAST *ast = new (_pool) DeclarationStatementAST;
+ ast->declaration = declaration;
+ node = ast;
+ return true;
+}
+
+bool Parser::lookAtCVQualifier() const
+{
+ switch (LA()) {
+ case T_CONST:
+ case T_VOLATILE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Parser::lookAtFunctionSpecifier() const
+{
+ switch (LA()) {
+ case T_INLINE:
+ case T_VIRTUAL:
+ case T_EXPLICIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Parser::lookAtStorageClassSpecifier() const
+{
+ switch (LA()) {
+ case T_FRIEND:
+ case T_AUTO:
+ case T_REGISTER:
+ case T_STATIC:
+ case T_EXTERN:
+ case T_MUTABLE:
+ case T_TYPEDEF:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Parser::lookAtBuiltinTypeSpecifier() const
+{
+ switch (LA()) {
+ case T_CHAR:
+ case T_WCHAR_T:
+ case T_BOOL:
+ case T_SHORT:
+ case T_INT:
+ case T_LONG:
+ case T_SIGNED:
+ case T_UNSIGNED:
+ case T_FLOAT:
+ case T_DOUBLE:
+ case T_VOID:
+ return true;
+ // [gcc] extensions
+ case T___TYPEOF__:
+ case T___ATTRIBUTE__:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Parser::lookAtClassKey() const
+{
+ switch (LA()) {
+ case T_CLASS:
+ case T_STRUCT:
+ case T_UNION:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Parser::parseAttributeSpecifier(SpecifierAST *&node)
+{
+ if (LA() != T___ATTRIBUTE__)
+ return false;
+
+ AttributeSpecifierAST *ast = new (_pool) AttributeSpecifierAST;
+ ast->attribute_token = consumeToken();
+ match(T_LPAREN, &ast->first_lparen_token);
+ match(T_LPAREN, &ast->second_lparen_token);
+ parseAttributeList(ast->attributes);
+ match(T_RPAREN, &ast->first_rparen_token);
+ match(T_RPAREN, &ast->second_rparen_token);
+ node = ast;
+ return true;
+}
+
+bool Parser::parseAttributeList(AttributeAST *&node)
+{
+ AttributeAST **attribute_ptr = &node;
+ while (LA() == T_IDENTIFIER || LA() == T_CONST) {
+ AttributeAST *ast = new (_pool) AttributeAST;
+ ast->identifier_token = consumeToken();
+ if (LA() == T_LPAREN) {
+ consumeToken();
+ if (LA() == T_IDENTIFIER && (LA(2) == T_COMMA || LA(2) == T_RPAREN)) {
+ ast->tag_token = consumeToken();
+ if (LA() == T_COMMA) {
+ consumeToken();
+ parseExpressionList(ast->expression_list);
+ }
+ } else {
+ parseExpressionList(ast->expression_list);
+ }
+ unsigned rparen_token = 0;
+ match(T_RPAREN, &rparen_token);
+ }
+ *attribute_ptr = ast;
+
+ if (LA() != T_COMMA)
+ break;
+
+ consumeToken();
+ attribute_ptr = &(*attribute_ptr)->next;
+ }
+ return true;
+}
+
+bool Parser::parseBuiltinTypeSpecifier(SpecifierAST *&node)
+{
+ if (LA() == T___ATTRIBUTE__) {
+ return parseAttributeSpecifier(node);
+ } else if (LA() == T___TYPEOF__) {
+ TypeofSpecifierAST *ast = new (_pool) TypeofSpecifierAST;
+ ast->typeof_token = consumeToken();
+ if (LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+ if (parseTypeId(ast->expression) && LA() == T_RPAREN) {
+ consumeToken();
+ node = ast;
+ return true;
+ }
+ rewind(lparen_token);
+ }
+ parseUnaryExpression(ast->expression);
+ node = ast;
+ return true;
+ } else if (lookAtBuiltinTypeSpecifier()) {
+ SimpleSpecifierAST *ast = new (_pool) SimpleSpecifierAST;
+ ast->specifier_token = consumeToken();
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseSimpleDeclaration(DeclarationAST *&node,
+ bool acceptStructDeclarator)
+{
+ // parse a simple declaration, a function definition,
+ // or a contructor declaration.
+ cursor();
+
+ bool has_type_specifier = false;
+ bool has_complex_type_specifier = false;
+ unsigned startOfNamedTypeSpecifier = 0;
+ NameAST *named_type_specifier = 0;
+ SpecifierAST *decl_specifier_seq = 0,
+ **decl_specifier_seq_ptr = &decl_specifier_seq;
+ for (;;) {
+ if (lookAtCVQualifier() || lookAtFunctionSpecifier()
+ || lookAtStorageClassSpecifier()) {
+ SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
+ spec->specifier_token = consumeToken();
+ *decl_specifier_seq_ptr = spec;
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ } else if (LA() == T___ATTRIBUTE__) {
+ parseAttributeSpecifier(*decl_specifier_seq_ptr);
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ } else if (! named_type_specifier && ! has_complex_type_specifier && lookAtBuiltinTypeSpecifier()) {
+ parseBuiltinTypeSpecifier(*decl_specifier_seq_ptr);
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ has_type_specifier = true;
+ } else if (! has_type_specifier && (LA() == T_COLON_COLON ||
+ LA() == T_IDENTIFIER)) {
+ startOfNamedTypeSpecifier = cursor();
+ if (parseName(named_type_specifier)) {
+ NamedTypeSpecifierAST *spec = new (_pool) NamedTypeSpecifierAST;
+ spec->name = named_type_specifier;
+ *decl_specifier_seq_ptr = spec;
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ has_type_specifier = true;
+ } else {
+ rewind(startOfNamedTypeSpecifier);
+ break;
+ }
+ } else if (! has_type_specifier && LA() == T_ENUM) {
+ unsigned startOfTypeSpecifier = cursor();
+ if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr) || LA() == T_LBRACE) {
+ rewind(startOfTypeSpecifier);
+ if (! parseEnumSpecifier(*decl_specifier_seq_ptr)) {
+ _translationUnit->error(startOfTypeSpecifier,
+ "expected an enum specifier");
+ break;
+ }
+ has_complex_type_specifier = true;
+ }
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ has_type_specifier = true;
+ } else if (! has_type_specifier && LA() == T_TYPENAME) {
+ unsigned startOfElaboratedTypeSpecifier = cursor();
+ if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr)) {
+ _translationUnit->error(startOfElaboratedTypeSpecifier,
+ "expected an elaborated type specifier");
+ break;
+ }
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ has_type_specifier = true;
+ } else if (! has_type_specifier && lookAtClassKey()) {
+ unsigned startOfTypeSpecifier = cursor();
+ if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr) ||
+ (LA() == T_COLON || LA() == T_LBRACE || (LA(0) == T_IDENTIFIER && LA(1) == T_IDENTIFIER &&
+ (LA(2) == T_COLON || LA(2) == T_LBRACE)))) {
+ rewind(startOfTypeSpecifier);
+ if (! parseClassSpecifier(*decl_specifier_seq_ptr)) {
+ _translationUnit->error(startOfTypeSpecifier,
+ "wrong type specifier");
+ break;
+ }
+ has_complex_type_specifier = true;
+ }
+ decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+ has_type_specifier = true;
+ } else
+ break;
+ }
+
+ DeclaratorListAST *declarator_list = 0,
+ **declarator_ptr = &declarator_list;
+
+ const bool maybeCtor = (LA() == T_LPAREN && named_type_specifier);
+ DeclaratorAST *declarator = 0;
+ if (! parseInitDeclarator(declarator, acceptStructDeclarator) && maybeCtor) {
+ rewind(startOfNamedTypeSpecifier);
+ named_type_specifier = 0;
+ // pop the named type specifier from the decl-specifier-seq
+ SpecifierAST **spec_ptr = &decl_specifier_seq;
+ for (; *spec_ptr; spec_ptr = &(*spec_ptr)->next) {
+ if (! (*spec_ptr)->next) {
+ *spec_ptr = 0;
+ break;
+ }
+ }
+ if (! parseInitDeclarator(declarator, acceptStructDeclarator))
+ return false;
+ }
+
+ DeclaratorAST *firstDeclarator = declarator;
+
+ if (declarator) {
+ *declarator_ptr = new (_pool) DeclaratorListAST;
+ (*declarator_ptr)->declarator = declarator;
+ declarator_ptr = &(*declarator_ptr)->next;
+ }
+
+ if (LA() == T_COMMA || LA() == T_SEMICOLON || has_complex_type_specifier) {
+ while (LA() == T_COMMA) {
+ consumeToken();
+ declarator = 0;
+ if (parseInitDeclarator(declarator, acceptStructDeclarator)) {
+ *declarator_ptr = new (_pool) DeclaratorListAST;
+ (*declarator_ptr)->declarator = declarator;
+ declarator_ptr = &(*declarator_ptr)->next;
+ }
+ }
+ SimpleDeclarationAST *ast = new (_pool) SimpleDeclarationAST;
+ ast->decl_specifier_seq = decl_specifier_seq;
+ ast->declarators = declarator_list;
+ match(T_SEMICOLON, &ast->semicolon_token);
+ node = ast;
+ return true;
+ } else if (! _inFunctionBody && declarator && (LA() == T_COLON || LA() == T_LBRACE || LA() == T_TRY)) {
+ CtorInitializerAST *ctor_initializer = 0;
+ if (LA() == T_COLON)
+ parseCtorInitializer(ctor_initializer);
+
+ if (LA() == T_LBRACE) {
+ FunctionDefinitionAST *ast = new (_pool) FunctionDefinitionAST;
+ ast->decl_specifier_seq = decl_specifier_seq;
+ ast->declarator = firstDeclarator;
+ ast->ctor_initializer = ctor_initializer;
+ parseFunctionBody(ast->function_body);
+ node = ast;
+ return true; // recognized a function definition.
+ } else if (LA() == T_TRY) {
+ FunctionDefinitionAST *ast = new (_pool) FunctionDefinitionAST;
+ ast->decl_specifier_seq = decl_specifier_seq;
+ ast->declarator = firstDeclarator;
+ ast->ctor_initializer = ctor_initializer;
+ parseTryBlockStatement(ast->function_body);
+ node = ast;
+ return true; // recognized a function definition.
+ }
+ }
+
+ _translationUnit->error(cursor(), "unexpected token `%s'", tok().spell());
+ return false;
+}
+
+bool Parser::parseFunctionBody(StatementAST *&node)
+{
+ if (_translationUnit->skipFunctionBody()) {
+ unsigned token_lbrace = 0;
+ match(T_LBRACE, &token_lbrace);
+ if (! token_lbrace)
+ return false;
+
+ const Token &tk = _translationUnit->tokenAt(token_lbrace);
+ if (tk.close_brace)
+ rewind(tk.close_brace);
+ unsigned token_rbrace = 0;
+ match(T_RBRACE, &token_rbrace);
+ return true;
+ }
+
+ _inFunctionBody = true;
+ const bool parsed = parseCompoundStatement(node);
+ _inFunctionBody = false;
+ return parsed;
+}
+
+bool Parser::parseTryBlockStatement(StatementAST *&node)
+{
+ if (LA() == T_TRY) {
+ TryBlockStatementAST *ast = new (_pool) TryBlockStatementAST;
+ ast->try_token = consumeToken();
+ parseCompoundStatement(ast->statement);
+ CatchClauseAST **catch_clause_ptr = &ast->catch_clause_seq;
+ while (parseCatchClause(*catch_clause_ptr))
+ catch_clause_ptr = &(*catch_clause_ptr)->next;
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseCatchClause(CatchClauseAST *&node)
+{
+ if (LA() == T_CATCH) {
+ CatchClauseAST *ast = new (_pool) CatchClauseAST;
+ ast->catch_token = consumeToken();
+ match(T_LPAREN, &ast->lparen_token);
+ parseExceptionDeclaration(ast->exception_declaration);
+ match(T_RPAREN, &ast->rparen_token);
+ parseCompoundStatement(ast->statement);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseExceptionDeclaration(ExceptionDeclarationAST *&node)
+{
+ if (LA() == T_DOT_DOT_DOT) {
+ ExceptionDeclarationAST *ast = new (_pool) ExceptionDeclarationAST;
+ ast->dot_dot_dot_token = consumeToken();
+ node = ast;
+ return true;
+ }
+
+ SpecifierAST *type_specifier = 0;
+ if (parseTypeSpecifier(type_specifier)) {
+ ExceptionDeclarationAST *ast = new (_pool) ExceptionDeclarationAST;
+ ast->type_specifier = type_specifier;
+ parseDeclaratorOrAbstractDeclarator(ast->declarator);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseBoolLiteral(ExpressionAST *&node)
+{
+ if (LA() == T_TRUE || LA() == T_FALSE) {
+ BoolLiteralAST *ast = new (_pool) BoolLiteralAST;
+ ast->token = consumeToken();
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseNumericLiteral(ExpressionAST *&node)
+{
+ if (LA() == T_INT_LITERAL || LA() == T_FLOAT_LITERAL || LA() == T_CHAR_LITERAL) {
+ NumericLiteralAST *ast = new (_pool) NumericLiteralAST;
+ ast->token = consumeToken();
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseThisExpression(ExpressionAST *&node)
+{
+ if (LA() == T_THIS) {
+ ThisExpressionAST *ast = new (_pool) ThisExpressionAST;
+ ast->this_token = consumeToken();
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parsePrimaryExpression(ExpressionAST *&node)
+{
+ switch (LA()) {
+ case T_STRING_LITERAL:
+ case T_WIDE_STRING_LITERAL:
+ return parseStringLiteral(node);
+
+ case T_INT_LITERAL:
+ case T_FLOAT_LITERAL:
+ case T_CHAR_LITERAL:
+ case T_WIDE_CHAR_LITERAL:
+ return parseNumericLiteral(node);
+
+ case T_TRUE:
+ case T_FALSE:
+ return parseBoolLiteral(node);
+
+ case T_THIS:
+ return parseThisExpression(node);
+
+ case T_LPAREN:
+ return parseNestedExpression(node);
+
+ case T_SIGNAL:
+ case T_SLOT:
+ return parseQtMethod(node);
+
+ default: {
+ NameAST *name = 0;
+ if (parseNameId(name)) {
+ node = name;
+ return true;
+ }
+ break;
+ } // default
+
+ } // switch
+
+ return false;
+}
+
+bool Parser::parseNameId(NameAST *&name)
+{
+ unsigned start = cursor();
+ if (! parseName(name))
+ return false;
+
+ if (LA() == T_IDENTIFIER ||
+ tok().isLiteral() ||
+ (tok().isOperator() && LA() != T_LPAREN && LA() != T_LBRACKET))
+ {
+ rewind(start);
+ return parseName(name, false);
+ }
+
+ return true;
+}
+
+bool Parser::parseNestedExpression(ExpressionAST *&node)
+{
+ if (LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+
+ if (LA() == T_LBRACE) {
+ NestedExpressionAST *ast = new (_pool) NestedExpressionAST;
+ ast->lparen_token = lparen_token;
+
+ // ### ast
+ StatementAST *statement = 0;
+ parseCompoundStatement(statement);
+ match(T_RPAREN, &ast->rparen_token);
+ node = ast;
+ return true;
+ }
+
+ bool previousTemplateArguments = switchTemplateArguments(false);
+
+ ExpressionAST *expression = 0;
+ if (parseExpression(expression) && LA() == T_RPAREN) {
+ NestedExpressionAST *ast = new (_pool) NestedExpressionAST;
+ ast->lparen_token = lparen_token;
+ ast->expression = expression;
+ ast->rparen_token = consumeToken();
+ node = ast;
+ (void) switchTemplateArguments(previousTemplateArguments);
+ return true;
+ }
+ (void) switchTemplateArguments(previousTemplateArguments);
+ }
+ return false;
+}
+
+bool Parser::parseCppCastExpression(ExpressionAST *&node)
+{
+ if (LA() == T_DYNAMIC_CAST || LA() == T_STATIC_CAST ||
+ LA() == T_REINTERPRET_CAST || LA() == T_CONST_CAST) {
+ CppCastExpressionAST *ast = new (_pool) CppCastExpressionAST;
+ ast->cast_token = consumeToken();
+ match(T_LESS, &ast->less_token);
+ parseTypeId(ast->type_id);
+ match(T_GREATER, &ast->greater_token);
+ match(T_LPAREN, &ast->lparen_token);
+ parseExpression(ast->expression);
+ match(T_RPAREN, &ast->rparen_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+// typename ::opt nested-name-specifier identifier ( expression-listopt )
+// typename ::opt nested-name-specifier templateopt template-id ( expression-listopt )
+bool Parser::parseTypenameCallExpression(ExpressionAST *&node)
+{
+ if (LA() == T_TYPENAME) {
+ unsigned typename_token = consumeToken();
+ NameAST *name = 0;
+ if (parseName(name) && LA() == T_LPAREN) {
+ TypenameCallExpressionAST *ast = new (_pool) TypenameCallExpressionAST;
+ ast->typename_token = typename_token;
+ ast->name = name;
+ ast->lparen_token = consumeToken();
+ parseExpressionList(ast->expression_list);
+ match(T_RPAREN, &ast->rparen_token);
+ node = ast;
+ return true;
+ }
+ }
+ return false;
+}
+
+// typeid ( expression )
+// typeid ( type-id )
+bool Parser::parseTypeidExpression(ExpressionAST *&node)
+{
+ if (LA() == T_TYPEID) {
+ TypeidExpressionAST *ast = new (_pool) TypeidExpressionAST;
+ ast->typeid_token = consumeToken();
+ if (LA() == T_LPAREN)
+ ast->lparen_token = consumeToken();
+ unsigned saved = cursor();
+ if (! (parseTypeId(ast->expression) && LA() == T_RPAREN)) {
+ rewind(saved);
+ parseExpression(ast->expression);
+ }
+ match(T_RPAREN, &ast->rparen_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseCorePostfixExpression(ExpressionAST *&node)
+{
+ if (parseCppCastExpression(node))
+ return true;
+ else if (parseTypenameCallExpression(node))
+ return true;
+ else if (parseTypeidExpression(node))
+ return true;
+ else {
+ unsigned start = cursor();
+ SpecifierAST *type_specifier = 0;
+ bool blocked = blockErrors(true);
+ if (lookAtBuiltinTypeSpecifier() &&
+ parseSimpleTypeSpecifier(type_specifier) &&
+ LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+ ExpressionListAST *expression_list = 0;
+ parseExpressionList(expression_list);
+ if (LA() == T_RPAREN) {
+ unsigned rparen_token = consumeToken();
+ TypeConstructorCallAST *ast = new (_pool) TypeConstructorCallAST;
+ ast->type_specifier = type_specifier;
+ ast->lparen_token = lparen_token;
+ ast->expression_list = expression_list;
+ ast->rparen_token = rparen_token;
+ node = ast;
+ blockErrors(blocked);
+ return true;
+ }
+ }
+ rewind(start);
+
+ // look for compound literals
+ if (LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+ ExpressionAST *type_id = 0;
+ if (parseTypeId(type_id) && LA() == T_RPAREN) {
+ unsigned rparen_token = consumeToken();
+ if (LA() == T_LBRACE) {
+ blockErrors(blocked);
+
+ CompoundLiteralAST *ast = new (_pool) CompoundLiteralAST;
+ ast->lparen_token = lparen_token;
+ ast->type_id = type_id;
+ ast->rparen_token = rparen_token;
+ parseInitializerClause(ast->initializer);
+ node = ast;
+ return true;
+ }
+ }
+ rewind(start);
+ }
+
+ blockErrors(blocked);
+ return parsePrimaryExpression(node);
+ }
+}
+
+bool Parser::parsePostfixExpression(ExpressionAST *&node)
+{
+ if (parseCorePostfixExpression(node)) {
+ PostfixAST *postfix_expressions = 0,
+ **postfix_ptr = &postfix_expressions;
+ while (LA()) {
+ if (LA() == T_LPAREN) {
+ CallAST *ast = new (_pool) CallAST;
+ ast->lparen_token = consumeToken();
+ parseExpressionList(ast->expression_list);
+ match(T_RPAREN, &ast->rparen_token);
+ *postfix_ptr = ast;
+ postfix_ptr = &(*postfix_ptr)->next;
+ } else if (LA() == T_LBRACKET) {
+ ArrayAccessAST *ast = new (_pool) ArrayAccessAST;
+ ast->lbracket_token = consumeToken();
+ parseExpression(ast->expression);
+ match(T_RBRACKET, &ast->rbracket_token);
+ *postfix_ptr = ast;
+ postfix_ptr = &(*postfix_ptr)->next;
+ } else if (LA() == T_PLUS_PLUS || LA() == T_MINUS_MINUS) {
+ PostIncrDecrAST *ast = new (_pool) PostIncrDecrAST;
+ ast->incr_decr_token = consumeToken();
+ *postfix_ptr = ast;
+ postfix_ptr = &(*postfix_ptr)->next;
+ } else if (LA() == T_DOT || LA() == T_ARROW) {
+ MemberAccessAST *ast = new (_pool) MemberAccessAST;
+ ast->access_token = consumeToken();
+ if (LA() == T_TEMPLATE)
+ ast->template_token = consumeToken();
+ if (! parseNameId(ast->member_name))
+ _translationUnit->error(cursor(), "expected unqualified-id before token `%s'",
+ tok().spell());
+ *postfix_ptr = ast;
+ postfix_ptr = &(*postfix_ptr)->next;
+ } else break;
+ } // while
+
+ if (postfix_expressions) {
+ PostfixExpressionAST *ast = new (_pool) PostfixExpressionAST;
+ ast->base_expression = node;
+ ast->postfix_expressions = postfix_expressions;
+ node = ast;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseUnaryExpression(ExpressionAST *&node)
+{
+ switch (LA()) {
+ case T_PLUS_PLUS:
+ case T_MINUS_MINUS:
+ case T_STAR:
+ case T_AMPER:
+ case T_PLUS:
+ case T_MINUS:
+ case T_EXCLAIM: {
+ UnaryExpressionAST *ast = new (_pool) UnaryExpressionAST;
+ ast->unary_op_token = consumeToken();
+ parseCastExpression(ast->expression);
+ node = ast;
+ return true;
+ }
+
+ case T_TILDE: {
+ if (LA(2) == T_IDENTIFIER && LA(3) == T_LPAREN)
+ break; // prefer destructor names
+
+ UnaryExpressionAST *ast = new (_pool) UnaryExpressionAST;
+ ast->unary_op_token = consumeToken();
+ parseCastExpression(ast->expression);
+ node = ast;
+ return true;
+ }
+
+ case T_SIZEOF: {
+ SizeofExpressionAST *ast = new (_pool) SizeofExpressionAST;
+ ast->sizeof_token = consumeToken();
+
+ if (LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+ if (parseTypeId(ast->expression) && LA() == T_RPAREN) {
+ consumeToken();
+ node = ast;
+ return true;
+ } else {
+ rewind(lparen_token);
+ }
+ }
+
+ parseUnaryExpression(ast->expression);
+ node = ast;
+ return true;
+ }
+
+ default:
+ break;
+ } // switch
+
+ if (LA() == T_NEW || (LA(1) == T_COLON_COLON &&
+ LA(2) == T_NEW))
+ return parseNewExpression(node);
+ else if (LA() == T_DELETE || (LA(1) == T_COLON_COLON &&
+ LA(2) == T_DELETE))
+ return parseDeleteExpression(node);
+ else
+ return parsePostfixExpression(node);
+}
+
+bool Parser::parseNewExpression(ExpressionAST *&node)
+{
+ if (LA() == T_NEW || (LA() == T_COLON_COLON && LA(2) == T_NEW)) {
+ NewExpressionAST *ast = new (_pool) NewExpressionAST;
+
+ if (LA() == T_COLON_COLON)
+ ast->scope_token = consumeToken();
+
+ ast->new_token = consumeToken();
+
+ if (LA() == T_LPAREN) {
+ consumeToken();
+ parseExpression(ast->expression);
+ if (LA() == T_RPAREN)
+ consumeToken();
+ }
+
+ if (LA() == T_LPAREN) {
+ consumeToken();
+ parseTypeId(ast->type_id);
+ if (LA() == T_RPAREN)
+ consumeToken();
+ } else {
+ parseNewTypeId(ast->new_type_id);
+ }
+
+ parseNewInitializer(ast->new_initializer);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseNewTypeId(NewTypeIdAST *&node)
+{
+ SpecifierAST *typeSpec = 0;
+ if (! parseTypeSpecifier(typeSpec))
+ return false;
+
+ NewTypeIdAST *ast = new (_pool) NewTypeIdAST;
+ ast->type_specifier = typeSpec;
+ parseNewDeclarator(ast->new_declarator);
+ node = ast;
+ return true;
+}
+
+bool Parser::parseNewDeclarator(NewDeclaratorAST *&node)
+{
+ NewDeclaratorAST *ast = new (_pool) NewDeclaratorAST;
+
+ PtrOperatorAST **ptr_operators_tail = &ast->ptr_operators;
+ while (parsePtrOperator(*ptr_operators_tail))
+ ptr_operators_tail = &(*ptr_operators_tail)->next;
+
+ while (LA() == T_LBRACKET) { // ### create the AST
+ consumeToken();
+ ExpressionAST *expression = 0;
+ parseExpression(expression);
+ unsigned rbracket_token = 0;
+ match(T_RBRACKET, &rbracket_token);
+ }
+
+ node = ast;
+ return true;
+}
+
+bool Parser::parseNewInitializer(NewInitializerAST *&node)
+{
+ if (LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+ ExpressionAST *expression = 0;
+ if (LA() == T_RPAREN || parseExpression(expression)) {
+ NewInitializerAST *ast = new (_pool) NewInitializerAST;
+ ast->lparen_token = lparen_token;
+ ast->expression = expression;
+ match(T_RPAREN, &ast->rparen_token);
+ node = ast;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Parser::parseDeleteExpression(ExpressionAST *&node)
+{
+ if (LA() == T_DELETE || (LA() == T_COLON_COLON && LA(2) == T_DELETE)) {
+ DeleteExpressionAST *ast = new (_pool) DeleteExpressionAST;
+
+ if (LA() == T_COLON_COLON)
+ ast->scope_token = consumeToken();
+
+ ast->delete_token = consumeToken();
+
+ if (LA() == T_LBRACKET) {
+ ast->lbracket_token = consumeToken();
+ match(T_RBRACKET, &ast->rbracket_token);
+ }
+
+ parseCastExpression(ast->expression);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseCastExpression(ExpressionAST *&node)
+{
+ if (LA() == T_LPAREN) {
+ unsigned lparen_token = consumeToken();
+ ExpressionAST *type_id = 0;
+ if (parseTypeId(type_id) && LA() == T_RPAREN) {
+ unsigned rparen_token = consumeToken();
+ ExpressionAST *expression = 0;
+ if (parseCastExpression(expression)) {
+ CastExpressionAST *ast = new (_pool) CastExpressionAST;
+ ast->lparen_token = lparen_token;
+ ast->type_id = type_id;
+ ast->rparen_token = rparen_token;
+ ast->expression = expression;
+ node = ast;
+ return true;
+ }
+ }
+ rewind(lparen_token);
+ }
+ return parseUnaryExpression(node);
+}
+
+bool Parser::parsePmExpression(ExpressionAST *&node)
+{
+ if (! parseCastExpression(node))
+ return false;
+
+ while (LA() == T_ARROW_STAR || LA() == T_DOT_STAR) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseCastExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseMultiplicativeExpression(ExpressionAST *&node)
+{
+ if (! parsePmExpression(node))
+ return false;
+
+ while (LA() == T_STAR || LA() == T_SLASH || LA() == T_PERCENT) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parsePmExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseAdditiveExpression(ExpressionAST *&node)
+{
+ if (! parseMultiplicativeExpression(node))
+ return false;
+
+ while (LA() == T_PLUS || LA() == T_MINUS) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseMultiplicativeExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseShiftExpression(ExpressionAST *&node)
+{
+ if (! parseAdditiveExpression(node))
+ return false;
+
+ while (LA() == T_LESS_LESS || LA() == T_GREATER_GREATER) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseAdditiveExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseRelationalExpression(ExpressionAST *&node)
+{
+ if (! parseShiftExpression(node))
+ return false;
+
+ while (LA() == T_LESS || (LA() == T_GREATER && ! _templateArguments) ||
+ LA() == T_LESS_EQUAL || LA() == T_GREATER_EQUAL) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseShiftExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseEqualityExpression(ExpressionAST *&node)
+{
+ if (! parseRelationalExpression(node))
+ return false;
+
+ while (LA() == T_EQUAL_EQUAL || LA() == T_EXCLAIM_EQUAL) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseRelationalExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseAndExpression(ExpressionAST *&node)
+{
+ if (! parseEqualityExpression(node))
+ return false;
+
+ while (LA() == T_AMPER) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseEqualityExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseExclusiveOrExpression(ExpressionAST *&node)
+{
+ if (! parseAndExpression(node))
+ return false;
+
+ while (LA() == T_CARET) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseAndExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseInclusiveOrExpression(ExpressionAST *&node)
+{
+ if (! parseExclusiveOrExpression(node))
+ return false;
+
+ while (LA() == T_PIPE) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseExclusiveOrExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseLogicalAndExpression(ExpressionAST *&node)
+{
+ if (! parseInclusiveOrExpression(node))
+ return false;
+
+ while (LA() == T_AMPER_AMPER) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseInclusiveOrExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseLogicalOrExpression(ExpressionAST *&node)
+{
+ if (! parseLogicalAndExpression(node))
+ return false;
+
+ while (LA() == T_PIPE_PIPE) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseLogicalAndExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseConditionalExpression(ExpressionAST *&node)
+{
+ if (! parseLogicalOrExpression(node))
+ return false;
+
+ if (LA() != T_QUESTION)
+ return true;
+
+ ConditionalExpressionAST *ast = new (_pool) ConditionalExpressionAST;
+ ast->condition = node;
+ ast->question_token = consumeToken();
+ parseAssignmentExpression(ast->left_expression);
+ match(T_COLON, &ast->colon_token);
+ parseAssignmentExpression(ast->right_expression);
+ node = ast;
+ return true;
+}
+
+bool Parser::lookAtAssignmentOperator() const
+{
+ switch (LA()) {
+ case T_EQUAL:
+ case T_AMPER_EQUAL:
+ case T_CARET_EQUAL:
+ case T_SLASH_EQUAL:
+ case T_GREATER_GREATER_EQUAL:
+ case T_LESS_LESS_EQUAL:
+ case T_MINUS_EQUAL:
+ case T_PERCENT_EQUAL:
+ case T_PIPE_EQUAL:
+ case T_PLUS_EQUAL:
+ case T_STAR_EQUAL:
+ case T_TILDE_EQUAL:
+ return true;
+ default:
+ return false;
+ } // switch
+}
+
+bool Parser::parseAssignmentExpression(ExpressionAST *&node)
+{
+ if (LA() == T_THROW)
+ return parseThrowExpression(node);
+ else if (! parseConditionalExpression(node))
+ return false;
+
+ if (lookAtAssignmentOperator()) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseAssignmentExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+
+ return true;
+}
+
+bool Parser::parseQtMethod(ExpressionAST *&node)
+{
+ if (LA() == T_SIGNAL || LA() == T_SLOT) {
+ QtMethodAST *ast = new (_pool) QtMethodAST;
+ ast->method_token = consumeToken();
+ match(T_LPAREN, &ast->lparen_token);
+ if (! parseDeclarator(ast->declarator))
+ _translationUnit->error(cursor(), "expected a function declarator before token `%s'",
+ tok().spell());
+ match(T_RPAREN, &ast->rparen_token);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseConstantExpression(ExpressionAST *&node)
+{
+ return parseConditionalExpression(node);
+}
+
+bool Parser::parseExpression(ExpressionAST *&node)
+{
+ return parseCommaExpression(node);
+}
+
+bool Parser::parseCommaExpression(ExpressionAST *&node)
+{
+ if (! parseAssignmentExpression(node))
+ return false;
+
+ while (LA() == T_COMMA) {
+ unsigned op = consumeToken();
+
+ ExpressionAST *rightExpr = 0;
+ if (! parseAssignmentExpression(rightExpr))
+ return false;
+
+ BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
+ ast->binary_op_token = op;
+ ast->left_expression = node;
+ ast->right_expression = rightExpr;
+ node = ast;
+ }
+ return true;
+}
+
+bool Parser::parseThrowExpression(ExpressionAST *&node)
+{
+ if (LA() == T_THROW) {
+ ThrowExpressionAST *ast = new (_pool) ThrowExpressionAST;
+ ast->throw_token = consumeToken();
+ parseAssignmentExpression(ast->expression);
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::lookAtObjCSelector() const
+{
+ switch (LA()) {
+ case T_IDENTIFIER:
+ case T_OR:
+ case T_AND:
+ case T_NOT:
+ case T_XOR:
+ case T_BITOR:
+ case T_COMPL:
+ case T_OR_EQ:
+ case T_AND_EQ:
+ case T_BITAND:
+ case T_NOT_EQ:
+ case T_XOR_EQ:
+ return true;
+
+ default:
+ if (tok().isKeyword())
+ return true;
+ } // switch
+
+ return false;
+}
+
+// objc-class-declaraton ::= T_AT_CLASS (T_IDENTIFIER @ T_COMMA) T_SEMICOLON
+//
+bool Parser::parseObjCClassDeclaration(DeclarationAST *&)
+{
+ if (LA() != T_AT_CLASS)
+ return false;
+
+ /*unsigned objc_class_token = */ consumeToken();
+ unsigned identifier_token = 0;
+ match(T_IDENTIFIER, &identifier_token);
+ while (LA() == T_COMMA) {
+ consumeToken(); // skip T_COMMA
+ match(T_IDENTIFIER, &identifier_token);
+ }
+
+ unsigned semicolon_token = 0;
+ match(T_SEMICOLON, &semicolon_token);
+ return true;
+}
+
+// objc-interface ::= attribute-specifier-list-opt objc-class-interface
+// objc-interface ::= objc-category-interface
+//
+// objc-class-interface ::= T_AT_INTERFACE T_IDENTIFIER (T_COLON T_IDENTIFIER)?
+// objc-protocol-refs-opt
+// objc-class-instance-variables-opt
+// objc-interface-declaration-list
+// T_AT_END
+//
+// objc-category-interface ::= T_AT_INTERFACE T_IDENTIFIER
+// T_LPAREN T_IDENTIFIER? T_RPAREN
+// objc-protocol-refs-opt
+// objc-interface-declaration-list
+// T_AT_END
+//
+bool Parser::parseObjCInterface(DeclarationAST *&,
+ SpecifierAST *attributes)
+{
+ if (! attributes && LA() == T___ATTRIBUTE__) {
+ SpecifierAST **attr = &attributes;
+ while (parseAttributeSpecifier(*attr))
+ attr = &(*attr)->next;
+ }
+
+ if (LA() != T_AT_INTERFACE)
+ return false;
+
+ /*unsigned objc_interface_token = */ consumeToken();
+ unsigned identifier_token = 0;
+ match(T_IDENTIFIER, &identifier_token);
+
+ if (LA() == T_LPAREN) {
+ // a category interface
+
+ if (attributes)
+ _translationUnit->error(attributes->firstToken(),
+ "invalid attributes for category interface declaration");
+
+ unsigned lparen_token = 0, rparen_token = 0;
+ match(T_LPAREN, &lparen_token);
+ if (LA() == T_IDENTIFIER)
+ consumeToken();
+
+ match(T_RPAREN, &rparen_token);
+
+ parseObjCProtocolRefs();
+ while (parseObjCInterfaceMemberDeclaration()) {
+ }
+ unsigned objc_end_token = 0;
+ match(T_AT_END, &objc_end_token);
+ return true;
+ }
+
+ // a class interface declaration
+ if (LA() == T_COLON) {
+ consumeToken();
+ unsigned identifier_token = 0;
+ match(T_IDENTIFIER, &identifier_token);
+ }
+
+ parseObjCProtocolRefs();
+ parseObjClassInstanceVariables();
+ while (parseObjCInterfaceMemberDeclaration()) {
+ }
+ unsigned objc_end_token = 0;
+ match(T_AT_END, &objc_end_token);
+ return true;
+}
+
+// objc-protocol ::= T_AT_PROTOCOL (T_IDENTIFIER @ T_COMMA) T_SEMICOLON
+//
+bool Parser::parseObjCProtocol(DeclarationAST *&,
+ SpecifierAST *attributes)
+{
+ if (! attributes && LA() == T___ATTRIBUTE__) {
+ SpecifierAST **attr = &attributes;
+ while (parseAttributeSpecifier(*attr))
+ attr = &(*attr)->next;
+ }
+
+ if (LA() != T_AT_PROTOCOL)
+ return false;
+
+ /*unsigned objc_protocol_token = */ consumeToken();
+ unsigned identifier_token = 0;
+ match(T_IDENTIFIER, &identifier_token);
+
+ if (LA() == T_COMMA || LA() == T_SEMICOLON) {
+ // a protocol forward declaration
+
+ while (LA() == T_COMMA) {
+ consumeToken();
+ match(T_IDENTIFIER, &identifier_token);
+ }
+ unsigned semicolon_token = 0;
+ match(T_SEMICOLON, &semicolon_token);
+ return true;
+ }
+
+ // a protocol definition
+ parseObjCProtocolRefs();
+
+ while (parseObjCInterfaceMemberDeclaration()) {
+ }
+
+ unsigned objc_end_token = 0;
+ match(T_AT_END, &objc_end_token);
+
+ return true;
+}
+
+// objc-implementation ::= T_AT_IMPLEMENTAION T_IDENTIFIER (T_COLON T_IDENTIFIER)?
+// objc-class-instance-variables-opt
+// objc-implementation ::= T_AT_IMPLEMENTAION T_IDENTIFIER T_LPAREN T_IDENTIFIER T_RPAREN
+//
+bool Parser::parseObjCImplementation(DeclarationAST *&)
+{
+ if (LA() != T_AT_IMPLEMENTATION)
+ return false;
+
+ consumeToken();
+
+ unsigned identifier_token = 0;
+ match(T_IDENTIFIER, &identifier_token);
+
+ if (LA() == T_LPAREN) {
+ // a category implementation
+ unsigned lparen_token = 0, rparen_token = 0;
+ unsigned category_name_token = 0;
+ match(T_LPAREN, &lparen_token);
+ match(T_IDENTIFIER, &category_name_token);
+ match(T_RPAREN, &rparen_token);
+ return true;
+ }
+
+ // a class implementation
+ if (LA() == T_COLON) {
+ consumeToken();
+ unsigned super_class_name_token = 0;
+ match(T_IDENTIFIER, &super_class_name_token);
+ }
+
+ parseObjClassInstanceVariables();
+ return true;
+}
+
+// objc-protocol-refs ::= T_LESS (T_IDENTIFIER @ T_COMMA) T_GREATER
+//
+bool Parser::parseObjCProtocolRefs()
+{
+ if (LA() != T_LESS)
+ return false;
+ unsigned less_token = 0, greater_token = 0;
+ unsigned identifier_token = 0;
+ match(T_LESS, &less_token);
+ match(T_IDENTIFIER, &identifier_token);
+ while (LA() == T_COMMA) {
+ consumeToken();
+ match(T_IDENTIFIER, &identifier_token);
+ }
+ match(T_GREATER, &greater_token);
+ return true;
+}
+
+// objc-class-instance-variables ::= T_LBRACE
+// objc-instance-variable-decl-list-opt
+// T_RBRACE
+//
+bool Parser::parseObjClassInstanceVariables()
+{
+ if (LA() != T_LBRACE)
+ return false;
+
+ unsigned lbrace_token = 0, rbrace_token = 0;
+
+ match(T_LBRACE, &lbrace_token);
+ while (LA()) {
+ if (LA() == T_RBRACE)
+ break;
+
+ const unsigned start = cursor();
+
+ DeclarationAST *declaration = 0;
+ parseObjCInstanceVariableDeclaration(declaration);
+
+ if (start == cursor()) {
+ // skip stray token.
+ _translationUnit->error(cursor(), "skip stray token `%s'", tok().spell());
+ consumeToken();
+ }
+ }
+
+ match(T_RBRACE, &rbrace_token);
+ return true;
+}
+
+// objc-interface-declaration ::= T_AT_REQUIRED
+// objc-interface-declaration ::= T_AT_OPTIONAL
+// objc-interface-declaration ::= T_SEMICOLON
+// objc-interface-declaration ::= objc-property-declaration
+// objc-interface-declaration ::= objc-method-prototype
+bool Parser::parseObjCInterfaceMemberDeclaration()
+{
+ switch (LA()) {
+ case T_AT_END:
+ return false;
+
+ case T_AT_REQUIRED:
+ case T_AT_OPTIONAL:
+ consumeToken();
+ return true;
+
+ case T_SEMICOLON:
+ consumeToken();
+ return true;
+
+ case T_AT_PROPERTY: {
+ DeclarationAST *declaration = 0;
+ return parseObjCPropertyDeclaration(declaration);
+ }
+
+ case T_PLUS:
+ case T_MINUS:
+ return parseObjCMethodPrototype();
+
+ case T_ENUM:
+ case T_CLASS:
+ case T_STRUCT:
+ case T_UNION: {
+ DeclarationAST *declaration = 0;
+ return parseSimpleDeclaration(declaration, /*accept struct declarators */ true);
+ }
+
+ default: {
+ DeclarationAST *declaration = 0;
+ return parseSimpleDeclaration(declaration, /*accept struct declarators */ true);
+ } // default
+
+ } // switch
+}
+
+// objc-instance-variable-declaration ::= objc-visibility-specifier
+// objc-instance-variable-declaration ::= block-declaration
+//
+bool Parser::parseObjCInstanceVariableDeclaration(DeclarationAST *&node)
+{
+ switch (LA()) {
+ case T_AT_PRIVATE:
+ case T_AT_PROTECTED:
+ case T_AT_PUBLIC:
+ case T_AT_PACKAGE:
+ consumeToken();
+ return true;
+
+ default:
+ return parseSimpleDeclaration(node, true);
+ }
+}
+
+// objc-property-declaration ::=
+// T_AT_PROPERTY T_LPAREN (property-attribute @ T_COMMA) T_RPAREN simple-declaration
+//
+bool Parser::parseObjCPropertyDeclaration(DeclarationAST *&, SpecifierAST *)
+{
+ if (LA() != T_AT_PROPERTY)
+ return false;
+
+ /*unsigned objc_property_token = */ consumeToken();
+
+ if (LA() == T_LPAREN) {
+ unsigned lparen_token = 0, rparen_token = 0;
+ match(T_LPAREN, &lparen_token);
+ while (parseObjCPropertyAttribute()) {
+ }
+ match(T_RPAREN, &rparen_token);
+ }
+
+ DeclarationAST *simple_declaration = 0;
+ parseSimpleDeclaration(simple_declaration, /*accept-struct-declarators = */ true);
+ return true;
+}
+
+// objc-method-prototype ::= (T_PLUS | T_MINUS) objc-method-decl objc-method-attrs-opt
+//
+// objc-method-decl ::= objc-type-name? objc-selector
+// objc-method-decl ::= objc-type-name? objc-keyword-decl-list objc-parmlist-opt
+//
+bool Parser::parseObjCMethodPrototype()
+{
+ if (LA() != T_PLUS && LA() != T_MINUS)
+ return false;
+
+ /*unsigned method_type_token = */ consumeToken();
+
+ parseObjCTypeName();
+
+ if ((lookAtObjCSelector() && LA(2) == T_COLON) || LA() == T_COLON) {
+ while (parseObjCKeywordDeclaration()) {
+ }
+
+ while (LA() == T_COMMA) {
+ consumeToken();
+
+ if (LA() == T_DOT_DOT_DOT) {
+ consumeToken();
+ break;
+ }
+
+ DeclarationAST *parameter_declaration = 0;
+ parseParameterDeclaration(parameter_declaration);
+ }
+ } else if (lookAtObjCSelector()) {
+ parseObjCSelector();
+ } else {
+ _translationUnit->error(cursor(), "expected a selector");
+ }
+
+ SpecifierAST *attributes = 0, **attr = &attributes;
+ while (parseAttributeSpecifier(*attr))
+ attr = &(*attr)->next;
+
+ return true;
+}
+
+// objc-property-attribute ::= getter '=' identifier
+// objc-property-attribute ::= setter '=' identifier ':'
+// objc-property-attribute ::= readonly
+// objc-property-attribute ::= readwrite
+// objc-property-attribute ::= assign
+// objc-property-attribute ::= retain
+// objc-property-attribute ::= copy
+// objc-property-attribute ::= nonatomic
+bool Parser::parseObjCPropertyAttribute()
+{
+ if (LA() != T_IDENTIFIER)
+ return false;
+
+ unsigned identifier_token = 0;
+ match(T_IDENTIFIER, &identifier_token);
+ if (LA() == T_EQUAL) {
+ consumeToken();
+ match(T_IDENTIFIER, &identifier_token);
+ if (LA() == T_COLON)
+ consumeToken();
+ }
+
+ return true;
+}
+
+// objc-type-name ::= T_LPAREN objc-type-qualifiers-opt type-id T_RPAREN
+//
+bool Parser::parseObjCTypeName()
+{
+ if (LA() != T_LPAREN)
+ return false;
+
+ unsigned lparen_token = 0, rparen_token = 0;
+ match(T_LPAREN, &lparen_token);
+ parseObjCTypeQualifiers();
+ ExpressionAST *type_id = 0;
+ parseTypeId(type_id);
+ match(T_RPAREN, &rparen_token);
+ return true;
+}
+
+// objc-selector ::= T_IDENTIFIER | keyword
+//
+bool Parser::parseObjCSelector()
+{
+ if (! lookAtObjCSelector())
+ return false;
+
+ consumeToken();
+ return true;
+}
+
+// objc-keyword-decl ::= objc-selector? T_COLON objc-type-name? objc-keyword-attributes-opt T_IDENTIFIER
+//
+bool Parser::parseObjCKeywordDeclaration()
+{
+ if (! (LA() == T_COLON || (lookAtObjCSelector() && LA(2) == T_COLON)))
+ return false;
+
+ parseObjCSelector();
+
+ unsigned colon_token = 0;
+ match(T_COLON, &colon_token);
+
+ parseObjCTypeName();
+
+ SpecifierAST *attributes = 0, **attr = &attributes;
+ while (parseAttributeSpecifier(*attr))
+ attr = &(*attr)->next;
+
+ unsigned identifier_token = 0;
+ match(T_IDENTIFIER, &identifier_token);
+
+ return true;
+}
+
+bool Parser::parseObjCTypeQualifiers()
+{
+ if (LA() != T_IDENTIFIER)
+ return false;
+
+ Identifier *id = tok().identifier;
+ if (! strcmp("in", id->chars()) ||
+ ! strcmp("out", id->chars()) ||
+ ! strcmp("inout", id->chars()) ||
+ ! strcmp("bycopy", id->chars()) ||
+ ! strcmp("byref", id->chars()) ||
+ ! strcmp("oneway", id->chars())) {
+ consumeToken();
+ return true;
+ }
+ return false;
+}
+
+// objc-end: T_AT_END
+bool Parser::parseObjCEnd(DeclarationAST *&)
+{
+ if (LA() != T_AT_END)
+ return false;
+
+ consumeToken();
+ return true;
+}
+
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Parser.h b/src/shared/cplusplus/Parser.h
new file mode 100644
index 0000000000..d99d8d27fc
--- /dev/null
+++ b/src/shared/cplusplus/Parser.h
@@ -0,0 +1,292 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_PARSER_H
+#define CPLUSPLUS_PARSER_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "ASTfwd.h"
+#include "Token.h"
+#include "TranslationUnit.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Parser
+{
+public:
+ Parser(TranslationUnit *translationUnit);
+ ~Parser();
+
+ bool qtMocRunEnabled() const;
+ void setQtMocRunEnabled(bool onoff);
+
+ bool objCEnabled() const;
+ void setObjCEnabled(bool onoff);
+
+ bool parseTranslationUnit(TranslationUnitAST *&node);
+
+public:
+ bool parseAccessSpecifier(SpecifierAST *&node);
+ bool parseExpressionList(ExpressionListAST *&node);
+ bool parseAbstractCoreDeclarator(DeclaratorAST *&node);
+ bool parseAbstractDeclarator(DeclaratorAST *&node);
+ bool parseEmptyDeclaration(DeclarationAST *&node);
+ bool parseAccessDeclaration(DeclarationAST *&node);
+ bool parseAdditiveExpression(ExpressionAST *&node);
+ bool parseAndExpression(ExpressionAST *&node);
+ bool parseAsmDefinition(DeclarationAST *&node);
+ bool parseAssignmentExpression(ExpressionAST *&node);
+ bool parseBaseClause(BaseSpecifierAST *&node);
+ bool parseBaseSpecifier(BaseSpecifierAST *&node);
+ bool parseBlockDeclaration(DeclarationAST *&node);
+ bool parseCppCastExpression(ExpressionAST *&node);
+ bool parseCastExpression(ExpressionAST *&node);
+ bool parseClassSpecifier(SpecifierAST *&node);
+ bool parseCommaExpression(ExpressionAST *&node);
+ bool parseCompoundStatement(StatementAST *&node);
+ bool parseBreakStatement(StatementAST *&node);
+ bool parseContinueStatement(StatementAST *&node);
+ bool parseGotoStatement(StatementAST *&node);
+ bool parseReturnStatement(StatementAST *&node);
+ bool parseCondition(ExpressionAST *&node);
+ bool parseConditionalExpression(ExpressionAST *&node);
+ bool parseConstantExpression(ExpressionAST *&node);
+ bool parseCtorInitializer(CtorInitializerAST *&node);
+ bool parseCvQualifiers(SpecifierAST *&node);
+ bool parseDeclaratorOrAbstractDeclarator(DeclaratorAST *&node);
+ bool parseDeclaration(DeclarationAST *&node);
+ bool parseSimpleDeclaration(DeclarationAST *&node, bool acceptStructDeclarator = false);
+ bool parseDeclarationStatement(StatementAST *&node);
+ bool parseCoreDeclarator(DeclaratorAST *&node);
+ bool parseDeclarator(DeclaratorAST *&node);
+ bool parseDeleteExpression(ExpressionAST *&node);
+ bool parseDoStatement(StatementAST *&node);
+ bool parseElaboratedTypeSpecifier(SpecifierAST *&node);
+ bool parseEnumSpecifier(SpecifierAST *&node);
+ bool parseEnumerator(EnumeratorAST *&node);
+ bool parseEqualityExpression(ExpressionAST *&node);
+ bool parseExceptionDeclaration(ExceptionDeclarationAST *&node);
+ bool parseExceptionSpecification(ExceptionSpecificationAST *&node);
+ bool parseExclusiveOrExpression(ExpressionAST *&node);
+ bool parseExpression(ExpressionAST *&node);
+ bool parseExpressionOrDeclarationStatement(StatementAST *&node);
+ bool parseExpressionStatement(StatementAST *&node);
+ bool parseForInitStatement(StatementAST *&node);
+ bool parseForStatement(StatementAST *&node);
+ bool parseFunctionBody(StatementAST *&node);
+ bool parseIfStatement(StatementAST *&node);
+ bool parseInclusiveOrExpression(ExpressionAST *&node);
+ bool parseInitDeclarator(DeclaratorAST *&node, bool acceptStructDeclarator);
+ bool parseInitializerList(ExpressionListAST *&node);
+ bool parseInitializer(ExpressionAST *&node);
+ bool parseInitializerClause(ExpressionAST *&node);
+ bool parseLabeledStatement(StatementAST *&node);
+ bool parseLinkageBody(DeclarationAST *&node);
+ bool parseLinkageSpecification(DeclarationAST *&node);
+ bool parseLogicalAndExpression(ExpressionAST *&node);
+ bool parseLogicalOrExpression(ExpressionAST *&node);
+ bool parseMemInitializer(MemInitializerAST *&node);
+ bool parseMemInitializerList(MemInitializerAST *&node);
+ bool parseMemberSpecification(DeclarationAST *&node);
+ bool parseMultiplicativeExpression(ExpressionAST *&node);
+ bool parseTemplateId(NameAST *&node);
+ bool parseClassOrNamespaceName(NameAST *&node);
+ bool parseNameId(NameAST *&node);
+ bool parseName(NameAST *&node, bool acceptTemplateId = true);
+ bool parseNestedNameSpecifier(NestedNameSpecifierAST *&node, bool acceptTemplateId);
+ bool parseNestedNameSpecifierOpt(NestedNameSpecifierAST *&name, bool acceptTemplateId);
+ bool parseNamespace(DeclarationAST *&node);
+ bool parseNamespaceAliasDefinition(DeclarationAST *&node);
+ bool parseNewDeclarator(NewDeclaratorAST *&node);
+ bool parseNewExpression(ExpressionAST *&node);
+ bool parseNewInitializer(NewInitializerAST *&node);
+ bool parseNewTypeId(NewTypeIdAST *&node);
+ bool parseOperator(OperatorAST *&node);
+ bool parseConversionFunctionId(NameAST *&node);
+ bool parseOperatorFunctionId(NameAST *&node);
+ bool parseParameterDeclaration(DeclarationAST *&node);
+ bool parseParameterDeclarationClause(ParameterDeclarationClauseAST *&node);
+ bool parseParameterDeclarationList(DeclarationAST *&node);
+ bool parsePmExpression(ExpressionAST *&node);
+ bool parseTypeidExpression(ExpressionAST *&node);
+ bool parseTypenameCallExpression(ExpressionAST *&node);
+ bool parseCorePostfixExpression(ExpressionAST *&node);
+ bool parsePostfixExpression(ExpressionAST *&node);
+ bool parsePostfixExpressionInternal(ExpressionAST *&node);
+ bool parsePrimaryExpression(ExpressionAST *&node);
+ bool parseNestedExpression(ExpressionAST *&node);
+ bool parsePtrOperator(PtrOperatorAST *&node);
+ bool parseRelationalExpression(ExpressionAST *&node);
+ bool parseShiftExpression(ExpressionAST *&node);
+ bool parseStatement(StatementAST *&node);
+ bool parseThisExpression(ExpressionAST *&node);
+ bool parseBoolLiteral(ExpressionAST *&node);
+ bool parseNumericLiteral(ExpressionAST *&node);
+ bool parseStringLiteral(ExpressionAST *&node);
+ bool parseSwitchStatement(StatementAST *&node);
+ bool parseTemplateArgument(ExpressionAST *&node);
+ bool parseTemplateArgumentList(TemplateArgumentListAST *&node);
+ bool parseTemplateDeclaration(DeclarationAST *&node);
+ bool parseTemplateParameter(DeclarationAST *&node);
+ bool parseTemplateParameterList(DeclarationAST *&node);
+ bool parseThrowExpression(ExpressionAST *&node);
+ bool parseTryBlockStatement(StatementAST *&node);
+ bool parseCatchClause(CatchClauseAST *&node);
+ bool parseTypeId(ExpressionAST *&node);
+ bool parseTypeIdList(ExpressionListAST *&node);
+ bool parseTypenameTypeParameter(DeclarationAST *&node);
+ bool parseTemplateTypeParameter(DeclarationAST *&node);
+ bool parseTypeParameter(DeclarationAST *&node);
+
+ bool parseBuiltinTypeSpecifier(SpecifierAST *&node);
+ bool parseAttributeSpecifier(SpecifierAST *&node);
+ bool parseAttributeList(AttributeAST *&node);
+
+ bool parseSimpleTypeSpecifier(SpecifierAST *&node)
+ { return parseDeclSpecifierSeq(node, true, true); }
+
+ bool parseTypeSpecifier(SpecifierAST *&node)
+ { return parseDeclSpecifierSeq(node, true); }
+
+ bool parseDeclSpecifierSeq(SpecifierAST *&node,
+ bool onlyTypeSpecifiers = false,
+ bool simplified = false);
+ bool parseUnaryExpression(ExpressionAST *&node);
+ bool parseUnqualifiedName(NameAST *&node, bool acceptTemplateId = true);
+ bool parseUsing(DeclarationAST *&node);
+ bool parseUsingDirective(DeclarationAST *&node);
+ bool parseWhileStatement(StatementAST *&node);
+
+ // Qt MOC run
+ bool parseQtMethod(ExpressionAST *&node);
+
+ // ObjC++
+ bool parseObjCClassDeclaration(DeclarationAST *&node);
+ bool parseObjCInterface(DeclarationAST *&node,
+ SpecifierAST *attributes = 0);
+ bool parseObjCProtocol(DeclarationAST *&node,
+ SpecifierAST *attributes = 0);
+
+ bool parseObjCProtocolRefs();
+ bool parseObjClassInstanceVariables();
+ bool parseObjCInterfaceMemberDeclaration();
+ bool parseObjCInstanceVariableDeclaration(DeclarationAST *&node);
+ bool parseObjCPropertyDeclaration(DeclarationAST *&node,
+ SpecifierAST *attributes = 0);
+ bool parseObjCImplementation(DeclarationAST *&node);
+ bool parseObjCMethodPrototype();
+ bool parseObjCPropertyAttribute();
+ bool parseObjCTypeName();
+ bool parseObjCSelector();
+ bool parseObjCKeywordDeclaration();
+ bool parseObjCTypeQualifiers();
+ bool parseObjCEnd(DeclarationAST *&node);
+
+ bool lookAtObjCSelector() const;
+
+ bool skipUntil(int token);
+ bool skipUntilDeclaration();
+ bool skipUntilStatement();
+ bool skip(int l, int r);
+
+ bool lookAtCVQualifier() const;
+ bool lookAtFunctionSpecifier() const;
+ bool lookAtStorageClassSpecifier() const;
+ bool lookAtBuiltinTypeSpecifier() const;
+ bool lookAtClassKey() const;
+ bool lookAtAssignmentOperator() const;
+
+ void match(int kind, unsigned *token);
+
+ bool maybeFunctionCall(SimpleDeclarationAST *simpleDecl) const;
+ bool maybeSimpleExpression(SimpleDeclarationAST *simpleDecl) const;
+
+private:
+ bool switchTemplateArguments(bool templateArguments);
+ bool blockErrors(bool block);
+
+ inline const Token &tok(int i = 1) const
+ { return _translationUnit->tokenAt(_tokenIndex + i - 1); }
+
+ inline int LA(int n = 1) const
+ { return _translationUnit->tokenKind(_tokenIndex + n - 1); }
+
+ inline int consumeToken()
+ { return _tokenIndex++; }
+
+ inline unsigned cursor() const
+ { return _tokenIndex; }
+
+ inline void rewind(unsigned cursor)
+ { _tokenIndex = cursor; }
+
+private:
+ TranslationUnit *_translationUnit;
+ Control *_control;
+ MemoryPool *_pool;
+ unsigned _tokenIndex;
+ bool _templateArguments: 1;
+ bool _qtMocRunEnabled: 1;
+ bool _objCEnabled: 1;
+ bool _inFunctionBody: 1;
+ bool _inObjCImplementationContext: 1;
+
+private:
+ Parser(const Parser& source);
+ void operator =(const Parser& source);
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_PARSER_H
diff --git a/src/shared/cplusplus/PrettyPrinter.cpp b/src/shared/cplusplus/PrettyPrinter.cpp
new file mode 100644
index 0000000000..6acb109dcf
--- /dev/null
+++ b/src/shared/cplusplus/PrettyPrinter.cpp
@@ -0,0 +1,1293 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "PrettyPrinter.h"
+#include "AST.h"
+#include "Token.h"
+#include <iostream>
+#include <string>
+#include <cassert>
+
+CPLUSPLUS_USE_NAMESPACE
+
+PrettyPrinter::PrettyPrinter(Control *control, std::ostream &out)
+ : ASTVisitor(control),
+ out(out),
+ depth(0)
+{ }
+
+void PrettyPrinter::operator()(AST *ast)
+{ accept(ast); }
+
+void PrettyPrinter::indent()
+{ ++depth; }
+
+void PrettyPrinter::deindent()
+{ --depth; }
+
+void PrettyPrinter::newline()
+{ out << '\n' << std::string(depth * 4, ' '); }
+
+bool PrettyPrinter::visit(AccessDeclarationAST *ast)
+{
+ deindent();
+ newline();
+ out << spell(ast->access_specifier_token);
+ if (ast->slots_token)
+ out << ' ' << spell(ast->slots_token);
+ out << ':' << std::endl;
+ indent();
+ return false;
+}
+
+bool PrettyPrinter::visit(ArrayAccessAST *ast)
+{
+ out << '[';
+ accept(ast->expression);
+ out << ']';
+ return false;
+}
+
+bool PrettyPrinter::visit(ArrayDeclaratorAST *ast)
+{
+ out << '[';
+ accept(ast->expression);
+ out << ']';
+ return false;
+}
+
+bool PrettyPrinter::visit(ArrayInitializerAST *ast)
+{
+ out << '{';
+ for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
+ accept(it->expression);
+ if (it->next)
+ out << ", ";
+ }
+ out << '}';
+ return false;
+}
+
+bool PrettyPrinter::visit(AsmDefinitionAST *ast)
+{
+ out << spell(ast->asm_token);
+ for (SpecifierAST *it = ast->cv_qualifier_seq; it; it = it->next) {
+ out << ' ';
+ accept(it);
+ }
+ out << '(';
+ out << "/* ### implement me */";
+ out << ");";
+ return false;
+}
+
+bool PrettyPrinter::visit(AttributeSpecifierAST *ast)
+{
+ out << "attribute((";
+ for (AttributeAST *it = ast->attributes; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ", ";
+ }
+ out << "))";
+ return false;
+}
+
+bool PrettyPrinter::visit(AttributeAST *ast)
+{
+ out << spell(ast->identifier_token);
+ if (ast->lparen_token) {
+ out << '(';
+ out << spell(ast->tag_token);
+ if (ast->expression_list) {
+ out << '(';
+ for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
+ accept(it->expression);
+ if (it->next)
+ out << ", ";
+ }
+ out << ')';
+ }
+ out << ')';
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(BaseSpecifierAST *ast)
+{
+ if (ast->token_virtual && ast->token_access_specifier) {
+ out << "virtual";
+ out << ' ';
+ out << spell(ast->token_access_specifier);
+ out << ' ';
+ } else if (ast->token_virtual) {
+ out << "virtual";
+ out << ' ';
+ } else if (ast->token_access_specifier) {
+ out << spell(ast->token_access_specifier);
+ out << ' ';
+ }
+ accept(ast->name);
+ return false;
+}
+
+bool PrettyPrinter::visit(BinaryExpressionAST *ast)
+{
+ accept(ast->left_expression);
+ out << ' ' << spell(ast->binary_op_token) << ' ';
+ accept(ast->right_expression);
+ return false;
+}
+
+bool PrettyPrinter::visit(BoolLiteralAST *ast)
+{
+ out << spell(ast->token);
+ return false;
+}
+
+bool PrettyPrinter::visit(BreakStatementAST *)
+{
+ out << "break;";
+ return false;
+}
+
+bool PrettyPrinter::visit(CallAST *ast)
+{
+ out << '(';
+ for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
+ accept(it->expression);
+ if (it->next)
+ out << ", ";
+ }
+ out << ')';
+ return false;
+}
+
+bool PrettyPrinter::visit(CaseStatementAST *ast)
+{
+ out << "case ";
+ accept(ast->expression);
+ out << ':';
+ if (! ast->statement) {
+ newline();
+ return false;
+ }
+
+ if (ast->statement->asCompoundStatement()) {
+ out << ' ';
+ accept(ast->statement);
+ } else if (ast->statement->asCaseStatement() || ast->statement->asLabeledStatement()) {
+ newline();
+ accept(ast->statement);
+ } else {
+ indent();
+ newline();
+ accept(ast->statement);
+ deindent();
+ newline();
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(CastExpressionAST *ast)
+{
+ out << '(';
+ accept(ast->type_id);
+ out << ')';
+ accept(ast->expression);
+ return false;
+}
+
+bool PrettyPrinter::visit(CatchClauseAST *ast)
+{
+ out << "catch";
+ out << '(';
+ accept(ast->exception_declaration);
+ out << ')';
+ accept(ast->statement);
+ return false;
+}
+
+bool PrettyPrinter::visit(ClassSpecifierAST *ast)
+{
+ out << spell(ast->classkey_token);
+ out << ' ';
+ if (ast->attributes) {
+ accept(ast->attributes);
+ out << ' ';
+ }
+ accept(ast->name);
+ if (ast->colon_token) {
+ out << ':';
+ out << ' ';
+ for (BaseSpecifierAST *it = ast->base_clause; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ", ";
+ }
+ }
+ newline();
+ out << '{';
+ if (ast->member_specifiers) {
+ indent();
+ newline();
+ if (ast->member_specifiers) {
+ for (DeclarationAST *it = ast->member_specifiers; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ newline();
+ }
+ }
+ deindent();
+ newline();
+ }
+ out << '}';
+ return false;
+}
+
+bool PrettyPrinter::visit(CompoundStatementAST *ast)
+{
+ out << '{';
+ if (ast->statements) {
+ indent();
+ newline();
+ for (StatementAST *it = ast->statements; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ newline();
+ }
+ deindent();
+ newline();
+ }
+ out << '}';
+ return false;
+}
+
+bool PrettyPrinter::visit(ConditionAST *ast)
+{
+ for (SpecifierAST *it = ast->type_specifier; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ' ';
+ }
+ if (ast->declarator) {
+ if (ast->type_specifier)
+ out << ' ';
+
+ accept(ast->declarator);
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(ConditionalExpressionAST *ast)
+{
+ accept(ast->condition);
+ out << '?';
+ accept(ast->left_expression);
+ out << ':';
+ accept(ast->right_expression);
+ return false;
+}
+
+bool PrettyPrinter::visit(ContinueStatementAST *)
+{
+ out << "continue";
+ out << ';';
+ return false;
+}
+
+bool PrettyPrinter::visit(ConversionFunctionIdAST *ast)
+{
+ out << "operator";
+ out << ' ';
+ for (SpecifierAST *it = ast->type_specifier; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ' ';
+ }
+ for (PtrOperatorAST *it = ast->ptr_operators; it; it = it->next) {
+ accept(it);
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(CppCastExpressionAST *ast)
+{
+ out << spell(ast->cast_token);
+ out << '<';
+ out << ' ';
+ accept(ast->type_id);
+ out << ' ';
+ out << '>';
+ out << '(';
+ accept(ast->expression);
+ out << ')';
+ return false;
+}
+
+bool PrettyPrinter::visit(CtorInitializerAST *ast)
+{
+ out << ':';
+ out << ' ';
+ for (MemInitializerAST *it = ast->member_initializers; it; it = it->next) {
+ accept(it->name);
+ out << '(';
+ accept(it->expression);
+ out << ')';
+ if (it->next)
+ out << ", ";
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(DeclaratorAST *ast)
+{
+ for (PtrOperatorAST *it = ast->ptr_operators; it; it = it->next) {
+ accept(it);
+ }
+ if (ast->core_declarator) {
+ if (ast->ptr_operators)
+ out << ' ';
+ accept(ast->core_declarator);
+ }
+ for (PostfixDeclaratorAST *it = ast->postfix_declarators; it; it = it->next) {
+ accept(it);
+ }
+ for (SpecifierAST *it = ast->attributes; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ' ';
+ }
+ if (ast->initializer) {
+ out << ' ';
+ out << '=';
+ out << ' ';
+ accept(ast->initializer);
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(DeclarationStatementAST *ast)
+{
+ accept(ast->declaration);
+ return false;
+}
+
+bool PrettyPrinter::visit(DeclaratorIdAST *ast)
+{
+ accept(ast->name);
+ return false;
+}
+
+bool PrettyPrinter::visit(DeclaratorListAST *ast)
+{
+ for (DeclaratorListAST *it = ast; it; it = it->next) {
+ accept(it->declarator);
+ if (it->next)
+ out << ", ";
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(DeleteExpressionAST *ast)
+{
+ if (ast->scope_token)
+ out << "::";
+ out << "delete";
+ if (ast->expression) {
+ out << ' ';
+ accept(ast->expression);
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(DestructorNameAST *ast)
+{
+ out << '~';
+ out << spell(ast->identifier_token);
+ return false;
+}
+
+bool PrettyPrinter::visit(DoStatementAST *ast)
+{
+ out << "do";
+ if (ast->statement) {
+ out << ' ';
+ accept(ast->statement);
+ }
+ out << "while";
+ out << '(';
+ accept(ast->expression);
+ out << ')';
+ out << ';';
+ return false;
+}
+
+bool PrettyPrinter::visit(ElaboratedTypeSpecifierAST *ast)
+{
+ out << spell(ast->classkey_token);
+ if (ast->name) {
+ out << ' ';
+ accept(ast->name);
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(EmptyDeclarationAST *)
+{
+ out << ';';
+ return false;
+}
+
+bool PrettyPrinter::visit(EnumSpecifierAST *ast)
+{
+ out << "enum";
+ if (ast->name) {
+ out << ' ';
+ accept(ast->name);
+ }
+ out << ' ';
+ out << '{';
+ if (ast->enumerators) {
+ indent();
+ newline();
+ for (EnumeratorAST *it = ast->enumerators; it; it = it->next) {
+ accept(it);
+ if (it->next) {
+ out << ", ";
+ newline();
+ }
+ }
+ deindent();
+ newline();
+ }
+ out << '}';
+ return false;
+}
+
+bool PrettyPrinter::visit(EnumeratorAST *ast)
+{
+ out << spell(ast->identifier_token);
+ if (ast->equal_token) {
+ out << ' ';
+ out << '=';
+ out << ' ';
+ accept(ast->expression);
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(ExceptionDeclarationAST *ast)
+{
+ for (SpecifierAST *it = ast->type_specifier; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ' ';
+ }
+ if (ast->declarator) {
+ if (ast->type_specifier)
+ out << ' ';
+ accept(ast->declarator);
+ }
+ if (ast->dot_dot_dot_token)
+ out << "...";
+ return false;
+}
+
+bool PrettyPrinter::visit(ExceptionSpecificationAST *ast)
+{
+ out << "throw";
+ out << '(';
+ if (ast->dot_dot_dot_token)
+ out << "...";
+ else {
+ for (ExpressionListAST *it = ast->type_ids; it; it = it->next) {
+ accept(it->expression);
+ if (it->next)
+ out << ", ";
+ }
+ }
+ out << ')';
+ return false;
+}
+
+bool PrettyPrinter::visit(ExpressionListAST *ast)
+{
+ for (ExpressionListAST *it = ast; it; it = it->next) {
+ accept(it->expression);
+ if (it->next)
+ out << ", ";
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(ExpressionOrDeclarationStatementAST *ast)
+{
+ accept(ast->declaration);
+ return false;
+}
+
+bool PrettyPrinter::visit(ExpressionStatementAST *ast)
+{
+ accept(ast->expression);
+ out << ';';
+ return false;
+}
+
+bool PrettyPrinter::visit(ForStatementAST *ast)
+{
+ out << "for";
+ out << ' ';
+ out << '(';
+ accept(ast->initializer);
+ accept(ast->condition);
+ out << ';';
+ accept(ast->expression);
+ out << ')';
+ accept(ast->statement);
+ return false;
+}
+
+bool PrettyPrinter::visit(FunctionDeclaratorAST *ast)
+{
+ out << '(';
+ accept(ast->parameters);
+ out << ')';
+ for (SpecifierAST *it = ast->cv_qualifier_seq; it; it = it->next) {
+ out << ' ';
+ accept(it);
+ }
+ if (ast->exception_specification) {
+ out << ' ';
+ accept(ast->exception_specification);
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(FunctionDefinitionAST *ast)
+{
+ for (SpecifierAST *it = ast->decl_specifier_seq; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ' ';
+ }
+ if (ast->declarator) {
+ if (ast->decl_specifier_seq)
+ out << ' ';
+ accept(ast->declarator);
+ }
+ accept(ast->ctor_initializer);
+ newline();
+ accept(ast->function_body);
+ if (ast->next)
+ newline(); // one extra line after the function definiton.
+ return false;
+}
+
+bool PrettyPrinter::visit(GotoStatementAST *ast)
+{
+ out << "goto";
+ out << ' ';
+ out << spell(ast->identifier_token);
+ out << ';';
+ return false;
+}
+
+bool PrettyPrinter::visit(IfStatementAST *ast)
+{
+ out << "if";
+ out << ' ';
+ out << '(';
+ accept(ast->condition);
+ out << ')';
+ if (ast->statement->asCompoundStatement()) {
+ out << ' ';
+ accept(ast->statement);
+ } else {
+ indent();
+ newline();
+ accept(ast->statement);
+ deindent();
+ newline();
+ }
+ if (ast->else_token) {
+ out << "else";
+ out << ' ';
+ accept(ast->else_statement);
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(LabeledStatementAST *ast)
+{
+ out << spell(ast->label_token);
+ out << ':';
+ accept(ast->statement);
+ return false;
+}
+
+bool PrettyPrinter::visit(LinkageBodyAST *ast)
+{
+ out << '{';
+ if (ast->declarations) {
+ indent();
+ newline();
+ for (DeclarationAST *it = ast->declarations; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ newline();
+ }
+ deindent();
+ newline();
+ }
+ out << '}';
+ return false;
+}
+
+bool PrettyPrinter::visit(LinkageSpecificationAST *ast)
+{
+ out << "extern";
+ out << ' ';
+ if (ast->extern_type) {
+ out << '"' << spell(ast->extern_type) << '"';
+ out << ' ';
+ }
+
+ accept(ast->declaration);
+ return false;
+}
+
+bool PrettyPrinter::visit(MemInitializerAST *ast)
+{
+ accept(ast->name);
+ out << '(';
+ accept(ast->expression);
+ out << ')';
+ return false;
+}
+
+bool PrettyPrinter::visit(MemberAccessAST *ast)
+{
+ out << spell(ast->access_token);
+ if (ast->template_token) {
+ out << "template";
+ out << ' ';
+ }
+ accept(ast->member_name);
+ return false;
+}
+
+bool PrettyPrinter::visit(NamedTypeSpecifierAST *ast)
+{
+ accept(ast->name);
+ return false;
+}
+
+bool PrettyPrinter::visit(NamespaceAST *ast)
+{
+ out << "namespace";
+ if (ast->identifier_token) {
+ out << ' ';
+ out << spell(ast->identifier_token);
+ }
+ for (SpecifierAST *it = ast->attributes; it; it = it->next) {
+ out << ' ';
+ accept(it);
+ }
+ out << ' ';
+ accept(ast->linkage_body);
+ return false;
+}
+
+bool PrettyPrinter::visit(NamespaceAliasDefinitionAST *ast)
+{
+ out << "namespace";
+ out << ' ';
+ out << spell(ast->namespace_name);
+ out << ' ';
+ out << '=';
+ out << ' ';
+ accept(ast->name);
+ out << ';';
+ return false;
+}
+
+bool PrettyPrinter::visit(NestedDeclaratorAST *ast)
+{
+ out << '(';
+ accept(ast->declarator);
+ out << ')';
+ return false;
+}
+
+bool PrettyPrinter::visit(NestedExpressionAST *ast)
+{
+ out << '(';
+ accept(ast->expression);
+ out << ')';
+ return false;
+}
+
+bool PrettyPrinter::visit(NestedNameSpecifierAST *ast)
+{
+ accept(ast->class_or_namespace_name);
+ if (ast->scope_token)
+ out << "::";
+ return false;
+}
+
+bool PrettyPrinter::visit(NewDeclaratorAST *ast)
+{
+ for (PtrOperatorAST *it = ast->ptr_operators; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ' ';
+ }
+ if (ast->declarator)
+ accept(ast->declarator);
+ return false;
+}
+
+bool PrettyPrinter::visit(NewExpressionAST *ast)
+{
+ if (ast->scope_token)
+ out << "::";
+ out << "new";
+ out << ' ';
+ if (ast->expression) {
+ accept(ast->expression);
+ if (ast->type_id)
+ out << ' ';
+ }
+ if (ast->type_id) {
+ accept(ast->type_id);
+ if (ast->new_type_id)
+ out << ' ';
+ }
+ if (ast->new_type_id) {
+ accept(ast->new_type_id);
+ if (ast->new_initializer)
+ out << ' ';
+ }
+ accept(ast->new_initializer);
+ return false;
+}
+
+bool PrettyPrinter::visit(NewInitializerAST *ast)
+{
+ out << '(';
+ accept(ast->expression);
+ out << ')';
+ return false;
+}
+
+bool PrettyPrinter::visit(NewTypeIdAST *ast)
+{
+ for (SpecifierAST *it = ast->type_specifier; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ' ';
+ }
+ if (ast->type_specifier)
+ out << ' ';
+ if (ast->new_initializer) {
+ accept(ast->new_initializer);
+ if (ast->new_declarator)
+ out << ' ';
+ }
+ accept(ast->new_declarator);
+ return false;
+}
+
+bool PrettyPrinter::visit(NumericLiteralAST *ast)
+{
+ switch (tokenKind(ast->token)) {
+ case T_CHAR_LITERAL:
+ out << '\'' << spell(ast->token) << '\'';
+ break;
+ case T_WIDE_CHAR_LITERAL:
+ out << "L\'" << spell(ast->token) << '\'';
+ break;
+
+ default:
+ out << spell(ast->token);
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(OperatorAST *ast)
+{
+ out << spell(ast->op_token);
+ if (ast->open_token) {
+ out << spell(ast->open_token);
+ out << spell(ast->close_token);
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(OperatorFunctionIdAST *ast)
+{
+ out << "operator";
+ out << ' ';
+ accept(ast->op);
+ return false;
+}
+
+bool PrettyPrinter::visit(ParameterDeclarationAST *ast)
+{
+ for (SpecifierAST *it = ast->type_specifier; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ' ';
+ }
+ if (ast->declarator) {
+ out << ' ';
+ accept(ast->declarator);
+ }
+ if (ast->equal_token) {
+ out << ' ';
+ out << '=';
+ out << ' ';
+ }
+ accept(ast->expression);
+ return false;
+}
+
+bool PrettyPrinter::visit(ParameterDeclarationClauseAST *ast)
+{
+ for (DeclarationAST *it = ast->parameter_declarations; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ", ";
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(PointerAST *ast)
+{
+ out << '*';
+ for (SpecifierAST *it = ast->cv_qualifier_seq; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ' ';
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(PointerToMemberAST *ast)
+{
+ if (ast->global_scope_token)
+ out << "::";
+ for (NestedNameSpecifierAST *it = ast->nested_name_specifier; it; it = it->next) {
+ accept(it);
+ }
+ out << '*';
+ for (SpecifierAST *it = ast->cv_qualifier_seq; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ' ';
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(PostIncrDecrAST *ast)
+{
+ out << spell(ast->incr_decr_token);
+ return false;
+}
+
+bool PrettyPrinter::visit(PostfixExpressionAST *ast)
+{
+ accept(ast->base_expression);
+ for (PostfixAST *it = ast->postfix_expressions; it; it = it->next) {
+ accept(it);
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(QualifiedNameAST *ast)
+{
+ if (ast->global_scope_token)
+ out << "::";
+ for (NestedNameSpecifierAST *it = ast->nested_name_specifier; it; it = it->next) {
+ accept(it);
+ }
+ accept(ast->unqualified_name);
+ return false;
+}
+
+bool PrettyPrinter::visit(ReferenceAST *)
+{
+ out << '&';
+ return false;
+}
+
+bool PrettyPrinter::visit(ReturnStatementAST *ast)
+{
+ out << "return";
+ if (ast->expression) {
+ out << ' ';
+ accept(ast->expression);
+ }
+ out << ';';
+ return false;
+}
+
+bool PrettyPrinter::visit(SimpleDeclarationAST *ast)
+{
+ for (SpecifierAST *it = ast->decl_specifier_seq; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ' ';
+ }
+ if (ast->declarators) {
+ if (ast->decl_specifier_seq)
+ out << ' ';
+
+ for (DeclaratorListAST *it = ast->declarators; it; it = it->next) {
+ accept(it->declarator);
+ if (it->next)
+ out << ", ";
+ }
+ }
+ out << ';';
+ return false;
+}
+
+bool PrettyPrinter::visit(SimpleNameAST *ast)
+{
+ out << spell(ast->identifier_token);
+ return false;
+}
+
+bool PrettyPrinter::visit(SimpleSpecifierAST *ast)
+{
+ out << spell(ast->specifier_token);
+ return false;
+}
+
+bool PrettyPrinter::visit(SizeofExpressionAST *ast)
+{
+ out << "sizeof";
+ out << ' ';
+ accept(ast->expression);
+ return false;
+}
+
+bool PrettyPrinter::visit(StringLiteralAST *ast)
+{
+ for (StringLiteralAST *it = ast; it; it = it->next) {
+ if (tokenKind(ast->token) == T_STRING_LITERAL)
+ out << '"' << spell(ast->token) << '"';
+ else
+ out << "L\"" << spell(ast->token) << '"';
+ if (it->next)
+ out << ' ';
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(SwitchStatementAST *ast)
+{
+ out << "switch";
+ out << ' ';
+ out << '(';
+ accept(ast->condition);
+ out << ')';
+ accept(ast->statement);
+ return false;
+}
+
+bool PrettyPrinter::visit(TemplateArgumentListAST *ast)
+{
+ for (TemplateArgumentListAST *it = ast; it; it = it->next) {
+ accept(it->template_argument);
+ if (it->next)
+ out << ", ";
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(TemplateDeclarationAST *ast)
+{
+ if (ast->export_token) {
+ out << "export";
+ out << ' ';
+ }
+ out << "template";
+ out << ' ';
+ out << '<';
+ if (ast->template_parameters) {
+ out << ' ';
+ for (DeclarationAST *it = ast->template_parameters; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ", ";
+ }
+ out << ' ';
+ }
+ out << '>';
+ newline();
+ accept(ast->declaration);
+ return false;
+}
+
+bool PrettyPrinter::visit(TemplateIdAST *ast)
+{
+ out << spell(ast->identifier_token);
+ out << '<';
+ if (ast->template_arguments) {
+ out << ' ';
+ for (TemplateArgumentListAST *it = ast->template_arguments; it; it = it->next) {
+ accept(it->template_argument);
+ if (it->next)
+ out << ", ";
+ }
+ out << ' ';
+ }
+ out << '>';
+ return false;
+}
+
+bool PrettyPrinter::visit(TemplateTypeParameterAST *ast)
+{
+ out << "template";
+ out << ' ';
+ out << '<';
+ if (ast->template_parameters) {
+ out << ' ';
+ for (DeclarationAST *it = ast->template_parameters; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ", ";
+ }
+ out << ' ';
+ }
+ out << '>';
+ out << ' ';
+ out << "class";
+ out << ' ';
+ accept(ast->name);
+ if (ast->equal_token) {
+ out << ' ';
+ out << '=';
+ out << ' ';
+ accept(ast->type_id);
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(ThisExpressionAST *)
+{
+ out << "this";
+ return false;
+}
+
+bool PrettyPrinter::visit(ThrowExpressionAST *ast)
+{
+ out << "throw";
+ out << ' ';
+ accept(ast->expression);
+ return false;
+}
+
+bool PrettyPrinter::visit(TranslationUnitAST *ast)
+{
+ for (DeclarationAST *it = ast->declarations; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ newline();
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(TryBlockStatementAST *ast)
+{
+ out << "try";
+ out << ' ';
+ accept(ast->statement);
+ for (CatchClauseAST *it = ast->catch_clause_seq; it; it = it->next) {
+ accept(it);
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(TypeConstructorCallAST *ast)
+{
+ for (SpecifierAST *it = ast->type_specifier; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ' ';
+ }
+ out << '(';
+ for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
+ accept(it->expression);
+ if (it->next)
+ out << ", ";
+ }
+ out << ')';
+ return false;
+}
+
+bool PrettyPrinter::visit(TypeIdAST *ast)
+{
+ for (SpecifierAST *it = ast->type_specifier; it; it = it->next) {
+ accept(it);
+ if (it->next)
+ out << ' ';
+ }
+ if (ast->type_specifier && ast->declarator) {
+ out << ' ';
+ accept(ast->declarator);
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(TypeidExpressionAST *ast)
+{
+ out << "typeid";
+ out << '(';
+ accept(ast->expression);
+ out << ')';
+ return false;
+}
+
+bool PrettyPrinter::visit(TypeofSpecifierAST *ast)
+{
+ out << "typeof";
+ out << '(';
+ accept(ast->expression);
+ out << ')';
+ return false;
+}
+
+bool PrettyPrinter::visit(TypenameCallExpressionAST *ast)
+{
+ out << "typename";
+ out << ' ';
+ accept(ast->name);
+ out << '(';
+ for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
+ accept(it->expression);
+ if (it->next)
+ out << ", ";
+ }
+ out << ')';
+ return false;
+}
+
+bool PrettyPrinter::visit(TypenameTypeParameterAST *ast)
+{
+ out << spell(ast->classkey_token);
+ if (ast->name) {
+ out << ' ';
+ accept(ast->name);
+ }
+ if (ast->equal_token) {
+ out << ' ';
+ out << '=';
+ out << ' ';
+ accept(ast->type_id);
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(UnaryExpressionAST *ast)
+{
+ out << spell(ast->unary_op_token);
+ accept(ast->expression);
+ return false;
+}
+
+bool PrettyPrinter::visit(UsingAST *ast)
+{
+ out << "using";
+ out << ' ';
+ if (ast->typename_token) {
+ out << "typename";
+ out << ' ';
+ }
+ accept(ast->name);
+ out << ';';
+ return false;
+}
+
+bool PrettyPrinter::visit(UsingDirectiveAST *ast)
+{
+ out << "using";
+ out << ' ';
+ out << "namespace";
+ out << ' ';
+ accept(ast->name);
+ out << ';';
+ return false;
+}
+
+bool PrettyPrinter::visit(WhileStatementAST *ast)
+{
+ out << "while";
+ out << ' ';
+ out << '(';
+ accept(ast->condition);
+ out << ')';
+ out << ' ';
+ if (ast->statement && ast->statement->asCompoundStatement())
+ accept(ast->statement);
+ else {
+ indent();
+ newline();
+ accept(ast->statement);
+ deindent();
+ newline();
+ }
+ return false;
+}
+
+bool PrettyPrinter::visit(QtMethodAST *ast)
+{
+ out << ast->method_token;
+ out << '(';
+ accept(ast->declarator);
+ out << ')';
+ return false;
+}
+
+bool PrettyPrinter::visit(CompoundLiteralAST *ast)
+{
+ out << '(';
+ accept(ast->type_id);
+ out << ')';
+ out << ' ';
+ accept(ast->initializer);
+ return false;
+}
diff --git a/src/shared/cplusplus/PrettyPrinter.h b/src/shared/cplusplus/PrettyPrinter.h
new file mode 100644
index 0000000000..c69ea2cf54
--- /dev/null
+++ b/src/shared/cplusplus/PrettyPrinter.h
@@ -0,0 +1,163 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef CPLUSPLUS_PRETTYPRINTER_H
+#define CPLUSPLUS_PRETTYPRINTER_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "ASTVisitor.h"
+
+#include <iosfwd>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class PrettyPrinter: protected ASTVisitor
+{
+public:
+ PrettyPrinter(Control *control, std::ostream &out);
+
+ void operator()(AST *ast);
+
+protected:
+ virtual bool visit(AccessDeclarationAST *ast);
+ virtual bool visit(ArrayAccessAST *ast);
+ virtual bool visit(ArrayDeclaratorAST *ast);
+ virtual bool visit(ArrayInitializerAST *ast);
+ virtual bool visit(AsmDefinitionAST *ast);
+ virtual bool visit(AttributeSpecifierAST *ast);
+ virtual bool visit(AttributeAST *ast);
+ virtual bool visit(BaseSpecifierAST *ast);
+ virtual bool visit(BinaryExpressionAST *ast);
+ virtual bool visit(BoolLiteralAST *ast);
+ virtual bool visit(BreakStatementAST *ast);
+ virtual bool visit(CallAST *ast);
+ virtual bool visit(CaseStatementAST *ast);
+ virtual bool visit(CastExpressionAST *ast);
+ virtual bool visit(CatchClauseAST *ast);
+ virtual bool visit(ClassSpecifierAST *ast);
+ virtual bool visit(CompoundLiteralAST *ast);
+ virtual bool visit(CompoundStatementAST *ast);
+ virtual bool visit(ConditionAST *ast);
+ virtual bool visit(ConditionalExpressionAST *ast);
+ virtual bool visit(ContinueStatementAST *ast);
+ virtual bool visit(ConversionFunctionIdAST *ast);
+ virtual bool visit(CppCastExpressionAST *ast);
+ virtual bool visit(CtorInitializerAST *ast);
+ virtual bool visit(DeclaratorAST *ast);
+ virtual bool visit(DeclarationStatementAST *ast);
+ virtual bool visit(DeclaratorIdAST *ast);
+ virtual bool visit(DeclaratorListAST *ast);
+ virtual bool visit(DeleteExpressionAST *ast);
+ virtual bool visit(DestructorNameAST *ast);
+ virtual bool visit(DoStatementAST *ast);
+ virtual bool visit(ElaboratedTypeSpecifierAST *ast);
+ virtual bool visit(EmptyDeclarationAST *ast);
+ virtual bool visit(EnumSpecifierAST *ast);
+ virtual bool visit(EnumeratorAST *ast);
+ virtual bool visit(ExceptionDeclarationAST *ast);
+ virtual bool visit(ExceptionSpecificationAST *ast);
+ virtual bool visit(ExpressionListAST *ast);
+ virtual bool visit(ExpressionOrDeclarationStatementAST *ast);
+ virtual bool visit(ExpressionStatementAST *ast);
+ virtual bool visit(ForStatementAST *ast);
+ virtual bool visit(FunctionDeclaratorAST *ast);
+ virtual bool visit(FunctionDefinitionAST *ast);
+ virtual bool visit(GotoStatementAST *ast);
+ virtual bool visit(IfStatementAST *ast);
+ virtual bool visit(LabeledStatementAST *ast);
+ virtual bool visit(LinkageBodyAST *ast);
+ virtual bool visit(LinkageSpecificationAST *ast);
+ virtual bool visit(MemInitializerAST *ast);
+ virtual bool visit(MemberAccessAST *ast);
+ virtual bool visit(NamedTypeSpecifierAST *ast);
+ virtual bool visit(NamespaceAST *ast);
+ virtual bool visit(NamespaceAliasDefinitionAST *ast);
+ virtual bool visit(NestedDeclaratorAST *ast);
+ virtual bool visit(NestedExpressionAST *ast);
+ virtual bool visit(NestedNameSpecifierAST *ast);
+ virtual bool visit(NewDeclaratorAST *ast);
+ virtual bool visit(NewExpressionAST *ast);
+ virtual bool visit(NewInitializerAST *ast);
+ virtual bool visit(NewTypeIdAST *ast);
+ virtual bool visit(NumericLiteralAST *ast);
+ virtual bool visit(OperatorAST *ast);
+ virtual bool visit(OperatorFunctionIdAST *ast);
+ virtual bool visit(ParameterDeclarationAST *ast);
+ virtual bool visit(ParameterDeclarationClauseAST *ast);
+ virtual bool visit(PointerAST *ast);
+ virtual bool visit(PointerToMemberAST *ast);
+ virtual bool visit(PostIncrDecrAST *ast);
+ virtual bool visit(PostfixExpressionAST *ast);
+ virtual bool visit(QualifiedNameAST *ast);
+ virtual bool visit(ReferenceAST *ast);
+ virtual bool visit(ReturnStatementAST *ast);
+ virtual bool visit(SimpleDeclarationAST *ast);
+ virtual bool visit(SimpleNameAST *ast);
+ virtual bool visit(SimpleSpecifierAST *ast);
+ virtual bool visit(SizeofExpressionAST *ast);
+ virtual bool visit(StringLiteralAST *ast);
+ virtual bool visit(SwitchStatementAST *ast);
+ virtual bool visit(TemplateArgumentListAST *ast);
+ virtual bool visit(TemplateDeclarationAST *ast);
+ virtual bool visit(TemplateIdAST *ast);
+ virtual bool visit(TemplateTypeParameterAST *ast);
+ virtual bool visit(ThisExpressionAST *ast);
+ virtual bool visit(ThrowExpressionAST *ast);
+ virtual bool visit(TranslationUnitAST *ast);
+ virtual bool visit(TryBlockStatementAST *ast);
+ virtual bool visit(TypeConstructorCallAST *ast);
+ virtual bool visit(TypeIdAST *ast);
+ virtual bool visit(TypeidExpressionAST *ast);
+ virtual bool visit(TypeofSpecifierAST *ast);
+ virtual bool visit(TypenameCallExpressionAST *ast);
+ virtual bool visit(TypenameTypeParameterAST *ast);
+ virtual bool visit(UnaryExpressionAST *ast);
+ virtual bool visit(UsingAST *ast);
+ virtual bool visit(UsingDirectiveAST *ast);
+ virtual bool visit(WhileStatementAST *ast);
+ virtual bool visit(QtMethodAST *ast);
+
+ void indent();
+ void deindent();
+ void newline();
+
+private:
+ std::ostream &out;
+ unsigned depth;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_PRETTYPRINTER_H
diff --git a/src/shared/cplusplus/Scope.cpp b/src/shared/cplusplus/Scope.cpp
new file mode 100644
index 0000000000..bdca9f8536
--- /dev/null
+++ b/src/shared/cplusplus/Scope.cpp
@@ -0,0 +1,310 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Scope.h"
+#include "Symbols.h"
+#include "Names.h"
+#include "Literals.h"
+#include <cstdlib>
+#include <cassert>
+#include <cstring>
+#include <iostream>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+Scope::Scope(ScopedSymbol *owner)
+ : _owner(owner),
+ _symbols(0),
+ _allocatedSymbols(0),
+ _symbolCount(-1),
+ _hash(0),
+ _hashSize(0),
+ _uses(0),
+ _allocatedUses(0),
+ _useCount(-1)
+{ }
+
+Scope::~Scope()
+{
+ if (_symbols)
+ free(_symbols);
+ if (_hash)
+ free(_hash);
+ if (_uses)
+ free(_uses);
+}
+
+ScopedSymbol *Scope::owner() const
+{ return _owner; }
+
+void Scope::setOwner(ScopedSymbol *owner)
+{ _owner = owner; }
+
+Scope *Scope::enclosingScope() const
+{
+ if (! _owner)
+ return 0;
+
+ return _owner->scope();
+}
+
+Scope *Scope::enclosingNamespaceScope() const
+{
+ Scope *scope = enclosingScope();
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->owner()->isNamespace())
+ break;
+ }
+ return scope;
+}
+
+Scope *Scope::enclosingClassScope() const
+{
+ Scope *scope = enclosingScope();
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->owner()->isClass())
+ break;
+ }
+ return scope;
+}
+
+Scope *Scope::enclosingEnumScope() const
+{
+ Scope *scope = enclosingScope();
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->owner()->isEnum())
+ break;
+ }
+ return scope;
+}
+
+Scope *Scope::enclosingFunctionScope() const
+{
+ Scope *scope = enclosingScope();
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->owner()->isFunction())
+ break;
+ }
+ return scope;
+}
+
+Scope *Scope::enclosingBlockScope() const
+{
+ Scope *scope = enclosingScope();
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->owner()->isBlock())
+ break;
+ }
+ return scope;
+}
+
+bool Scope::isNamespaceScope() const
+{ return dynamic_cast<const Namespace *>(_owner) != 0; }
+
+bool Scope::isClassScope() const
+{ return dynamic_cast<const Class *>(_owner) != 0; }
+
+bool Scope::isEnumScope() const
+{ return dynamic_cast<const Enum *>(_owner) != 0; }
+
+bool Scope::isBlockScope() const
+{ return dynamic_cast<const Block *>(_owner) != 0; }
+
+bool Scope::isPrototypeScope() const
+{
+ if (const Function *f = dynamic_cast<const Function *>(_owner))
+ return f->arguments() == this;
+ return false;
+}
+
+bool Scope::isFunctionScope() const
+{
+ if (const Function *f = dynamic_cast<const Function *>(_owner))
+ return f->arguments() != this;
+ return false;
+}
+
+void Scope::enterSymbol(Symbol *symbol)
+{
+ if (++_symbolCount == _allocatedSymbols) {
+ _allocatedSymbols <<= 1;
+ if (! _allocatedSymbols)
+ _allocatedSymbols = DefaultInitialSize;
+
+ _symbols = reinterpret_cast<Symbol **>(realloc(_symbols, sizeof(Symbol *) * _allocatedSymbols));
+ }
+
+ assert(! symbol->_scope || symbol->scope() == this);
+ symbol->_index = _symbolCount;
+ symbol->_scope = this;
+ _symbols[_symbolCount] = symbol;
+
+ if (_symbolCount >= _hashSize * 0.6)
+ rehash();
+ else {
+ const unsigned h = hashValue(symbol);
+ symbol->_next = _hash[h];
+ _hash[h] = symbol;
+ }
+}
+
+Symbol *Scope::lookat(Identifier *id) const
+{
+ if (! _hash)
+ return 0;
+
+ const unsigned h = id->hashCode() % _hashSize;
+ Symbol *symbol = _hash[h];
+ for (; symbol; symbol = symbol->_next) {
+ Name *identity = symbol->identity();
+ if (NameId *nameId = identity->asNameId()) {
+ if (nameId->identifier()->isEqualTo(id))
+ break;
+ } else if (TemplateNameId *t = identity->asTemplateNameId()) {
+ if (t->identifier()->isEqualTo(id))
+ break;
+ } else if (DestructorNameId *d = identity->asDestructorNameId()) {
+ if (d->identifier()->isEqualTo(id))
+ break;
+ } else if (identity->isQualifiedNameId()) {
+ assert(0);
+ }
+ }
+ return symbol;
+}
+
+Symbol *Scope::lookat(int operatorId) const
+{
+ if (! _hash)
+ return 0;
+
+ const unsigned h = operatorId % _hashSize;
+ Symbol *symbol = _hash[h];
+ for (; symbol; symbol = symbol->_next) {
+ Name *identity = symbol->identity();
+ if (OperatorNameId *op = identity->asOperatorNameId()) {
+ if (op->kind() == operatorId)
+ break;
+ }
+ }
+ return symbol;
+}
+
+void Scope::rehash()
+{
+ _hashSize <<= 1;
+
+ if (! _hashSize)
+ _hashSize = DefaultInitialSize;
+
+ _hash = reinterpret_cast<Symbol **>(realloc(_hash, sizeof(Symbol *) * _hashSize));
+ memset(_hash, 0, sizeof(Symbol *) * _hashSize);
+
+ for (int index = 0; index < _symbolCount + 1; ++index) {
+ Symbol *symbol = _symbols[index];
+ const unsigned h = hashValue(symbol);
+ symbol->_next = _hash[h];
+ _hash[h] = symbol;
+ }
+}
+
+unsigned Scope::hashValue(Symbol *symbol) const
+{
+ if (! symbol)
+ return 0;
+
+ return symbol->hashCode() % _hashSize;
+}
+
+bool Scope::isEmpty() const
+{ return _symbolCount == -1; }
+
+unsigned Scope::symbolCount() const
+{ return _symbolCount + 1; }
+
+Symbol *Scope::symbolAt(unsigned index) const
+{
+ if (! _symbols)
+ return 0;
+ return _symbols[index];
+}
+
+Scope::iterator Scope::firstSymbol() const
+{ return _symbols; }
+
+Scope::iterator Scope::lastSymbol() const
+{ return _symbols + _symbolCount + 1; }
+
+unsigned Scope::useCount() const
+{ return _useCount + 1; }
+
+Use *Scope::useAt(unsigned index) const
+{ return &_uses[index]; }
+
+void Scope::addUse(unsigned sourceOffset, Name *name)
+{
+#ifdef CPLUSPLUS_WITH_USES
+ if (++_useCount == _allocatedUses) {
+ _allocatedUses += 4;
+ _uses = reinterpret_cast<Use *>(realloc(_uses, _allocatedUses * sizeof(Use)));
+ }
+
+ Symbol *lastVisibleSymbol;
+ if (_symbolCount == -1)
+ lastVisibleSymbol = owner();
+ else
+ lastVisibleSymbol = _symbols[_symbolCount];
+ _uses[_useCount].init(sourceOffset, name, lastVisibleSymbol);
+#endif
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Scope.h b/src/shared/cplusplus/Scope.h
new file mode 100644
index 0000000000..44387718ff
--- /dev/null
+++ b/src/shared/cplusplus/Scope.h
@@ -0,0 +1,198 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_SCOPE_H
+#define CPLUSPLUS_SCOPE_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Use
+{
+public:
+ inline Name *name() const
+ { return _name; }
+
+ inline unsigned sourceOffset() const
+ { return _sourceOffset; }
+
+ inline Symbol *lastVisibleSymbol() const
+ { return _lastVisibleSymbol; }
+
+private:
+ void init(unsigned sourceOffset, Name *name, Symbol *lastVisibleSymbol)
+ {
+ _sourceOffset = sourceOffset;
+ _name = name;
+ _lastVisibleSymbol = lastVisibleSymbol;
+ }
+
+ unsigned _sourceOffset;
+
+ Name *_name;
+ Symbol *_lastVisibleSymbol;
+
+ friend class Scope;
+};
+
+class CPLUSPLUS_EXPORT Scope
+{
+ Scope(const Scope &other);
+ void operator =(const Scope &other);
+
+public:
+ typedef Symbol **iterator;
+
+public:
+ /// Constructs an empty Scope.
+ Scope(ScopedSymbol *owner = 0);
+
+ /// Destroy this scope.
+ ~Scope();
+
+ /// Returns this scope's owner Symbol.
+ ScopedSymbol *owner() const;
+
+ /// Sets this scope's owner Symbol.
+ void setOwner(ScopedSymbol *owner); // ### remove me
+
+ /// Returns the enclosing scope.
+ Scope *enclosingScope() const;
+
+ /// Returns the eclosing namespace scope.
+ Scope *enclosingNamespaceScope() const;
+
+ /// Returns the enclosing class scope.
+ Scope *enclosingClassScope() const;
+
+ /// Returns the enclosing enum scope.
+ Scope *enclosingEnumScope() const;
+
+ /// Rerturns the enclosing function scope.
+ Scope *enclosingFunctionScope() const;
+
+ /// Rerturns the enclosing Block scope.
+ Scope *enclosingBlockScope() const;
+
+ /// Returns true if this scope's owner is a Namespace Symbol.
+ bool isNamespaceScope() const;
+
+ /// Returns true if this scope's owner is a Class Symbol.
+ bool isClassScope() const;
+
+ /// Returns true if this scope's owner is an Enum Symbol.
+ bool isEnumScope() const;
+
+ /// Returns true if this scope's owner is a Block Symbol.
+ bool isBlockScope() const;
+
+ /// Returns true if this scope's owner is a Function Symbol.
+ bool isFunctionScope() const;
+
+ /// Returns true if this scope's owner is a Prototype Symbol.
+ bool isPrototypeScope() const;
+
+ /// Adds a Symbol to this Scope.
+ void enterSymbol(Symbol *symbol);
+
+ /// Returns true if this Scope is empty; otherwise returns false.
+ bool isEmpty() const;
+
+ /// Returns the number of symbols is in the scope.
+ unsigned symbolCount() const;
+
+ /// Returns the Symbol at the given position.
+ Symbol *symbolAt(unsigned index) const;
+
+ /// Returns the first Symbol in the scope.
+ iterator firstSymbol() const;
+
+ /// Returns the last Symbol in the scope.
+ iterator lastSymbol() const;
+
+ Symbol *lookat(Identifier *id) const;
+ Symbol *lookat(int operatorId) const;
+
+ unsigned useCount() const;
+ Use *useAt(unsigned index) const;
+ void addUse(unsigned sourceOffset, Name *name);
+
+private:
+ /// Returns the hash value for the given Symbol.
+ unsigned hashValue(Symbol *symbol) const;
+
+ /// Updates the hash table.
+ void rehash();
+
+private:
+ enum { DefaultInitialSize = 11 };
+
+ ScopedSymbol *_owner;
+
+ Symbol **_symbols;
+ int _allocatedSymbols;
+ int _symbolCount;
+
+ Symbol **_hash;
+ int _hashSize;
+
+ Use *_uses;
+ int _allocatedUses;
+ int _useCount;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_SCOPE_H
diff --git a/src/shared/cplusplus/Semantic.cpp b/src/shared/cplusplus/Semantic.cpp
new file mode 100644
index 0000000000..41716eb5aa
--- /dev/null
+++ b/src/shared/cplusplus/Semantic.cpp
@@ -0,0 +1,198 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Semantic.h"
+#include "TranslationUnit.h"
+#include "Control.h"
+#include "Scope.h"
+#include "Symbols.h"
+#include "Token.h"
+#include "CheckSpecifier.h"
+#include "CheckDeclaration.h"
+#include "CheckDeclarator.h"
+#include "CheckStatement.h"
+#include "CheckExpression.h"
+#include "CheckName.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class Semantic::Data
+{
+public:
+ Data(Semantic *semantic, Control *control)
+ : semantic(semantic),
+ control(control),
+ visibility(Symbol::Public),
+ methodKey(Function::NormalMethod),
+ checkSpecifier(0),
+ checkDeclaration(0),
+ checkDeclarator(0),
+ checkExpression(0),
+ checkStatement(0),
+ checkName(0)
+ { }
+
+ ~Data()
+ {
+ delete checkSpecifier;
+ delete checkDeclaration;
+ delete checkDeclarator;
+ delete checkExpression;
+ delete checkStatement;
+ delete checkName;
+ }
+
+ Semantic *semantic;
+ Control *control;
+ int visibility;
+ int methodKey;
+ CheckSpecifier *checkSpecifier;
+ CheckDeclaration *checkDeclaration;
+ CheckDeclarator *checkDeclarator;
+ CheckExpression *checkExpression;
+ CheckStatement *checkStatement;
+ CheckName *checkName;
+};
+
+Semantic::Semantic(Control *control)
+{
+ d = new Data(this, control);
+ d->checkSpecifier = new CheckSpecifier(this);
+ d->checkDeclaration = new CheckDeclaration(this);
+ d->checkDeclarator = new CheckDeclarator(this);
+ d->checkExpression = new CheckExpression(this);
+ d->checkStatement = new CheckStatement(this);
+ d->checkName = new CheckName(this);
+}
+
+Semantic::~Semantic()
+{ delete d; }
+
+Control *Semantic::control() const
+{ return d->control; }
+
+FullySpecifiedType Semantic::check(SpecifierAST *specifier, Scope *scope)
+{ return d->checkSpecifier->check(specifier, scope); }
+
+void Semantic::check(DeclarationAST *declaration, Scope *scope, Scope *templateParameters)
+{ d->checkDeclaration->check(declaration, scope, templateParameters); }
+
+FullySpecifiedType Semantic::check(DeclaratorAST *declarator, FullySpecifiedType type,
+ Scope *scope, Name **name)
+{ return d->checkDeclarator->check(declarator, type, scope, name); }
+
+FullySpecifiedType Semantic::check(PtrOperatorAST *ptrOperators, FullySpecifiedType type,
+ Scope *scope)
+{ return d->checkDeclarator->check(ptrOperators, type, scope); }
+
+FullySpecifiedType Semantic::check(ExpressionAST *expression, Scope *scope)
+{ return d->checkExpression->check(expression, scope); }
+
+void Semantic::check(StatementAST *statement, Scope *scope)
+{ d->checkStatement->check(statement, scope); }
+
+Name *Semantic::check(NameAST *name, Scope *scope)
+{ return d->checkName->check(name, scope); }
+
+Name *Semantic::check(NestedNameSpecifierAST *name, Scope *scope)
+{ return d->checkName->check(name, scope); }
+
+int Semantic::currentVisibility() const
+{ return d->visibility; }
+
+int Semantic::switchVisibility(int visibility)
+{
+ int previousVisibility = d->visibility;
+ d->visibility = visibility;
+ return previousVisibility;
+}
+
+int Semantic::currentMethodKey() const
+{ return d->methodKey; }
+
+int Semantic::switchMethodKey(int methodKey)
+{
+ int previousMethodKey = d->methodKey;
+ d->methodKey = methodKey;
+ return previousMethodKey;
+}
+
+int Semantic::visibilityForAccessSpecifier(int tokenKind) const
+{
+ switch (tokenKind) {
+ case T_PUBLIC:
+ return Symbol::Public;
+ case T_PROTECTED:
+ return Symbol::Protected;
+ case T_PRIVATE:
+ return Symbol::Private;
+ case T_SIGNALS:
+ return Symbol::Protected;
+ default:
+ return Symbol::Public;
+ }
+}
+
+int Semantic::visibilityForClassKey(int tokenKind) const
+{
+ switch (tokenKind) {
+ case T_CLASS:
+ return Symbol::Private;
+ case T_STRUCT:
+ case T_UNION:
+ return Symbol::Public;
+ default:
+ return Symbol::Public;
+ }
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Semantic.h b/src/shared/cplusplus/Semantic.h
new file mode 100644
index 0000000000..ac7b1b8c86
--- /dev/null
+++ b/src/shared/cplusplus/Semantic.h
@@ -0,0 +1,109 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_SEMANTIC_H
+#define CPLUSPLUS_SEMANTIC_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "ASTfwd.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Semantic
+{
+ Semantic(const Semantic &other);
+ void operator =(const Semantic &other);
+
+public:
+ Semantic(Control *control);
+ virtual ~Semantic();
+
+ Control *control() const;
+
+ FullySpecifiedType check(SpecifierAST *specifier, Scope *scope);
+
+ FullySpecifiedType check(DeclaratorAST *declarator, FullySpecifiedType type,
+ Scope *scope, Name **name = 0); // ### ugly
+
+ FullySpecifiedType check(PtrOperatorAST *ptrOperators, FullySpecifiedType type,
+ Scope *scope);
+
+ FullySpecifiedType check(ExpressionAST *expression, Scope *scope);
+
+ void check(DeclarationAST *declaration, Scope *scope, Scope *templateParameters = 0);
+
+ void check(StatementAST *statement, Scope *scope);
+
+ Name *check(NameAST *name, Scope *scope);
+
+ Name *check(NestedNameSpecifierAST *name, Scope *scope);
+
+ int currentVisibility() const;
+ int switchVisibility(int visibility);
+
+ int currentMethodKey() const;
+ int switchMethodKey(int methodKey);
+
+ int visibilityForClassKey(int tokenKind) const;
+ int visibilityForAccessSpecifier(int tokenKind) const;
+
+private:
+ class Data;
+ friend class Data;
+ Data *d;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_SEMANTIC_H
diff --git a/src/shared/cplusplus/SemanticCheck.cpp b/src/shared/cplusplus/SemanticCheck.cpp
new file mode 100644
index 0000000000..27b1a56429
--- /dev/null
+++ b/src/shared/cplusplus/SemanticCheck.cpp
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "SemanticCheck.h"
+#include "Semantic.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+SemanticCheck::SemanticCheck(Semantic *semantic)
+ : ASTVisitor(semantic->control()),
+ _semantic(semantic)
+{ }
+
+SemanticCheck::~SemanticCheck()
+{ }
+
+Semantic *SemanticCheck::semantic() const
+{ return _semantic; }
+
+Control *SemanticCheck::control() const
+{ return _semantic->control(); }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/SemanticCheck.h b/src/shared/cplusplus/SemanticCheck.h
new file mode 100644
index 0000000000..0ecdeac603
--- /dev/null
+++ b/src/shared/cplusplus/SemanticCheck.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_SEMANTICCHECK_H
+#define CPLUSPLUS_SEMANTICCHECK_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "ASTVisitor.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT SemanticCheck: public ASTVisitor
+{
+public:
+ SemanticCheck(Semantic *semantic);
+ virtual ~SemanticCheck();
+
+ Control *control() const;
+ Semantic *semantic() const;
+
+private:
+ Semantic *_semantic;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_SEMANTICCHECK_H
diff --git a/src/shared/cplusplus/Symbol.cpp b/src/shared/cplusplus/Symbol.cpp
new file mode 100644
index 0000000000..cdcd389118
--- /dev/null
+++ b/src/shared/cplusplus/Symbol.cpp
@@ -0,0 +1,421 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Symbol.h"
+#include "Symbols.h"
+#include "Control.h"
+#include "Names.h"
+#include "TranslationUnit.h"
+#include "Literals.h"
+#include "MemoryPool.h"
+#include "SymbolVisitor.h"
+#include "NameVisitor.h"
+#include <cstddef>
+#include <cassert>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class Symbol::HashCode: protected NameVisitor
+{
+public:
+ HashCode()
+ : _value(0)
+ { }
+
+ virtual ~HashCode()
+ { }
+
+ unsigned operator()(Name *name)
+ {
+ unsigned previousValue = switchValue(0);
+ accept(name);
+ return switchValue(previousValue);
+ }
+
+protected:
+ unsigned switchValue(unsigned value)
+ {
+ unsigned previousValue = _value;
+ _value = value;
+ return previousValue;
+ }
+
+ virtual void visit(NameId *name)
+ { _value = name->identifier()->hashCode(); }
+
+ virtual void visit(TemplateNameId *name)
+ { _value = name->identifier()->hashCode(); }
+
+ virtual void visit(DestructorNameId *name)
+ { _value = name->identifier()->hashCode(); }
+
+ virtual void visit(OperatorNameId *name)
+ { _value = unsigned(name->kind()); }
+
+ virtual void visit(ConversionNameId *)
+ { _value = 0; } // ### TODO: implement me
+
+ virtual void visit(QualifiedNameId *name)
+ { _value = operator()(name->unqualifiedNameId()); }
+
+private:
+ unsigned _value;
+};
+
+class Symbol::IdentityForName: protected NameVisitor
+{
+public:
+ IdentityForName()
+ : _identity(0)
+ { }
+
+ virtual ~IdentityForName()
+ { }
+
+ Name *operator()(Name *name)
+ {
+ Name *previousIdentity = switchIdentity(0);
+ accept(name);
+ return switchIdentity(previousIdentity);
+ }
+
+protected:
+ Name *switchIdentity(Name *identity)
+ {
+ Name *previousIdentity = _identity;
+ _identity = identity;
+ return previousIdentity;
+ }
+
+ virtual void visit(NameId *name)
+ { _identity = name; }
+
+ virtual void visit(TemplateNameId *name)
+ { _identity = name; }
+
+ virtual void visit(DestructorNameId *name)
+ { _identity = name; }
+
+ virtual void visit(OperatorNameId *name)
+ { _identity = name; }
+
+ virtual void visit(ConversionNameId *name)
+ { _identity = name; }
+
+ virtual void visit(QualifiedNameId *name)
+ { _identity = name->unqualifiedNameId(); }
+
+private:
+ Name *_identity;
+};
+
+Symbol::Symbol(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : _control(translationUnit->control()),
+ _sourceLocation(sourceLocation),
+ _sourceOffset(0),
+ _name(0),
+ _hashCode(0),
+ _storage(Symbol::NoStorage),
+ _visibility(Symbol::Public),
+ _scope(0),
+ _index(0),
+ _next(0)
+{
+ if (sourceLocation)
+ _sourceOffset = translationUnit->tokenAt(sourceLocation).offset;
+
+ setName(name);
+}
+
+Symbol::~Symbol()
+{ }
+
+Control *Symbol::control() const
+{ return _control; }
+
+TranslationUnit *Symbol::translationUnit() const
+{ return _control->translationUnit(); }
+
+void Symbol::visitSymbol(SymbolVisitor *visitor)
+{
+ if (visitor->preVisit(this))
+ visitSymbol0(visitor);
+ visitor->postVisit(this);
+}
+
+void Symbol::visitSymbol(Symbol *symbol, SymbolVisitor *visitor)
+{
+ if (! symbol)
+ return;
+
+ symbol->visitSymbol(visitor);
+}
+
+unsigned Symbol::sourceLocation() const
+{ return _sourceLocation; }
+
+unsigned Symbol::sourceOffset() const
+{ return _sourceOffset; }
+
+unsigned Symbol::line() const
+{
+ unsigned line = 0, column = 0;
+ StringLiteral *fileId = 0;
+ translationUnit()->getPosition(_sourceOffset, &line, &column, &fileId);
+ return line;
+}
+
+unsigned Symbol::column() const
+{
+#ifdef CPLUSPLUS_WITH_COLUMNS
+ unsigned line = 0, column = 0;
+ StringLiteral *fileId = 0;
+ translationUnit()->getPosition(_sourceOffset, &line, &column, &fileId);
+ return column;
+#else
+ return 0;
+#endif
+}
+
+StringLiteral *Symbol::fileId() const
+{
+ unsigned line = 0, column = 0;
+ StringLiteral *fileId = 0;
+ translationUnit()->getPosition(_sourceOffset, &line, &column, &fileId);
+ return fileId;
+}
+
+const char *Symbol::fileName() const
+{ return fileId()->chars(); }
+
+unsigned Symbol::fileNameLength() const
+{ return fileId()->size(); }
+
+Name *Symbol::identity() const
+{
+ IdentityForName id;
+ return id(_name);
+}
+
+Name *Symbol::name() const
+{ return _name; }
+
+void Symbol::setName(Name *name)
+{
+ _name = name;
+
+ if (! _name)
+ _hashCode = 0;
+ else {
+ IdentityForName identityForName;
+ HashCode hh;
+ _hashCode = hh(identityForName(_name));
+ }
+}
+
+Scope *Symbol::scope() const
+{ return _scope; }
+
+void Symbol::setScope(Scope *scope)
+{
+ assert(! _scope);
+ _scope = scope;
+}
+
+unsigned Symbol::index() const
+{ return _index; }
+
+Symbol *Symbol::next() const
+{ return _next; }
+
+unsigned Symbol::hashCode() const
+{ return _hashCode; }
+
+int Symbol::storage() const
+{ return _storage; }
+
+void Symbol::setStorage(int storage)
+{ _storage = storage; }
+
+int Symbol::visibility() const
+{ return _visibility; }
+
+void Symbol::setVisibility(int visibility)
+{ _visibility = visibility; }
+
+bool Symbol::isFriend() const
+{ return _storage == Friend; }
+
+bool Symbol::isRegister() const
+{ return _storage == Register; }
+
+bool Symbol::isStatic() const
+{ return _storage == Static; }
+
+bool Symbol::isExtern() const
+{ return _storage == Extern; }
+
+bool Symbol::isMutable() const
+{ return _storage == Mutable; }
+
+bool Symbol::isTypedef() const
+{ return _storage == Typedef; }
+
+bool Symbol::isPublic() const
+{ return _visibility == Public; }
+
+bool Symbol::isProtected() const
+{ return _visibility == Protected; }
+
+bool Symbol::isPrivate() const
+{ return _visibility == Private; }
+
+bool Symbol::isScopedSymbol() const
+{ return dynamic_cast<const ScopedSymbol *>(this) != 0; }
+
+bool Symbol::isEnum() const
+{ return dynamic_cast<const Enum *>(this) != 0; }
+
+bool Symbol::isFunction() const
+{ return dynamic_cast<const Function *>(this) != 0; }
+
+bool Symbol::isNamespace() const
+{ return dynamic_cast<const Namespace *>(this) != 0; }
+
+bool Symbol::isClass() const
+{ return dynamic_cast<const Class *>(this) != 0; }
+
+bool Symbol::isBlock() const
+{ return dynamic_cast<const Block *>(this) != 0; }
+
+bool Symbol::isUsingNamespaceDirective() const
+{ return dynamic_cast<const UsingNamespaceDirective *>(this) != 0; }
+
+bool Symbol::isUsingDeclaration() const
+{ return dynamic_cast<const UsingDeclaration *>(this) != 0; }
+
+bool Symbol::isDeclaration() const
+{ return dynamic_cast<const Declaration *>(this) != 0; }
+
+bool Symbol::isArgument() const
+{ return dynamic_cast<const Argument *>(this) != 0; }
+
+bool Symbol::isBaseClass() const
+{ return dynamic_cast<const BaseClass *>(this) != 0; }
+
+const ScopedSymbol *Symbol::asScopedSymbol() const
+{ return dynamic_cast<const ScopedSymbol *>(this); }
+
+const Enum *Symbol::asEnum() const
+{ return dynamic_cast<const Enum *>(this); }
+
+const Function *Symbol::asFunction() const
+{ return dynamic_cast<const Function *>(this); }
+
+const Namespace *Symbol::asNamespace() const
+{ return dynamic_cast<const Namespace *>(this); }
+
+const Class *Symbol::asClass() const
+{ return dynamic_cast<const Class *>(this); }
+
+const Block *Symbol::asBlock() const
+{ return dynamic_cast<const Block *>(this); }
+
+const UsingNamespaceDirective *Symbol::asUsingNamespaceDirective() const
+{ return dynamic_cast<const UsingNamespaceDirective *>(this); }
+
+const UsingDeclaration *Symbol::asUsingDeclaration() const
+{ return dynamic_cast<const UsingDeclaration *>(this); }
+
+const Declaration *Symbol::asDeclaration() const
+{ return dynamic_cast<const Declaration *>(this); }
+
+const Argument *Symbol::asArgument() const
+{ return dynamic_cast<const Argument *>(this); }
+
+const BaseClass *Symbol::asBaseClass() const
+{ return dynamic_cast<const BaseClass *>(this); }
+
+ScopedSymbol *Symbol::asScopedSymbol()
+{ return dynamic_cast<ScopedSymbol *>(this); }
+
+Enum *Symbol::asEnum()
+{ return dynamic_cast<Enum *>(this); }
+
+Function *Symbol::asFunction()
+{ return dynamic_cast<Function *>(this); }
+
+Namespace *Symbol::asNamespace()
+{ return dynamic_cast<Namespace *>(this); }
+
+Class *Symbol::asClass()
+{ return dynamic_cast<Class *>(this); }
+
+Block *Symbol::asBlock()
+{ return dynamic_cast<Block *>(this); }
+
+UsingNamespaceDirective *Symbol::asUsingNamespaceDirective()
+{ return dynamic_cast<UsingNamespaceDirective *>(this); }
+
+UsingDeclaration *Symbol::asUsingDeclaration()
+{ return dynamic_cast<UsingDeclaration *>(this); }
+
+Declaration *Symbol::asDeclaration()
+{ return dynamic_cast<Declaration *>(this); }
+
+Argument *Symbol::asArgument()
+{ return dynamic_cast<Argument *>(this); }
+
+BaseClass *Symbol::asBaseClass()
+{ return dynamic_cast<BaseClass *>(this); }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Symbol.h b/src/shared/cplusplus/Symbol.h
new file mode 100644
index 0000000000..e9d150e8d5
--- /dev/null
+++ b/src/shared/cplusplus/Symbol.h
@@ -0,0 +1,266 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_SYMBOL_H
+#define CPLUSPLUS_SYMBOL_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Symbol
+{
+ Symbol(const Symbol &other);
+ void operator =(const Symbol &other);
+
+public:
+ /// Storage class specifier
+ enum Storage {
+ NoStorage = 0,
+ Friend,
+ Register,
+ Static,
+ Extern,
+ Mutable,
+ Typedef
+ };
+
+ /// Access specifier.
+ enum Visibility {
+ Public,
+ Protected,
+ Private
+ };
+
+public:
+ /// Constructs a Symbol with the given source location, name and translation unit.
+ Symbol(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+
+ /// Destroy this Symbol.
+ virtual ~Symbol();
+
+ /// Returns this Symbol's Control object.
+ Control *control() const;
+
+ /// Returns this Symbol's source location.
+ unsigned sourceLocation() const;
+
+ /// Returns this Symbol's source offset.
+ unsigned sourceOffset() const;
+
+ /// Returns this Symbol's line number.
+ unsigned line() const;
+
+ /// Returns this Symbol's column number.
+ unsigned column() const;
+
+ /// Returns this Symbol's file name.
+ StringLiteral *fileId() const;
+
+ /// Returns this Symbol's file name.
+ const char *fileName() const;
+
+ /// Returns this Symbol's file name length.
+ unsigned fileNameLength() const;
+
+ /// Returns this Symbol's name.
+ Name *name() const;
+
+ /// Sets this Symbol's name.
+ void setName(Name *name); // ### dangerous
+
+ /// Returns this Symbol's storage class specifier.
+ int storage() const;
+
+ /// Sets this Symbol's storage class specifier.
+ void setStorage(int storage);
+
+ /// Returns this Symbol's visibility.
+ int visibility() const;
+
+ /// Sets this Symbol's visibility.
+ void setVisibility(int visibility);
+
+ /// Returns this Symbol's scope.
+ Scope *scope() const;
+
+ /// Returns the next chained Symbol.
+ Symbol *next() const;
+
+ /// Returns true if this Symbol has friend storage specifier.
+ bool isFriend() const;
+
+ /// Returns true if this Symbol has register storage specifier.
+ bool isRegister() const;
+
+ /// Returns true if this Symbol has static storage specifier.
+ bool isStatic() const;
+
+ /// Returns true if this Symbol has extern storage specifier.
+ bool isExtern() const;
+
+ /// Returns true if this Symbol has mutable storage specifier.
+ bool isMutable() const;
+
+ /// Returns true if this Symbol has typedef storage specifier.
+ bool isTypedef() const;
+
+ /// Returns true if this Symbol's visibility is public.
+ bool isPublic() const;
+
+ /// Returns true if this Symbol's visibility is protected.
+ bool isProtected() const;
+
+ /// Returns true if this Symbol's visibility is private.
+ bool isPrivate() const;
+
+ /// Returns true if this Symbol is a ScopedSymbol.
+ bool isScopedSymbol() const;
+
+ /// Returns true if this Symbol is an Enum.
+ bool isEnum() const;
+
+ /// Returns true if this Symbol is an Function.
+ bool isFunction() const;
+
+ /// Returns true if this Symbol is a Namespace.
+ bool isNamespace() const;
+
+ /// Returns true if this Symbol is a Class.
+ bool isClass() const;
+
+ /// Returns true if this Symbol is a Block.
+ bool isBlock() const;
+
+ /// Returns true if this Symbol is a UsingNamespaceDirective.
+ bool isUsingNamespaceDirective() const;
+
+ /// Returns true if this Symbol is a UsingDeclaration.
+ bool isUsingDeclaration() const;
+
+ /// Returns true if this Symbol is a Declaration.
+ bool isDeclaration() const;
+
+ /// Returns true if this Symbol is an Argument.
+ bool isArgument() const;
+
+ /// Returns true if this Symbol is a BaseClass.
+ bool isBaseClass() const;
+
+ const ScopedSymbol *asScopedSymbol() const;
+ const Enum *asEnum() const;
+ const Function *asFunction() const;
+ const Namespace *asNamespace() const;
+ const Class *asClass() const;
+ const Block *asBlock() const;
+ const UsingNamespaceDirective *asUsingNamespaceDirective() const;
+ const UsingDeclaration *asUsingDeclaration() const;
+ const Declaration *asDeclaration() const;
+ const Argument *asArgument() const;
+ const BaseClass *asBaseClass() const;
+
+ ScopedSymbol *asScopedSymbol();
+ Enum *asEnum();
+ Function *asFunction();
+ Namespace *asNamespace();
+ Class *asClass();
+ Block *asBlock();
+ UsingNamespaceDirective *asUsingNamespaceDirective();
+ UsingDeclaration *asUsingDeclaration();
+ Declaration *asDeclaration();
+ Argument *asArgument();
+ BaseClass *asBaseClass();
+
+ /// Returns this Symbol's type.
+ virtual FullySpecifiedType type() const = 0;
+
+ /// Returns this Symbol's hash value.
+ unsigned hashCode() const;
+
+ /// Returns this Symbol's index.
+ unsigned index() const;
+
+ Name *identity() const;
+
+ void setScope(Scope *scope); // ### make me private
+
+ void visitSymbol(SymbolVisitor *visitor);
+ static void visitSymbol(Symbol *symbol, SymbolVisitor *visitor);
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor) = 0;
+
+ TranslationUnit *translationUnit() const;
+
+private:
+ Control *_control;
+ unsigned _sourceLocation;
+ unsigned _sourceOffset;
+ Name *_name;
+ unsigned _hashCode;
+ int _storage;
+ int _visibility;
+ Scope *_scope;
+ unsigned _index;
+ Symbol *_next;
+
+ class IdentityForName;
+ class HashCode;
+
+ friend class Scope;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_SYMBOL_H
diff --git a/src/shared/cplusplus/SymbolVisitor.cpp b/src/shared/cplusplus/SymbolVisitor.cpp
new file mode 100644
index 0000000000..95cab998ed
--- /dev/null
+++ b/src/shared/cplusplus/SymbolVisitor.cpp
@@ -0,0 +1,66 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "SymbolVisitor.h"
+#include "Symbol.h"
+
+CPLUSPLUS_USE_NAMESPACE
+
+SymbolVisitor::SymbolVisitor()
+{ }
+
+SymbolVisitor::~SymbolVisitor()
+{ }
+
+void SymbolVisitor::accept(Symbol *symbol)
+{ Symbol::visitSymbol(symbol, this); }
+
diff --git a/src/shared/cplusplus/SymbolVisitor.h b/src/shared/cplusplus/SymbolVisitor.h
new file mode 100644
index 0000000000..f0f4738de7
--- /dev/null
+++ b/src/shared/cplusplus/SymbolVisitor.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef SYMBOLVISITOR_H
+#define SYMBOLVISITOR_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT SymbolVisitor
+{
+ SymbolVisitor(const SymbolVisitor &other);
+ void operator =(const SymbolVisitor &other);
+
+public:
+ SymbolVisitor();
+ virtual ~SymbolVisitor();
+
+ void accept(Symbol *symbol);
+
+ virtual bool preVisit(Symbol *) { return true; }
+ virtual void postVisit(Symbol *) {}
+
+ virtual bool visit(UsingNamespaceDirective *) { return true; }
+ virtual bool visit(UsingDeclaration *) { return true; }
+ virtual bool visit(Declaration *) { return true; }
+ virtual bool visit(Argument *) { return true; }
+ virtual bool visit(BaseClass *) { return true; }
+ virtual bool visit(Enum *) { return true; }
+ virtual bool visit(Function *) { return true; }
+ virtual bool visit(Namespace *) { return true; }
+ virtual bool visit(Class *) { return true; }
+ virtual bool visit(Block *) { return true; }
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // SYMBOLVISITOR_H
diff --git a/src/shared/cplusplus/Symbols.cpp b/src/shared/cplusplus/Symbols.cpp
new file mode 100644
index 0000000000..a7ed4682ff
--- /dev/null
+++ b/src/shared/cplusplus/Symbols.cpp
@@ -0,0 +1,484 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Symbols.h"
+#include "Names.h"
+#include "TypeVisitor.h"
+#include "SymbolVisitor.h"
+#include "Scope.h"
+#include <cstdlib>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+UsingNamespaceDirective::UsingNamespaceDirective(TranslationUnit *translationUnit,
+ unsigned sourceLocation, Name *name)
+ : Symbol(translationUnit, sourceLocation, name)
+{ }
+
+UsingNamespaceDirective::~UsingNamespaceDirective()
+{ }
+
+FullySpecifiedType UsingNamespaceDirective::type() const
+{ return FullySpecifiedType(); }
+
+void UsingNamespaceDirective::visitSymbol0(SymbolVisitor *visitor)
+{ visitor->visit(this); }
+
+UsingDeclaration::UsingDeclaration(TranslationUnit *translationUnit,
+ unsigned sourceLocation, Name *name)
+ : Symbol(translationUnit, sourceLocation, name)
+{ }
+
+UsingDeclaration::~UsingDeclaration()
+{ }
+
+FullySpecifiedType UsingDeclaration::type() const
+{ return FullySpecifiedType(); }
+
+void UsingDeclaration::visitSymbol0(SymbolVisitor *visitor)
+{ visitor->visit(this); }
+
+Declaration::Declaration(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : Symbol(translationUnit, sourceLocation, name),
+ _templateParameters(0)
+{ }
+
+Declaration::~Declaration()
+{ delete _templateParameters; }
+
+unsigned Declaration::templateParameterCount() const
+{
+ if (! _templateParameters)
+ return 0;
+ return _templateParameters->symbolCount();
+}
+
+Symbol *Declaration::templateParameterAt(unsigned index) const
+{ return _templateParameters->symbolAt(index); }
+
+Scope *Declaration::templateParameters() const
+{ return _templateParameters; }
+
+void Declaration::setTemplateParameters(Scope *templateParameters)
+{ _templateParameters = templateParameters; }
+
+void Declaration::setType(FullySpecifiedType type)
+{ _type = type; }
+
+FullySpecifiedType Declaration::type() const
+{ return _type; }
+
+void Declaration::visitSymbol0(SymbolVisitor *visitor)
+{ visitor->visit(this); }
+
+Argument::Argument(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : Symbol(translationUnit, sourceLocation, name),
+ _initializer(false)
+{ }
+
+Argument::~Argument()
+{ }
+
+bool Argument::hasInitializer() const
+{ return _initializer; }
+
+void Argument::setInitializer(bool hasInitializer)
+{ _initializer = hasInitializer; }
+
+void Argument::setType(FullySpecifiedType type)
+{ _type = type; }
+
+FullySpecifiedType Argument::type() const
+{ return _type; }
+
+void Argument::visitSymbol0(SymbolVisitor *visitor)
+{ visitor->visit(this); }
+
+Function::Function(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : ScopedSymbol(translationUnit, sourceLocation, name),
+ _templateParameters(0),
+ _flags(0)
+{ _arguments = new Scope(this); }
+
+Function::~Function()
+{
+ delete _templateParameters;
+ delete _arguments;
+}
+
+bool Function::isNormal() const
+{ return _methodKey == NormalMethod; }
+
+bool Function::isSignal() const
+{ return _methodKey == SignalMethod; }
+
+bool Function::isSlot() const
+{ return _methodKey == SlotMethod; }
+
+int Function::methodKey() const
+{ return _methodKey; }
+
+void Function::setMethodKey(int key)
+{ _methodKey = key; }
+
+unsigned Function::templateParameterCount() const
+{
+ if (! _templateParameters)
+ return 0;
+ return _templateParameters->symbolCount();
+}
+
+Symbol *Function::templateParameterAt(unsigned index) const
+{ return _templateParameters->symbolAt(index); }
+
+Scope *Function::templateParameters() const
+{ return _templateParameters; }
+
+void Function::setTemplateParameters(Scope *templateParameters)
+{ _templateParameters = templateParameters; }
+
+bool Function::isEqualTo(const Type *other) const
+{
+ const Function *o = other->asFunction();
+ if (! o)
+ return false;
+ Name *l = identity();
+ Name *r = o->identity();
+ if (l == r || (l && l->isEqualTo(r))) {
+ if (_arguments->symbolCount() != o->_arguments->symbolCount())
+ return false;
+ else if (! _returnType.isEqualTo(o->_returnType))
+ return false;
+ for (unsigned i = 0; i < _arguments->symbolCount(); ++i) {
+ Symbol *l = _arguments->symbolAt(i);
+ Symbol *r = o->_arguments->symbolAt(i);
+ if (! l->type().isEqualTo(r->type()))
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+void Function::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+FullySpecifiedType Function::type() const
+{ return FullySpecifiedType(const_cast<Function *>(this)); }
+
+FullySpecifiedType Function::returnType() const
+{ return _returnType; }
+
+void Function::setReturnType(FullySpecifiedType returnType)
+{ _returnType = returnType; }
+
+unsigned Function::argumentCount() const
+{
+ if (! _arguments)
+ return 0;
+
+ return _arguments->symbolCount();
+}
+
+Symbol *Function::argumentAt(unsigned index) const
+{ return _arguments->symbolAt(index); }
+
+Scope *Function::arguments() const
+{ return _arguments; }
+
+bool Function::isVariadic() const
+{ return _isVariadic; }
+
+void Function::setVariadic(bool isVariadic)
+{ _isVariadic = isVariadic; }
+
+bool Function::isConst() const
+{ return _isConst; }
+
+void Function::setConst(bool isConst)
+{ _isConst = isConst; }
+
+bool Function::isVolatile() const
+{ return _isVolatile; }
+
+void Function::setVolatile(bool isVolatile)
+{ _isVolatile = isVolatile; }
+
+bool Function::isPureVirtual() const
+{ return _isPureVirtual; }
+
+void Function::setPureVirtual(bool isPureVirtual)
+{ _isPureVirtual = isPureVirtual; }
+
+void Function::visitSymbol0(SymbolVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (unsigned i = 0; i < _arguments->symbolCount(); ++i) {
+ visitSymbol(_arguments->symbolAt(i), visitor);
+ }
+ for (unsigned i = 0; i < memberCount(); ++i) {
+ visitSymbol(memberAt(i), visitor);
+ }
+ }
+}
+
+ScopedSymbol::ScopedSymbol(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : Symbol(translationUnit, sourceLocation, name)
+{ _members = new Scope(this); }
+
+ScopedSymbol::~ScopedSymbol()
+{ delete _members; }
+
+unsigned ScopedSymbol::memberCount() const
+{
+ if (! _members)
+ return 0;
+ return _members->symbolCount();
+}
+
+Symbol *ScopedSymbol::memberAt(unsigned index) const
+{
+ if (! _members)
+ return 0;
+ return _members->symbolAt(index);
+}
+
+Scope *ScopedSymbol::members() const
+{ return _members; }
+
+void ScopedSymbol::addMember(Symbol *member)
+{ _members->enterSymbol(member); }
+
+Block::Block(TranslationUnit *translationUnit, unsigned sourceLocation)
+ : ScopedSymbol(translationUnit, sourceLocation, /*name = */ 0)
+{ }
+
+Block::~Block()
+{ }
+
+FullySpecifiedType Block::type() const
+{ return FullySpecifiedType(); }
+
+void Block::visitSymbol0(SymbolVisitor *visitor)
+{ visitor->visit(this); }
+
+Enum::Enum(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : ScopedSymbol(translationUnit, sourceLocation, name)
+{ }
+
+Enum::~Enum()
+{ }
+
+FullySpecifiedType Enum::type() const
+{ return FullySpecifiedType(const_cast<Enum *>(this)); }
+
+bool Enum::isEqualTo(const Type *other) const
+{
+ const Enum *o = other->asEnum();
+ if (! o)
+ return false;
+ Name *l = identity();
+ Name *r = o->identity();
+ if (l == r)
+ return true;
+ else if (! l)
+ return false;
+ return l->isEqualTo(r);
+}
+
+void Enum::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+void Enum::visitSymbol0(SymbolVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (unsigned i = 0; i < memberCount(); ++i) {
+ visitSymbol(memberAt(i), visitor);
+ }
+ }
+}
+
+Namespace::Namespace(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : ScopedSymbol(translationUnit, sourceLocation, name)
+{ }
+
+Namespace::~Namespace()
+{ }
+
+bool Namespace::isEqualTo(const Type *other) const
+{
+ const Namespace *o = other->asNamespace();
+ if (! o)
+ return false;
+ Name *l = identity();
+ Name *r = o->identity();
+ if (l == r || (l && l->isEqualTo(r)))
+ return true;
+ return false;
+}
+
+void Namespace::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+void Namespace::visitSymbol0(SymbolVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (unsigned i = 0; i < memberCount(); ++i) {
+ visitSymbol(memberAt(i), visitor);
+ }
+ }
+}
+
+FullySpecifiedType Namespace::type() const
+{ return FullySpecifiedType(const_cast<Namespace *>(this)); }
+
+BaseClass::BaseClass(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : Symbol(translationUnit, sourceLocation, name),
+ _isVirtual(false)
+{ }
+
+BaseClass::~BaseClass()
+{ }
+
+FullySpecifiedType BaseClass::type() const
+{ return FullySpecifiedType(); }
+
+bool BaseClass::isVirtual() const
+{ return _isVirtual; }
+
+void BaseClass::setVirtual(bool isVirtual)
+{ _isVirtual = isVirtual; }
+
+void BaseClass::visitSymbol0(SymbolVisitor *visitor)
+{ visitor->visit(this); }
+
+Class::Class(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
+ : ScopedSymbol(translationUnit, sourceLocation, name),
+ _key(ClassKey),
+ _templateParameters(0)
+{ }
+
+Class::~Class()
+{ delete _templateParameters; }
+
+bool Class::isClass() const
+{ return _key == ClassKey; }
+
+bool Class::isStruct() const
+{ return _key == StructKey; }
+
+bool Class::isUnion() const
+{ return _key == UnionKey; }
+
+Class::Key Class::classKey() const
+{ return _key; }
+
+void Class::setClassKey(Key key)
+{ _key = key; }
+
+unsigned Class::templateParameterCount() const
+{
+ if (! _templateParameters)
+ return 0;
+ return _templateParameters->symbolCount();
+}
+
+Symbol *Class::templateParameterAt(unsigned index) const
+{ return _templateParameters->symbolAt(index); }
+
+Scope *Class::templateParameters() const
+{ return _templateParameters; }
+
+void Class::setTemplateParameters(Scope *templateParameters)
+{ _templateParameters = templateParameters; }
+
+void Class::accept0(TypeVisitor *visitor)
+{ visitor->visit(this); }
+
+unsigned Class::baseClassCount() const
+{ return _baseClasses.count(); }
+
+BaseClass *Class::baseClassAt(unsigned index) const
+{ return _baseClasses.at(index); }
+
+void Class::addBaseClass(BaseClass *baseClass)
+{ _baseClasses.push_back(baseClass); }
+
+FullySpecifiedType Class::type() const
+{ return FullySpecifiedType(const_cast<Class *>(this)); }
+
+bool Class::isEqualTo(const Type *other) const
+{
+ const Class *o = other->asClass();
+ if (! o)
+ return false;
+ Name *l = identity();
+ Name *r = o->identity();
+ if (l == r || (l && l->isEqualTo(r)))
+ return true;
+ else
+ return false;
+}
+
+void Class::visitSymbol0(SymbolVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (unsigned i = 0; i < _baseClasses.size(); ++i) {
+ visitSymbol(_baseClasses.at(i), visitor);
+ }
+ for (unsigned i = 0; i < memberCount(); ++i) {
+ visitSymbol(memberAt(i), visitor);
+ }
+ }
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Symbols.h b/src/shared/cplusplus/Symbols.h
new file mode 100644
index 0000000000..c69483a251
--- /dev/null
+++ b/src/shared/cplusplus/Symbols.h
@@ -0,0 +1,338 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_SYMBOLS_H
+#define CPLUSPLUS_SYMBOLS_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "Symbol.h"
+#include "Type.h"
+#include "FullySpecifiedType.h"
+#include "Array.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT UsingNamespaceDirective: public Symbol
+{
+public:
+ UsingNamespaceDirective(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~UsingNamespaceDirective();
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT UsingDeclaration: public Symbol
+{
+public:
+ UsingDeclaration(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~UsingDeclaration();
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT Declaration: public Symbol
+{
+public:
+ Declaration(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~Declaration();
+
+ unsigned templateParameterCount() const;
+ Symbol *templateParameterAt(unsigned index) const;
+
+ Scope *templateParameters() const;
+ void setTemplateParameters(Scope *templateParameters);
+
+ void setType(FullySpecifiedType type);
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+
+private:
+ FullySpecifiedType _type;
+ Scope *_templateParameters;
+};
+
+class CPLUSPLUS_EXPORT Argument: public Symbol
+{
+public:
+ Argument(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~Argument();
+
+ void setType(FullySpecifiedType type);
+
+ bool hasInitializer() const;
+ void setInitializer(bool hasInitializer);
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+
+private:
+ FullySpecifiedType _type;
+ bool _initializer: 1;
+};
+
+class CPLUSPLUS_EXPORT ScopedSymbol: public Symbol
+{
+public:
+ ScopedSymbol(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~ScopedSymbol();
+
+ unsigned memberCount() const;
+ Symbol *memberAt(unsigned index) const;
+ Scope *members() const;
+ void addMember(Symbol *member);
+
+private:
+ Scope *_members;
+};
+
+class CPLUSPLUS_EXPORT Block: public ScopedSymbol
+{
+public:
+ Block(TranslationUnit *translationUnit, unsigned sourceLocation);
+ virtual ~Block();
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT Enum: public ScopedSymbol, public Type
+{
+public:
+ Enum(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~Enum();
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+ // Type's interface
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+ virtual void accept0(TypeVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT Function: public ScopedSymbol, public Type
+{
+public:
+ enum MethodKey {
+ NormalMethod,
+ SlotMethod,
+ SignalMethod
+ };
+
+public:
+ Function(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~Function();
+
+ bool isNormal() const;
+ bool isSignal() const;
+ bool isSlot() const;
+ int methodKey() const;
+ void setMethodKey(int key);
+
+ unsigned templateParameterCount() const;
+ Symbol *templateParameterAt(unsigned index) const;
+
+ Scope *templateParameters() const;
+ void setTemplateParameters(Scope *templateParameters);
+
+ FullySpecifiedType returnType() const;
+ void setReturnType(FullySpecifiedType returnType);
+
+ unsigned argumentCount() const;
+ Symbol *argumentAt(unsigned index) const;
+ Scope *arguments() const;
+
+ bool isVariadic() const;
+ void setVariadic(bool isVariadic);
+
+ bool isConst() const;
+ void setConst(bool isConst);
+
+ bool isVolatile() const;
+ void setVolatile(bool isVolatile);
+
+ bool isPureVirtual() const;
+ void setPureVirtual(bool isPureVirtual);
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+ // Type's interface
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ Name *_name;
+ Scope *_templateParameters;
+ FullySpecifiedType _returnType;
+ union {
+ unsigned _flags;
+
+ struct {
+ unsigned _isVariadic: 1;
+ unsigned _isPureVirtual: 1;
+ unsigned _isConst: 1;
+ unsigned _isVolatile: 1;
+ unsigned _methodKey: 3;
+ };
+ };
+ Scope *_arguments;
+};
+
+class CPLUSPLUS_EXPORT Namespace: public ScopedSymbol, public Type
+{
+public:
+ Namespace(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~Namespace();
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+ // Type's interface
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+ virtual void accept0(TypeVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT BaseClass: public Symbol
+{
+public:
+ BaseClass(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~BaseClass();
+
+ bool isVirtual() const;
+ void setVirtual(bool isVirtual);
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+
+private:
+ bool _isVirtual;
+};
+
+class CPLUSPLUS_EXPORT Class: public ScopedSymbol, public Type
+{
+public:
+ Class(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name);
+ virtual ~Class();
+
+ enum Key {
+ ClassKey,
+ StructKey,
+ UnionKey
+ };
+
+ bool isClass() const;
+ bool isStruct() const;
+ bool isUnion() const;
+ Key classKey() const;
+ void setClassKey(Key key);
+
+ unsigned templateParameterCount() const;
+ Symbol *templateParameterAt(unsigned index) const;
+
+ Scope *templateParameters() const;
+ void setTemplateParameters(Scope *templateParameters);
+
+ unsigned baseClassCount() const;
+ BaseClass *baseClassAt(unsigned index) const;
+ void addBaseClass(BaseClass *baseClass);
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+ // Type's interface
+ virtual bool isEqualTo(const Type *other) const;
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+ virtual void accept0(TypeVisitor *visitor);
+
+private:
+ Key _key;
+ Scope *_templateParameters;
+ Array<BaseClass *> _baseClasses;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_SYMBOLS_H
diff --git a/src/shared/cplusplus/Token.cpp b/src/shared/cplusplus/Token.cpp
new file mode 100644
index 0000000000..eb672958cd
--- /dev/null
+++ b/src/shared/cplusplus/Token.cpp
@@ -0,0 +1,140 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Token.h"
+#include "Literals.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+static const char *token_names[] = {
+ (""), ("<error>"),
+
+ ("<comment>"),
+
+ ("<identifier>"), ("<int literal>"), ("<float literal>"), ("<char literal>"),
+ ("<wide char literal>"), ("<string literal>"), ("<wide char literal>"),
+ ("<@string literal>"), ("<angle string literal>"),
+
+ ("&"), ("&&"), ("&="), ("->"), ("->*"), ("^"), ("^="), (":"), ("::"),
+ (","), ("/"), ("/="), ("."), ("..."), (".*"), ("="), ("=="), ("!"),
+ ("!="), (">"), (">="), (">>"), (">>="), ("{"), ("["), ("<"), ("<="),
+ ("<<"), ("<<="), ("("), ("-"), ("-="), ("--"), ("%"), ("%="), ("|"),
+ ("|="), ("||"), ("+"), ("+="), ("++"), ("#"), ("##"), ("?"), ("}"),
+ ("]"), (")"), (";"), ("*"), ("*="), ("~"), ("~="),
+
+ ("asm"), ("auto"), ("bool"), ("break"), ("case"), ("catch"), ("char"),
+ ("class"), ("const"), ("const_cast"), ("continue"), ("default"),
+ ("delete"), ("do"), ("double"), ("dynamic_cast"), ("else"), ("enum"),
+ ("explicit"), ("export"), ("extern"), ("false"), ("float"), ("for"),
+ ("friend"), ("goto"), ("if"), ("inline"), ("int"), ("long"),
+ ("mutable"), ("namespace"), ("new"), ("operator"), ("private"),
+ ("protected"), ("public"), ("register"), ("reinterpret_cast"),
+ ("return"), ("short"), ("signed"), ("sizeof"), ("static"),
+ ("static_cast"), ("struct"), ("switch"), ("template"), ("this"),
+ ("throw"), ("true"), ("try"), ("typedef"), ("typeid"), ("typename"),
+ ("union"), ("unsigned"), ("using"), ("virtual"), ("void"),
+ ("volatile"), ("wchar_t"), ("while"),
+
+ // gnu
+ ("__attribute__"), ("__typeof__"),
+
+ // objc @keywords
+ ("@catch"), ("@class"), ("@compatibility_alias"), ("@defs"), ("@dynamic"),
+ ("@encode"), ("@end"), ("@finally"), ("@implementation"), ("@interface"),
+ ("@not_keyword"), ("@optional"), ("@package"), ("@private"), ("@property"),
+ ("@protected"), ("@protocol"), ("@public"), ("@required"), ("@selector"),
+ ("@synchronized"), ("@synthesize"), ("@throw"), ("@try"),
+
+ ("SIGNAL"), ("SLOT"), ("Q_SIGNALS"), ("Q_SLOTS")
+};
+
+Token::Token() :
+ flags(0), offset(0), ptr(0)
+{
+}
+
+Token::~Token()
+{
+}
+
+void Token::reset()
+{
+ flags = 0;
+ offset = 0;
+ ptr = 0;
+}
+
+const char *Token::name(int kind)
+{ return token_names[kind]; }
+
+const char *Token::spell() const
+{
+ switch (kind) {
+ case T_IDENTIFIER:
+ return identifier->chars();
+
+ case T_INT_LITERAL:
+ case T_FLOAT_LITERAL:
+ case T_CHAR_LITERAL:
+ case T_STRING_LITERAL:
+ case T_AT_STRING_LITERAL:
+ case T_ANGLE_STRING_LITERAL:
+ case T_WIDE_CHAR_LITERAL:
+ case T_WIDE_STRING_LITERAL:
+ return literal->chars();
+
+ default:
+ return token_names[kind];
+ } // switch
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Token.h b/src/shared/cplusplus/Token.h
new file mode 100644
index 0000000000..f48654aa77
--- /dev/null
+++ b/src/shared/cplusplus/Token.h
@@ -0,0 +1,336 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_TOKEN_H
+#define CPLUSPLUS_TOKEN_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include <cstddef>
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+enum Kind {
+ T_EOF_SYMBOL = 0,
+ T_ERROR,
+
+ T_COMMENT,
+ T_IDENTIFIER,
+
+ T_FIRST_LITERAL,
+ T_INT_LITERAL = T_FIRST_LITERAL,
+ T_FLOAT_LITERAL,
+ T_CHAR_LITERAL,
+ T_WIDE_CHAR_LITERAL,
+ T_STRING_LITERAL,
+ T_WIDE_STRING_LITERAL,
+ T_AT_STRING_LITERAL,
+ T_ANGLE_STRING_LITERAL,
+ T_LAST_LITERAL = T_ANGLE_STRING_LITERAL,
+
+ T_FIRST_OPERATOR,
+ T_AMPER = T_FIRST_OPERATOR,
+ T_AMPER_AMPER,
+ T_AMPER_EQUAL,
+ T_ARROW,
+ T_ARROW_STAR,
+ T_CARET,
+ T_CARET_EQUAL,
+ T_COLON,
+ T_COLON_COLON,
+ T_COMMA,
+ T_SLASH,
+ T_SLASH_EQUAL,
+ T_DOT,
+ T_DOT_DOT_DOT,
+ T_DOT_STAR,
+ T_EQUAL,
+ T_EQUAL_EQUAL,
+ T_EXCLAIM,
+ T_EXCLAIM_EQUAL,
+ T_GREATER,
+ T_GREATER_EQUAL,
+ T_GREATER_GREATER,
+ T_GREATER_GREATER_EQUAL,
+ T_LBRACE,
+ T_LBRACKET,
+ T_LESS,
+ T_LESS_EQUAL,
+ T_LESS_LESS,
+ T_LESS_LESS_EQUAL,
+ T_LPAREN,
+ T_MINUS,
+ T_MINUS_EQUAL,
+ T_MINUS_MINUS,
+ T_PERCENT,
+ T_PERCENT_EQUAL,
+ T_PIPE,
+ T_PIPE_EQUAL,
+ T_PIPE_PIPE,
+ T_PLUS,
+ T_PLUS_EQUAL,
+ T_PLUS_PLUS,
+ T_POUND,
+ T_POUND_POUND,
+ T_QUESTION,
+ T_RBRACE,
+ T_RBRACKET,
+ T_RPAREN,
+ T_SEMICOLON,
+ T_STAR,
+ T_STAR_EQUAL,
+ T_TILDE,
+ T_TILDE_EQUAL,
+ T_LAST_OPERATOR = T_TILDE_EQUAL,
+
+ T_FIRST_KEYWORD,
+ T_ASM = T_FIRST_KEYWORD,
+ T_AUTO,
+ T_BOOL,
+ T_BREAK,
+ T_CASE,
+ T_CATCH,
+ T_CHAR,
+ T_CLASS,
+ T_CONST,
+ T_CONST_CAST,
+ T_CONTINUE,
+ T_DEFAULT,
+ T_DELETE,
+ T_DO,
+ T_DOUBLE,
+ T_DYNAMIC_CAST,
+ T_ELSE,
+ T_ENUM,
+ T_EXPLICIT,
+ T_EXPORT,
+ T_EXTERN,
+ T_FALSE,
+ T_FLOAT,
+ T_FOR,
+ T_FRIEND,
+ T_GOTO,
+ T_IF,
+ T_INLINE,
+ T_INT,
+ T_LONG,
+ T_MUTABLE,
+ T_NAMESPACE,
+ T_NEW,
+ T_OPERATOR,
+ T_PRIVATE,
+ T_PROTECTED,
+ T_PUBLIC,
+ T_REGISTER,
+ T_REINTERPRET_CAST,
+ T_RETURN,
+ T_SHORT,
+ T_SIGNED,
+ T_SIZEOF,
+ T_STATIC,
+ T_STATIC_CAST,
+ T_STRUCT,
+ T_SWITCH,
+ T_TEMPLATE,
+ T_THIS,
+ T_THROW,
+ T_TRUE,
+ T_TRY,
+ T_TYPEDEF,
+ T_TYPEID,
+ T_TYPENAME,
+ T_UNION,
+ T_UNSIGNED,
+ T_USING,
+ T_VIRTUAL,
+ T_VOID,
+ T_VOLATILE,
+ T_WCHAR_T,
+ T_WHILE,
+
+ T___ATTRIBUTE__,
+ T___TYPEOF__,
+
+ // obj c++ @ keywords
+ T_FIRST_OBJC_AT_KEYWORD,
+
+ T_AT_CATCH = T_FIRST_OBJC_AT_KEYWORD,
+ T_AT_CLASS,
+ T_AT_COMPATIBILITY_ALIAS,
+ T_AT_DEFS,
+ T_AT_DYNAMIC,
+ T_AT_ENCODE,
+ T_AT_END,
+ T_AT_FINALLY,
+ T_AT_IMPLEMENTATION,
+ T_AT_INTERFACE,
+ T_AT_NOT_KEYWORD,
+ T_AT_OPTIONAL,
+ T_AT_PACKAGE,
+ T_AT_PRIVATE,
+ T_AT_PROPERTY,
+ T_AT_PROTECTED,
+ T_AT_PROTOCOL,
+ T_AT_PUBLIC,
+ T_AT_REQUIRED,
+ T_AT_SELECTOR,
+ T_AT_SYNCHRONIZED,
+ T_AT_SYNTHESIZE,
+ T_AT_THROW,
+ T_AT_TRY,
+
+ T_LAST_OBJC_AT_KEYWORD,
+
+ T_FIRST_QT_KEYWORD = T_LAST_OBJC_AT_KEYWORD,
+
+ // Qt keywords
+ T_SIGNAL = T_FIRST_QT_KEYWORD,
+ T_SLOT,
+ T_SIGNALS,
+ T_SLOTS,
+
+ T_LAST_KEYWORD = T_SLOTS,
+
+ // aliases
+ T_OR = T_PIPE_PIPE,
+ T_AND = T_AMPER_AMPER,
+ T_NOT = T_EXCLAIM,
+ T_XOR = T_CARET,
+ T_BITOR = T_PIPE,
+ T_COMPL = T_TILDE,
+ T_OR_EQ = T_PIPE_EQUAL,
+ T_AND_EQ = T_AMPER_EQUAL,
+ T_BITAND = T_AMPER,
+ T_NOT_EQ = T_EXCLAIM_EQUAL,
+ T_XOR_EQ = T_CARET_EQUAL,
+
+ T___ASM = T_ASM,
+ T___ASM__ = T_ASM,
+
+ T_TYPEOF = T___TYPEOF__,
+ T___TYPEOF = T___TYPEOF__,
+
+ T___INLINE = T_INLINE,
+ T___INLINE__ = T_INLINE,
+
+ T___CONST = T_CONST,
+ T___CONST__ = T_CONST,
+
+ T___VOLATILE = T_VOLATILE,
+ T___VOLATILE__ = T_VOLATILE,
+
+ T___ATTRIBUTE = T___ATTRIBUTE__
+};
+
+class CPLUSPLUS_EXPORT Token
+{
+public:
+ Token();
+ ~Token();
+
+ inline bool is(unsigned k) const { return kind == k; }
+ inline bool isNot(unsigned k) const { return kind != k; }
+ const char *spell() const;
+ void reset();
+
+ inline unsigned begin() const
+ { return offset; }
+
+ inline unsigned end() const
+ { return offset + length; }
+
+ inline bool isLiteral() const
+ { return kind >= T_FIRST_LITERAL && kind <= T_LAST_LITERAL; }
+
+ inline bool isOperator() const
+ { return kind >= T_FIRST_OPERATOR && kind <= T_LAST_OPERATOR; }
+
+ inline bool isKeyword() const
+ { return kind >= T_FIRST_KEYWORD && kind < T_FIRST_QT_KEYWORD; }
+
+ inline bool isObjCAtKeyword() const
+ { return kind >= T_FIRST_OBJC_AT_KEYWORD && kind < T_LAST_OBJC_AT_KEYWORD; }
+
+ static const char *name(int kind);
+
+public:
+ union {
+ unsigned flags;
+
+ struct {
+ unsigned kind : 8;
+ unsigned newline : 1;
+ unsigned whitespace : 1;
+ unsigned joined : 1;
+ unsigned expanded : 1;
+ unsigned pad : 4;
+ unsigned length : 16;
+ };
+ };
+
+ unsigned offset;
+
+ union {
+ void *ptr;
+ Literal *literal;
+ NumericLiteral *number;
+ StringLiteral *string;
+ Identifier *identifier;
+ unsigned close_brace;
+ unsigned lineno;
+ };
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_TOKEN_H
diff --git a/src/shared/cplusplus/TranslationUnit.cpp b/src/shared/cplusplus/TranslationUnit.cpp
new file mode 100644
index 0000000000..40a95c0f05
--- /dev/null
+++ b/src/shared/cplusplus/TranslationUnit.cpp
@@ -0,0 +1,474 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "TranslationUnit.h"
+#include "Control.h"
+#include "Parser.h"
+#include "Lexer.h"
+#include "MemoryPool.h"
+#include "AST.h"
+#include "Literals.h"
+#include "DiagnosticClient.h"
+#include <stack>
+#include <cstdlib>
+#include <cstdarg>
+#include <algorithm>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+TranslationUnit::TranslationUnit(Control *control, StringLiteral *fileId)
+ : _control(control),
+ _fileId(fileId),
+ _firstSourceChar(0),
+ _lastSourceChar(0),
+ _pool(0),
+ _ast(0),
+ _flags(0)
+{
+ _tokens = new Array<Token, 8>();
+ _previousTranslationUnit = control->switchTranslationUnit(this);
+ _pool = new MemoryPool();
+}
+
+TranslationUnit::~TranslationUnit()
+{
+ (void) _control->switchTranslationUnit(_previousTranslationUnit);
+ delete _tokens;
+ delete _pool;
+}
+
+bool TranslationUnit::qtMocRunEnabled() const
+{ return _qtMocRunEnabled; }
+
+void TranslationUnit::setQtMocRunEnabled(bool onoff)
+{ _qtMocRunEnabled = onoff; }
+
+bool TranslationUnit::objCEnabled() const
+{ return _objCEnabled; }
+
+void TranslationUnit::setObjCEnabled(bool onoff)
+{ _objCEnabled = onoff; }
+
+Control *TranslationUnit::control() const
+{ return _control; }
+
+StringLiteral *TranslationUnit::fileId() const
+{ return _fileId; }
+
+const char *TranslationUnit::fileName() const
+{ return _fileId->chars(); }
+
+unsigned TranslationUnit::fileNameLength() const
+{ return _fileId->size(); }
+
+const char *TranslationUnit::firstSourceChar() const
+{ return _firstSourceChar; }
+
+const char *TranslationUnit::lastSourceChar() const
+{ return _lastSourceChar; }
+
+unsigned TranslationUnit::sourceLength() const
+{ return _lastSourceChar - _firstSourceChar; }
+
+void TranslationUnit::setSource(const char *source, unsigned size)
+{
+ _firstSourceChar = source;
+ _lastSourceChar = source + size;
+}
+
+unsigned TranslationUnit::tokenCount() const
+{ return _tokens->size(); }
+
+const Token &TranslationUnit::tokenAt(unsigned index) const
+{ return _tokens->at(index); }
+
+int TranslationUnit::tokenKind(unsigned index) const
+{ return _tokens->at(index).kind; }
+
+Identifier *TranslationUnit::identifier(unsigned index) const
+{ return _tokens->at(index).identifier; }
+
+Literal *TranslationUnit::literal(unsigned index) const
+{ return _tokens->at(index).literal; }
+
+StringLiteral *TranslationUnit::stringLiteral(unsigned index) const
+{ return _tokens->at(index).string; }
+
+NumericLiteral *TranslationUnit::numericLiteral(unsigned index) const
+{ return _tokens->at(index).number; }
+
+unsigned TranslationUnit::matchingBrace(unsigned index) const
+{ return _tokens->at(index).close_brace; }
+
+MemoryPool *TranslationUnit::memoryPool() const
+{ return _pool; }
+
+AST *TranslationUnit::ast() const
+{ return _ast; }
+
+bool TranslationUnit::isTokenized() const
+{ return _tokenized; }
+
+bool TranslationUnit::isParsed() const
+{ return _parsed; }
+
+void TranslationUnit::tokenize()
+{
+ if (isTokenized())
+ return;
+
+ _tokenized = true;
+
+ Lexer lex(this);
+ lex.setQtMocRunEnabled(_qtMocRunEnabled);
+ lex.setObjCEnabled(_objCEnabled);
+
+ std::stack<unsigned> braces;
+ _tokens->push_back(Token()); // the first token needs to be invalid!
+
+ pushLineOffset(0);
+ pushPreprocessorLine(0, 1, fileId());
+
+ Identifier *lineId = control()->findOrInsertIdentifier("line");
+
+ Token tk;
+ do {
+ lex(&tk);
+
+ _Lrecognize:
+ if (tk.is(T_POUND)) {
+ unsigned offset = tk.offset;
+ lex(&tk);
+ if (! tk.newline && tk.is(T_IDENTIFIER) && tk.identifier == lineId)
+ lex(&tk);
+ if (! tk.newline && tk.is(T_INT_LITERAL)) {
+ unsigned line = (unsigned) strtoul(tk.spell(), 0, 0);
+ lex(&tk);
+ if (! tk.newline && tk.is(T_STRING_LITERAL)) {
+ StringLiteral *fileName = control()->findOrInsertFileName(tk.string->chars(),
+ tk.string->size());
+ pushPreprocessorLine(offset, line, fileName);
+ lex(&tk);
+ }
+ }
+ while (tk.isNot(T_EOF_SYMBOL) && ! tk.newline)
+ lex(&tk);
+ goto _Lrecognize;
+ } else if (tk.kind == T_LBRACE) {
+ braces.push(_tokens->size());
+ } else if (tk.kind == T_RBRACE && ! braces.empty()) {
+ const unsigned open_brace_index = braces.top();
+ braces.pop();
+ (*_tokens)[open_brace_index].close_brace = _tokens->size();
+ }
+ _tokens->push_back(tk);
+ } while (tk.kind);
+
+ for (; ! braces.empty(); braces.pop()) {
+ unsigned open_brace_index = braces.top();
+ (*_tokens)[open_brace_index].close_brace = _tokens->size();
+ }
+}
+
+bool TranslationUnit::skipFunctionBody() const
+{ return _skipFunctionBody; }
+
+void TranslationUnit::setSkipFunctionBody(bool skipFunctionBody)
+{ _skipFunctionBody = skipFunctionBody; }
+
+bool TranslationUnit::parse(ParseMode mode)
+{
+ if (isParsed())
+ return false;
+
+ if (! isTokenized())
+ tokenize();
+
+ Parser parser(this);
+ parser.setQtMocRunEnabled(_qtMocRunEnabled);
+ parser.setObjCEnabled(_objCEnabled);
+
+ bool parsed = false;
+
+ switch (mode) {
+ case ParseTranlationUnit: {
+ TranslationUnitAST *node = 0;
+ parsed = parser.parseTranslationUnit(node);
+ _ast = node;
+ } break;
+
+ case ParseDeclaration: {
+ DeclarationAST *node = 0;
+ parsed = parser.parseDeclaration(node);
+ _ast = node;
+ } break;
+
+ case ParseExpression: {
+ ExpressionAST *node = 0;
+ parsed = parser.parseExpression(node);
+ _ast = node;
+ } break;
+
+ case ParseStatement: {
+ StatementAST *node = 0;
+ parsed = parser.parseStatement(node);
+ _ast = node;
+ } break;
+
+ default:
+ break;
+ } // switch
+
+ return parsed;
+}
+
+void TranslationUnit::pushLineOffset(unsigned offset)
+{ _lineOffsets.push_back(offset); }
+
+void TranslationUnit::pushPreprocessorLine(unsigned offset,
+ unsigned line,
+ StringLiteral *fileName)
+{ _ppLines.push_back(PPLine(offset, line, fileName)); }
+
+unsigned TranslationUnit::findLineNumber(unsigned offset) const
+{
+ std::vector<unsigned>::const_iterator it =
+ std::lower_bound(_lineOffsets.begin(), _lineOffsets.end(), offset);
+
+ if (it != _lineOffsets.begin())
+ --it;
+
+ return it - _lineOffsets.begin();
+}
+
+TranslationUnit::PPLine TranslationUnit::findPreprocessorLine(unsigned offset) const
+{
+ std::vector<PPLine>::const_iterator it =
+ std::lower_bound(_ppLines.begin(), _ppLines.end(), PPLine(offset));
+
+ if (it != _ppLines.begin())
+ --it;
+
+ return *it;
+}
+
+unsigned TranslationUnit::findColumnNumber(unsigned offset, unsigned lineNumber) const
+{
+ if (! offset)
+ return 0;
+
+ return offset - _lineOffsets[lineNumber];
+}
+
+void TranslationUnit::getTokenPosition(unsigned index,
+ unsigned *line,
+ unsigned *column,
+ StringLiteral **fileName) const
+{ return getPosition(tokenAt(index).offset, line, column, fileName); }
+
+void TranslationUnit::getPosition(unsigned tokenOffset,
+ unsigned *line,
+ unsigned *column,
+ StringLiteral **fileName) const
+{
+ unsigned lineNumber = findLineNumber(tokenOffset);
+ unsigned columnNumber = findColumnNumber(tokenOffset, lineNumber);
+ const PPLine ppLine = findPreprocessorLine(tokenOffset);
+
+ lineNumber -= findLineNumber(ppLine.offset) + 1;
+ lineNumber += ppLine.line;
+
+ if (line)
+ *line = lineNumber;
+
+ if (column)
+ *column = columnNumber;
+
+ if (fileName)
+ *fileName = ppLine.fileName;
+}
+
+bool TranslationUnit::blockErrors(bool block)
+{
+ bool previous = _blockErrors;
+ _blockErrors = block;
+ return previous;
+}
+
+void TranslationUnit::warning(unsigned index, const char *format, ...)
+{
+ if (_blockErrors)
+ return;
+
+ index = std::min(index, tokenCount() - 1);
+
+ unsigned line = 0, column = 0;
+ StringLiteral *fileName = 0;
+ getTokenPosition(index, &line, &column, &fileName);
+
+ if (DiagnosticClient *client = control()->diagnosticClient()) {
+ va_list args;
+ va_start(args, format);
+ client->report(DiagnosticClient::Warning, fileName, line, column,
+ format, args);
+ va_end(args);
+ } else {
+ fprintf(stderr, "%s:%d: ", fileName->chars(), line);
+ fprintf(stderr, "warning: ");
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fputc('\n', stderr);
+
+ showErrorLine(index, column, stderr);
+ }
+}
+
+void TranslationUnit::error(unsigned index, const char *format, ...)
+{
+ if (_blockErrors)
+ return;
+
+ index = std::min(index, tokenCount() - 1);
+
+ unsigned line = 0, column = 0;
+ StringLiteral *fileName = 0;
+ getTokenPosition(index, &line, &column, &fileName);
+
+ if (DiagnosticClient *client = control()->diagnosticClient()) {
+ va_list args;
+ va_start(args, format);
+ client->report(DiagnosticClient::Error, fileName, line, column,
+ format, args);
+ va_end(args);
+ } else {
+ fprintf(stderr, "%s:%d: ", fileName->chars(), line);
+ fprintf(stderr, "error: ");
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fputc('\n', stderr);
+
+ showErrorLine(index, column, stderr);
+ }
+}
+
+void TranslationUnit::fatal(unsigned index, const char *format, ...)
+{
+ if (_blockErrors)
+ return;
+
+ index = std::min(index, tokenCount() - 1);
+
+ unsigned line = 0, column = 0;
+ StringLiteral *fileName = 0;
+ getTokenPosition(index, &line, &column, &fileName);
+
+ if (DiagnosticClient *client = control()->diagnosticClient()) {
+ va_list args;
+ va_start(args, format);
+ client->report(DiagnosticClient::Fatal, fileName, line, column,
+ format, args);
+ va_end(args);
+ } else {
+ fprintf(stderr, "%s:%d: ", fileName->chars(), line);
+ fprintf(stderr, "fatal: ");
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fputc('\n', stderr);
+
+ showErrorLine(index, column, stderr);
+ }
+
+ exit(EXIT_FAILURE);
+}
+
+void TranslationUnit::showErrorLine(unsigned index, unsigned column, FILE *out)
+{
+ unsigned lineOffset = _lineOffsets[findLineNumber(_tokens->at(index).offset)];
+ for (const char *cp = _firstSourceChar + lineOffset + 1; *cp && *cp != '\n'; ++cp) {
+ fputc(*cp, out);
+ }
+ fputc('\n', out);
+
+ const char *end = _firstSourceChar + lineOffset + 1 + column - 1;
+ for (const char *cp = _firstSourceChar + lineOffset + 1; cp != end; ++cp) {
+ if (*cp != '\t')
+ fputc(' ', out);
+ else
+ fputc('\t', out);
+ }
+ fputc('^', out);
+ fputc('\n', out);
+}
+
+void TranslationUnit::resetAST()
+{
+ delete _pool;
+ _pool = 0;
+}
+
+void TranslationUnit::release()
+{
+ resetAST();
+ delete _tokens;
+ _tokens = 0;
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/TranslationUnit.h b/src/shared/cplusplus/TranslationUnit.h
new file mode 100644
index 0000000000..aa490701ef
--- /dev/null
+++ b/src/shared/cplusplus/TranslationUnit.h
@@ -0,0 +1,201 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_TRANSLATIONUNIT_H
+#define CPLUSPLUS_TRANSLATIONUNIT_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include "ASTfwd.h"
+#include "Token.h"
+#include "Array.h"
+#include <cstdio>
+#include <vector> // ### remove me
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT TranslationUnit
+{
+ TranslationUnit(const TranslationUnit &other);
+ void operator =(const TranslationUnit &other);
+
+public:
+ TranslationUnit(Control *control, StringLiteral *fileId);
+ ~TranslationUnit();
+
+ Control *control() const;
+
+ StringLiteral *fileId() const;
+ const char *fileName() const;
+ unsigned fileNameLength() const;
+
+ const char *firstSourceChar() const;
+ const char *lastSourceChar() const;
+ unsigned sourceLength() const;
+
+ void setSource(const char *source, unsigned size);
+
+ unsigned tokenCount() const;
+ const Token &tokenAt(unsigned index) const;
+ int tokenKind(unsigned index) const;
+
+ unsigned matchingBrace(unsigned index) const;
+ Identifier *identifier(unsigned index) const;
+ Literal *literal(unsigned index) const;
+ StringLiteral *stringLiteral(unsigned index) const;
+ NumericLiteral *numericLiteral(unsigned index) const;
+
+ MemoryPool *memoryPool() const;
+ AST *ast() const;
+
+ bool blockErrors(bool block);
+
+ bool qtMocRunEnabled() const;
+ void setQtMocRunEnabled(bool onoff);
+
+ bool objCEnabled() const;
+ void setObjCEnabled(bool onoff);
+
+ void warning(unsigned index, const char *fmt, ...);
+ void error(unsigned index, const char *fmt, ...);
+ void fatal(unsigned index, const char *fmt, ...);
+
+ bool isTokenized() const;
+ void tokenize();
+
+ bool skipFunctionBody() const;
+ void setSkipFunctionBody(bool skipFunctionBody);
+
+ bool isParsed() const;
+
+ enum ParseMode {
+ ParseTranlationUnit,
+ ParseDeclaration,
+ ParseExpression,
+ ParseStatement
+ };
+
+ bool parse(ParseMode mode = ParseTranlationUnit);
+
+ void resetAST();
+ void release();
+
+ void getPosition(unsigned offset,
+ unsigned *line,
+ unsigned *column = 0,
+ StringLiteral **fileName = 0) const;
+
+ void getTokenPosition(unsigned index,
+ unsigned *line,
+ unsigned *column = 0,
+ StringLiteral **fileName = 0) const;
+
+ void pushLineOffset(unsigned offset);
+ void pushPreprocessorLine(unsigned offset,
+ unsigned line,
+ StringLiteral *fileName);
+
+public:
+ struct PPLine {
+ unsigned offset;
+ unsigned line;
+ StringLiteral *fileName;
+
+ PPLine(unsigned offset = 0,
+ unsigned line = 0,
+ StringLiteral *fileName = 0)
+ : offset(offset), line(line), fileName(fileName)
+ { }
+
+ bool operator == (const PPLine &other) const
+ { return offset == other.offset; }
+
+ bool operator != (const PPLine &other) const
+ { return offset != other.offset; }
+
+ bool operator < (const PPLine &other) const
+ { return offset < other.offset; }
+ };
+
+private:
+ unsigned findLineNumber(unsigned offset) const;
+ unsigned findColumnNumber(unsigned offset, unsigned lineNumber) const;
+ PPLine findPreprocessorLine(unsigned offset) const;
+ void showErrorLine(unsigned index, unsigned column, FILE *out);
+
+ Control *_control;
+ StringLiteral *_fileId;
+ const char *_firstSourceChar;
+ const char *_lastSourceChar;
+ Array<Token, 8> *_tokens;
+ std::vector<unsigned> _lineOffsets;
+ std::vector<PPLine> _ppLines;
+ MemoryPool *_pool;
+ AST *_ast;
+ TranslationUnit *_previousTranslationUnit;
+ union {
+ unsigned _flags;
+ struct {
+ unsigned _tokenized: 1;
+ unsigned _parsed: 1;
+ unsigned _blockErrors: 1;
+ unsigned _skipFunctionBody: 1;
+ unsigned _qtMocRunEnabled: 1;
+ unsigned _objCEnabled: 1;
+ };
+ };
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_TRANSLATIONUNIT_H
diff --git a/src/shared/cplusplus/Type.cpp b/src/shared/cplusplus/Type.cpp
new file mode 100644
index 0000000000..98ccd3c893
--- /dev/null
+++ b/src/shared/cplusplus/Type.cpp
@@ -0,0 +1,198 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Type.h"
+#include "TypeVisitor.h"
+#include "CoreTypes.h"
+#include "Symbols.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+Type::Type()
+{ }
+
+Type::~Type()
+{ }
+
+bool Type::isVoidType() const
+{ return dynamic_cast<const VoidType *>(this) != 0; }
+
+bool Type::isIntegerType() const
+{ return dynamic_cast<const IntegerType *>(this) != 0; }
+
+bool Type::isFloatType() const
+{ return dynamic_cast<const FloatType *>(this) != 0; }
+
+bool Type::isPointerType() const
+{ return dynamic_cast<const PointerType *>(this) != 0; }
+
+bool Type::isPointerToMemberType() const
+{ return dynamic_cast<const PointerToMemberType *>(this) != 0; }
+
+bool Type::isReferenceType() const
+{ return dynamic_cast<const ReferenceType *>(this) != 0; }
+
+bool Type::isArrayType() const
+{ return dynamic_cast<const ArrayType *>(this) != 0; }
+
+bool Type::isNamedType() const
+{ return dynamic_cast<const NamedType *>(this) != 0; }
+
+bool Type::isFunction() const
+{ return dynamic_cast<const Function *>(this) != 0; }
+
+bool Type::isNamespace() const
+{ return dynamic_cast<const Namespace *>(this) != 0; }
+
+bool Type::isClass() const
+{ return dynamic_cast<const Class *>(this) != 0; }
+
+bool Type::isEnum() const
+{ return dynamic_cast<const Enum *>(this) != 0; }
+
+bool Type::isScopedSymbol() const
+{ return dynamic_cast<const ScopedSymbol *>(this) != 0; }
+
+const VoidType *Type::asVoidType() const
+{ return dynamic_cast<const VoidType *>(this); }
+
+const IntegerType *Type::asIntegerType() const
+{ return dynamic_cast<const IntegerType *>(this); }
+
+const FloatType *Type::asFloatType() const
+{ return dynamic_cast<const FloatType *>(this); }
+
+const PointerType *Type::asPointerType() const
+{ return dynamic_cast<const PointerType *>(this); }
+
+const PointerToMemberType *Type::asPointerToMemberType() const
+{ return dynamic_cast<const PointerToMemberType *>(this); }
+
+const ReferenceType *Type::asReferenceType() const
+{ return dynamic_cast<const ReferenceType *>(this); }
+
+const ArrayType *Type::asArrayType() const
+{ return dynamic_cast<const ArrayType *>(this); }
+
+const NamedType *Type::asNamedType() const
+{ return dynamic_cast<const NamedType *>(this); }
+
+const Function *Type::asFunction() const
+{ return dynamic_cast<const Function *>(this); }
+
+const Namespace *Type::asNamespace() const
+{ return dynamic_cast<const Namespace *>(this); }
+
+const Class *Type::asClass() const
+{ return dynamic_cast<const Class *>(this); }
+
+const Enum *Type::asEnum() const
+{ return dynamic_cast<const Enum *>(this); }
+
+const ScopedSymbol *Type::asScopedSymbol() const
+{ return dynamic_cast<const ScopedSymbol *>(this); }
+
+VoidType *Type::asVoidType()
+{ return dynamic_cast<VoidType *>(this); }
+
+IntegerType *Type::asIntegerType()
+{ return dynamic_cast<IntegerType *>(this); }
+
+FloatType *Type::asFloatType()
+{ return dynamic_cast<FloatType *>(this); }
+
+PointerType *Type::asPointerType()
+{ return dynamic_cast<PointerType *>(this); }
+
+PointerToMemberType *Type::asPointerToMemberType()
+{ return dynamic_cast<PointerToMemberType *>(this); }
+
+ReferenceType *Type::asReferenceType()
+{ return dynamic_cast<ReferenceType *>(this); }
+
+ArrayType *Type::asArrayType()
+{ return dynamic_cast<ArrayType *>(this); }
+
+NamedType *Type::asNamedType()
+{ return dynamic_cast<NamedType *>(this); }
+
+Function *Type::asFunction()
+{ return dynamic_cast<Function *>(this); }
+
+Namespace *Type::asNamespace()
+{ return dynamic_cast<Namespace *>(this); }
+
+Class *Type::asClass()
+{ return dynamic_cast<Class *>(this); }
+
+Enum *Type::asEnum()
+{ return dynamic_cast<Enum *>(this); }
+
+ScopedSymbol *Type::asScopedSymbol()
+{ return dynamic_cast<ScopedSymbol *>(this); }
+
+void Type::accept(TypeVisitor *visitor)
+{
+ if (visitor->preVisit(this))
+ accept0(visitor);
+ visitor->postVisit(this);
+}
+
+void Type::accept(Type *type, TypeVisitor *visitor)
+{
+ if (! type)
+ return;
+
+ type->accept(visitor);
+}
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/Type.h b/src/shared/cplusplus/Type.h
new file mode 100644
index 0000000000..7cc347d553
--- /dev/null
+++ b/src/shared/cplusplus/Type.h
@@ -0,0 +1,124 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_TYPE_H
+#define CPLUSPLUS_TYPE_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT Type
+{
+ Type(const Type &other);
+ void operator =(const Type &other);
+
+public:
+ Type();
+ virtual ~Type();
+
+ bool isVoidType() const;
+ bool isIntegerType() const;
+ bool isFloatType() const;
+ bool isPointerType() const;
+ bool isPointerToMemberType() const;
+ bool isReferenceType() const;
+ bool isArrayType() const;
+ bool isNamedType() const;
+ bool isFunction() const;
+ bool isNamespace() const;
+ bool isClass() const;
+ bool isEnum() const;
+ bool isScopedSymbol() const;
+
+ const VoidType *asVoidType() const;
+ const IntegerType *asIntegerType() const;
+ const FloatType *asFloatType() const;
+ const PointerType *asPointerType() const;
+ const PointerToMemberType *asPointerToMemberType() const;
+ const ReferenceType *asReferenceType() const;
+ const ArrayType *asArrayType() const;
+ const NamedType *asNamedType() const;
+ const Function *asFunction() const;
+ const Namespace *asNamespace() const;
+ const Class *asClass() const;
+ const Enum *asEnum() const;
+ const ScopedSymbol *asScopedSymbol() const;
+
+ VoidType *asVoidType();
+ IntegerType *asIntegerType();
+ FloatType *asFloatType();
+ PointerType *asPointerType();
+ PointerToMemberType *asPointerToMemberType();
+ ReferenceType *asReferenceType();
+ ArrayType *asArrayType();
+ NamedType *asNamedType();
+ Function *asFunction();
+ Namespace *asNamespace();
+ Class *asClass();
+ Enum *asEnum();
+ ScopedSymbol *asScopedSymbol();
+
+ void accept(TypeVisitor *visitor);
+ static void accept(Type *type, TypeVisitor *visitor);
+
+ virtual bool isEqualTo(const Type *other) const = 0;
+
+protected:
+ virtual void accept0(TypeVisitor *visitor) = 0;
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_TYPE_H
diff --git a/src/shared/cplusplus/TypeVisitor.cpp b/src/shared/cplusplus/TypeVisitor.cpp
new file mode 100644
index 0000000000..937080e5a5
--- /dev/null
+++ b/src/shared/cplusplus/TypeVisitor.cpp
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "TypeVisitor.h"
+#include "Type.h"
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+TypeVisitor::TypeVisitor()
+{ }
+
+TypeVisitor::~TypeVisitor()
+{ }
+
+void TypeVisitor::accept(Type *type)
+{ Type::accept(type, this); }
+
+CPLUSPLUS_END_NAMESPACE
diff --git a/src/shared/cplusplus/TypeVisitor.h b/src/shared/cplusplus/TypeVisitor.h
new file mode 100644
index 0000000000..16fb37c4ad
--- /dev/null
+++ b/src/shared/cplusplus/TypeVisitor.h
@@ -0,0 +1,92 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef CPLUSPLUS_TYPEVISITOR_H
+#define CPLUSPLUS_TYPEVISITOR_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+CPLUSPLUS_BEGIN_HEADER
+CPLUSPLUS_BEGIN_NAMESPACE
+
+class CPLUSPLUS_EXPORT TypeVisitor
+{
+ TypeVisitor(const TypeVisitor &other);
+ void operator =(const TypeVisitor &other);
+
+public:
+ TypeVisitor();
+ virtual ~TypeVisitor();
+
+ void accept(Type *type);
+
+ virtual bool preVisit(Type *) { return true; }
+ virtual void postVisit(Type *) {}
+
+ virtual void visit(VoidType *) {}
+ virtual void visit(IntegerType *) {}
+ virtual void visit(FloatType *) {}
+ virtual void visit(PointerToMemberType *) {}
+ virtual void visit(PointerType *) {}
+ virtual void visit(ReferenceType *) {}
+ virtual void visit(ArrayType *) {}
+ virtual void visit(NamedType *) {}
+ virtual void visit(Function *) {}
+ virtual void visit(Namespace *) {}
+ virtual void visit(Class *) {}
+ virtual void visit(Enum *) {}
+};
+
+CPLUSPLUS_END_NAMESPACE
+CPLUSPLUS_END_HEADER
+
+#endif // CPLUSPLUS_TYPEVISITOR_H
diff --git a/src/shared/cplusplus/cplusplus.pri b/src/shared/cplusplus/cplusplus.pri
new file mode 100644
index 0000000000..041aff67be
--- /dev/null
+++ b/src/shared/cplusplus/cplusplus.pri
@@ -0,0 +1,77 @@
+
+DEPENDPATH += $$PWD
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/AST.h \
+ $$PWD/ASTVisitor.h \
+ $$PWD/ASTfwd.h \
+ $$PWD/Array.h \
+ $$PWD/CPlusPlusForwardDeclarations.h \
+ $$PWD/CheckDeclaration.h \
+ $$PWD/CheckDeclarator.h \
+ $$PWD/CheckExpression.h \
+ $$PWD/CheckName.h \
+ $$PWD/CheckSpecifier.h \
+ $$PWD/CheckStatement.h \
+ $$PWD/Control.h \
+ $$PWD/CoreTypes.h \
+ $$PWD/DiagnosticClient.h \
+ $$PWD/FullySpecifiedType.h \
+ $$PWD/Lexer.h \
+ $$PWD/LiteralTable.h \
+ $$PWD/Literals.h \
+ $$PWD/MemoryPool.h \
+ $$PWD/Name.h \
+ $$PWD/NameVisitor.h \
+ $$PWD/Names.h \
+ $$PWD/Parser.h \
+ $$PWD/Scope.h \
+ $$PWD/Semantic.h \
+ $$PWD/SemanticCheck.h \
+ $$PWD/Symbol.h \
+ $$PWD/Symbols.h \
+ $$PWD/SymbolVisitor.h \
+ $$PWD/Token.h \
+ $$PWD/TranslationUnit.h \
+ $$PWD/Type.h \
+ $$PWD/TypeVisitor.h \
+ $$PWD/PrettyPrinter.h
+
+
+SOURCES += \
+ $$PWD/AST.cpp \
+ $$PWD/ASTVisitor.cpp \
+ $$PWD/Array.cpp \
+ $$PWD/CheckDeclaration.cpp \
+ $$PWD/CheckDeclarator.cpp \
+ $$PWD/CheckExpression.cpp \
+ $$PWD/CheckName.cpp \
+ $$PWD/CheckSpecifier.cpp \
+ $$PWD/CheckStatement.cpp \
+ $$PWD/Control.cpp \
+ $$PWD/CoreTypes.cpp \
+ $$PWD/DiagnosticClient.cpp \
+ $$PWD/FullySpecifiedType.cpp \
+ $$PWD/Keywords.cpp \
+ $$PWD/ObjectiveCAtKeywords.cpp \
+ $$PWD/Lexer.cpp \
+ $$PWD/LiteralTable.cpp \
+ $$PWD/Literals.cpp \
+ $$PWD/MemoryPool.cpp \
+ $$PWD/Name.cpp \
+ $$PWD/NameVisitor.cpp \
+ $$PWD/Names.cpp \
+ $$PWD/Parser.cpp \
+ $$PWD/Scope.cpp \
+ $$PWD/Semantic.cpp \
+ $$PWD/SemanticCheck.cpp \
+ $$PWD/Symbol.cpp \
+ $$PWD/Symbols.cpp \
+ $$PWD/SymbolVisitor.cpp \
+ $$PWD/Token.cpp \
+ $$PWD/TranslationUnit.cpp \
+ $$PWD/Type.cpp \
+ $$PWD/TypeVisitor.cpp \
+ $$PWD/PrettyPrinter.cpp
+
diff --git a/src/shared/designerintegrationv2/README.txt b/src/shared/designerintegrationv2/README.txt
new file mode 100644
index 0000000000..f5351eaa64
--- /dev/null
+++ b/src/shared/designerintegrationv2/README.txt
@@ -0,0 +1,10 @@
+This is a new Designer integration, started on 28.02.2008.
+
+The reason for it is the introduction of layout caching
+in Qt 4.4, which unearthed a lot of mainwindow-size related
+bugs in Designer and all integrations.
+
+The goal of it is to have a closed layout chain from
+integration top level to form window.
+
+Friedemann
diff --git a/src/shared/designerintegrationv2/designerintegration.pri b/src/shared/designerintegrationv2/designerintegration.pri
new file mode 100644
index 0000000000..f3a02f6eba
--- /dev/null
+++ b/src/shared/designerintegrationv2/designerintegration.pri
@@ -0,0 +1,11 @@
+INCLUDEPATH *= $$PWD $$PWD/..
+
+SOURCES += $$PWD/widgethost.cpp \
+ $$PWD/sizehandlerect.cpp \
+ $$PWD/formresizer.cpp
+
+HEADERS += $$PWD/widgethost.h \
+ $$PWD/sizehandlerect.h \
+ $$PWD/formresizer.h \
+ $$PWD/widgethostconstants.h \
+ $$PWD/../namespace_global.h
diff --git a/src/shared/designerintegrationv2/formresizer.cpp b/src/shared/designerintegrationv2/formresizer.cpp
new file mode 100644
index 0000000000..29326f6989
--- /dev/null
+++ b/src/shared/designerintegrationv2/formresizer.cpp
@@ -0,0 +1,197 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "formresizer.h"
+#include "sizehandlerect.h"
+#include "widgethostconstants.h"
+
+#include <QtCore/QDebug>
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+
+#include <QtGui/QResizeEvent>
+#include <QtGui/QPalette>
+#include <QtGui/QLayout>
+#include <QtGui/QFrame>
+#include <QtGui/QResizeEvent>
+
+enum { debugFormResizer = 0 };
+
+using namespace SharedTools::Internal;
+
+FormResizer::FormResizer(QWidget *parent) :
+ QWidget(parent),
+ m_frame(new QFrame),
+ m_formWindow(0)
+{
+ // Make the resize grip of a mainwindow form find us as resizable window.
+ setWindowFlags(windowFlags() | Qt::SubWindow);
+ setBackgroundRole(QPalette::Base);
+
+ QVBoxLayout *handleLayout = new QVBoxLayout(this);
+ handleLayout->setMargin(SELECTION_MARGIN);
+ handleLayout->addWidget(m_frame);
+
+ m_frame->setFrameStyle(QFrame::Panel | QFrame::Raised);
+ QVBoxLayout *layout = new QVBoxLayout(m_frame);
+ layout->setMargin(0);
+ // handles
+ m_handles.reserve(SizeHandleRect::Left);
+ for (int i = SizeHandleRect::LeftTop; i <= SizeHandleRect::Left; ++i) {
+ SizeHandleRect *shr = new SizeHandleRect(this, static_cast<SizeHandleRect::Direction>(i), this);
+ connect(shr, SIGNAL(mouseButtonReleased(QRect,QRect)), this, SIGNAL(formWindowSizeChanged(QRect,QRect)));
+ m_handles.push_back(shr);
+ }
+ setState(SelectionHandleActive);
+ updateGeometry();
+}
+
+void FormResizer::updateGeometry()
+{
+ const QRect &geom = m_frame->geometry();
+
+ if (debugFormResizer)
+ qDebug() << "FormResizer::updateGeometry() " << size() << " frame " << geom;
+
+ const int w = SELECTION_HANDLE_SIZE;
+ const int h = SELECTION_HANDLE_SIZE;
+
+ const Handles::iterator hend = m_handles.end();
+ for (Handles::iterator it = m_handles.begin(); it != hend; ++it) {
+ SizeHandleRect *hndl = *it;;
+ switch (hndl->dir()) {
+ case SizeHandleRect::LeftTop:
+ hndl->move(geom.x() - w / 2, geom.y() - h / 2);
+ break;
+ case SizeHandleRect::Top:
+ hndl->move(geom.x() + geom.width() / 2 - w / 2, geom.y() - h / 2);
+ break;
+ case SizeHandleRect::RightTop:
+ hndl->move(geom.x() + geom.width() - w / 2, geom.y() - h / 2);
+ break;
+ case SizeHandleRect::Right:
+ hndl->move(geom.x() + geom.width() - w / 2, geom.y() + geom.height() / 2 - h / 2);
+ break;
+ case SizeHandleRect::RightBottom:
+ hndl->move(geom.x() + geom.width() - w / 2, geom.y() + geom.height() - h / 2);
+ break;
+ case SizeHandleRect::Bottom:
+ hndl->move(geom.x() + geom.width() / 2 - w / 2, geom.y() + geom.height() - h / 2);
+ break;
+ case SizeHandleRect::LeftBottom:
+ hndl->move(geom.x() - w / 2, geom.y() + geom.height() - h / 2);
+ break;
+ case SizeHandleRect::Left:
+ hndl->move(geom.x() - w / 2, geom.y() + geom.height() / 2 - h / 2);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void FormResizer::update()
+{
+ const Handles::iterator hend = m_handles.end();
+ for (Handles::iterator it = m_handles.begin(); it != hend; ++it) {
+ (*it)->update();
+ }
+}
+
+void FormResizer::setState(SelectionHandleState st)
+{
+ if (debugFormResizer)
+ qDebug() << "FormResizer::setState " << st;
+
+ const Handles::iterator hend = m_handles.end();
+ for (Handles::iterator it = m_handles.begin(); it != hend; ++it)
+ (*it)->setState(st);
+}
+
+void FormResizer::setFormWindow(QDesignerFormWindowInterface *fw)
+{
+ if (debugFormResizer)
+ qDebug() << "FormResizer::setFormWindow " << fw;
+ QVBoxLayout *layout = qobject_cast<QVBoxLayout *>(m_frame->layout());
+ Q_ASSERT(layout);
+ if (layout->count())
+ delete layout->takeAt(0);
+ m_formWindow = fw;
+
+ if (m_formWindow)
+ layout->addWidget(m_formWindow);
+ mainContainerChanged();
+ connect(fw, SIGNAL(mainContainerChanged(QWidget*)), this, SLOT(mainContainerChanged()));
+}
+
+void FormResizer::resizeEvent(QResizeEvent *event)
+{
+ if (debugFormResizer)
+ qDebug() << ">FormResizer::resizeEvent" << event->size();
+ updateGeometry();
+ QWidget::resizeEvent(event);
+ if (debugFormResizer)
+ qDebug() << "<FormResizer::resizeEvent";
+}
+
+QSize FormResizer::decorationSize() const
+{
+ const int margin = 2 * SELECTION_MARGIN + 2 * m_frame->lineWidth();
+ return QSize(margin, margin);
+}
+
+QWidget *FormResizer::mainContainer()
+{
+ if (m_formWindow)
+ return m_formWindow->mainContainer();
+ return 0;
+}
+
+void FormResizer::mainContainerChanged()
+{
+ const QSize maxWidgetSize = QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
+ if (const QWidget *mc = mainContainer()) {
+ // Set Maximum size which is not handled via a hint (as opposed to minimum size)
+ const QSize maxWidgetSize = QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
+ const QSize formMaxSize = mc->maximumSize();
+ QSize newMaxSize = maxWidgetSize;
+ if (formMaxSize != maxWidgetSize)
+ newMaxSize = formMaxSize + decorationSize();
+ if (debugFormResizer)
+ qDebug() << "FormResizer::mainContainerChanged" << mc << " Size " << mc->size()<< newMaxSize;
+ setMaximumSize(newMaxSize);
+ resize(decorationSize() + mc->size());
+ } else {
+ setMaximumSize(maxWidgetSize);
+ }
+}
diff --git a/src/shared/designerintegrationv2/formresizer.h b/src/shared/designerintegrationv2/formresizer.h
new file mode 100644
index 0000000000..c76c644a73
--- /dev/null
+++ b/src/shared/designerintegrationv2/formresizer.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FORMRESIZER_H
+#define FORMRESIZER_H
+
+#include "namespace_global.h"
+
+#include "widgethostconstants.h"
+
+#include <QtGui/QWidget>
+#include <QtCore/QVector>
+
+QT_FORWARD_DECLARE_CLASS(QDesignerFormWindowInterface)
+QT_FORWARD_DECLARE_CLASS(QFrame)
+
+namespace SharedTools {
+namespace Internal {
+
+class SizeHandleRect;
+
+/* A window to embed a form window interface as follows:
+ *
+ * Widget
+ * |
+ * +---+----+
+ * | |
+ * | |
+ * Handles QVBoxLayout [margin: SELECTION_MARGIN]
+ * |
+ * Frame [margin: lineWidth]
+ * |
+ * QVBoxLayout
+ * |
+ * QDesignerFormWindowInterface
+ *
+ * Can be embedded into a QScrollArea. */
+
+class FormResizer : public QWidget
+{
+ Q_OBJECT
+public:
+
+ FormResizer(QWidget *parent = 0);
+
+ void updateGeometry();
+ void setState(SelectionHandleState st);
+ void update();
+
+ void setFormWindow(QDesignerFormWindowInterface *fw);
+
+signals:
+ void formWindowSizeChanged(const QRect &oldGeo, const QRect &newGeo);
+
+protected:
+ virtual void resizeEvent(QResizeEvent *event);
+
+private slots:
+ void mainContainerChanged();
+
+private:
+ QSize decorationSize() const;
+ QWidget *mainContainer();
+
+ QFrame *m_frame;
+ typedef QVector<SizeHandleRect*> Handles;
+ Handles m_handles;
+ QDesignerFormWindowInterface * m_formWindow;
+};
+
+}
+} // namespace SharedTools
+
+#endif // FORMRESIZER_H
diff --git a/src/shared/designerintegrationv2/sizehandlerect.cpp b/src/shared/designerintegrationv2/sizehandlerect.cpp
new file mode 100644
index 0000000000..7d6c21407e
--- /dev/null
+++ b/src/shared/designerintegrationv2/sizehandlerect.cpp
@@ -0,0 +1,192 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "sizehandlerect.h"
+#include "widgethostconstants.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+
+#include <QtGui/QMouseEvent>
+#include <QtGui/QPainter>
+#include <QtGui/QFrame>
+#include <QtCore/QDebug>
+
+enum { debugSizeHandle = 0 };
+
+using namespace SharedTools::Internal;
+
+SizeHandleRect::SizeHandleRect(QWidget *parent, Direction d, QWidget *resizable) :
+ QWidget(parent),
+ m_dir(d),
+ m_resizable(resizable),
+ m_state(SelectionHandleOff)
+{
+ setBackgroundRole(QPalette::Text);
+ setAutoFillBackground(true);
+
+ setFixedSize(SELECTION_HANDLE_SIZE, SELECTION_HANDLE_SIZE);
+ setMouseTracking(false);
+ updateCursor();
+}
+
+void SizeHandleRect::updateCursor()
+{
+ switch (m_dir) {
+ case Right:
+ case RightTop:
+ setCursor(Qt::SizeHorCursor);
+ return;
+ case RightBottom:
+ setCursor(Qt::SizeFDiagCursor);
+ return;
+ case LeftBottom:
+ case Bottom:
+ setCursor(Qt::SizeVerCursor);
+ return;
+ default:
+ break;
+ }
+
+ setCursor(Qt::ArrowCursor);
+}
+
+void SizeHandleRect::paintEvent(QPaintEvent *)
+{
+ switch (m_state) {
+ case SelectionHandleOff:
+ break;
+ case SelectionHandleInactive: {
+ QPainter p(this);
+ p.setPen(Qt::red);
+ p.drawRect(0, 0, width() - 1, height() - 1);
+ }
+ break;
+ case SelectionHandleActive: {
+ QPainter p(this);
+ p.setPen(Qt::blue);
+ p.drawRect(0, 0, width() - 1, height() - 1);
+ }
+ break;
+ }
+}
+
+void SizeHandleRect::mousePressEvent(QMouseEvent *e)
+{
+ e->accept();
+
+ if (e->button() != Qt::LeftButton)
+ return;
+
+ m_startSize = m_curSize = m_resizable->size();
+ m_startPos = m_curPos = m_resizable->mapFromGlobal(e->globalPos());
+ if (debugSizeHandle)
+ qDebug() << "SizeHandleRect::mousePressEvent" << m_startSize << m_startPos << m_curPos;
+
+}
+
+void SizeHandleRect::mouseMoveEvent(QMouseEvent *e)
+{
+ if (!(e->buttons() & Qt::LeftButton))
+ return;
+
+ // Try resize with delta against start position.
+ // We don't take little deltas in consecutive move events as this
+ // causes the handle and the mouse cursor to become out of sync
+ // once a min/maxSize limit is hit. When the cursor reenters the valid
+ // areas, it will now snap to it.
+ m_curPos = m_resizable->mapFromGlobal(e->globalPos());
+ QSize delta = QSize(m_curPos.x() - m_startPos.x(), m_curPos.y() - m_startPos.y());
+ switch (m_dir) {
+ case Right:
+ case RightTop: // Only width
+ delta.setHeight(0);
+ break;
+ case RightBottom: // All dimensions
+ break;
+ case LeftBottom:
+ case Bottom: // Only height
+ delta.setWidth(0);
+ break;
+ default:
+ delta = QSize(0, 0);
+ break;
+ }
+ if (delta != QSize(0, 0))
+ tryResize(delta);
+}
+
+void SizeHandleRect::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (e->button() != Qt::LeftButton)
+ return;
+
+ e->accept();
+ if (m_startSize != m_curSize) {
+ const QRect startRect = QRect(0, 0, m_startPos.x(), m_startPos.y());
+ const QRect newRect = QRect(0, 0, m_curPos.x(), m_curPos.y());
+ if (debugSizeHandle)
+ qDebug() << "SizeHandleRect::mouseReleaseEvent" << startRect << newRect;
+ emit mouseButtonReleased(startRect, newRect);
+ }
+}
+
+void SizeHandleRect::tryResize(const QSize &delta)
+{
+ // Try resize with delta against start position
+ QSize newSize = m_startSize + delta;
+ newSize = newSize.expandedTo(m_resizable->minimumSizeHint());
+ newSize = newSize.expandedTo(m_resizable->minimumSize());
+ newSize = newSize.boundedTo(m_resizable->maximumSize());
+ if (newSize == m_resizable->size())
+ return;
+ if (debugSizeHandle)
+ qDebug() << "SizeHandleRect::tryResize by (" << m_startSize << '+' << delta << ')' << newSize;
+ m_resizable->resize(newSize);
+ m_curSize = m_resizable->size();
+}
+
+void SizeHandleRect::setState(SelectionHandleState st)
+{
+ if (st == m_state)
+ return;
+ switch (st) {
+ case SelectionHandleOff:
+ hide();
+ break;
+ case SelectionHandleInactive:
+ case SelectionHandleActive:
+ show();
+ raise();
+ break;
+ }
+ m_state = st;
+}
diff --git a/src/shared/designerintegrationv2/sizehandlerect.h b/src/shared/designerintegrationv2/sizehandlerect.h
new file mode 100644
index 0000000000..1800f29f50
--- /dev/null
+++ b/src/shared/designerintegrationv2/sizehandlerect.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef SIZEHANDLERECT_H
+#define SIZEHANDLERECT_H
+
+#include "namespace_global.h"
+
+#include "widgethostconstants.h"
+
+#include <QtGui/QWidget>
+#include <QtCore/QPoint>
+
+namespace SharedTools {
+namespace Internal {
+
+class SizeHandleRect : public QWidget
+{
+ Q_OBJECT
+public:
+ enum Direction { LeftTop, Top, RightTop, Right, RightBottom, Bottom, LeftBottom, Left };
+
+ SizeHandleRect(QWidget *parent, Direction d, QWidget *resizable);
+
+ Direction dir() const { return m_dir; }
+ void updateCursor();
+ void setState(SelectionHandleState st);
+
+signals:
+
+ void mouseButtonReleased(const QRect &, const QRect &);
+
+protected:
+ void paintEvent(QPaintEvent *e);
+ void mousePressEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+
+private:
+ void tryResize(const QSize &delta);
+
+private:
+ const Direction m_dir;
+ QPoint m_startPos;
+ QPoint m_curPos;
+ QSize m_startSize;
+ QSize m_curSize;
+ QWidget *m_resizable;
+ SelectionHandleState m_state;
+};
+
+}
+} // namespace SharedTools
+
+
+#endif // SIZEHANDLERECT_H
+
diff --git a/src/shared/designerintegrationv2/widgethost.cpp b/src/shared/designerintegrationv2/widgethost.cpp
new file mode 100644
index 0000000000..bc5d6336e0
--- /dev/null
+++ b/src/shared/designerintegrationv2/widgethost.cpp
@@ -0,0 +1,109 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "widgethost.h"
+#include "formresizer.h"
+#include "widgethostconstants.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormWindowCursorInterface>
+
+#include <QtGui/QPalette>
+#include <QtGui/QLayout>
+#include <QtGui/QFrame>
+#include <QtGui/QResizeEvent>
+#include <QtCore/QDebug>
+
+using namespace SharedTools;
+
+// ---------- WidgetHost
+WidgetHost::WidgetHost(QWidget *parent, QDesignerFormWindowInterface *formWindow) :
+ QScrollArea(parent),
+ m_formWindow(0),
+ m_formResizer(new Internal::FormResizer)
+{
+ setWidget(m_formResizer);
+ // Re-set flag (gets cleared by QScrollArea): Make the resize grip of a mainwindow form find the resizer as resizable window.
+ m_formResizer->setWindowFlags(m_formResizer->windowFlags() | Qt::SubWindow);
+ setFormWindow(formWindow);
+}
+
+WidgetHost::~WidgetHost()
+{
+ if (m_formWindow)
+ delete m_formWindow;
+}
+
+void WidgetHost::setFormWindow(QDesignerFormWindowInterface *fw)
+{
+ m_formWindow = fw;
+ if (!fw)
+ return;
+
+ m_formResizer->setFormWindow(fw);
+
+ setBackgroundRole(QPalette::Base);
+ m_formWindow->setAutoFillBackground(true);
+ m_formWindow->setBackgroundRole(QPalette::Background);
+
+ connect(m_formResizer, SIGNAL(formWindowSizeChanged(QRect, QRect)),
+ this, SLOT(fwSizeWasChanged(QRect, QRect)));
+}
+
+QSize WidgetHost::formWindowSize() const
+{
+ if (!m_formWindow || !m_formWindow->mainContainer())
+ return QSize();
+ return m_formWindow->mainContainer()->size();
+}
+
+void WidgetHost::fwSizeWasChanged(const QRect &, const QRect &)
+{
+ // newGeo is the mouse coordinates, thus moving the Right will actually emit wrong height
+ emit formWindowSizeChanged(formWindowSize().width(), formWindowSize().height());
+}
+
+void WidgetHost::updateFormWindowSelectionHandles(bool active)
+{
+ Internal::SelectionHandleState state = Internal::SelectionHandleOff;
+ const QDesignerFormWindowCursorInterface *cursor = m_formWindow->cursor();
+ if (cursor->isWidgetSelected(m_formWindow->mainContainer()))
+ state = active ? Internal::SelectionHandleActive : Internal::SelectionHandleInactive;
+
+ m_formResizer->setState(state);
+}
+
+QWidget *WidgetHost::integrationContainer() const
+{
+ return m_formResizer;
+}
diff --git a/src/shared/designerintegrationv2/widgethost.h b/src/shared/designerintegrationv2/widgethost.h
new file mode 100644
index 0000000000..c8500aff90
--- /dev/null
+++ b/src/shared/designerintegrationv2/widgethost.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef WIDGETHOST_H
+#define WIDGETHOST_H
+
+#include "namespace_global.h"
+
+#include <QtGui/QScrollArea>
+
+QT_FORWARD_DECLARE_CLASS(QDesignerFormWindowInterface)
+
+namespace SharedTools {
+
+namespace Internal {
+ class FormResizer;
+}
+
+/* A scroll area that embeds a Designer form window */
+
+class WidgetHost : public QScrollArea
+{
+ Q_OBJECT
+public:
+ WidgetHost(QWidget *parent = 0, QDesignerFormWindowInterface *formWindow = 0);
+ virtual ~WidgetHost();
+ // Show handles if active and main container is selected.
+ void updateFormWindowSelectionHandles(bool active);
+
+ inline QDesignerFormWindowInterface *formWindow() const { return m_formWindow; }
+
+ QWidget *integrationContainer() const;
+
+protected:
+ void setFormWindow(QDesignerFormWindowInterface *fw);
+
+signals:
+ void formWindowSizeChanged(int, int);
+
+private slots:
+ void fwSizeWasChanged(const QRect &, const QRect &);
+
+private:
+ QSize formWindowSize() const;
+
+ QDesignerFormWindowInterface *m_formWindow;
+ Internal::FormResizer *m_formResizer;
+ QSize m_oldFakeWidgetSize;
+};
+
+} // namespace SharedTools
+
+#endif // WIDGETHOST_H
diff --git a/src/shared/designerintegrationv2/widgethostconstants.h b/src/shared/designerintegrationv2/widgethostconstants.h
new file mode 100644
index 0000000000..f42f1851ac
--- /dev/null
+++ b/src/shared/designerintegrationv2/widgethostconstants.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef WIDGETHOST_CONSTANTS_H
+#define WIDGETHOST_CONSTANTS_H
+
+namespace SharedTools {
+ namespace Internal {
+ enum { SELECTION_HANDLE_SIZE = 6, SELECTION_MARGIN = 10 };
+ enum SelectionHandleState { SelectionHandleOff, SelectionHandleInactive, SelectionHandleActive };
+ }
+}
+
+#endif // WIDGETHOST_CONSTANTS_H
+
diff --git a/src/shared/help/bookmarkdialog.ui b/src/shared/help/bookmarkdialog.ui
new file mode 100644
index 0000000000..7a878f9656
--- /dev/null
+++ b/src/shared/help/bookmarkdialog.ui
@@ -0,0 +1,146 @@
+<ui version="4.0" >
+ <class>BookmarkDialog</class>
+ <widget class="QDialog" name="BookmarkDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>450</width>
+ <height>135</height>
+ </rect>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle" >
+ <string>Add Bookmark</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3" >
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout" >
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2" >
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Bookmark:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Add in Folder:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <widget class="QLineEdit" name="bookmarkEdit" />
+ </item>
+ <item>
+ <widget class="QComboBox" name="bookmarkFolders" />
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3" >
+ <item>
+ <widget class="QToolButton" name="toolButton" >
+ <property name="minimumSize" >
+ <size>
+ <width>25</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>+</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTreeView" name="treeView" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Ignored" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4" >
+ <item>
+ <widget class="QPushButton" name="newFolderButton" >
+ <property name="text" >
+ <string>New Folder</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>BookmarkDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>BookmarkDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/shared/help/bookmarkmanager.cpp b/src/shared/help/bookmarkmanager.cpp
new file mode 100644
index 0000000000..dfe4b7f9d5
--- /dev/null
+++ b/src/shared/help/bookmarkmanager.cpp
@@ -0,0 +1,866 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "bookmarkmanager.h"
+#include "centralwidget.h"
+
+#include <QtGui/QMenu>
+#include <QtGui/QIcon>
+#include <QtGui/QStyle>
+#include <QtGui/QLabel>
+#include <QtGui/QLayout>
+#include <QtCore/QEvent>
+#include <QtGui/QComboBox>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QLineEdit>
+#include <QtGui/QMessageBox>
+#include <QtGui/QHeaderView>
+#include <QtGui/QToolButton>
+#include <QtGui/QPushButton>
+#include <QtGui/QApplication>
+#include <QtHelp/QHelpEngineCore>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QSortFilterProxyModel>
+
+QT_BEGIN_NAMESPACE
+
+BookmarkDialog::BookmarkDialog(BookmarkManager *manager, const QString &title,
+ const QString &url, QWidget *parent)
+ : QDialog(parent)
+ , m_url(url)
+ , m_title(title)
+ , bookmarkManager(manager)
+{
+ installEventFilter(this);
+
+ ui.setupUi(this);
+ ui.bookmarkEdit->setText(title);
+ ui.newFolderButton->setVisible(false);
+ ui.buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+ ui.bookmarkFolders->addItems(bookmarkManager->bookmarkFolders());
+
+ proxyModel = new QSortFilterProxyModel(this);
+ proxyModel->setFilterKeyColumn(0);
+ proxyModel->setDynamicSortFilter(true);
+ proxyModel->setFilterRole(Qt::UserRole + 10);
+ proxyModel->setSourceModel(bookmarkManager->treeBookmarkModel());
+ proxyModel->setFilterRegExp(QRegExp(QLatin1String("Folder"),
+ Qt::CaseSensitive, QRegExp::FixedString));
+ ui.treeView->setModel(proxyModel);
+
+ ui.treeView->expandAll();
+ ui.treeView->setVisible(false);
+ ui.treeView->header()->setVisible(false);
+ ui.treeView->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+ connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(addAccepted()));
+ connect(ui.newFolderButton, SIGNAL(clicked()), this, SLOT(addNewFolder()));
+ connect(ui.toolButton, SIGNAL(clicked()), this, SLOT(toolButtonClicked()));
+ connect(ui.bookmarkEdit, SIGNAL(textChanged(const QString&)), this,
+ SLOT(textChanged(const QString&)));
+
+ connect(bookmarkManager->treeBookmarkModel(), SIGNAL(itemChanged(QStandardItem*)),
+ this, SLOT(itemChanged(QStandardItem*)));
+
+ connect(ui.bookmarkFolders, SIGNAL(currentIndexChanged(const QString&)), this,
+ SLOT(selectBookmarkFolder(const QString&)));
+
+ connect(ui.treeView, SIGNAL(customContextMenuRequested(const QPoint&)), this,
+ SLOT(customContextMenuRequested(const QPoint&)));
+
+ connect(ui.treeView->selectionModel(),
+ SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
+ this, SLOT(currentChanged(const QModelIndex&, const QModelIndex&)));
+}
+
+BookmarkDialog::~BookmarkDialog()
+{
+}
+
+void BookmarkDialog::addAccepted()
+{
+ const QItemSelection selection = ui.treeView->selectionModel()->selection();
+ const QModelIndexList list = selection.indexes();
+
+ QModelIndex index;
+ if (!list.isEmpty())
+ index = proxyModel->mapToSource(list.at(0));
+
+ bookmarkManager->addNewBookmark(index, ui.bookmarkEdit->text(), m_url);
+ accept();
+}
+
+void BookmarkDialog::addNewFolder()
+{
+ const QItemSelection selection = ui.treeView->selectionModel()->selection();
+ const QModelIndexList list = selection.indexes();
+
+ QModelIndex index;
+ if (!list.isEmpty())
+ index = list.at(0);
+
+ QModelIndex newFolder =
+ bookmarkManager->addNewFolder(proxyModel->mapToSource(index));
+ if (newFolder.isValid()) {
+ ui.treeView->expand(index);
+ const QModelIndex &index = proxyModel->mapFromSource(newFolder);
+ ui.treeView->selectionModel()->setCurrentIndex(index,
+ QItemSelectionModel::ClearAndSelect);
+
+ ui.bookmarkFolders->clear();
+ ui.bookmarkFolders->addItems(bookmarkManager->bookmarkFolders());
+
+ const QString name = index.data().toString();
+ ui.bookmarkFolders->setCurrentIndex(ui.bookmarkFolders->findText(name));
+ }
+ ui.treeView->setFocus();
+}
+
+void BookmarkDialog::toolButtonClicked()
+{
+ bool visible = !ui.treeView->isVisible();
+ ui.treeView->setVisible(visible);
+ ui.newFolderButton->setVisible(visible);
+
+ if (visible) {
+ resize(QSize(width(), 400));
+ ui.toolButton->setText(QLatin1String("-"));
+ } else {
+ resize(width(), minimumHeight());
+ ui.toolButton->setText(QLatin1String("+"));
+ }
+}
+
+void BookmarkDialog::itemChanged(QStandardItem *item)
+{
+ if (renameItem != item) {
+ renameItem = item;
+ oldText = item->text();
+ return;
+ }
+
+ if (item->text() != oldText) {
+ ui.bookmarkFolders->clear();
+ ui.bookmarkFolders->addItems(bookmarkManager->bookmarkFolders());
+
+ QString name = tr("Bookmarks");
+ const QModelIndex& index = ui.treeView->currentIndex();
+ if (index.isValid())
+ name = index.data().toString();
+ ui.bookmarkFolders->setCurrentIndex(ui.bookmarkFolders->findText(name));
+ }
+}
+
+void BookmarkDialog::textChanged(const QString& string)
+{
+ ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!string.isEmpty());
+}
+
+void BookmarkDialog::selectBookmarkFolder(const QString &folderName)
+{
+ if (folderName.isEmpty())
+ return;
+
+ if (folderName == tr("Bookmarks")) {
+ ui.treeView->clearSelection();
+ return;
+ }
+
+ QStandardItemModel *model = bookmarkManager->treeBookmarkModel();
+ QList<QStandardItem*> list = model->findItems(folderName,
+ Qt::MatchCaseSensitive | Qt::MatchRecursive, 0);
+ if (!list.isEmpty()) {
+ QModelIndex index = model->indexFromItem(list.at(0));
+ ui.treeView->selectionModel()->setCurrentIndex(
+ proxyModel->mapFromSource(index), QItemSelectionModel::ClearAndSelect);
+ }
+}
+
+void BookmarkDialog::customContextMenuRequested(const QPoint &point)
+{
+ QModelIndex index = ui.treeView->indexAt(point);
+ if (!index.isValid())
+ return;
+
+ QMenu menu(QLatin1String(""), this);
+
+ QAction *removeItem = menu.addAction(tr("Delete Folder"));
+ QAction *renameItem = menu.addAction(tr("Rename Folder"));
+
+ QAction *picked_action = menu.exec(ui.treeView->mapToGlobal(point));
+ if (!picked_action)
+ return;
+
+ if (picked_action == removeItem) {
+ bookmarkManager->removeBookmarkItem(ui.treeView,
+ proxyModel->mapToSource(index));
+ ui.bookmarkFolders->clear();
+ ui.bookmarkFolders->addItems(bookmarkManager->bookmarkFolders());
+
+ QString name = tr("Bookmarks");
+ index = ui.treeView->currentIndex();
+ if (index.isValid())
+ name = index.data().toString();
+ ui.bookmarkFolders->setCurrentIndex(ui.bookmarkFolders->findText(name));
+ }
+ else if (picked_action == renameItem) {
+ QStandardItem *item = bookmarkManager->treeBookmarkModel()->
+ itemFromIndex(proxyModel->mapToSource(index));
+ if (item) {
+ item->setEditable(true);
+ ui.treeView->edit(index);
+ item->setEditable(false);
+ }
+ }
+}
+
+void BookmarkDialog::currentChanged(const QModelIndex& current,
+ const QModelIndex& previous)
+{
+ Q_UNUSED(previous)
+
+ if (!current.isValid()) {
+ ui.bookmarkFolders->setCurrentIndex(
+ ui.bookmarkFolders->findText(tr("Bookmarks")));
+ return;
+ }
+
+ ui.bookmarkFolders->setCurrentIndex(
+ ui.bookmarkFolders->findText(current.data().toString()));
+}
+
+bool BookmarkDialog::eventFilter(QObject *object, QEvent *e)
+{
+ if (object == this && e->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+
+ QModelIndex index = ui.treeView->currentIndex();
+ switch (ke->key()) {
+ case Qt::Key_F2: {
+ const QModelIndex& source = proxyModel->mapToSource(index);
+ QStandardItem *item =
+ bookmarkManager->treeBookmarkModel()->itemFromIndex(source);
+ if (item) {
+ item->setEditable(true);
+ ui.treeView->edit(index);
+ item->setEditable(false);
+ }
+ } break;
+
+ case Qt::Key_Delete: {
+ bookmarkManager->removeBookmarkItem(ui.treeView,
+ proxyModel->mapToSource(index));
+ ui.bookmarkFolders->clear();
+ ui.bookmarkFolders->addItems(bookmarkManager->bookmarkFolders());
+
+ QString name = tr("Bookmarks");
+ index = ui.treeView->currentIndex();
+ if (index.isValid())
+ name = index.data().toString();
+ ui.bookmarkFolders->setCurrentIndex(ui.bookmarkFolders->findText(name));
+ } break;
+
+ default:
+ break;
+ }
+ }
+ return QObject::eventFilter(object, e);
+}
+
+
+
+
+BookmarkWidget::BookmarkWidget(BookmarkManager *manager, QWidget *parent,
+ bool showButtons)
+ : QWidget(parent)
+ , addButton(0)
+ , removeButton(0)
+ , bookmarkManager(manager)
+{
+ setup(showButtons);
+ installEventFilter(this);
+}
+
+BookmarkWidget::~BookmarkWidget()
+{
+}
+
+void BookmarkWidget::removeClicked()
+{
+ const QModelIndex& index = treeView->currentIndex();
+ if (searchField->text().isEmpty()) {
+ bookmarkManager->removeBookmarkItem(treeView,
+ filterBookmarkModel->mapToSource(index));
+ }
+}
+
+void BookmarkWidget::filterChanged()
+{
+ bool searchBookmarks = searchField->text().isEmpty();
+ if (!searchBookmarks) {
+ regExp.setPattern(searchField->text());
+ filterBookmarkModel->setSourceModel(bookmarkManager->listBookmarkModel());
+ } else {
+ regExp.setPattern(QLatin1String(""));
+ filterBookmarkModel->setSourceModel(bookmarkManager->treeBookmarkModel());
+ }
+
+ if (addButton)
+ addButton->setEnabled(searchBookmarks);
+
+ if (removeButton)
+ removeButton->setEnabled(searchBookmarks);
+
+ filterBookmarkModel->setFilterRegExp(regExp);
+
+ QModelIndex index = treeView->indexAt(QPoint(1, 1));
+ if (index.isValid())
+ treeView->setCurrentIndex(index);
+
+ if (searchBookmarks)
+ expandItems();
+}
+
+void BookmarkWidget::expand(const QModelIndex& index)
+{
+ const QModelIndex& source = filterBookmarkModel->mapToSource(index);
+ QStandardItem *item = bookmarkManager->treeBookmarkModel()->itemFromIndex(source);
+ if (item)
+ item->setData(treeView->isExpanded(index), Qt::UserRole + 11);
+}
+
+void BookmarkWidget::activated(const QModelIndex &index)
+{
+ if (!index.isValid())
+ return;
+
+ QString data = index.data(Qt::UserRole + 10).toString();
+ if (data != QLatin1String("Folder"))
+ emit requestShowLink(data);
+}
+
+void BookmarkWidget::customContextMenuRequested(const QPoint &point)
+{
+ QModelIndex index = treeView->indexAt(point);
+ if (!index.isValid())
+ return;
+
+ QAction *showItem = 0;
+ QAction *removeItem = 0;
+ QAction *renameItem = 0;
+ QAction *showItemNewTab = 0;
+
+ QMenu menu(QLatin1String(""), this);
+ QString data = index.data(Qt::UserRole + 10).toString();
+ if (data == QLatin1String("Folder")) {
+ removeItem = menu.addAction(tr("Delete Folder"));
+ renameItem = menu.addAction(tr("Rename Folder"));
+ } else {
+ showItem = menu.addAction(tr("Show Bookmark"));
+ showItemNewTab = menu.addAction(tr("Show Bookmark in New Tab"));
+ if (searchField->text().isEmpty()) {
+ menu.addSeparator();
+ removeItem = menu.addAction(tr("Delete Bookmark"));
+ renameItem = menu.addAction(tr("Rename Bookmark"));
+ }
+ }
+
+ QAction *picked_action = menu.exec(treeView->mapToGlobal(point));
+ if (!picked_action)
+ return;
+
+ if (picked_action == showItem) {
+ emit requestShowLink(data);
+ }
+ else if (picked_action == showItemNewTab) {
+ CentralWidget::instance()->setSourceInNewTab(data);
+ }
+ else if (picked_action == removeItem) {
+ bookmarkManager->removeBookmarkItem(treeView,
+ filterBookmarkModel->mapToSource(index));
+ }
+ else if (picked_action == renameItem) {
+ const QModelIndex& source = filterBookmarkModel->mapToSource(index);
+ QStandardItem *item =
+ bookmarkManager->treeBookmarkModel()->itemFromIndex(source);
+ if (item) {
+ item->setEditable(true);
+ treeView->edit(index);
+ item->setEditable(false);
+ }
+ }
+}
+
+void BookmarkWidget::setup(bool showButtons)
+{
+ regExp.setPatternSyntax(QRegExp::FixedString);
+ regExp.setCaseSensitivity(Qt::CaseInsensitive);
+
+ QLayout *vlayout = new QVBoxLayout(this);
+ vlayout->setMargin(4);
+
+ QLabel *label = new QLabel(tr("Filter:"), this);
+ vlayout->addWidget(label);
+
+ searchField = new QLineEdit(this);
+ vlayout->addWidget(searchField);
+ connect(searchField, SIGNAL(textChanged(const QString &)), this,
+ SLOT(filterChanged()));
+
+ treeView = new TreeView(this);
+ vlayout->addWidget(treeView);
+
+ QString system = QLatin1String("win");
+#ifdef Q_OS_MAC
+ system = QLatin1String("mac");
+#endif
+
+ if (showButtons) {
+ QLayout *hlayout = new QHBoxLayout();
+ vlayout->addItem(hlayout);
+
+ hlayout->addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding));
+
+ addButton = new QToolButton(this);
+ addButton->setText(tr("Add"));
+ addButton->setIcon(QIcon(QString::fromUtf8(
+ ":/trolltech/assistant/images/%1/addtab.png").arg(system)));
+ addButton->setAutoRaise(true);
+ addButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ hlayout->addWidget(addButton);
+ connect(addButton, SIGNAL(clicked()), this, SIGNAL(addBookmark()));
+
+ removeButton = new QToolButton(this);
+ removeButton->setText(tr("Remove"));
+ removeButton->setIcon(QIcon(QString::fromUtf8(
+ ":/trolltech/assistant/images/%1/closetab.png").arg(system)));
+ removeButton->setAutoRaise(true);
+ removeButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ hlayout->addWidget(removeButton);
+ connect(removeButton, SIGNAL(clicked()), this, SLOT(removeClicked()));
+ }
+
+ filterBookmarkModel = new QSortFilterProxyModel(this);
+ treeView->setModel(filterBookmarkModel);
+
+ treeView->setDragEnabled(true);
+ treeView->setAcceptDrops(true);
+ treeView->setAutoExpandDelay(1000);
+ treeView->setDropIndicatorShown(true);
+ treeView->header()->setVisible(false);
+ treeView->viewport()->installEventFilter(this);
+ treeView->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(treeView, SIGNAL(expanded(const QModelIndex&)), this,
+ SLOT(expand(const QModelIndex&)));
+
+ connect(treeView, SIGNAL(collapsed(const QModelIndex&)), this,
+ SLOT(expand(const QModelIndex&)));
+
+ connect(treeView, SIGNAL(activated(const QModelIndex&)), this,
+ SLOT(activated(const QModelIndex&)));
+
+ connect(treeView, SIGNAL(customContextMenuRequested(const QPoint&)),
+ this, SLOT(customContextMenuRequested(const QPoint&)));
+
+ filterBookmarkModel->setFilterKeyColumn(0);
+ filterBookmarkModel->setDynamicSortFilter(true);
+ filterBookmarkModel->setSourceModel(bookmarkManager->treeBookmarkModel());
+
+ expandItems();
+}
+
+void BookmarkWidget::expandItems()
+{
+ QStandardItemModel *model = bookmarkManager->treeBookmarkModel();
+ QList<QStandardItem*>list = model->findItems(QLatin1String("*"),
+ Qt::MatchWildcard | Qt::MatchRecursive, 0);
+ foreach (const QStandardItem* item, list) {
+ const QModelIndex& index = model->indexFromItem(item);
+ treeView->setExpanded(filterBookmarkModel->mapFromSource(index),
+ item->data(Qt::UserRole + 11).toBool());
+ }
+}
+
+void BookmarkWidget::focusInEvent(QFocusEvent *e)
+{
+ if (e->reason() != Qt::MouseFocusReason) {
+ searchField->selectAll();
+ searchField->setFocus();
+
+ QModelIndex index = treeView->indexAt(QPoint(1, 1));
+ if (index.isValid())
+ treeView->setCurrentIndex(index);
+
+ }
+}
+
+bool BookmarkWidget::eventFilter(QObject *object, QEvent *e)
+{
+ if (object == this && e->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+ QModelIndex index = treeView->currentIndex();
+ switch (ke->key()) {
+ if (index.isValid() && searchField->text().isEmpty()) {
+ case Qt::Key_F2: {
+ const QModelIndex& source = filterBookmarkModel->mapToSource(index);
+ QStandardItem *item =
+ bookmarkManager->treeBookmarkModel()->itemFromIndex(source);
+ if (item) {
+ item->setEditable(true);
+ treeView->edit(index);
+ item->setEditable(false);
+ }
+ } break;
+
+ case Qt::Key_Delete: {
+ bookmarkManager->removeBookmarkItem(treeView,
+ filterBookmarkModel->mapToSource(index));
+ } break;
+ }
+
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ treeView->subclassKeyPressEvent(ke);
+ break;
+
+ case Qt::Key_Enter: {
+ case Qt::Key_Return:
+ index = treeView->selectionModel()->currentIndex();
+ if (index.isValid()) {
+ QString data = index.data(Qt::UserRole + 10).toString();
+ if (!data.isEmpty() && data != QLatin1String("Folder"))
+ emit requestShowLink(data);
+ }
+ } break;
+
+ case Qt::Key_Escape:
+ emit escapePressed();
+ break;
+
+ default:
+ break;
+ }
+ }
+ else if (object == treeView->viewport() && e->type() == QEvent::MouseButtonRelease) {
+ const QModelIndex& index = treeView->currentIndex();
+ QMouseEvent *me = static_cast<QMouseEvent*>(e);
+ if (index.isValid() && (me->button() == Qt::MidButton)) {
+ QString data = index.data(Qt::UserRole + 10).toString();
+ if (!data.isEmpty() && data != QLatin1String("Folder"))
+ CentralWidget::instance()->setSourceInNewTab(data);
+ }
+ }
+ return QWidget::eventFilter(object, e);
+}
+
+
+
+
+BookmarkModel::BookmarkModel(int rows, int columns, QObject * parent)
+ : QStandardItemModel(rows, columns, parent)
+{
+}
+
+BookmarkModel::~BookmarkModel()
+{
+}
+
+Qt::DropActions BookmarkModel::supportedDropActions() const
+{
+ return Qt::MoveAction;
+}
+
+Qt::ItemFlags BookmarkModel::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags defaultFlags = QStandardItemModel::flags(index);
+ if (index.data(Qt::UserRole + 10).toString() == QLatin1String("Folder"))
+ return (Qt::ItemIsDropEnabled | defaultFlags) &~ Qt::ItemIsDragEnabled;
+
+ return (Qt::ItemIsDragEnabled | defaultFlags) &~ Qt::ItemIsDropEnabled;
+}
+
+
+
+
+BookmarkManager::BookmarkManager(QHelpEngineCore* _helpEngine)
+ : treeModel(new BookmarkModel(0, 1, this))
+ , listModel(new BookmarkModel(0, 1, this))
+ , helpEngine(_helpEngine)
+{
+ folderIcon = QApplication::style()->standardIcon(QStyle::SP_DirClosedIcon);
+ treeModel->setHeaderData(0, Qt::Horizontal, QObject::tr("Bookmark"));
+ listModel->setHeaderData(0, Qt::Horizontal, QObject::tr("Bookmark"));
+
+ connect(treeModel, SIGNAL(itemChanged(QStandardItem*)), this,
+ SLOT(itemChanged(QStandardItem*)));
+}
+
+BookmarkManager::~BookmarkManager()
+{
+ treeModel->clear();
+ listModel->clear();
+}
+
+BookmarkModel* BookmarkManager::treeBookmarkModel()
+{
+ return treeModel;
+}
+
+BookmarkModel* BookmarkManager::listBookmarkModel()
+{
+ return listModel;
+}
+
+void BookmarkManager::saveBookmarks()
+{
+ qint32 depth = 0;
+ QByteArray bookmarks;
+ QDataStream stream(&bookmarks, QIODevice::WriteOnly);
+ QStandardItem *root = treeModel->invisibleRootItem();
+
+ for (int i = 0; i < root->rowCount(); ++i) {
+ const QStandardItem *item = root->child(i);
+ stream << depth; // root
+ stream << item->data(Qt::DisplayRole).toString();
+ stream << item->data(Qt::UserRole + 10).toString();
+ stream << item->data(Qt::UserRole + 11).toBool();
+
+ if (item->rowCount() > 0) {
+ readBookmarksRecursive(item, stream, (depth +1));
+ }
+ }
+ helpEngine->setCustomValue(QLatin1String("Bookmarks"), bookmarks);
+}
+
+QStringList BookmarkManager::bookmarkFolders() const
+{
+ QStringList folders(tr("Bookmarks"));
+
+ QList<QStandardItem*>list = treeModel->findItems(QLatin1String("*"),
+ Qt::MatchWildcard | Qt::MatchRecursive, 0);
+
+ QString data;
+ foreach (const QStandardItem *item, list) {
+ data = item->data(Qt::UserRole + 10).toString();
+ if (data == QLatin1String("Folder"))
+ folders << item->data(Qt::DisplayRole).toString();
+ }
+ return folders;
+}
+
+QModelIndex BookmarkManager::addNewFolder(const QModelIndex& index)
+{
+ QStandardItem *item = new QStandardItem(uniqueFolderName());
+ item->setEditable(false);
+ item->setData(false, Qt::UserRole + 11);
+ item->setData(QLatin1String("Folder"), Qt::UserRole + 10);
+ item->setIcon(QApplication::style()->standardIcon(QStyle::SP_DirClosedIcon));
+
+ if (index.isValid()) {
+ treeModel->itemFromIndex(index)->appendRow(item);
+ } else {
+ treeModel->appendRow(item);
+ }
+ return treeModel->indexFromItem(item);
+}
+
+void BookmarkManager::removeBookmarkItem(QTreeView *treeView, const QModelIndex& index)
+{
+ QStandardItem *item = treeModel->itemFromIndex(index);
+ if (item) {
+ QString data = index.data(Qt::UserRole + 10).toString();
+ if (data == QLatin1String("Folder") && item->rowCount() > 0) {
+ int value = QMessageBox::question(treeView, tr("Remove"),
+ tr("You are going to delete a Folder, this will also<br>"
+ "remove it's content. Are you sure to continue?"),
+ QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
+
+ if (value == QMessageBox::Cancel)
+ return;
+ }
+
+ if (data != QLatin1String("Folder")) {
+ QList<QStandardItem*>itemList = listModel->findItems(item->text());
+ foreach (const QStandardItem *i, itemList) {
+ if (i->data(Qt::UserRole + 10) == data) {
+ listModel->removeRow(i->row());
+ break;
+ }
+ }
+ } else {
+ removeBookmarkFolderItems(item);
+ }
+ treeModel->removeRow(item->row(), index.parent());
+ }
+}
+
+void BookmarkManager::showBookmarkDialog(QWidget* parent, const QString &name,
+ const QString &url)
+{
+ BookmarkDialog dialog(this, name, url, parent);
+ dialog.exec();
+}
+
+void BookmarkManager::addNewBookmark(const QModelIndex& index,
+ const QString &name, const QString &url)
+{
+ QStandardItem *item = new QStandardItem(name);
+ item->setEditable(false);
+ item->setData(false, Qt::UserRole + 11);
+ item->setData(url, Qt::UserRole + 10);
+
+ if (index.isValid()) {
+ treeModel->itemFromIndex(index)->appendRow(item);
+ listModel->appendRow(item->clone());
+ } else {
+ treeModel->appendRow(item);
+ listModel->appendRow(item->clone());
+ }
+}
+
+void BookmarkManager::itemChanged(QStandardItem *item)
+{
+ if (renameItem != item) {
+ renameItem = item;
+ oldText = item->text();
+ return;
+ }
+
+ if (item->text() != oldText) {
+ if (item->data(Qt::UserRole + 10).toString() != QLatin1String("Folder")) {
+ QList<QStandardItem*>itemList = listModel->findItems(oldText);
+ if (itemList.count() > 0)
+ itemList.at(0)->setText(item->text());
+ }
+ }
+}
+
+void BookmarkManager::setupBookmarkModels()
+{
+ treeModel->clear();
+ listModel->clear();
+
+ qint32 depth;
+ bool expanded;
+ QString name, type;
+ QList<int> lastDepths;
+ QList<QStandardItem*> parents;
+
+ QByteArray ba = helpEngine->customValue(QLatin1String("Bookmarks")).toByteArray();
+ QDataStream stream(ba);
+ while (!stream.atEnd()) {
+ stream >> depth >> name >> type >> expanded;
+
+ QStandardItem *item = new QStandardItem(name);
+ item->setEditable(false);
+ item->setData(type, Qt::UserRole + 10);
+ item->setData(expanded, Qt::UserRole + 11);
+ if (depth == 0) {
+ parents.clear(); lastDepths.clear();
+ treeModel->appendRow(item);
+ parents << item; lastDepths << depth;
+ } else {
+ if (depth <= lastDepths.last()) {
+ while (depth <= lastDepths.last() && parents.count() > 0) {
+ parents.pop_back(); lastDepths.pop_back();
+ }
+ }
+ parents.last()->appendRow(item);
+ if (type == QLatin1String("Folder")) {
+ parents << item; lastDepths << depth;
+ }
+ }
+
+ if (type == QLatin1String("Folder"))
+ item->setIcon(folderIcon);
+ else
+ listModel->appendRow(item->clone());
+ }
+}
+
+QString BookmarkManager::uniqueFolderName() const
+{
+ QString folderName = tr("New Folder");
+ QList<QStandardItem*> list = treeModel->findItems(folderName,
+ Qt::MatchContains | Qt::MatchRecursive, 0);
+ if (!list.isEmpty()) {
+ QStringList names;
+ foreach (const QStandardItem *item, list)
+ names << item->text();
+
+ for (int i = 1; i <= names.count(); ++i) {
+ folderName = (tr("New Folder") + QLatin1String(" %1")).arg(i);
+ if (!names.contains(folderName))
+ break;
+ }
+ }
+ return folderName;
+}
+
+void BookmarkManager::removeBookmarkFolderItems(QStandardItem *item)
+{
+ for (int j = 0; j < item->rowCount(); ++j) {
+ QStandardItem *child = item->child(j);
+ if (child->rowCount() > 0)
+ removeBookmarkFolderItems(child);
+
+ QString data = child->data(Qt::UserRole + 10).toString();
+ QList<QStandardItem*>itemList = listModel->findItems(child->text());
+ foreach (const QStandardItem *i, itemList) {
+ if (i->data(Qt::UserRole + 10) == data) {
+ listModel->removeRow(i->row());
+ break;
+ }
+ }
+ }
+}
+
+void BookmarkManager::readBookmarksRecursive(const QStandardItem *item,
+ QDataStream &stream,
+ const qint32 depth) const
+{
+ for (int j = 0; j < item->rowCount(); ++j) {
+ const QStandardItem *child = item->child(j);
+ stream << depth;
+ stream << child->data(Qt::DisplayRole).toString();
+ stream << child->data(Qt::UserRole + 10).toString();
+ stream << child->data(Qt::UserRole + 11).toBool();
+
+ if (child->rowCount() > 0)
+ readBookmarksRecursive(child, stream, (depth +1));
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/shared/help/bookmarkmanager.h b/src/shared/help/bookmarkmanager.h
new file mode 100644
index 0000000000..a1b5e7171a
--- /dev/null
+++ b/src/shared/help/bookmarkmanager.h
@@ -0,0 +1,199 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef BOOKMARKMANAGER_H
+#define BOOKMARKMANAGER_H
+
+#include "ui_bookmarkdialog.h"
+
+#include <QtCore/QUrl>
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtCore/QByteArray>
+#include <QtCore/QDataStream>
+
+#include <QtGui/QIcon>
+#include <QtGui/QDialog>
+#include <QtGui/QWidget>
+#include <QtGui/QTreeView>
+#include <QtGui/QStandardItemModel>
+
+QT_BEGIN_NAMESPACE
+
+class QEvent;
+class QLineEdit;
+class QTreeView;
+class QToolButton;
+class QStandardItem;
+class QHelpEngineCore;
+class QAbstractItemModel;
+class QSortFilterProxyModel;
+
+class BookmarkManager;
+
+class BookmarkDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ BookmarkDialog(BookmarkManager *manager, const QString &title,
+ const QString &url, QWidget *parent = 0);
+ ~BookmarkDialog();
+
+private slots:
+ void addAccepted();
+ void addNewFolder();
+ void toolButtonClicked();
+ void itemChanged(QStandardItem *item);
+ void textChanged(const QString& string);
+ void selectBookmarkFolder(const QString &folderName);
+ void customContextMenuRequested(const QPoint &point);
+ void currentChanged(const QModelIndex& current, const QModelIndex& previous);
+
+private:
+ bool eventFilter(QObject *object, QEvent *e);
+
+private:
+ QString m_url;
+ QString m_title;
+
+ QString oldText;
+ QStandardItem *renameItem;
+
+ Ui::BookmarkDialog ui;
+ BookmarkManager *bookmarkManager;
+ QSortFilterProxyModel *proxyModel;
+};
+
+class TreeView : public QTreeView
+{
+ Q_OBJECT
+
+public:
+ TreeView(QWidget* parent = 0) : QTreeView(parent) {}
+ void subclassKeyPressEvent(QKeyEvent* event)
+ {
+ QTreeView::keyPressEvent(event);
+ }
+};
+
+class BookmarkWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ BookmarkWidget(BookmarkManager *manager, QWidget *parent = 0,
+ bool showButtons = true);
+ ~BookmarkWidget();
+
+signals:
+ void addBookmark();
+ void requestShowLink(const QUrl &url);
+ void escapePressed();
+
+private slots:
+ void removeClicked();
+ void filterChanged();
+ void expand(const QModelIndex& index);
+ void activated(const QModelIndex &index);
+ void customContextMenuRequested(const QPoint &point);
+
+private:
+ void setup(bool showButtons);
+ void expandItems();
+ void focusInEvent(QFocusEvent *e);
+ bool eventFilter(QObject *object, QEvent *event);
+
+private:
+ QRegExp regExp;
+ TreeView *treeView;
+ QLineEdit *searchField;
+ QToolButton *addButton;
+ QToolButton *removeButton;
+ BookmarkManager *bookmarkManager;
+ QSortFilterProxyModel* filterBookmarkModel;
+};
+
+class BookmarkModel : public QStandardItemModel
+{
+ Q_OBJECT
+
+public:
+ BookmarkModel(int rows, int columns, QObject *parent = 0);
+ ~BookmarkModel();
+
+ Qt::DropActions supportedDropActions() const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+};
+
+class BookmarkManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ BookmarkManager(QHelpEngineCore *helpEngine);
+ ~BookmarkManager();
+
+ BookmarkModel *treeBookmarkModel();
+ BookmarkModel *listBookmarkModel();
+
+ void saveBookmarks();
+ QStringList bookmarkFolders() const;
+ QModelIndex addNewFolder(const QModelIndex &index);
+ void removeBookmarkItem(QTreeView *treeView, const QModelIndex& index);
+ void showBookmarkDialog(QWidget *parent, const QString &name, const QString &url);
+ void addNewBookmark(const QModelIndex &index, const QString &name, const QString &url);
+ void setupBookmarkModels();
+
+private slots:
+ void itemChanged(QStandardItem *item);
+
+private:
+ QString uniqueFolderName() const;
+ void removeBookmarkFolderItems(QStandardItem *item);
+ void readBookmarksRecursive(const QStandardItem *item, QDataStream &stream,
+ const qint32 depth) const;
+
+private:
+ QString oldText;
+ QIcon folderIcon;
+
+ BookmarkModel *treeModel;
+ BookmarkModel *listModel;
+ QStandardItem *renameItem;
+ QHelpEngineCore *helpEngine;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/shared/help/contentwindow.cpp b/src/shared/help/contentwindow.cpp
new file mode 100644
index 0000000000..464f583947
--- /dev/null
+++ b/src/shared/help/contentwindow.cpp
@@ -0,0 +1,165 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "contentwindow.h"
+#include "centralwidget.h"
+
+#include <QtGui/QLayout>
+#include <QtGui/QFocusEvent>
+#include <QtGui/QMenu>
+
+#include <QtHelp/QHelpEngine>
+#include <QtHelp/QHelpContentWidget>
+
+QT_BEGIN_NAMESPACE
+
+ContentWindow::ContentWindow(QHelpEngine *helpEngine)
+ : m_helpEngine(helpEngine)
+ , m_contentWidget(0)
+ , m_expandDepth(-2)
+{
+ m_contentWidget = m_helpEngine->contentWidget();
+ m_contentWidget->viewport()->installEventFilter(this);
+ m_contentWidget->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setMargin(4);
+ layout->addWidget(m_contentWidget);
+
+ connect(m_contentWidget, SIGNAL(customContextMenuRequested(QPoint)), this,
+ SLOT(showContextMenu(QPoint)));
+ connect(m_contentWidget, SIGNAL(linkActivated(QUrl)), this,
+ SIGNAL(linkActivated(QUrl)));
+
+ QHelpContentModel *contentModel =
+ qobject_cast<QHelpContentModel*>(m_contentWidget->model());
+ connect(contentModel, SIGNAL(contentsCreated()), this, SLOT(expandTOC()));
+}
+
+ContentWindow::~ContentWindow()
+{
+}
+
+bool ContentWindow::syncToContent(const QUrl& url)
+{
+ QModelIndex idx = m_contentWidget->indexOf(url);
+ if (!idx.isValid())
+ return false;
+ m_contentWidget->setCurrentIndex(idx);
+ return true;
+}
+
+void ContentWindow::expandTOC()
+{
+ if (m_expandDepth > -2) {
+ expandToDepth(m_expandDepth);
+ m_expandDepth = -2;
+ }
+}
+
+void ContentWindow::expandToDepth(int depth)
+{
+ m_expandDepth = depth;
+ if (depth == -1)
+ m_contentWidget->expandAll();
+ else
+ m_contentWidget->expandToDepth(depth);
+}
+
+void ContentWindow::focusInEvent(QFocusEvent *e)
+{
+ if (e->reason() != Qt::MouseFocusReason)
+ m_contentWidget->setFocus();
+}
+
+void ContentWindow::keyPressEvent(QKeyEvent *e)
+{
+ if (e->key() == Qt::Key_Escape)
+ emit escapePressed();
+}
+
+bool ContentWindow::eventFilter(QObject *o, QEvent *e)
+{
+ if (m_contentWidget && o == m_contentWidget->viewport() && e->type()
+ == QEvent::MouseButtonRelease) {
+ QMouseEvent *me = static_cast<QMouseEvent*>(e);
+ if (m_contentWidget->indexAt(me->pos()).isValid()
+ && me->button() == Qt::LeftButton) {
+ itemClicked(m_contentWidget->currentIndex());
+ } else if (m_contentWidget->indexAt(me->pos()).isValid()
+ && me->button() == Qt::MidButton) {
+ QHelpContentModel *contentModel =
+ qobject_cast<QHelpContentModel*>(m_contentWidget->model());
+ QHelpContentItem *itm =
+ contentModel->contentItemAt(m_contentWidget->currentIndex());
+ CentralWidget::instance()->setSourceInNewTab(itm->url());
+ }
+ }
+ return QWidget::eventFilter(o, e);
+}
+
+void ContentWindow::showContextMenu(const QPoint &pos)
+{
+ if (!m_contentWidget->indexAt(pos).isValid())
+ return;
+
+ QMenu menu;
+ QAction *curTab = menu.addAction(tr("Open Link"));
+ QAction *newTab = menu.addAction(tr("Open Link in New Tab"));
+ menu.move(m_contentWidget->mapToGlobal(pos));
+
+ QHelpContentModel *contentModel =
+ qobject_cast<QHelpContentModel*>(m_contentWidget->model());
+ QHelpContentItem *itm =
+ contentModel->contentItemAt(m_contentWidget->currentIndex());
+
+ QAction *action = menu.exec();
+ if (curTab == action)
+ emit linkActivated(itm->url());
+ else if (newTab == action)
+ CentralWidget::instance()->setSourceInNewTab(itm->url());
+}
+
+void ContentWindow::itemClicked(const QModelIndex &index)
+{
+ if (!index.isValid())
+ return;
+ QHelpContentModel *contentModel =
+ qobject_cast<QHelpContentModel*>(m_contentWidget->model());
+ QHelpContentItem *itm =
+ contentModel->contentItemAt(index);
+ if (itm)
+ emit linkActivated(itm->url());
+}
+
+QT_END_NAMESPACE
diff --git a/src/shared/help/contentwindow.h b/src/shared/help/contentwindow.h
new file mode 100644
index 0000000000..f61f5e1e72
--- /dev/null
+++ b/src/shared/help/contentwindow.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef CONTENTWINDOW_H
+#define CONTENTWINDOW_H
+
+#include <QtCore/QUrl>
+#include <QtCore/QModelIndex>
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+class QHelpEngine;
+class QHelpContentWidget;
+
+class ContentWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ ContentWindow(QHelpEngine *helpEngine);
+ ~ContentWindow();
+
+ bool syncToContent(const QUrl &url);
+ void expandToDepth(int depth);
+
+signals:
+ void linkActivated(const QUrl &link);
+ void escapePressed();
+
+private slots:
+ void showContextMenu(const QPoint &pos);
+ void expandTOC();
+ void itemClicked(const QModelIndex &index);
+
+private:
+ void focusInEvent(QFocusEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+ bool eventFilter(QObject *o, QEvent *e);
+
+ QHelpEngine *m_helpEngine;
+ QHelpContentWidget *m_contentWidget;
+ int m_expandDepth;
+};
+
+QT_END_NAMESPACE
+
+#endif // CONTENTWINDOW_H
diff --git a/src/shared/help/filternamedialog.cpp b/src/shared/help/filternamedialog.cpp
new file mode 100644
index 0000000000..74d1b00187
--- /dev/null
+++ b/src/shared/help/filternamedialog.cpp
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include <QtGui/QPushButton>
+
+#include "filternamedialog.h"
+
+QT_BEGIN_NAMESPACE
+
+FilterNameDialog::FilterNameDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ m_ui.setupUi(this);
+ connect(m_ui.buttonBox->button(QDialogButtonBox::Ok),
+ SIGNAL(clicked()), this, SLOT(accept()));
+ connect(m_ui.buttonBox->button(QDialogButtonBox::Cancel),
+ SIGNAL(clicked()), this, SLOT(reject()));
+ connect(m_ui.lineEdit, SIGNAL(textChanged(QString)),
+ this, SLOT(updateOkButton()));
+ m_ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(true);
+
+}
+
+QString FilterNameDialog::filterName() const
+{
+ return m_ui.lineEdit->text();
+}
+
+void FilterNameDialog::updateOkButton()
+{
+ m_ui.buttonBox->button(QDialogButtonBox::Ok)
+ ->setDisabled(m_ui.lineEdit->text().isEmpty());
+}
+
+QT_END_NAMESPACE
diff --git a/src/shared/help/filternamedialog.h b/src/shared/help/filternamedialog.h
new file mode 100644
index 0000000000..00aa1eb485
--- /dev/null
+++ b/src/shared/help/filternamedialog.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef FILTERNAMEDIALOG_H
+#define FILTERNAMEDIALOG_H
+
+#include <QtGui/QDialog>
+#include "ui_filternamedialog.h"
+
+QT_BEGIN_NAMESPACE
+
+class FilterNameDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ FilterNameDialog(QWidget *parent = 0);
+ QString filterName() const;
+
+private slots:
+ void updateOkButton();
+
+private:
+ Ui::FilterNameDialogClass m_ui;
+};
+
+QT_END_NAMESPACE
+
+#endif // FILTERNAMEDIALOG_H
diff --git a/src/shared/help/filternamedialog.ui b/src/shared/help/filternamedialog.ui
new file mode 100644
index 0000000000..755a934799
--- /dev/null
+++ b/src/shared/help/filternamedialog.ui
@@ -0,0 +1,67 @@
+<ui version="4.0" >
+ <class>FilterNameDialogClass</class>
+ <widget class="QDialog" name="FilterNameDialogClass" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>312</width>
+ <height>95</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Add Filter Name</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Filter Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2" >
+ <widget class="QLineEdit" name="lineEdit" />
+ </item>
+ <item row="1" column="0" colspan="3" >
+ <widget class="Line" name="line" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="2" >
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/shared/help/help.pri b/src/shared/help/help.pri
new file mode 100644
index 0000000000..dff0ae7699
--- /dev/null
+++ b/src/shared/help/help.pri
@@ -0,0 +1,26 @@
+VPATH += $$PWD
+
+INCLUDEPATH *= $$PWD $$PWD/..
+
+# Input
+HEADERS += \
+ $$PWD/filternamedialog.h \
+ $$PWD/topicchooser.h \
+ $$PWD/helpviewer.h \
+ $$PWD/contentwindow.h \
+ $$PWD/bookmarkmanager.h \
+ $$PWD/../namespace_global.h \
+ $$PWD/indexwindow.h
+
+SOURCES += \
+ $$PWD/filternamedialog.cpp \
+ $$PWD/topicchooser.cpp \
+ $$PWD/helpviewer.cpp \
+ $$PWD/indexwindow.cpp \
+ $$PWD/contentwindow.cpp \
+ $$PWD/bookmarkmanager.cpp
+
+FORMS += \
+ $$PWD/filternamedialog.ui \
+ $$PWD/topicchooser.ui \
+ $$PWD/bookmarkdialog.ui
diff --git a/src/shared/help/helpviewer.cpp b/src/shared/help/helpviewer.cpp
new file mode 100644
index 0000000000..ab95e62b8c
--- /dev/null
+++ b/src/shared/help/helpviewer.cpp
@@ -0,0 +1,531 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "helpviewer.h"
+#include "centralwidget.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QEvent>
+#include <QtCore/QVariant>
+#include <QtCore/QByteArray>
+#include <QtCore/QTimer>
+
+#include <QtGui/QMenu>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QClipboard>
+#include <QtGui/QApplication>
+#include <QtGui/QMessageBox>
+#include <QtGui/QDesktopServices>
+
+#include <QtHelp/QHelpEngine>
+
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(QT_NO_WEBKIT)
+
+class HelpNetworkReply : public QNetworkReply
+{
+public:
+ HelpNetworkReply(const QNetworkRequest &request, const QByteArray &fileData,
+ const QString &mimeType);
+
+ virtual void abort();
+
+ virtual qint64 bytesAvailable() const
+ { return data.length() + QNetworkReply::bytesAvailable(); }
+
+protected:
+ virtual qint64 readData(char *data, qint64 maxlen);
+
+private:
+ QByteArray data;
+ qint64 origLen;
+};
+
+HelpNetworkReply::HelpNetworkReply(const QNetworkRequest &request,
+ const QByteArray &fileData, const QString &mimeType)
+ : data(fileData), origLen(fileData.length())
+{
+ setRequest(request);
+ setOpenMode(QIODevice::ReadOnly);
+
+ setHeader(QNetworkRequest::ContentTypeHeader, mimeType);
+ setHeader(QNetworkRequest::ContentLengthHeader, QByteArray::number(origLen));
+ QTimer::singleShot(0, this, SIGNAL(metaDataChanged()));
+ QTimer::singleShot(0, this, SIGNAL(readyRead()));
+}
+
+void HelpNetworkReply::abort()
+{
+ // nothing to do
+}
+
+qint64 HelpNetworkReply::readData(char *buffer, qint64 maxlen)
+{
+ qint64 len = qMin(qint64(data.length()), maxlen);
+ if (len) {
+ qMemCopy(buffer, data.constData(), len);
+ data.remove(0, len);
+ }
+ if (!data.length())
+ QTimer::singleShot(0, this, SIGNAL(finished()));
+ return len;
+}
+
+class HelpNetworkAccessManager : public QNetworkAccessManager
+{
+public:
+ HelpNetworkAccessManager(QHelpEngine *engine, QObject *parent);
+
+protected:
+ virtual QNetworkReply *createRequest(Operation op,
+ const QNetworkRequest &request, QIODevice *outgoingData = 0);
+
+private:
+ QHelpEngine *helpEngine;
+};
+
+HelpNetworkAccessManager::HelpNetworkAccessManager(QHelpEngine *engine,
+ QObject *parent)
+ : QNetworkAccessManager(parent), helpEngine(engine)
+{
+}
+
+QNetworkReply *HelpNetworkAccessManager::createRequest(Operation op,
+ const QNetworkRequest &request, QIODevice *outgoingData)
+{
+ const QString& scheme = request.url().scheme();
+ if (scheme == QLatin1String("qthelp") || scheme == QLatin1String("about")) {
+ const QUrl& url = request.url();
+ QString mimeType = url.toString();
+ if (mimeType.endsWith(QLatin1String(".svg"))
+ || mimeType.endsWith(QLatin1String(".svgz"))) {
+ mimeType = QLatin1String("image/svg+xml");
+ }
+ else if (mimeType.endsWith(QLatin1String(".css"))) {
+ mimeType = QLatin1String("text/css");
+ }
+ else if (mimeType.endsWith(QLatin1String(".js"))) {
+ mimeType = QLatin1String("text/javascript");
+ } else {
+ mimeType = QLatin1String("text/html");
+ }
+ return new HelpNetworkReply(request, helpEngine->fileData(url), mimeType);
+ }
+ return QNetworkAccessManager::createRequest(op, request, outgoingData);
+}
+
+class HelpPage : public QWebPage
+{
+public:
+ HelpPage(CentralWidget *central, QHelpEngine *engine, QObject *parent);
+
+protected:
+ virtual QWebPage *createWindow(QWebPage::WebWindowType);
+
+ virtual bool acceptNavigationRequest(QWebFrame *frame,
+ const QNetworkRequest &request, NavigationType type);
+
+private:
+ CentralWidget *centralWidget;
+ QHelpEngine *helpEngine;
+};
+
+HelpPage::HelpPage(CentralWidget *central, QHelpEngine *engine, QObject *parent)
+ : QWebPage(parent), centralWidget(central), helpEngine(engine)
+{
+}
+
+QWebPage *HelpPage::createWindow(QWebPage::WebWindowType)
+{
+ return centralWidget->newEmptyTab()->page();
+}
+
+static bool isLocalUrl(const QUrl &url)
+{
+ const QString scheme = url.scheme();
+ if (scheme.isEmpty()
+ || scheme == QLatin1String("file")
+ || scheme == QLatin1String("qrc")
+ || scheme == QLatin1String("data")
+ || scheme == QLatin1String("qthelp")
+ || scheme == QLatin1String("about"))
+ return true;
+ return false;
+}
+
+bool HelpPage::acceptNavigationRequest(QWebFrame *,
+ const QNetworkRequest &request, QWebPage::NavigationType)
+{
+ const QUrl &url = request.url();
+ if (isLocalUrl(url)) {
+ if (url.path().endsWith(QLatin1String("pdf"))) {
+ QString fileName = url.toString();
+ fileName = QDir::tempPath() + QDir::separator() + fileName.right
+ (fileName.length() - fileName.lastIndexOf(QChar('/')));
+
+ QFile tmpFile(QDir::cleanPath(fileName));
+ if (tmpFile.open(QIODevice::ReadWrite)) {
+ tmpFile.write(helpEngine->fileData(url));
+ tmpFile.close();
+ }
+ QDesktopServices::openUrl(QUrl(tmpFile.fileName()));
+ return false;
+ }
+ return true;
+ }
+
+ QDesktopServices::openUrl(url);
+ return false;
+}
+
+HelpViewer::HelpViewer(QHelpEngine *engine, CentralWidget *parent)
+ : QWebView(parent), helpEngine(engine), parentWidget(parent)
+{
+ setPage(new HelpPage(parent, helpEngine, this));
+
+ page()->setNetworkAccessManager(new HelpNetworkAccessManager(engine, this));
+
+ QAction* action = pageAction(QWebPage::OpenLinkInNewWindow);
+ action->setText(tr("Open Link in New Tab"));
+ if (!parent)
+ action->setVisible(false);
+
+ pageAction(QWebPage::DownloadLinkToDisk)->setVisible(false);
+ pageAction(QWebPage::DownloadImageToDisk)->setVisible(false);
+ pageAction(QWebPage::OpenImageInNewWindow)->setVisible(false);
+
+ connect(pageAction(QWebPage::Copy), SIGNAL(changed()), this,
+ SLOT(actionChanged()));
+ connect(pageAction(QWebPage::Back), SIGNAL(changed()), this,
+ SLOT(actionChanged()));
+ connect(pageAction(QWebPage::Forward), SIGNAL(changed()), this,
+ SLOT(actionChanged()));
+ connect(page(), SIGNAL(linkHovered(QString, QString, QString)), this,
+ SIGNAL(highlighted(QString)));
+ connect(this, SIGNAL(urlChanged(QUrl)), this, SIGNAL(sourceChanged(QUrl)));
+}
+
+void HelpViewer::setSource(const QUrl &url)
+{
+ if (!homeUrl.isValid())
+ homeUrl = url;
+ load(url);
+}
+
+void HelpViewer::resetZoom()
+{
+ setTextSizeMultiplier(1.0);
+}
+
+void HelpViewer::zoomIn(qreal range)
+{
+ setTextSizeMultiplier(textSizeMultiplier() + range / 10.0);
+}
+
+void HelpViewer::zoomOut(qreal range)
+{
+ setTextSizeMultiplier(qMax(0.0, textSizeMultiplier() - range / 10.0));
+}
+
+void HelpViewer::home()
+{
+ if (homeUrl.isValid())
+ setSource(homeUrl);
+}
+
+void HelpViewer::wheelEvent(QWheelEvent *e)
+{
+ if (e->modifiers() & Qt::ControlModifier) {
+ const int delta = e->delta();
+ if (delta > 0)
+ zoomIn(delta / 120);
+ else if (delta < 0)
+ zoomOut(-delta / 120);
+ e->accept();
+ return;
+ }
+ QWebView::wheelEvent(e);
+}
+
+void HelpViewer::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (e->button() == Qt::XButton1) {
+ triggerPageAction(QWebPage::Back);
+ return;
+ }
+
+ if (e->button() == Qt::XButton2) {
+ triggerPageAction(QWebPage::Forward);
+ return;
+ }
+
+ QWebView::mouseReleaseEvent(e);
+}
+
+void HelpViewer::actionChanged()
+{
+ QAction *a = qobject_cast<QAction *>(sender());
+ if (a == pageAction(QWebPage::Copy))
+ emit copyAvailable(a->isEnabled());
+ else if (a == pageAction(QWebPage::Back))
+ emit backwardAvailable(a->isEnabled());
+ else if (a == pageAction(QWebPage::Forward))
+ emit forwardAvailable(a->isEnabled());
+}
+
+#else // !defined(QT_NO_WEBKIT)
+
+HelpViewer::HelpViewer(QHelpEngine *engine, CentralWidget *parent)
+ : QTextBrowser(parent)
+ , zoomCount(0)
+ , controlPressed(false)
+ , lastAnchor(QString())
+ , helpEngine(engine)
+ , parentWidget(parent)
+{
+ document()->setDocumentMargin(8);
+}
+
+void HelpViewer::setSource(const QUrl &url)
+{
+ bool help = url.toString() == QLatin1String("help");
+ if (url.isValid() && !help) {
+ if (launchedWithExternalApp(url))
+ return;
+
+ QUrl u = helpEngine->findFile(url);
+ if (u.isValid()) {
+ if (!homeUrl.isValid())
+ homeUrl = url;
+ QTextBrowser::setSource(u);
+ return;
+ }
+ }
+
+ if (help) {
+ QTextBrowser::setSource(QUrl(QLatin1String("qthelp://com.trolltech.com."
+ "assistantinternal_1.0.0/assistant/assistant.html")));
+ } else {
+ QTextBrowser::setSource(url);
+ setHtml(tr("<title>Error 404...</title><div align=\"center\"><br><br>"
+ "<h1>The page could not be found</h1><br><h3>'%1'</h3></div>")
+ .arg(url.toString()));
+ emit sourceChanged(url);
+ }
+}
+
+void HelpViewer::resetZoom()
+{
+ if (zoomCount == 0)
+ return;
+
+ QTextBrowser::zoomOut(zoomCount);
+ zoomCount = 0;
+}
+
+void HelpViewer::zoomIn(int range)
+{
+ if (zoomCount == 10)
+ return;
+
+ QTextBrowser::zoomIn(range);
+ zoomCount++;
+}
+
+void HelpViewer::zoomOut(int range)
+{
+ if (zoomCount == -5)
+ return;
+
+ QTextBrowser::zoomOut(range);
+ zoomCount--;
+}
+
+bool HelpViewer::launchedWithExternalApp(const QUrl &url)
+{
+ bool isPdf = url.path().endsWith(QLatin1String("pdf"));
+ if (url.scheme() == QLatin1String("http")
+ || url.scheme() == QLatin1String("ftp")
+ || url.scheme() == QLatin1String("mailto") || isPdf) {
+ bool launched = false;
+ if (isPdf && url.scheme() == QLatin1String("qthelp")) {
+ QString fileName = url.toString();
+ fileName = QDir::tempPath() + QDir::separator() + fileName.right
+ (fileName.length() - fileName.lastIndexOf(QChar('/')));
+
+ QFile tmpFile(QDir::cleanPath(fileName));
+ if (tmpFile.open(QIODevice::ReadWrite)) {
+ tmpFile.write(helpEngine->fileData(url));
+ tmpFile.close();
+ }
+ launched = QDesktopServices::openUrl(QUrl(tmpFile.fileName()));
+ } else {
+ launched = QDesktopServices::openUrl(url);
+ }
+
+ if (!launched) {
+ QMessageBox::information(this, tr("Help"),
+ tr("Unable to launch external application.\n"), tr("OK"));
+ }
+ return true;
+ }
+ return false;
+}
+
+QVariant HelpViewer::loadResource(int type, const QUrl &name)
+{
+ QByteArray ba;
+ if (type < 4) {
+ ba = helpEngine->fileData(name);
+ if (name.toString().endsWith(QLatin1String(".svg"), Qt::CaseInsensitive)) {
+ QImage image;
+ image.loadFromData(ba, "svg");
+ if (!image.isNull())
+ return image;
+ }
+ }
+ return ba;
+}
+
+void HelpViewer::openLinkInNewTab()
+{
+ if (lastAnchor.isEmpty())
+ return;
+
+ parentWidget->setSourceInNewTab(QUrl(lastAnchor));
+ lastAnchor.clear();
+}
+
+void HelpViewer::openLinkInNewTab(const QString &link)
+{
+ lastAnchor = link;
+ openLinkInNewTab();
+}
+
+bool HelpViewer::hasAnchorAt(const QPoint& pos)
+{
+ lastAnchor = anchorAt(pos);
+ if (lastAnchor.isEmpty())
+ return false;
+
+ lastAnchor = source().resolved(lastAnchor).toString();
+ if (lastAnchor.at(0) == QLatin1Char('#')) {
+ QString src = source().toString();
+ int hsh = src.indexOf(QLatin1Char('#'));
+ lastAnchor = (hsh>=0 ? src.left(hsh) : src) + lastAnchor;
+ }
+
+ return true;
+}
+
+void HelpViewer::contextMenuEvent(QContextMenuEvent *e)
+{
+ QMenu menu(QLatin1String(""), 0);
+
+ QUrl link;
+ QAction *copyAnchorAction = 0;
+ if (hasAnchorAt(e->pos())) {
+ link = anchorAt(e->pos());
+ if (link.isRelative())
+ link = source().resolved(link);
+ copyAnchorAction = menu.addAction(tr("Copy &Link Location"));
+ copyAnchorAction->setEnabled(!link.isEmpty() && link.isValid());
+
+ menu.addAction(tr("Open Link in New Tab\tCtrl+LMB"), this,
+ SLOT(openLinkInNewTab()));
+ menu.addSeparator();
+ }
+ menu.addActions(parentWidget->globalActions());
+ QAction *action = menu.exec(e->globalPos());
+ if (action == copyAnchorAction)
+ QApplication::clipboard()->setText(link.toString());
+}
+
+void HelpViewer::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (e->button() == Qt::XButton1) {
+ QTextBrowser::backward();
+ return;
+ }
+
+ if (e->button() == Qt::XButton2) {
+ QTextBrowser::forward();
+ return;
+ }
+
+ controlPressed = e->modifiers() & Qt::ControlModifier;
+ if ((controlPressed && hasAnchorAt(e->pos())) ||
+ (e->button() == Qt::MidButton && hasAnchorAt(e->pos()))) {
+ openLinkInNewTab();
+ return;
+ }
+
+ QTextBrowser::mouseReleaseEvent(e);
+}
+
+void HelpViewer::keyPressEvent(QKeyEvent *e)
+{
+ if ((e->key() == Qt::Key_Home && e->modifiers() != Qt::NoModifier)
+ || (e->key() == Qt::Key_End && e->modifiers() != Qt::NoModifier)) {
+ QKeyEvent* event = new QKeyEvent(e->type(), e->key(), Qt::NoModifier,
+ e->text(), e->isAutoRepeat(), e->count());
+ e = event;
+ }
+ QTextBrowser::keyPressEvent(e);
+}
+
+void HelpViewer::home()
+{
+ if (homeUrl.isValid())
+ setSource(homeUrl);
+}
+
+void HelpViewer::wheelEvent(QWheelEvent *e)
+{
+ if (e->modifiers() == Qt::CTRL) {
+ e->accept();
+ (e->delta() > 0) ? zoomIn() : zoomOut();
+ } else {
+ e->ignore();
+ QTextBrowser::wheelEvent(e);
+ }
+}
+
+#endif // !defined(QT_NO_WEBKIT)
+
+QT_END_NAMESPACE
diff --git a/src/shared/help/helpviewer.h b/src/shared/help/helpviewer.h
new file mode 100644
index 0000000000..b268fa260c
--- /dev/null
+++ b/src/shared/help/helpviewer.h
@@ -0,0 +1,163 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef HELPVIEWER_H
+#define HELPVIEWER_H
+
+#include <QtCore/QUrl>
+#include <QtCore/QVariant>
+#include <QtGui/QTextBrowser>
+#include <QtGui/QAction>
+
+#if !defined(QT_NO_WEBKIT)
+#include <QWebView>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QHelpEngine;
+class CentralWidget;
+
+class QPoint;
+class QString;
+class QKeyEvent;
+class QMouseEvent;
+class QContextMenuEvent;
+
+#if !defined(QT_NO_WEBKIT)
+
+class HelpViewer : public QWebView
+{
+ Q_OBJECT
+
+public:
+ HelpViewer(QHelpEngine *helpEngine, CentralWidget *parent);
+ void setSource(const QUrl &url);
+
+ inline QUrl source() const
+ { return url(); }
+
+ inline QString documentTitle() const
+ { return title(); }
+
+ inline bool hasSelection() const
+ { return !selectedText().isEmpty(); } // ### this is suboptimal
+
+ void resetZoom();
+ void zoomIn(qreal range = 1);
+ void zoomOut(qreal range = 1);
+
+ inline void copy()
+ { return triggerPageAction(QWebPage::Copy); }
+
+ inline bool isForwardAvailable() const
+ { return pageAction(QWebPage::Forward)->isEnabled(); }
+ inline bool isBackwardAvailable() const
+ { return pageAction(QWebPage::Back)->isEnabled(); }
+
+public Q_SLOTS:
+ void home();
+ void backward() { back(); }
+
+Q_SIGNALS:
+ void copyAvailable(bool enabled);
+ void forwardAvailable(bool enabled);
+ void backwardAvailable(bool enabled);
+ void highlighted(const QString &);
+ void sourceChanged(const QUrl &);
+
+protected:
+ virtual void wheelEvent(QWheelEvent *);
+ void mouseReleaseEvent(QMouseEvent *e);
+
+private Q_SLOTS:
+ void actionChanged();
+
+private:
+ QHelpEngine *helpEngine;
+ CentralWidget* parentWidget;
+ QUrl homeUrl;
+};
+
+#else
+
+class HelpViewer : public QTextBrowser
+{
+ Q_OBJECT
+
+public:
+ HelpViewer(QHelpEngine *helpEngine, CentralWidget *parent);
+ void setSource(const QUrl &url);
+
+ void resetZoom();
+ void zoomIn(int range = 1);
+ void zoomOut(int range = 1);
+ int zoom() const { return zoomCount; }
+ void setZoom(int zoom) { zoomCount = zoom; }
+
+ inline bool hasSelection() const
+ { return textCursor().hasSelection(); }
+
+ bool launchedWithExternalApp(const QUrl &url);
+
+public Q_SLOTS:
+ void home();
+
+protected:
+ void wheelEvent(QWheelEvent *e);
+
+private:
+ QVariant loadResource(int type, const QUrl &name);
+ void openLinkInNewTab(const QString &link);
+ bool hasAnchorAt(const QPoint& pos);
+ void contextMenuEvent(QContextMenuEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+
+private slots:
+ void openLinkInNewTab();
+
+private:
+ int zoomCount;
+ bool controlPressed;
+ QString lastAnchor;
+ QHelpEngine *helpEngine;
+ CentralWidget* parentWidget;
+ QUrl homeUrl;
+};
+
+#endif
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/shared/help/indexwindow.cpp b/src/shared/help/indexwindow.cpp
new file mode 100644
index 0000000000..f55148c91d
--- /dev/null
+++ b/src/shared/help/indexwindow.cpp
@@ -0,0 +1,208 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "indexwindow.h"
+#include "centralwidget.h"
+#include "topicchooser.h"
+
+#include <QtGui/QLayout>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QMenu>
+#include <QtGui/QContextMenuEvent>
+#include <QtGui/QListWidgetItem>
+
+#include <QtHelp/QHelpEngine>
+#include <QtHelp/QHelpIndexWidget>
+
+QT_BEGIN_NAMESPACE
+
+IndexWindow::IndexWindow(QHelpEngine *helpEngine, QWidget *parent)
+ : QWidget(parent)
+ , m_searchLineEdit(0)
+ , m_indexWidget(0)
+ , m_helpEngine(helpEngine)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ QLabel *l = new QLabel(tr("&Look for:"));
+ layout->addWidget(l);
+
+ m_searchLineEdit = new QLineEdit();
+ l->setBuddy(m_searchLineEdit);
+ connect(m_searchLineEdit, SIGNAL(textChanged(QString)), this,
+ SLOT(filterIndices(QString)));
+ m_searchLineEdit->installEventFilter(this);
+ layout->setMargin(4);
+ layout->addWidget(m_searchLineEdit);
+
+ m_indexWidget = m_helpEngine->indexWidget();
+ m_indexWidget->installEventFilter(this);
+ connect(m_helpEngine->indexModel(), SIGNAL(indexCreationStarted()), this,
+ SLOT(disableSearchLineEdit()));
+ connect(m_helpEngine->indexModel(), SIGNAL(indexCreated()), this,
+ SLOT(enableSearchLineEdit()));
+ connect(m_indexWidget, SIGNAL(linkActivated(QUrl, QString)), this,
+ SIGNAL(linkActivated(QUrl)));
+ connect(m_indexWidget, SIGNAL(linksActivated(QMap<QString, QUrl>, QString)),
+ this, SIGNAL(linksActivated(QMap<QString, QUrl>, QString)));
+ connect(m_searchLineEdit, SIGNAL(returnPressed()), m_indexWidget,
+ SLOT(activateCurrentItem()));
+ layout->addWidget(m_indexWidget);
+
+ m_indexWidget->viewport()->installEventFilter(this);
+}
+
+IndexWindow::~IndexWindow()
+{
+}
+
+void IndexWindow::filterIndices(const QString &filter)
+{
+ if (filter.contains(QLatin1Char('*')))
+ m_indexWidget->filterIndices(filter, filter);
+ else
+ m_indexWidget->filterIndices(filter, QString());
+}
+
+bool IndexWindow::eventFilter(QObject *obj, QEvent *e)
+{
+ if (obj == m_searchLineEdit && e->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+ QModelIndex idx = m_indexWidget->currentIndex();
+ switch (ke->key()) {
+ case Qt::Key_Up:
+ idx = m_indexWidget->model()->index(idx.row()-1,
+ idx.column(), idx.parent());
+ if (idx.isValid())
+ m_indexWidget->setCurrentIndex(idx);
+ break;
+ case Qt::Key_Down:
+ idx = m_indexWidget->model()->index(idx.row()+1,
+ idx.column(), idx.parent());
+ if (idx.isValid())
+ m_indexWidget->setCurrentIndex(idx);
+ break;
+ case Qt::Key_Escape:
+ emit escapePressed();
+ break;
+ default:
+ ;
+ }
+ } else if (obj == m_indexWidget && e->type() == QEvent::ContextMenu) {
+ QContextMenuEvent *ctxtEvent = static_cast<QContextMenuEvent*>(e);
+ QModelIndex idx = m_indexWidget->indexAt(ctxtEvent->pos());
+ if (idx.isValid()) {
+ QMenu menu;
+ QAction *curTab = menu.addAction(tr("Open Link"));
+ QAction *newTab = menu.addAction(tr("Open Link in New Tab"));
+ menu.move(m_indexWidget->mapToGlobal(ctxtEvent->pos()));
+
+ QAction *action = menu.exec();
+ if (curTab == action)
+ m_indexWidget->activateCurrentItem();
+ else if (newTab == action) {
+ QHelpIndexModel *model =
+ qobject_cast<QHelpIndexModel*>(m_indexWidget->model());
+ QString keyword = model->data(idx, Qt::DisplayRole).toString();
+ if (model) {
+ QMap<QString, QUrl> links = model->linksForKeyword(keyword);
+ if (links.count() == 1) {
+ CentralWidget::instance()->
+ setSourceInNewTab(links.constBegin().value());
+ } else {
+ TopicChooser tc(this, keyword, links);
+ if (tc.exec() == QDialog::Accepted) {
+ CentralWidget::instance()->setSourceInNewTab(tc.link());
+ }
+ }
+ }
+ }
+ }
+ } else if (m_indexWidget && obj == m_indexWidget->viewport()
+ && e->type() == QEvent::MouseButtonRelease) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e);
+ QModelIndex idx = m_indexWidget->indexAt(mouseEvent->pos());
+ if (idx.isValid() && mouseEvent->button()==Qt::MidButton) {
+ QHelpIndexModel *model =
+ qobject_cast<QHelpIndexModel*>(m_indexWidget->model());
+ QString keyword = model->data(idx, Qt::DisplayRole).toString();
+ if (model) {
+ QMap<QString, QUrl> links = model->linksForKeyword(keyword);
+ if (links.count() > 1) {
+ TopicChooser tc(this, keyword, links);
+ if (tc.exec() == QDialog::Accepted) {
+ CentralWidget::instance()->setSourceInNewTab(tc.link());
+ }
+ } else {
+ CentralWidget::instance()->
+ setSourceInNewTab(links.constBegin().value());
+ }
+ }
+ }
+ }
+#ifdef Q_OS_MAC
+ else if (obj == m_indexWidget && e->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+ if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter)
+ m_indexWidget->activateCurrentItem();
+ }
+#endif
+ return QWidget::eventFilter(obj, e);
+}
+
+void IndexWindow::enableSearchLineEdit()
+{
+ m_searchLineEdit->setDisabled(false);
+ filterIndices(m_searchLineEdit->text());
+}
+
+void IndexWindow::disableSearchLineEdit()
+{
+ m_searchLineEdit->setDisabled(true);
+}
+
+void IndexWindow::setSearchLineEditText(const QString &text)
+{
+ m_searchLineEdit->setText(text);
+}
+
+void IndexWindow::focusInEvent(QFocusEvent *e)
+{
+ if (e->reason() != Qt::MouseFocusReason) {
+ m_searchLineEdit->selectAll();
+ m_searchLineEdit->setFocus();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/shared/help/indexwindow.h b/src/shared/help/indexwindow.h
new file mode 100644
index 0000000000..19cbca8b24
--- /dev/null
+++ b/src/shared/help/indexwindow.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef INDEXWINDOW_H
+#define INDEXWINDOW_H
+
+#include <QtCore/QUrl>
+#include <QtGui/QWidget>
+#include <QtGui/QLineEdit>
+
+QT_BEGIN_NAMESPACE
+
+class QHelpIndexWidget;
+class QHelpEngine;
+
+class IndexWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ IndexWindow(QHelpEngine *helpEngine, QWidget *parent = 0);
+ ~IndexWindow();
+
+ void setSearchLineEditText(const QString &text);
+ QString searchLineEditText() const
+ {
+ return m_searchLineEdit->text();
+ }
+
+signals:
+ void linkActivated(const QUrl &link);
+ void linksActivated(const QMap<QString, QUrl> &links,
+ const QString &keyword);
+ void escapePressed();
+
+private slots:
+ void filterIndices(const QString &filter);
+ void enableSearchLineEdit();
+ void disableSearchLineEdit();
+
+private:
+ bool eventFilter(QObject *obj, QEvent *e);
+ void focusInEvent(QFocusEvent *e);
+
+ QLineEdit *m_searchLineEdit;
+ QHelpIndexWidget *m_indexWidget;
+ QHelpEngine *m_helpEngine;
+};
+
+QT_END_NAMESPACE
+
+#endif // INDEXWINDOW_H
diff --git a/src/shared/help/topicchooser.cpp b/src/shared/help/topicchooser.cpp
new file mode 100644
index 0000000000..df9fbf9897
--- /dev/null
+++ b/src/shared/help/topicchooser.cpp
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include <QtCore/QMap>
+#include <QtCore/QUrl>
+
+#include "topicchooser.h"
+
+QT_BEGIN_NAMESPACE
+
+TopicChooser::TopicChooser(QWidget *parent, const QString &keyword,
+ const QMap<QString, QUrl> &links)
+ : QDialog(parent)
+{
+ ui.setupUi(this);
+ ui.label->setText(tr("Choose a topic for <b>%1</b>:").arg(keyword));
+
+ m_links = links;
+ QMap<QString, QUrl>::const_iterator it = m_links.constBegin();
+ for (; it != m_links.constEnd(); ++it)
+ ui.listWidget->addItem(it.key());
+
+ if (ui.listWidget->count() != 0)
+ ui.listWidget->setCurrentRow(0);
+ ui.listWidget->setFocus();
+
+ connect(ui.buttonDisplay, SIGNAL(clicked()),
+ this, SLOT(accept()));
+ connect(ui.buttonCancel, SIGNAL(clicked()),
+ this, SLOT(reject()));
+ connect(ui.listWidget, SIGNAL(itemActivated(QListWidgetItem*)),
+ this, SLOT(accept()));
+}
+
+QUrl TopicChooser::link() const
+{
+ QListWidgetItem *item = ui.listWidget->currentItem();
+ if (!item)
+ return QUrl();
+
+ QString title = item->text();
+ if (title.isEmpty() || !m_links.contains(title))
+ return QUrl();
+
+ return m_links.value(title);
+}
+
+QT_END_NAMESPACE
diff --git a/src/shared/help/topicchooser.h b/src/shared/help/topicchooser.h
new file mode 100644
index 0000000000..37fb3ab14c
--- /dev/null
+++ b/src/shared/help/topicchooser.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef TOPICCHOOSER_H
+#define TOPICCHOOSER_H
+
+#include "ui_topicchooser.h"
+
+#include <QUrl>
+#include <QMap>
+#include <QString>
+
+#include <QtGui/QDialog>
+
+QT_BEGIN_NAMESPACE
+
+class TopicChooser : public QDialog
+{
+ Q_OBJECT
+
+public:
+ TopicChooser(QWidget *parent, const QString &keyword,
+ const QMap<QString, QUrl> &links);
+
+ QUrl link() const;
+
+private:
+ Ui::TopicChooser ui;
+ QMap<QString, QUrl> m_links;
+};
+
+QT_END_NAMESPACE
+
+#endif // TOPICCHOOSER_H
diff --git a/src/shared/help/topicchooser.ui b/src/shared/help/topicchooser.ui
new file mode 100644
index 0000000000..d4c90bb4b3
--- /dev/null
+++ b/src/shared/help/topicchooser.ui
@@ -0,0 +1,116 @@
+<UI version="4.0" stdsetdef="1" >
+ <class>TopicChooser</class>
+ <widget class="QDialog" name="TopicChooser" >
+ <property name="objectName" >
+ <string notr="true">TopicChooser</string>
+ </property>
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>391</width>
+ <height>223</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Choose Topic</string>
+ </property>
+ <property name="sizeGripEnabled" >
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="objectName" >
+ <string notr="true">unnamed</string>
+ </property>
+ <property name="margin" >
+ <number>11</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="objectName" >
+ <string notr="true">label</string>
+ </property>
+ <property name="text" >
+ <string>&amp;Topics</string>
+ </property>
+ <property name="buddy" stdset="0" >
+ <cstring>listWidget</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QListWidget" name="listWidget" >
+ <property name="objectName" >
+ <string notr="true">listWidget</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="Layout16" >
+ <property name="objectName" >
+ <string notr="true">Layout16</string>
+ </property>
+ <layout class="QHBoxLayout" >
+ <property name="objectName" >
+ <string notr="true">unnamed</string>
+ </property>
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <spacer name="Horizontal Spacing2" >
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="sizeType" >
+ <enum>Expanding</enum>
+ </property>
+ <property name="orientation" >
+ <enum>Horizontal</enum>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonDisplay" >
+ <property name="objectName" >
+ <string notr="true">buttonDisplay</string>
+ </property>
+ <property name="text" >
+ <string>&amp;Display</string>
+ </property>
+ <property name="autoDefault" >
+ <bool>true</bool>
+ </property>
+ <property name="default" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonCancel" >
+ <property name="objectName" >
+ <string notr="true">buttonCancel</string>
+ </property>
+ <property name="text" >
+ <string>&amp;Close</string>
+ </property>
+ <property name="autoDefault" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+</UI>
diff --git a/src/shared/indenter/README b/src/shared/indenter/README
new file mode 100644
index 0000000000..deaac0168b
--- /dev/null
+++ b/src/shared/indenter/README
@@ -0,0 +1,9 @@
+C++ / Qt Script indenter based on:
+
+research/qsa/quickport/src/neweditor/yyindent.cpp
+
+Known issues:
+- Using an indentation different from 4 makes it goof up.
+
+History:
+- 070510: Split off the test application and made it work with Qt 4.
diff --git a/src/shared/indenter/constants.cpp b/src/shared/indenter/constants.cpp
new file mode 100644
index 0000000000..ec6b743a3a
--- /dev/null
+++ b/src/shared/indenter/constants.cpp
@@ -0,0 +1,66 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "indenter.h"
+
+using namespace SharedTools::IndenterInternal;
+
+// --- Constants
+Constants::Constants() :
+ m_slashAster(QLatin1String("/*")),
+ m_asterSlash(QLatin1String("*/")),
+ m_slashSlash(QLatin1String("//")),
+ m_else(QLatin1String("else")),
+ m_qobject(QLatin1String("Q_OBJECT")),
+ m_operators(QLatin1String("!=<>")),
+ m_bracesSemicolon(QLatin1String("{};")),
+ m_3dots(QLatin1String("...")),
+
+ m_literal(QLatin1String("([\"'])(?:\\\\.|[^\\\\])*\\1")),
+ m_label(QLatin1String("^\\s*((?:case\\b([^:]|::)+|[a-zA-Z_0-9]+)(?:\\s+slots|\\s+Q_SLOTS)?:)(?!:)")),
+ m_inlineCComment(QLatin1String("/\\*.*\\*/")),
+ m_braceX(QLatin1String("^\\s*\\}\\s*(?:else|catch)\\b")),
+ m_iflikeKeyword(QLatin1String("\\b(?:catch|do|for|if|while|foreach)\\b")),
+ m_caseLabel(QLatin1String("\\s*(?:case\\b(?:[^:]|::)+"
+ "|(?:public|protected|private|signals|Q_SIGNALS|default)(?:\\s+slots|\\s+Q_SLOTS)?\\s*"
+ ")?:.*"))
+{
+ m_literal.setMinimal(true);
+ m_inlineCComment.setMinimal(true);
+ Q_ASSERT(m_literal.isValid());
+ Q_ASSERT(m_label.isValid());
+ Q_ASSERT(m_inlineCComment.isValid());
+ Q_ASSERT(m_braceX.isValid());
+ Q_ASSERT(m_iflikeKeyword.isValid());
+ Q_ASSERT(m_caseLabel.isValid());
+}
diff --git a/src/shared/indenter/indenter.h b/src/shared/indenter/indenter.h
new file mode 100644
index 0000000000..03fb705a7c
--- /dev/null
+++ b/src/shared/indenter/indenter.h
@@ -0,0 +1,145 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef INDENTER_H
+#define INDENTER_H
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+
+namespace SharedTools {
+namespace IndenterInternal {
+/* String constants and regexps required by the indenter. Separate for code cleanliness*/
+struct Constants {
+ Constants();
+ const QString m_slashAster;
+ const QString m_asterSlash;
+ const QString m_slashSlash;
+ const QString m_else;
+ const QString m_qobject;
+ const QString m_operators;
+ const QString m_bracesSemicolon;
+ const QString m_3dots;
+
+ QRegExp m_literal;
+ QRegExp m_label;
+ QRegExp m_inlineCComment;
+ QRegExp m_braceX;
+ QRegExp m_iflikeKeyword;
+ QRegExp m_caseLabel;
+};
+
+/* The "linizer" is a group of functions and variables to iterate
+ * through the source code of the program to indent. The program is
+ * given as a list of strings, with the bottom line being the line to
+ * indent. The actual program might contain extra lines, but those are
+ * uninteresting and not passed over to us. */
+template <class Iterator>
+struct LinizerState {
+
+ QString line;
+ int braceDepth;
+ bool leftBraceFollows;
+
+ Iterator iter;
+ bool inCComment;
+ bool pendingRightBrace;
+};
+}
+
+/* Indenter singleton as a template of a bidirectional input iterator
+ * of a sequence of code lines represented as QString.
+ * When setting the parameters, be careful to
+ * specify the correct template parameters (best use a typedef). */
+template <class Iterator>
+class Indenter {
+ Indenter(const Indenter&);
+ Indenter &operator=(const Indenter&);
+ Indenter();
+
+public:
+
+ ~Indenter();
+
+ static Indenter &instance();
+
+ void setIndentSize(int size);
+ void setTabSize(int size );
+
+ /* Return indentation for the last line of the sequence
+ * based on the previous lines. */
+ int indentForBottomLine(const Iterator &current,
+ const Iterator &programBegin,
+ const Iterator &programEnd,
+ QChar typedIn);
+
+ // Helpers.
+ static bool isOnlyWhiteSpace( const QString& t);
+ static QChar firstNonWhiteSpace( const QString& t );
+
+private:
+ int columnForIndex( const QString& t, int index ) const;
+ int indentOfLine( const QString& t ) const;
+ QString trimmedCodeLine( const QString& t );
+ bool readLine();
+ void startLinizer();
+ bool bottomLineStartsInCComment();
+ int indentWhenBottomLineStartsInCComment() const;
+ bool matchBracelessControlStatement();
+ bool isUnfinishedLine();
+ bool isContinuationLine();
+ int indentForContinuationLine();
+ int indentForStandaloneLine();
+
+ IndenterInternal::Constants m_constants;
+ int ppHardwareTabSize;
+ int ppIndentSize;
+ int ppContinuationIndentSize;
+
+ Iterator yyProgramBegin;
+ Iterator yyProgramEnd;
+
+ typedef typename IndenterInternal::LinizerState<Iterator> LinizerState;
+
+ LinizerState *yyLinizerState ;
+
+ // shorthands
+ const QString *yyLine;
+ const int *yyBraceDepth;
+ const bool *yyLeftBraceFollows;
+};
+}
+
+#include "indenter_impl.h"
+
+#endif // INDENTER_H
diff --git a/src/shared/indenter/indenter.pri b/src/shared/indenter/indenter.pri
new file mode 100644
index 0000000000..3d1d4bbb1d
--- /dev/null
+++ b/src/shared/indenter/indenter.pri
@@ -0,0 +1,5 @@
+INCLUDEPATH *= $$PWD
+
+SOURCES += $$PWD/constants.cpp
+HEADERS += $$PWD/indenter.h \
+ $$PWD/indenter_impl.h
diff --git a/src/shared/indenter/indenter_impl.h b/src/shared/indenter/indenter_impl.h
new file mode 100644
index 0000000000..b09685e44d
--- /dev/null
+++ b/src/shared/indenter/indenter_impl.h
@@ -0,0 +1,1112 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef INDENTER_C
+#define INDENTER_C
+
+/*
+ This file is a self-contained interactive indenter for C++ and Qt
+ Script.
+
+ The general problem of indenting a C++ program is ill posed. On the
+ one hand, an indenter has to analyze programs written in a
+ free-form formal language that is best described in terms of
+ tokens, not characters, not lines. On the other hand, indentation
+ applies to lines and white space characters matter, and otherwise
+ the programs to indent are formally invalid in general, as they are
+ being edited.
+
+ The approach taken here works line by line. We receive a program
+ consisting of N lines or more, and we want to compute the
+ indentation appropriate for the Nth line. Lines beyond the Nth
+ lines are of no concern to us, so for simplicity we pretend the
+ program has exactly N lines and we call the Nth line the "bottom
+ line". Typically, we have to indent the bottom line when it's still
+ empty, so we concentrate our analysis on the N - 1 lines that
+ precede.
+
+ By inspecting the (N - 1)-th line, the (N - 2)-th line, ...
+ backwards, we determine the kind of the bottom line and indent it
+ accordingly.
+
+ * The bottom line is a comment line. See
+ bottomLineStartsInCComment() and
+ indentWhenBottomLineStartsInCComment().
+ * The bottom line is a continuation line. See isContinuationLine()
+ and indentForContinuationLine().
+ * The bottom line is a standalone line. See
+ indentForStandaloneLine().
+
+ Certain tokens that influence the indentation, notably braces, are
+ looked for in the lines. This is done by simple string comparison,
+ without a real tokenizer. Confusing constructs such as comments and
+ string literals are removed beforehand.
+*/
+
+namespace SharedTools {
+
+/* qmake ignore Q_OBJECT */
+
+/*
+ The indenter avoids getting stuck in almost infinite loops by
+ imposing arbitrary limits on the number of lines it analyzes when
+ looking for a construct.
+
+ For example, the indenter never considers more than BigRoof lines
+ backwards when looking for the start of a C-style comment.
+*/
+namespace {
+ enum { SmallRoof = 40, BigRoof = 400 };
+
+/*
+ The indenter supports a few parameters:
+
+ * ppHardwareTabSize is the size of a '\t' in your favorite editor.
+ * ppIndentSize is the size of an indentation, or software tab
+ size.
+ * ppContinuationIndentSize is the extra indent for a continuation
+ line, when there is nothing to align against on the previous
+ line.
+ * ppCommentOffset is the indentation within a C-style comment,
+ when it cannot be picked up.
+*/
+
+
+ enum { ppCommentOffset = 2 };
+}
+
+template <class Iterator>
+Indenter<Iterator>::Indenter() :
+ ppHardwareTabSize(8),
+ ppIndentSize(4),
+ ppContinuationIndentSize(8),
+ yyLinizerState(new LinizerState),
+ yyLine(0),
+ yyBraceDepth(0),
+ yyLeftBraceFollows(0)
+{
+}
+
+template <class Iterator>
+Indenter<Iterator>::~Indenter()
+{
+ delete yyLinizerState;
+}
+
+template <class Iterator>
+Indenter<Iterator> &Indenter<Iterator>::instance()
+{
+ static Indenter rc;
+ return rc;
+}
+
+template <class Iterator>
+void Indenter<Iterator>::setIndentSize(int size)
+{
+ ppIndentSize = size;
+ ppContinuationIndentSize = 2 * size;
+}
+
+template <class Iterator>
+void Indenter<Iterator>::setTabSize(int size )
+{
+ ppHardwareTabSize = size;
+}
+/*
+ Returns the first non-space character in the string t, or
+ QChar::null if the string is made only of white space.
+*/
+template <class Iterator>
+QChar Indenter<Iterator>::firstNonWhiteSpace( const QString& t )
+{
+ if (const int len = t.length())
+ for ( int i = 0; i < len; i++)
+ if ( !t[i].isSpace() )
+ return t[i];
+ return QChar::Null;
+}
+
+/*
+ Returns true if string t is made only of white space; otherwise
+ returns false.
+*/
+template <class Iterator>
+bool Indenter<Iterator>::isOnlyWhiteSpace( const QString& t )
+{
+ return t.isEmpty() || firstNonWhiteSpace( t ).isNull();
+}
+
+/*
+ Assuming string t is a line, returns the column number of a given
+ index. Column numbers and index are identical for strings that don't
+ contain '\t's.
+*/
+template <class Iterator>
+int Indenter<Iterator>::columnForIndex( const QString& t, int index ) const
+{
+ int col = 0;
+ if ( index > t.length() )
+ index = t.length();
+
+ const QChar tab = QLatin1Char('\t');
+
+ for ( int i = 0; i < index; i++ ) {
+ if ( t[i] == tab ) {
+ col = ( (col / ppHardwareTabSize) + 1 ) * ppHardwareTabSize;
+ } else {
+ col++;
+ }
+ }
+ return col;
+}
+
+/*
+ Returns the indentation size of string t.
+*/
+template <class Iterator>
+int Indenter<Iterator>::indentOfLine( const QString& t ) const
+{
+ return columnForIndex( t, t.indexOf(firstNonWhiteSpace(t)) );
+}
+
+/*
+ Replaces t[k] by ch, unless t[k] is '\t'. Tab characters are better
+ left alone since they break the "index equals column" rule. No
+ provisions are taken against '\n' or '\r', which shouldn't occur in
+ t anyway.
+*/
+static inline void eraseChar( QString& t, int k, QChar ch )
+{
+ if ( t[k] != QLatin1Char('\t') )
+ t[k] = ch;
+}
+
+/*
+ Removes some nefast constructs from a code line and returns the
+ resulting line.
+*/
+template <class Iterator>
+QString Indenter<Iterator>::trimmedCodeLine( const QString& t )
+{
+ QString trimmed = t;
+ int k;
+
+ const QChar capitalX = QLatin1Char('X');
+ const QChar blank = QLatin1Char(' ');
+ const QChar colon = QLatin1Char(':');
+ const QChar semicolon = QLatin1Char(';');
+ /*
+ Replace character and string literals by X's, since they may
+ contain confusing characters (such as '{' and ';'). "Hello!" is
+ replaced by XXXXXXXX. The literals are rigourously of the same
+ length before and after; otherwise, we would break alignment of
+ continuation lines.
+ */
+ k = 0;
+ while ( (k = m_constants.m_literal.indexIn(trimmed), k) != -1 ) {
+ const int matchedLength = m_constants.m_literal.matchedLength();
+ for ( int i = 0; i < matchedLength ; i++ )
+ eraseChar( trimmed, k + i, capitalX );
+ k += matchedLength;
+ }
+
+ /*
+ Replace inline C-style comments by spaces. Other comments are
+ handled elsewhere.
+ */
+ k = 0;
+ while ( (k = m_constants.m_inlineCComment.indexIn(trimmed, k)) != -1 ) {
+ const int matchedLength = m_constants.m_inlineCComment.matchedLength();
+ for ( int i = 0; i < matchedLength; i++ )
+ eraseChar( trimmed, k + i, blank );
+ k += matchedLength;
+ }
+
+ /*
+ Replace goto and switch labels by whitespace, but be careful
+ with this case:
+
+ foo1: bar1;
+ bar2;
+ */
+ while ( trimmed.lastIndexOf(colon ) != -1 && m_constants.m_label.indexIn(trimmed) != -1 ) {
+ const QString cap1 = m_constants.m_label.cap( 1 );
+ const int pos1 = m_constants.m_label.pos( 1 );
+ int stop = cap1.length();
+
+ if ( pos1 + stop < trimmed.length() && ppIndentSize < stop )
+ stop = ppIndentSize;
+
+ int i = 0;
+ while ( i < stop ) {
+ eraseChar( trimmed, pos1 + i, blank );
+ i++;
+ }
+ while ( i < cap1.length() ) {
+ eraseChar( trimmed, pos1 + i,semicolon );
+ i++;
+ }
+ }
+
+ /*
+ Remove C++-style comments.
+ */
+ k = trimmed.indexOf(m_constants.m_slashSlash );
+ if ( k != -1 )
+ trimmed.truncate( k );
+
+ return trimmed;
+}
+
+/*
+ Returns '(' if the last parenthesis is opening, ')' if it is
+ closing, and QChar::null if there are no parentheses in t.
+*/
+static inline QChar lastParen( const QString& t )
+{
+
+ const QChar opening = QLatin1Char('(');
+ const QChar closing = QLatin1Char(')');
+
+
+ int i = t.length();
+ while ( i > 0 ) {
+ i--;
+ const QChar c = t[i];
+ if (c == opening || c == closing )
+ return c;
+ }
+ return QChar::Null;
+}
+
+/*
+ Returns true if typedIn the same as okayCh or is null; otherwise
+ returns false.
+*/
+static inline bool okay( QChar typedIn, QChar okayCh )
+{
+ return typedIn == QChar::Null || typedIn == okayCh;
+}
+
+
+/*
+ Saves and restores the state of the global linizer. This enables
+ backtracking.
+*/
+#define YY_SAVE() \
+ LinizerState savedState = *yyLinizerState
+#define YY_RESTORE() \
+ *yyLinizerState = savedState
+
+/*
+ Advances to the previous line in yyProgram and update yyLine
+ accordingly. yyLine is cleaned from comments and other damageable
+ constructs. Empty lines are skipped.
+*/
+template <class Iterator>
+bool Indenter<Iterator>::readLine()
+{
+ int k;
+
+ const QChar openingBrace = QLatin1Char('{');
+ const QChar closingBrace = QLatin1Char('}');
+ const QChar blank = QLatin1Char(' ');
+ const QChar hash = QLatin1Char('#');
+
+ yyLinizerState->leftBraceFollows =
+ ( firstNonWhiteSpace(yyLinizerState->line) == openingBrace );
+
+ do {
+ if ( yyLinizerState->iter == yyProgramBegin ) {
+ yyLinizerState->line = QString::null;
+ return false;
+ }
+
+ --yyLinizerState->iter;
+ yyLinizerState->line = *yyLinizerState->iter;
+
+ yyLinizerState->line = trimmedCodeLine( yyLinizerState->line );
+
+ /*
+ Remove C-style comments that span multiple lines. If the
+ bottom line starts in a C-style comment, we are not aware
+ of that and eventually yyLine will contain a slash-aster.
+
+ Notice that both if's can be executed, since
+ yyLinizerState->inCComment is potentially set to false in
+ the first if. The order of the if's is also important.
+ */
+
+ if ( yyLinizerState->inCComment ) {
+
+ k = yyLinizerState->line.indexOf( m_constants.m_slashAster );
+ if ( k == -1 ) {
+ yyLinizerState->line = QString::null;
+ } else {
+ yyLinizerState->line.truncate( k );
+ yyLinizerState->inCComment = false;
+ }
+ }
+
+ if ( !yyLinizerState->inCComment ) {
+ k = yyLinizerState->line.indexOf( m_constants.m_asterSlash );
+ if ( k != -1 ) {
+ for ( int i = 0; i < k + 2; i++ )
+ eraseChar( yyLinizerState->line, i, blank );
+ yyLinizerState->inCComment = true;
+ }
+ }
+
+ /*
+ Remove preprocessor directives.
+ */
+ k = 0;
+ while ( k < yyLinizerState->line.length() ) {
+ QChar ch = yyLinizerState->line[k];
+ if ( ch == hash ) {
+ yyLinizerState->line = QString::null;
+ } else if ( !ch.isSpace() ) {
+ break;
+ }
+ k++;
+ }
+
+ /*
+ Remove trailing spaces.
+ */
+ k = yyLinizerState->line.length();
+ while ( k > 0 && yyLinizerState->line[k - 1].isSpace() )
+ k--;
+ yyLinizerState->line.truncate( k );
+
+ /*
+ '}' increment the brace depth and '{' decrements it and not
+ the other way around, as we are parsing backwards.
+ */
+ yyLinizerState->braceDepth +=
+ yyLinizerState->line.count( closingBrace ) - yyLinizerState->line.count( openingBrace );
+
+ /*
+ We use a dirty trick for
+
+ } else ...
+
+ We don't count the '}' yet, so that it's more or less
+ equivalent to the friendly construct
+
+ }
+ else ...
+ */
+ if ( yyLinizerState->pendingRightBrace )
+ yyLinizerState->braceDepth++;
+ yyLinizerState->pendingRightBrace =
+ ( m_constants.m_braceX.indexIn(yyLinizerState->line) == 0 );
+ if ( yyLinizerState->pendingRightBrace )
+ yyLinizerState->braceDepth--;
+ } while ( yyLinizerState->line.isEmpty() );
+
+ return true;
+}
+
+/*
+ Resets the linizer to its initial state, with yyLine containing the
+ line above the bottom line of the program.
+*/
+template <class Iterator>
+void Indenter<Iterator>::startLinizer()
+{
+ yyLinizerState->braceDepth = 0;
+ yyLinizerState->inCComment = false;
+ yyLinizerState->pendingRightBrace = false;
+
+ yyLine = &yyLinizerState->line;
+ yyBraceDepth = &yyLinizerState->braceDepth;
+ yyLeftBraceFollows = &yyLinizerState->leftBraceFollows;
+
+ yyLinizerState->iter = yyProgramEnd;
+ --yyLinizerState->iter;
+ yyLinizerState->line = *yyLinizerState->iter;
+ readLine();
+}
+
+/*
+ Returns true if the start of the bottom line of yyProgram (and
+ potentially the whole line) is part of a C-style comment; otherwise
+ returns false.
+*/
+template <class Iterator>
+bool Indenter<Iterator>::bottomLineStartsInCComment()
+{
+ /*
+ We could use the linizer here, but that would slow us down
+ terribly. We are better to trim only the code lines we need.
+ */
+ Iterator p = yyProgramEnd;
+ --p; // skip bottom line
+
+ for ( int i = 0; i < BigRoof; i++ ) {
+ if ( p == yyProgramBegin )
+ return false;
+ --p;
+
+ if ( (*p).contains(m_constants.m_slashAster) || (*p).contains(m_constants.m_asterSlash) ) {
+ QString trimmed = trimmedCodeLine( *p );
+
+ if ( trimmed.contains(m_constants.m_slashAster) ) {
+ return true;
+ } else if ( trimmed.contains(m_constants.m_asterSlash) ) {
+ return false;
+ }
+ }
+ }
+ return false;
+}
+
+/*
+ Returns the recommended indent for the bottom line of yyProgram
+ assuming that it starts in a C-style comment, a condition that is
+ tested elsewhere.
+
+ Essentially, we're trying to align against some text on the previous
+ line.
+*/
+template <class Iterator>
+int Indenter<Iterator>::indentWhenBottomLineStartsInCComment() const
+{
+ int k = yyLine->lastIndexOf(m_constants.m_slashAster );
+ if ( k == -1 ) {
+ /*
+ We found a normal text line in a comment. Align the
+ bottom line with the text on this line.
+ */
+ return indentOfLine( *yyLine );
+ } else {
+ /*
+ The C-style comment starts on this line. If there is
+ text on the same line, align with it. Otherwise, align
+ with the slash-aster plus a given offset.
+ */
+ const int indent = columnForIndex( *yyLine, k );
+ k += 2;
+ while ( k < yyLine->length() ) {
+ if ( !(*yyLine)[k].isSpace() )
+ return columnForIndex( *yyLine, k );
+ k++;
+ }
+ return indent + ppCommentOffset;
+ }
+}
+
+/*
+ A function called match...() modifies the linizer state. If it
+ returns true, yyLine is the top line of the matched construct;
+ otherwise, the linizer is left in an unknown state.
+
+ A function called is...() keeps the linizer state intact.
+*/
+
+/*
+ Returns true if the current line (and upwards) forms a braceless
+ control statement; otherwise returns false.
+
+ The first line of the following example is a "braceless control
+ statement":
+
+ if ( x )
+ y;
+*/
+template <class Iterator>
+bool Indenter<Iterator>::matchBracelessControlStatement()
+{
+ int delimDepth = 0;
+
+ const QChar semicolon = QLatin1Char(';');
+
+
+ if ( yyLine->endsWith(m_constants.m_else))
+ return true;
+
+ if ( !yyLine->endsWith(QLatin1Char(')')))
+ return false;
+
+ for ( int i = 0; i < SmallRoof; i++ ) {
+ int j = yyLine->length();
+ while ( j > 0 ) {
+ j--;
+ QChar ch = (*yyLine)[j];
+
+ switch ( ch.unicode() ) {
+ case ')':
+ delimDepth++;
+ break;
+ case '(':
+ delimDepth--;
+ if ( delimDepth == 0 ) {
+ if ( yyLine->contains(m_constants.m_iflikeKeyword) ) {
+ /*
+ We have
+
+ if ( x )
+ y
+
+ "if ( x )" is not part of the statement
+ "y".
+ */
+ return true;
+ }
+ }
+ if ( delimDepth == -1 ) {
+ /*
+ We have
+
+ if ( (1 +
+ 2)
+
+ and not
+
+ if ( 1 +
+ 2 )
+ */
+ return false;
+ }
+ break;
+ case '{':
+ case '}':
+ case ';':
+ /*
+ We met a statement separator, but not where we
+ expected it. What follows is probably a weird
+ continuation line. Be careful with ';' in for,
+ though.
+ */
+ if ( ch != semicolon || delimDepth == 0 )
+ return false;
+ }
+ }
+
+ if ( !readLine() )
+ break;
+ }
+ return false;
+}
+
+/*
+ Returns true if yyLine is an unfinished line; otherwise returns
+ false.
+
+ In many places we'll use the terms "standalone line", "unfinished
+ line" and "continuation line". The meaning of these should be
+ evident from this code example:
+
+ a = b; // standalone line
+ c = d + // unfinished line
+ e + // unfinished continuation line
+ f + // unfinished continuation line
+ g; // continuation line
+*/
+template <class Iterator>
+bool Indenter<Iterator>::isUnfinishedLine()
+{
+ bool unf = false;
+
+ YY_SAVE();
+
+ const QChar openingParenthesis = QLatin1Char('(');
+ const QChar semicolon = QLatin1Char(';');
+
+ if ( yyLine->isEmpty() )
+ return false;
+
+ const QChar lastCh = (*yyLine)[ yyLine->length() - 1];
+ if ( ! m_constants.m_bracesSemicolon.contains(lastCh) && !yyLine->endsWith(m_constants.m_3dots) ) {
+ /*
+ It doesn't end with ';' or similar. If it's neither
+ "Q_OBJECT" nor "if ( x )", it must be an unfinished line.
+ */
+ unf = ( yyLine->contains(m_constants.m_qobject) == 0 &&
+ !matchBracelessControlStatement() );
+ } else if ( lastCh == semicolon ) {
+ if ( lastParen(*yyLine) == openingParenthesis ) {
+ /*
+ Exception:
+
+ for ( int i = 1; i < 10;
+ */
+ unf = true;
+ } else if ( readLine() && yyLine->endsWith(semicolon) &&
+ lastParen(*yyLine) == openingParenthesis ) {
+ /*
+ Exception:
+
+ for ( int i = 1;
+ i < 10;
+ */
+ unf = true;
+ }
+ }
+
+ YY_RESTORE();
+ return unf;
+}
+
+/*
+ Returns true if yyLine is a continuation line; otherwise returns
+ false.
+*/
+template <class Iterator>
+bool Indenter<Iterator>::isContinuationLine()
+{
+ YY_SAVE();
+ const bool cont = readLine() && isUnfinishedLine();
+ YY_RESTORE();
+ return cont;
+}
+
+/*
+ Returns the recommended indent for the bottom line of yyProgram,
+ assuming it's a continuation line.
+
+ We're trying to align the continuation line against some parenthesis
+ or other bracked left opened on a previous line, or some interesting
+ operator such as '='.
+*/
+template <class Iterator>
+int Indenter<Iterator>::indentForContinuationLine()
+{
+ int braceDepth = 0;
+ int delimDepth = 0;
+
+ bool leftBraceFollowed = *yyLeftBraceFollows;
+
+ const QChar equals = QLatin1Char('=');
+ const QChar comma = QLatin1Char(',');
+ const QChar openingParenthesis = QLatin1Char('(');
+ const QChar closingParenthesis = QLatin1Char(')');
+
+ for ( int i = 0; i < SmallRoof; i++ ) {
+ int hook = -1;
+
+ int j = yyLine->length();
+ while ( j > 0 && hook < 0 ) {
+ j--;
+ QChar ch = (*yyLine)[j];
+
+ switch ( ch.unicode() ) {
+ case ')':
+ case ']':
+ delimDepth++;
+ break;
+ case '}':
+ braceDepth++;
+ break;
+ case '(':
+ case '[':
+ delimDepth--;
+ /*
+ An unclosed delimiter is a good place to align at,
+ at least for some styles (including Trolltech's).
+ */
+ if ( delimDepth == -1 )
+ hook = j;
+ break;
+ case '{':
+ braceDepth--;
+ /*
+ A left brace followed by other stuff on the same
+ line is typically for an enum or an initializer.
+ Such a brace must be treated just like the other
+ delimiters.
+ */
+ if ( braceDepth == -1 ) {
+ if ( j < yyLine->length() - 1 ) {
+ hook = j;
+ } else {
+ return 0; // shouldn't happen
+ }
+ }
+ break;
+ case '=':
+ /*
+ An equal sign is a very natural alignment hook
+ because it's usually the operator with the lowest
+ precedence in statements it appears in. Case in
+ point:
+
+ int x = 1 +
+ 2;
+
+ However, we have to beware of constructs such as
+ default arguments and explicit enum constant
+ values:
+
+ void foo( int x = 0,
+ int y = 0 );
+
+ And not
+
+ void foo( int x = 0,
+ int y = 0 );
+
+ These constructs are caracterized by a ',' at the
+ end of the unfinished lines or by unbalanced
+ parentheses.
+ */
+ if ( j > 0 && j < yyLine->length() - 1
+ && !m_constants.m_operators.contains((*yyLine)[j - 1])
+ && (*yyLine)[j + 1] != equals ) {
+ if ( braceDepth == 0 && delimDepth == 0 &&
+ !yyLine->endsWith(comma) &&
+ (yyLine->contains(openingParenthesis) == yyLine->contains(closingParenthesis)) )
+ hook = j;
+ }
+ }
+ }
+
+ if ( hook >= 0 ) {
+ /*
+ Yes, we have a delimiter or an operator to align
+ against! We don't really align against it, but rather
+ against the following token, if any. In this example,
+ the following token is "11":
+
+ int x = ( 11 +
+ 2 );
+
+ If there is no such token, we use a continuation indent:
+
+ static QRegExp foo( QString(
+ "foo foo foo foo foo foo foo foo foo") );
+ */
+ hook++;
+ while ( hook < yyLine->length() ) {
+ if ( !(*yyLine)[hook].isSpace() )
+ return columnForIndex( *yyLine, hook );
+ hook++;
+ }
+ return indentOfLine( *yyLine ) + ppContinuationIndentSize;
+ }
+
+ if ( braceDepth != 0 )
+ break;
+
+ /*
+ The line's delimiters are balanced. It looks like a
+ continuation line or something.
+ */
+ if ( delimDepth == 0 ) {
+ if ( leftBraceFollowed ) {
+ /*
+ We have
+
+ int main()
+ {
+
+ or
+
+ Bar::Bar()
+ : Foo( x )
+ {
+
+ The "{" should be flush left.
+ */
+ if ( !isContinuationLine() )
+ return indentOfLine( *yyLine );
+ } else if ( isContinuationLine() || yyLine->endsWith(comma)) {
+ /*
+ We have
+
+ x = a +
+ b +
+ c;
+
+ or
+
+ int t[] = {
+ 1, 2, 3,
+ 4, 5, 6
+
+ The "c;" should fall right under the "b +", and the
+ "4, 5, 6" right under the "1, 2, 3,".
+ */
+ return indentOfLine( *yyLine );
+ } else {
+ /*
+ We have
+
+ stream << 1 +
+ 2;
+
+ We could, but we don't, try to analyze which
+ operator has precedence over which and so on, to
+ obtain the excellent result
+
+ stream << 1 +
+ 2;
+
+ We do have a special trick above for the assignment
+ operator above, though.
+ */
+ return indentOfLine( *yyLine ) + ppContinuationIndentSize;
+ }
+ }
+
+ if ( !readLine() )
+ break;
+ }
+ return 0;
+}
+
+/*
+ Returns the recommended indent for the bottom line of yyProgram if
+ that line is standalone (or should be indented likewise).
+
+ Indenting a standalone line is tricky, mostly because of braceless
+ control statements. Grossly, we are looking backwards for a special
+ line, a "hook line", that we can use as a starting point to indent,
+ and then modify the indentation level according to the braces met
+ along the way to that hook.
+
+ Let's consider a few examples. In all cases, we want to indent the
+ bottom line.
+
+ Example 1:
+
+ x = 1;
+ y = 2;
+
+ The hook line is "x = 1;". We met 0 opening braces and 0 closing
+ braces. Therefore, "y = 2;" inherits the indent of "x = 1;".
+
+ Example 2:
+
+ if ( x ) {
+ y;
+
+ The hook line is "if ( x ) {". No matter what precedes it, "y;" has
+ to be indented one level deeper than the hook line, since we met one
+ opening brace along the way.
+
+ Example 3:
+
+ if ( a )
+ while ( b ) {
+ c;
+ }
+ d;
+
+ To indent "d;" correctly, we have to go as far as the "if ( a )".
+ Compare with
+
+ if ( a ) {
+ while ( b ) {
+ c;
+ }
+ d;
+
+ Still, we're striving to go back as little as possible to accomodate
+ people with irregular indentation schemes. A hook line near at hand
+ is much more reliable than a remote one.
+*/
+template <class Iterator>
+int Indenter<Iterator>::indentForStandaloneLine()
+{
+ const QChar semicolon = QLatin1Char(';');
+ const QChar openingBrace = QLatin1Char('{');
+
+ for ( int i = 0; i < SmallRoof; i++ ) {
+ if ( !*yyLeftBraceFollows ) {
+ YY_SAVE();
+
+ if ( matchBracelessControlStatement() ) {
+ /*
+ The situation is this, and we want to indent "z;":
+
+ if ( x &&
+ y )
+ z;
+
+ yyLine is "if ( x &&".
+ */
+ return indentOfLine( *yyLine ) + ppIndentSize;
+ }
+ YY_RESTORE();
+ }
+
+ if ( yyLine->endsWith(semicolon) || yyLine->count(openingBrace) > 0 ) {
+ /*
+ The situation is possibly this, and we want to indent
+ "z;":
+
+ while ( x )
+ y;
+ z;
+
+ We return the indent of "while ( x )". In place of "y;",
+ any arbitrarily complex compound statement can appear.
+ */
+
+ if ( *yyBraceDepth > 0 ) {
+ do {
+ if ( !readLine() )
+ break;
+ } while ( *yyBraceDepth > 0 );
+ }
+
+ LinizerState hookState;
+
+ while ( isContinuationLine() )
+ readLine();
+ hookState = *yyLinizerState;
+
+ readLine();
+ if ( *yyBraceDepth <= 0 ) {
+ do {
+ if ( !matchBracelessControlStatement() )
+ break;
+ hookState = *yyLinizerState;
+ } while ( readLine() );
+ }
+
+ *yyLinizerState = hookState;
+
+ while ( isContinuationLine() )
+ readLine();
+
+ /*
+ Never trust lines containing only '{' or '}', as some
+ people (Richard M. Stallman) format them weirdly.
+ */
+ if ( yyLine->trimmed().length() > 1 )
+ return indentOfLine( *yyLine ) - *yyBraceDepth * ppIndentSize;
+ }
+
+ if ( !readLine() )
+ return -*yyBraceDepth * ppIndentSize;
+ }
+ return 0;
+}
+
+/*
+ Returns the recommended indent for the bottom line of program.
+ Unless null, typedIn stores the character of yyProgram that
+ triggered reindentation.
+
+ This function works better if typedIn is set properly; it is
+ slightly more conservative if typedIn is completely wild, and
+ slighly more liberal if typedIn is always null. The user might be
+ annoyed by the liberal behavior.
+*/
+template <class Iterator>
+int Indenter<Iterator>::indentForBottomLine(const Iterator &current,
+ const Iterator &programBegin,
+ const Iterator &programEnd,
+ QChar typedIn )
+{
+ if ( programBegin == programEnd )
+ return 0;
+
+ yyProgramBegin = programBegin;
+ yyProgramEnd = programEnd;
+
+ startLinizer();
+
+ Iterator lastIt = current;
+
+ QString bottomLine = *lastIt;
+ QChar firstCh = firstNonWhiteSpace( bottomLine );
+ int indent;
+
+ const QChar hash = QLatin1Char('#');
+ const QChar closingBrace = QLatin1Char('}');
+ const QChar colon = QLatin1Char(':');
+
+ if ( bottomLineStartsInCComment() ) {
+ /*
+ The bottom line starts in a C-style comment. Indent it
+ smartly, unless the user has already played around with it,
+ in which case it's better to leave her stuff alone.
+ */
+ if ( isOnlyWhiteSpace(bottomLine) ) {
+ indent = indentWhenBottomLineStartsInCComment();
+ } else {
+ indent = indentOfLine( bottomLine );
+ }
+ } else if ( okay(typedIn, hash) && firstCh == hash ) {
+ /*
+ Preprocessor directives go flush left.
+ */
+ indent = 0;
+ } else {
+ if ( isUnfinishedLine() ) {
+ indent = indentForContinuationLine();
+ } else {
+ indent = indentForStandaloneLine();
+ }
+
+ if ( okay(typedIn, closingBrace) && firstCh == closingBrace ) {
+ /*
+ A closing brace is one level more to the left than the
+ code it follows.
+ */
+ indent -= ppIndentSize;
+ } else if ( okay(typedIn, colon) ) {
+ if ( m_constants.m_caseLabel.exactMatch(bottomLine) ) {
+ /*
+ Move a case label (or the ':' in front of a
+ constructor initialization list) one level to the
+ left, but only if the user did not play around with
+ it yet. Some users have exotic tastes in the
+ matter, and most users probably are not patient
+ enough to wait for the final ':' to format their
+ code properly.
+
+ We don't attempt the same for goto labels, as the
+ user is probably the middle of "foo::bar". (Who
+ uses goto, anyway?)
+ */
+ if ( indentOfLine(bottomLine) <= indent )
+ indent -= ppIndentSize;
+ else
+ indent = indentOfLine( bottomLine );
+ }
+ }
+ }
+ return qMax( 0, indent );
+}
+
+} // namespace SharedTools
+
+#undef YY_SAVE
+#undef YY_RESTORE
+
+#endif // INDENTER_C
diff --git a/src/shared/indenter/test/main.cpp b/src/shared/indenter/test/main.cpp
new file mode 100644
index 0000000000..9adca6a3ee
--- /dev/null
+++ b/src/shared/indenter/test/main.cpp
@@ -0,0 +1,182 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "indenter.h"
+
+#include <QtCore/QFile>
+#include <QtCore/QStringList>
+#include <QtCore/QDebug>
+#include <QtCore/QTextStream>
+#include <QtCore/QFileInfo>
+
+#include <stdio.h>
+
+typedef SharedTools::Indenter<QStringList::const_iterator> Indenter;
+
+static QString fileContents(const QString &fileName)
+{
+ QFile f(fileName);
+ if (!f.open(QIODevice::ReadOnly)) {
+ const QString msg = QString(QLatin1String("error: Cannot open file '%1' for reading: %2")).
+ arg(fileName).arg(f.errorString());
+ qWarning(msg.toLatin1().constData());
+ return QString::null;
+ }
+
+ const QString contents = QString::fromUtf8(f.readAll());
+ f.close();
+ if ( contents.isEmpty() ) {
+ const QString msg = QString(QLatin1String("error: File '%1' is empty")).arg(fileName);
+ qWarning(msg.toLatin1().constData());
+ return QString::null;
+ }
+ return contents;
+}
+
+static void printUsage(char *a0)
+{
+ const QFileInfo fi(QString::fromUtf8(a0));
+ const QString usage = QString(QLatin1String("Usage: %1 [-i indent-size] [-t tab-size] file.cpp")).
+ arg(fi.fileName());
+ qWarning(usage.toUtf8().constData());
+}
+
+static int integerOptionArgument(char ** &aptr, char **end)
+{
+ if (++aptr == end)
+ return -1;
+ const QString arg = QString::fromUtf8(*aptr);
+ bool ok;
+ const int rc = arg.toInt (&ok);
+ if (!ok)
+ return -1;
+ return rc;
+}
+
+static QStringList parseCommandLine(char **begin, char **end)
+{
+ char **aptr = begin;
+ if (++aptr == end)
+ return QStringList();
+
+ QStringList fileNames;
+ for ( ; aptr != end; ++aptr) {
+ const char *arg = *aptr;
+ if (arg[0] == '-') {
+ switch (arg[1]) {
+ case 't': {
+ const int tabSize = integerOptionArgument(aptr, end);
+ if ( tabSize == -1)
+ return QStringList();
+ Indenter::instance().setTabSize(tabSize);
+ }
+ break;
+ case 'i': {
+ const int indentSize = integerOptionArgument(aptr, end);
+ if (indentSize == -1)
+ return QStringList();
+ Indenter::instance().setIndentSize(indentSize);
+ }
+ break;
+ default:
+ return QStringList();
+ }
+ } else {
+ fileNames.push_back(QString::fromUtf8(arg));
+ }
+ }
+ return fileNames;
+}
+
+int format(const QString &fileName)
+{
+ const QString code = fileContents(fileName);
+ if (code == QString::null)
+ return 1;
+
+ QStringList program = code.split(QLatin1Char('\n'), QString::KeepEmptyParts);
+ while (!program.isEmpty()) {
+ if (!program.back().trimmed().isEmpty())
+ break;
+ program.pop_back();
+ }
+
+ QStringList p;
+ QString out;
+
+ const QChar colon = QLatin1Char(':');
+ const QChar blank = QLatin1Char(' ');
+ const QChar newLine = QLatin1Char('\n');
+
+ QStringList::const_iterator cend = program.constEnd();
+ for (QStringList::const_iterator it = program.constBegin(); it != cend; ++it) {
+ p.push_back(*it);
+ QString &line = p.back();
+
+ QChar typedIn = Indenter::instance().firstNonWhiteSpace(line);
+ if (p.last().endsWith(colon))
+ typedIn = colon;
+
+ const int indent = Indenter::instance().indentForBottomLine(p.constBegin(), p.constEnd(), typedIn);
+
+ const QString trimmed = line.trimmed();
+ // Indent the line in the list so that the formatter code sees the indented line.
+ if (!trimmed.isEmpty()) {
+ line = QString(indent, blank);
+ line += trimmed;
+ }
+ out += line;
+ out += newLine ;
+ }
+
+ while (out.endsWith(newLine))
+ out.truncate(out.length() - 1 );
+
+ fputs(out.toUtf8().constData(), stdout);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ const QStringList fileNames = parseCommandLine(argv, argv + argc);
+ if (fileNames.empty()) {
+ printUsage(argv[0]);
+ return 1;
+ }
+
+ foreach (const QString &fileName, fileNames)
+ if (const int rc = format(fileName))
+ return rc;
+
+ return 0;
+}
diff --git a/src/shared/indenter/test/test.pro b/src/shared/indenter/test/test.pro
new file mode 100644
index 0000000000..9600b7abeb
--- /dev/null
+++ b/src/shared/indenter/test/test.pro
@@ -0,0 +1,10 @@
+######################################################################
+# Automatically generated by qmake (2.01a) Mon Apr 16 13:02:01 2007
+######################################################################
+
+TEMPLATE = app
+TARGET=indenter
+CONFIG += console
+
+include(../indenter.pri)
+SOURCES += main.cpp
diff --git a/src/shared/namespace_global.h b/src/shared/namespace_global.h
new file mode 100644
index 0000000000..9a63debfde
--- /dev/null
+++ b/src/shared/namespace_global.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef NAMESPACE_GLOBAL_H
+#define NAMESPACE_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if QT_VERSION < 0x040400
+# define QT_ADD_NAMESPACE(name) ::name
+# define QT_USE_NAMESPACE
+# define QT_BEGIN_NAMESPACE
+# define QT_END_NAMESPACE
+# define QT_BEGIN_INCLUDE_NAMESPACE
+# define QT_END_INCLUDE_NAMESPACE
+# define QT_BEGIN_MOC_NAMESPACE
+# define QT_END_MOC_NAMESPACE
+# define QT_FORWARD_DECLARE_CLASS(name) class name;
+# define QT_MANGLE_NAMESPACE(name) name
+#endif
+
+#endif // NAMESPACE_GLOBAL_H
diff --git a/src/shared/proparser/abstractproitemvisitor.h b/src/shared/proparser/abstractproitemvisitor.h
new file mode 100644
index 0000000000..adc224ff70
--- /dev/null
+++ b/src/shared/proparser/abstractproitemvisitor.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef ABSTRACTPROITEMVISITOR
+#define ABSTRACTPROITEMVISITOR
+
+#include "proitems.h"
+
+QT_BEGIN_NAMESPACE
+
+struct AbstractProItemVisitor
+{
+ virtual ~AbstractProItemVisitor() {}
+ virtual bool visitBeginProBlock(ProBlock *block) = 0;
+ virtual bool visitEndProBlock(ProBlock *block) = 0;
+
+ virtual bool visitBeginProVariable(ProVariable *variable) = 0;
+ virtual bool visitEndProVariable(ProVariable *variable) = 0;
+
+ virtual bool visitBeginProFile(ProFile *value) = 0;
+ virtual bool visitEndProFile(ProFile *value) = 0;
+
+ virtual bool visitProValue(ProValue *value) = 0;
+ virtual bool visitProFunction(ProFunction *function) = 0;
+ virtual bool visitProOperator(ProOperator *function) = 0;
+ virtual bool visitProCondition(ProCondition *function) = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // ABSTRACTPROITEMVISITOR
+
diff --git a/src/shared/proparser/images/append.png b/src/shared/proparser/images/append.png
new file mode 100644
index 0000000000..5ae826e56c
--- /dev/null
+++ b/src/shared/proparser/images/append.png
Binary files differ
diff --git a/src/shared/proparser/images/other.png b/src/shared/proparser/images/other.png
new file mode 100644
index 0000000000..044ce1ebb8
--- /dev/null
+++ b/src/shared/proparser/images/other.png
Binary files differ
diff --git a/src/shared/proparser/images/profile.png b/src/shared/proparser/images/profile.png
new file mode 100644
index 0000000000..4a24ce3c2f
--- /dev/null
+++ b/src/shared/proparser/images/profile.png
Binary files differ
diff --git a/src/shared/proparser/images/remove.png b/src/shared/proparser/images/remove.png
new file mode 100644
index 0000000000..039f05a005
--- /dev/null
+++ b/src/shared/proparser/images/remove.png
Binary files differ
diff --git a/src/shared/proparser/images/scope.png b/src/shared/proparser/images/scope.png
new file mode 100644
index 0000000000..eefcb59954
--- /dev/null
+++ b/src/shared/proparser/images/scope.png
Binary files differ
diff --git a/src/shared/proparser/images/set.png b/src/shared/proparser/images/set.png
new file mode 100644
index 0000000000..69a8fe0523
--- /dev/null
+++ b/src/shared/proparser/images/set.png
Binary files differ
diff --git a/src/shared/proparser/images/value.png b/src/shared/proparser/images/value.png
new file mode 100644
index 0000000000..433cd527f4
--- /dev/null
+++ b/src/shared/proparser/images/value.png
Binary files differ
diff --git a/src/shared/proparser/procommandmanager.cpp b/src/shared/proparser/procommandmanager.cpp
new file mode 100644
index 0000000000..2be4ad69f4
--- /dev/null
+++ b/src/shared/proparser/procommandmanager.cpp
@@ -0,0 +1,164 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "procommandmanager.h"
+
+using namespace Qt4ProjectManager::Internal;
+
+ProCommandGroup::ProCommandGroup(const QString &name)
+ : m_name(name)
+{ }
+
+ProCommandGroup::~ProCommandGroup()
+{
+ qDeleteAll(m_commands);
+}
+
+void ProCommandGroup::appendCommand(ProCommand *cmd)
+{
+ m_commands.append(cmd);
+}
+
+void ProCommandGroup::undo()
+{
+ for (int i = m_commands.count(); i > 0; --i)
+ m_commands[i-1]->undo();
+}
+
+void ProCommandGroup::redo()
+{
+ for (int i = 0; i < m_commands.count(); ++i)
+ m_commands[i]->redo();
+}
+
+ProCommandManager::ProCommandManager(QObject *parent)
+ : QObject(parent)
+{
+ m_savepoint = 0;
+ m_pos = 0;
+ m_group = 0;
+}
+
+ProCommandManager::~ProCommandManager()
+{
+ qDeleteAll(m_groups);
+}
+
+void ProCommandManager::beginGroup(const QString &name)
+{
+ Q_ASSERT(!m_group);
+
+ if (m_pos != m_groups.count()) {
+ int removecount = m_groups.count() - m_pos;
+ for (int i = 0; i < removecount; ++i)
+ delete m_groups.takeLast();
+ m_pos = m_groups.count();
+ }
+
+ m_group = new ProCommandGroup(name);
+}
+
+bool ProCommandManager::hasGroup() const
+{
+ return m_group != 0;
+}
+
+void ProCommandManager::endGroup()
+{
+ Q_ASSERT(m_group);
+
+ m_groups.append(m_group);
+ m_pos = m_groups.count();
+ m_group = 0;
+
+ emit modified();
+}
+
+bool ProCommandManager::command(ProCommand *cmd)
+{
+ Q_ASSERT(m_group);
+
+ if (cmd->redo()) {
+ m_group->appendCommand(cmd);
+ return true;
+ }
+
+ return false;
+}
+
+void ProCommandManager::undo()
+{
+ if (canUndo()) {
+ --m_pos;
+ m_groups[m_pos]->undo();
+ }
+
+ emit modified();
+}
+
+void ProCommandManager::redo()
+{
+ if (canRedo()) {
+ m_groups[m_pos]->redo();
+ ++m_pos;
+ }
+
+ emit modified();
+}
+
+bool ProCommandManager::isDirty() const
+{
+ if (m_groups.isEmpty())
+ return false;
+
+ if (m_pos != 0 && m_groups.at(m_pos - 1) == m_savepoint)
+ return false;
+
+ return true;
+}
+
+void ProCommandManager::notifySave()
+{
+ if (m_pos > 0)
+ m_savepoint = m_groups.at(m_pos - 1);
+}
+
+bool ProCommandManager::canUndo() const
+{
+ return !m_groups.isEmpty() && m_pos > 0;
+}
+
+bool ProCommandManager::canRedo() const
+{
+ return m_groups.count() > m_pos;
+}
diff --git a/src/shared/proparser/procommandmanager.h b/src/shared/proparser/procommandmanager.h
new file mode 100644
index 0000000000..2c493bac03
--- /dev/null
+++ b/src/shared/proparser/procommandmanager.h
@@ -0,0 +1,112 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef PROCOMMANDMANAGER_H
+#define PROCOMMANDMANAGER_H
+
+#include "namespace_global.h"
+
+#include <QtCore/QModelIndex>
+
+QT_BEGIN_NAMESPACE
+class ProItem;
+QT_END_NAMESPACE
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProCommand
+{
+public:
+ virtual ~ProCommand() {}
+ virtual bool redo() = 0;
+ virtual void undo() = 0;
+};
+
+class ProCommandGroup
+{
+public:
+ ProCommandGroup(const QString &name);
+ ~ProCommandGroup();
+
+ void appendCommand(ProCommand *cmd);
+
+ void undo();
+ void redo();
+
+private:
+ QString m_name;
+ QList<ProCommand *> m_commands;
+};
+
+class ProCommandManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ ProCommandManager(QObject *parent);
+ ~ProCommandManager();
+
+ void beginGroup(const QString &name);
+ void endGroup();
+
+ // excutes the Command and adds it to the open group
+ bool command(ProCommand *cmd);
+
+ bool hasGroup() const;
+ bool isDirty() const;
+
+ void notifySave();
+
+ bool canUndo() const;
+ bool canRedo() const;
+
+public slots:
+ void undo();
+ void redo();
+
+signals:
+ void modified();
+
+private:
+ ProCommandGroup *m_group;
+ QList<ProCommandGroup *> m_groups;
+
+ int m_pos;
+ ProCommandGroup *m_savepoint;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif // PROCOMMANDMANAGER_H
diff --git a/src/shared/proparser/proeditor.cpp b/src/shared/proparser/proeditor.cpp
new file mode 100644
index 0000000000..23eef39c77
--- /dev/null
+++ b/src/shared/proparser/proeditor.cpp
@@ -0,0 +1,383 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "proeditor.h"
+#include "proitems.h"
+#include "proeditormodel.h"
+#include "procommandmanager.h"
+#include "proxml.h"
+
+#include <QtGui/QMenu>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QClipboard>
+
+using namespace Qt4ProjectManager::Internal;
+
+ProEditor::ProEditor(QWidget *parent, bool shortcuts)
+ : QWidget(parent)
+{
+ m_shortcuts = shortcuts;
+ m_advanced = false;
+ setupUi(this);
+
+ m_setFocusToListView = true;
+ m_blockSelectionSignal = false;
+ m_cutAction = new QAction(tr("Cut"), this);
+ m_copyAction = new QAction(tr("Copy"), this);
+ m_pasteAction = new QAction(tr("Paste"), this);
+}
+
+ProEditor::~ProEditor()
+{
+}
+
+void ProEditor::initialize(ProEditorModel *model, ProItemInfoManager *infomanager)
+{
+ m_model = model;
+ m_infomanager = infomanager;
+ initialize();
+}
+
+ProScopeFilter *ProEditor::filterModel() const
+{
+ return m_filter;
+}
+
+void ProEditor::selectScope(const QModelIndex &scope)
+{
+ m_setFocusToListView = false;
+ QModelIndex parent = m_filter->mapToSource(scope);
+ m_editListView->setRootIndex(parent);
+ m_editListView->setCurrentIndex(m_model->index(0,0,parent));
+ m_setFocusToListView = true;
+}
+
+void ProEditor::initialize()
+{
+ m_model->setInfoManager(m_infomanager);
+ m_filter = new ProScopeFilter(this);
+ m_filter->setSourceModel(m_model);
+
+ m_contextMenu = new QMenu(this);
+
+ if (m_shortcuts) {
+ m_cutAction->setShortcut(QKeySequence(tr("Ctrl+X")));
+ m_copyAction->setShortcut(QKeySequence(tr("Ctrl+C")));
+ m_pasteAction->setShortcut(QKeySequence(tr("Ctrl+V")));
+ m_editListView->installEventFilter(this);
+ }
+
+ m_contextMenu->addAction(m_cutAction);
+ m_contextMenu->addAction(m_copyAction);
+ m_contextMenu->addAction(m_pasteAction);
+
+ QMenu *addMenu = new QMenu(m_addToolButton);
+ m_addVariable = addMenu->addAction(tr("Add Variable"), this, SLOT(addVariable()));
+ m_addScope = addMenu->addAction(tr("Add Scope"), this, SLOT(addScope()));
+ m_addBlock = addMenu->addAction(tr("Add Block"), this, SLOT(addBlock()));
+ m_addToolButton->setMenu(addMenu);
+ m_addToolButton->setPopupMode(QToolButton::InstantPopup);
+
+ m_editListView->setModel(m_model);
+ m_editListView->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(m_editListView, SIGNAL(customContextMenuRequested(const QPoint &)),
+ this, SLOT(showContextMenu(const QPoint &)));
+
+ connect(m_editListView->selectionModel(),
+ SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
+ this, SLOT(updateState()));
+
+ connect(m_moveUpToolButton, SIGNAL(clicked()),
+ this, SLOT(moveUp()));
+ connect(m_moveDownToolButton, SIGNAL(clicked()),
+ this, SLOT(moveDown()));
+ connect(m_removeToolButton, SIGNAL(clicked()),
+ this, SLOT(remove()));
+ connect(m_cutAction, SIGNAL(triggered()),
+ this, SLOT(cut()));
+ connect(m_copyAction, SIGNAL(triggered()),
+ this, SLOT(copy()));
+ connect(m_pasteAction, SIGNAL(triggered()),
+ this, SLOT(paste()));
+
+ updatePasteAction();
+}
+
+bool ProEditor::eventFilter(QObject *, QEvent *event)
+{
+ if (event->type() == QEvent::ShortcutOverride) {
+ QKeyEvent *k = static_cast<QKeyEvent*>(event);
+ if (k->modifiers() == Qt::ControlModifier) {
+ switch (k->key()) {
+ case Qt::Key_X:
+ cut(); return true;
+ case Qt::Key_C:
+ copy(); return true;
+ case Qt::Key_V:
+ paste(); return true;
+ }
+ }
+ } else if (event->type() == QEvent::FocusIn) {
+ updateActions(true);
+ } else if (event->type() == QEvent::FocusOut) {
+ updateActions(false);
+ }
+
+ return false;
+}
+
+void ProEditor::showContextMenu(const QPoint &pos)
+{
+ updatePasteAction();
+ m_contextMenu->popup(m_editListView->viewport()->mapToGlobal(pos));
+}
+
+void ProEditor::updatePasteAction()
+{
+ bool pasteEnabled = false;
+
+ const QMimeData *data = QApplication::clipboard()->mimeData();
+ if (data && data->hasFormat(QLatin1String("application/x-problock")))
+ pasteEnabled = true;
+
+ m_pasteAction->setEnabled(pasteEnabled);
+}
+
+void ProEditor::updateActions(bool focus)
+{
+ bool copyEnabled = false;
+
+ if (focus)
+ copyEnabled = m_editListView->currentIndex().isValid();
+
+ m_cutAction->setEnabled(copyEnabled);
+ m_copyAction->setEnabled(copyEnabled);
+}
+
+void ProEditor::updateState()
+{
+ bool addEnabled = false;
+ bool removeEnabled = false;
+ bool upEnabled = false;
+ bool downEnabled = false;
+
+ QModelIndex parent = m_editListView->rootIndex();
+ ProBlock *scope = m_model->proBlock(parent);
+
+ if (scope) {
+ addEnabled = true;
+ QModelIndex index = m_editListView->currentIndex();
+ if (index.isValid()) {
+ removeEnabled = true;
+ int count = m_model->rowCount(parent);
+ int row = index.row();
+ if (row > 0)
+ upEnabled = true;
+ if (row < (count - 1))
+ downEnabled = true;
+ }
+ }
+
+ if (!m_blockSelectionSignal) {
+ emit itemSelected(m_editListView->currentIndex());
+ if (m_setFocusToListView)
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ }
+
+ updateActions(m_editListView->hasFocus());
+
+ m_addToolButton->setEnabled(addEnabled);
+ m_removeToolButton->setEnabled(removeEnabled);
+ m_moveUpToolButton->setEnabled(upEnabled);
+ m_moveDownToolButton->setEnabled(downEnabled);
+}
+
+void ProEditor::moveUp()
+{
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ QModelIndex index = m_editListView->currentIndex();
+ QModelIndex parent = index.parent();
+ int row = index.row() - 1;
+
+ m_blockSelectionSignal = true;
+ m_model->moveItem(index, row);
+ m_blockSelectionSignal = false;
+
+ index = m_model->index(row, 0, parent);
+ m_editListView->setCurrentIndex(index);
+}
+
+void ProEditor::moveDown()
+{
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ QModelIndex index = m_editListView->currentIndex();
+ QModelIndex parent = index.parent();
+ int row = index.row() + 1;
+
+ m_blockSelectionSignal = true;
+ m_model->moveItem(index, row);
+ m_blockSelectionSignal = false;
+
+ index = m_model->index(row, 0, parent);
+ m_editListView->setCurrentIndex(index);
+}
+
+void ProEditor::remove()
+{
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ m_model->removeItem(m_editListView->currentIndex());
+ updateState();
+}
+
+void ProEditor::cut()
+{
+ QModelIndex index = m_editListView->currentIndex();
+ if (!index.isValid())
+ return;
+
+ if (ProItem *item = m_model->proItem(index)) {
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ m_model->removeItem(index);
+
+ QMimeData *data = new QMimeData();
+ QString xml = ProXmlParser::itemToString(item);
+ if (item->kind() == ProItem::ValueKind)
+ data->setData(QLatin1String("application/x-provalue"), xml.toUtf8());
+ else
+ data->setData(QLatin1String("application/x-problock"), xml.toUtf8());
+ QApplication::clipboard()->setMimeData(data);
+ }
+}
+
+void ProEditor::copy()
+{
+ QModelIndex index = m_editListView->currentIndex();
+ if (!index.isValid())
+ return;
+
+ if (ProItem *item = m_model->proItem(index)) {
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ QMimeData *data = new QMimeData();
+ QString xml = ProXmlParser::itemToString(item);
+ if (item->kind() == ProItem::ValueKind)
+ data->setData(QLatin1String("application/x-provalue"), xml.toUtf8());
+ else
+ data->setData(QLatin1String("application/x-problock"), xml.toUtf8());
+ QApplication::clipboard()->setMimeData(data);
+ }
+}
+
+void ProEditor::paste()
+{
+ if (const QMimeData *data = QApplication::clipboard()->mimeData()) {
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ QModelIndex parent = m_editListView->rootIndex();
+ ProBlock *block = m_model->proBlock(parent);
+ if (!block)
+ return;
+
+ QString xml;
+ if (data->hasFormat(QLatin1String("application/x-provalue"))) {
+ xml = QString::fromUtf8(data->data(QLatin1String("application/x-provalue")));
+ } else if (data->hasFormat(QLatin1String("application/x-problock"))) {
+ xml = QString::fromUtf8(data->data(QLatin1String("application/x-problock")));
+ }
+
+ if (ProItem *item = ProXmlParser::stringToItem(xml)) {
+ QModelIndex parent = m_editListView->rootIndex();
+ int row = m_model->rowCount(parent);
+ m_model->insertItem(item, row, parent);
+ m_editListView->setCurrentIndex(m_model->index(row,0,parent));
+ }
+ }
+}
+
+void ProEditor::addVariable()
+{
+ QModelIndex parent = m_editListView->rootIndex();
+ if (ProBlock *pblock = m_model->proBlock(parent)) {
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ int row = m_model->rowCount(parent);
+
+ QString defid("...");
+ ProVariable::VariableOperator op = ProVariable::SetOperator;
+ QList<ProVariableInfo *> vars = m_infomanager->variables();
+ if (!vars.isEmpty()) {
+ defid = vars.first()->id();
+ op = vars.first()->defaultOperator();
+ }
+
+ ProVariable *var = new ProVariable(defid, pblock);
+ var->setVariableOperator(op);
+
+ m_model->insertItem(var, row, parent);
+ m_editListView->setCurrentIndex(m_model->index(row,0,parent));
+ }
+}
+
+void ProEditor::addScope()
+{
+ QModelIndex parent = m_editListView->rootIndex();
+ if (ProBlock *pblock = m_model->proBlock(parent)) {
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ int row = m_model->rowCount(parent);
+ ProBlock *scope = new ProBlock(pblock);
+ scope->setBlockKind(ProBlock::ScopeKind);
+ ProBlock *scopecontents = new ProBlock(scope);
+ scopecontents->setBlockKind(ProBlock::ScopeContentsKind);
+
+ QString defid("...");
+ QList<ProScopeInfo *> vars = m_infomanager->scopes();
+ if (!vars.isEmpty())
+ defid = vars.first()->id();
+
+ scope->setItems(QList<ProItem *>() << new ProCondition(defid) << scopecontents);
+ m_model->insertItem(scope, row, parent);
+ m_editListView->setCurrentIndex(m_model->index(row,0,parent));
+ }
+}
+
+void ProEditor::addBlock()
+{
+ QModelIndex parent = m_editListView->rootIndex();
+ if (ProBlock *pblock = m_model->proBlock(parent)) {
+ m_editListView->setFocus(Qt::OtherFocusReason);
+ int row = m_model->rowCount(parent);
+ ProBlock *block = new ProBlock(pblock);
+ block->setBlockKind(ProBlock::NormalKind);
+ block->setItems(QList<ProItem *>() << new ProFunction("..."));
+ m_model->insertItem(block, row, parent);
+ m_editListView->setCurrentIndex(m_model->index(row,0,parent));
+ }
+}
diff --git a/src/shared/proparser/proeditor.h b/src/shared/proparser/proeditor.h
new file mode 100644
index 0000000000..6469245f5e
--- /dev/null
+++ b/src/shared/proparser/proeditor.h
@@ -0,0 +1,128 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef PROEDITOR_H
+#define PROEDITOR_H
+
+#include "namespace_global.h"
+
+#include "ui_proeditor.h"
+
+#include "proiteminfo.h"
+
+#include <QtCore/QList>
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+class QMenu;
+class QAction;
+class ProBlock;
+class ProVariable;
+class ProFile;
+QT_END_NAMESPACE
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProEditorModel;
+class ProScopeFilter;
+
+class ProEditor : public QWidget, protected Ui::ProEditor
+{
+ Q_OBJECT
+
+public:
+ ProEditor(QWidget *parent, bool shortcuts = true);
+ ~ProEditor();
+
+ virtual void initialize(ProEditorModel *model, ProItemInfoManager *infomanager);
+
+ ProScopeFilter *filterModel() const;
+
+public slots:
+ void selectScope(const QModelIndex &scope);
+
+signals:
+ void itemSelected(const QModelIndex &index);
+
+protected slots:
+ void showContextMenu(const QPoint &pos);
+ void updatePasteAction();
+ void updateState();
+
+ void moveUp();
+ void moveDown();
+ void remove();
+ void cut();
+ void copy();
+ void paste();
+
+ void addVariable();
+ void addScope();
+ void addBlock();
+
+protected:
+ void updateActions(bool focus);
+ bool eventFilter(QObject *obj, QEvent *event);
+
+private:
+ void initialize();
+
+protected:
+ ProEditorModel *m_model;
+ QAction *m_cutAction;
+ QAction *m_copyAction;
+ QAction *m_pasteAction;
+
+private:
+ QMenu *m_contextMenu;
+
+ QAction *m_addVariable;
+ QAction *m_addScope;
+ QAction *m_addBlock;
+
+ ProScopeFilter *m_filter;
+ ProItemInfoManager *m_infomanager;
+
+ bool m_blockSelectionSignal;
+
+ // used because of some strange behavior when integrated into eclipse
+ bool m_setFocusToListView;
+ bool m_shortcuts;
+ bool m_advanced;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+#endif // PROEDITOR_H
diff --git a/src/shared/proparser/proeditor.ui b/src/shared/proparser/proeditor.ui
new file mode 100644
index 0000000000..b4daca4150
--- /dev/null
+++ b/src/shared/proparser/proeditor.ui
@@ -0,0 +1,143 @@
+<ui version="4.0" >
+ <class>Qt4ProjectManager::Internal::ProEditor</class>
+ <widget class="QWidget" name="Qt4ProjectManager::Internal::ProEditor" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>621</width>
+ <height>557</height>
+ </rect>
+ </property>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QListView" name="m_editListView" >
+ <property name="editTriggers" >
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="dragEnabled" >
+ <bool>true</bool>
+ </property>
+ <property name="uniformItemSizes" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QToolButton" name="m_addToolButton" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>New</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="m_removeToolButton" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="m_moveUpToolButton" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Up</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="m_moveDownToolButton" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Down</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/shared/proparser/proeditormodel.cpp b/src/shared/proparser/proeditormodel.cpp
new file mode 100644
index 0000000000..787ea76410
--- /dev/null
+++ b/src/shared/proparser/proeditormodel.cpp
@@ -0,0 +1,988 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "proxml.h"
+#include "proitems.h"
+#include "proeditormodel.h"
+#include "procommandmanager.h"
+#include "proiteminfo.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QMimeData>
+#include <QtCore/QStringList>
+#include <QtGui/QIcon>
+
+using namespace Qt4ProjectManager::Internal;
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProAddCommand : public ProCommand
+{
+public:
+ ProAddCommand(ProEditorModel *model, ProItem *item, int row, const QModelIndex &parent, bool dodelete = true)
+ : m_model(model), m_item(item), m_row(row), m_parent(parent), m_dodelete(dodelete), m_delete(false) { }
+
+ ~ProAddCommand() {
+ if (m_delete)
+ delete m_item;
+ }
+
+ bool redo() {
+ m_delete = false;
+ return m_model->insertModelItem(m_item, m_row, m_parent);
+ }
+
+ void undo() {
+ m_delete = m_dodelete;
+ m_model->removeModelItem(m_model->index(m_row, 0, m_parent));
+ }
+
+private:
+ ProEditorModel *m_model;
+ ProItem *m_item;
+ int m_row;
+ const QModelIndex m_parent;
+ bool m_dodelete;
+ bool m_delete;
+};
+
+class ProRemoveCommand : public ProCommand
+{
+public:
+ ProRemoveCommand(ProEditorModel *model, const QModelIndex &index, bool dodelete = true)
+ : m_model(model), m_index(index), m_dodelete(dodelete), m_delete(dodelete) { }
+
+ ~ProRemoveCommand() {
+ if (m_delete)
+ delete m_model->proItem(m_index);
+ }
+
+ bool redo() {
+ m_delete = m_dodelete;
+ return m_model->removeModelItem(m_index);
+ }
+
+ void undo() {
+ m_delete = false;
+ m_model->insertModelItem(m_model->proItem(m_index),
+ m_index.row(), m_index.parent());
+ }
+
+private:
+ ProEditorModel *m_model;
+ const QModelIndex m_index;
+ bool m_dodelete;
+ bool m_delete;
+};
+
+class ChangeProVariableIdCommand : public ProCommand
+{
+public:
+ ChangeProVariableIdCommand(ProEditorModel *model, ProVariable *variable, const QString &newId)
+ : m_newId(newId), m_model(model), m_variable(variable)
+ {
+ m_oldId = m_variable->variable();
+ }
+
+ ~ChangeProVariableIdCommand() { }
+
+ bool redo() {
+ m_variable->setVariable(m_newId);
+ return true;
+ }
+
+ void undo() {
+ m_variable->setVariable(m_oldId);
+ }
+
+private:
+ QString m_oldId;
+ QString m_newId;
+
+ ProEditorModel *m_model;
+ ProVariable *m_variable;
+};
+
+class ChangeProVariableOpCommand : public ProCommand
+{
+public:
+ ChangeProVariableOpCommand(ProEditorModel *model, ProVariable *variable, ProVariable::VariableOperator newOp)
+ : m_newOp(newOp), m_model(model), m_variable(variable)
+ {
+ m_oldOp = m_variable->variableOperator();
+ }
+
+ ~ChangeProVariableOpCommand() { }
+
+ bool redo() {
+ m_variable->setVariableOperator(m_newOp);
+ return true;
+ }
+
+ void undo() {
+ m_variable->setVariableOperator(m_oldOp);
+ }
+
+private:
+ ProVariable::VariableOperator m_oldOp;
+ ProVariable::VariableOperator m_newOp;
+
+ ProEditorModel *m_model;
+ ProVariable *m_variable;
+};
+
+class ChangeProScopeCommand : public ProCommand
+{
+public:
+ ChangeProScopeCommand(ProEditorModel *model, ProBlock *scope, const QString &newExp)
+ : m_newExp(newExp), m_model(model), m_scope(scope) {
+ m_oldExp = m_model->expressionToString(m_scope);
+ }
+
+ ~ChangeProScopeCommand() { }
+
+ bool redo() {
+ setScopeCondition(m_newExp);
+ return true;
+ }
+
+ void undo() {
+ setScopeCondition(m_oldExp);
+ }
+
+private:
+ void setScopeCondition(const QString &exp) {
+ ProItem *contents = m_model->scopeContents(m_scope);
+ QList<ProItem *> items = m_scope->items();
+ for (int i=items.count() - 1; i>=0; --i) {
+ if (items.at(i) != contents)
+ delete items[i];
+ }
+
+ items = m_model->stringToExpression(exp);
+ items << contents;
+ m_scope->setItems(items);
+ }
+
+ QString m_oldExp;
+ QString m_newExp;
+
+ ProEditorModel *m_model;
+ ProBlock *m_scope;
+};
+
+class ChangeProAdvancedCommand : public ProCommand
+{
+public:
+ ChangeProAdvancedCommand(ProEditorModel *model, ProBlock *block, const QString &newExp)
+ : m_newExp(newExp), m_model(model), m_block(block) {
+ m_oldExp = m_model->expressionToString(m_block);
+ }
+
+ ~ChangeProAdvancedCommand() { }
+
+ bool redo() {
+ setExpression(m_newExp);
+ return true;
+ }
+
+ void undo() {
+ setExpression(m_oldExp);
+ }
+
+private:
+ void setExpression(const QString &exp) {
+ qDeleteAll(m_block->items());
+ m_block->setItems(m_model->stringToExpression(exp));
+ }
+
+ QString m_oldExp;
+ QString m_newExp;
+
+ ProEditorModel *m_model;
+ ProBlock *m_block;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+ProEditorModel::ProEditorModel(QObject *parent)
+ : QAbstractItemModel(parent)
+{
+ m_infomanager = 0;
+ m_cmdmanager = new ProCommandManager(this);
+}
+
+ProEditorModel::~ProEditorModel()
+{
+}
+
+void ProEditorModel::setInfoManager(ProItemInfoManager *infomanager)
+{
+ m_infomanager = infomanager;
+ reset();
+}
+
+ProItemInfoManager *ProEditorModel::infoManager() const
+{
+ return m_infomanager;
+}
+
+ProCommandManager *ProEditorModel::cmdManager() const
+{
+ return m_cmdmanager;
+}
+
+void ProEditorModel::setProFiles(QList<ProFile*> proFiles)
+{
+ m_changed.clear();
+ m_proFiles = proFiles;
+ reset();
+}
+
+QList<ProFile*> ProEditorModel::proFiles() const
+{
+ return m_proFiles;
+}
+
+QList<QModelIndex> ProEditorModel::findVariables(const QStringList &varnames, const QModelIndex &parent) const
+{
+ QList<QModelIndex> result;
+
+ if (varnames.isEmpty())
+ return result;
+
+ if (ProVariable *var = proVariable(parent)) {
+ if (varnames.contains(var->variable()))
+ result << parent;
+ return result;
+ }
+
+ for (int i=0; i<rowCount(parent); ++i) {
+ result += findVariables(varnames, index(i, 0, parent));
+ }
+
+ return result;
+}
+
+QList<QModelIndex> ProEditorModel::findBlocks(const QModelIndex &parent) const
+{
+ QList<QModelIndex> result;
+
+ if (proBlock(parent)) {
+ result << parent;
+ return result;
+ }
+
+ for (int i = 0; i < rowCount(parent); ++i)
+ result += findBlocks(index(i, 0, parent));
+
+ return result;
+}
+
+QString ProEditorModel::blockName(ProBlock *block) const
+{
+ // variables has a name
+ if (block->blockKind() & ProBlock::VariableKind) {
+ ProVariable *v = static_cast<ProVariable*>(block);
+ if (m_infomanager) {
+ if (ProVariableInfo *info = m_infomanager->variable(v->variable()))
+ return info->name();
+ }
+ return v->variable();
+ }
+
+ return expressionToString(block, true);
+}
+
+QModelIndex ProEditorModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (row < 0 || (column != 0))
+ return QModelIndex();
+
+ if (parent.isValid()) {
+ ProItem *item = proItem(parent);
+ if (item->kind() != ProItem::BlockKind)
+ return QModelIndex();
+
+ ProBlock *block = static_cast<ProBlock*>(item);
+ if (block->blockKind() & ProBlock::VariableKind
+ || block->blockKind() & ProBlock::ProFileKind) {
+ const QList<ProItem*> items = block->items();
+ if (row >= items.count())
+ return QModelIndex();
+ ProItem *data = items.at(row);
+ return createIndex(row, 0, (void*)data);
+ } else if (ProBlock *scope = scopeContents(block)) {
+ const QList<ProItem*> items = scope->items();
+ if (row >= items.count())
+ return QModelIndex();
+ ProItem *data = items.at(row);
+ return createIndex(row, 0, (void*)data);
+ }
+
+ return QModelIndex();
+ }
+
+ if (row >= m_proFiles.count())
+ return QModelIndex();
+ ProItem *data = m_proFiles.at(row);
+ return createIndex(row, 0, (void*)data);
+}
+
+QModelIndex ProEditorModel::parent(const QModelIndex &index) const
+{
+ ProBlock *p = 0;
+ ProItem *item = proItem(index);
+ if (!item) {
+ return QModelIndex();
+ }
+
+ if (item->kind() == ProItem::BlockKind) {
+ ProBlock *block = static_cast<ProBlock *>(item);
+ if (block->blockKind() & ProBlock::ProFileKind) {
+ return QModelIndex();
+ }
+ p = block->parent();
+ } else if (item->kind() == ProItem::ValueKind) {
+ p = static_cast<ProValue *>(item)->variable();
+ }
+
+ if (p->blockKind() & ProBlock::ScopeContentsKind)
+ p = p->parent();
+
+ int row = -1;
+ if (p->blockKind() & ProBlock::ProFileKind) {
+ row = m_proFiles.indexOf(static_cast<ProFile*>(p));
+ } else {
+ ProBlock *pp = p->parent();
+ row = pp->items().indexOf(p);
+ }
+
+ if (row == -1) {
+ return QModelIndex();
+ }
+
+ ProItem *data = p;
+ return createIndex(row, 0, (void*)data);
+}
+
+int ProEditorModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid()) {
+ ProItem *s = proItem(parent);
+ if (!s)
+ return 0;
+
+ if (s->kind() != ProItem::BlockKind)
+ return 0;
+
+ ProBlock *block = static_cast<ProBlock*>(s);
+
+ if (block->blockKind() & ProBlock::VariableKind
+ || block->blockKind() & ProBlock::ProFileKind) {
+ int rows = block->items().count();
+ return rows;
+ }
+
+ if (ProBlock *scope = scopeContents(block)) {
+ int rows = scope->items().count();
+ return rows;
+ }
+
+ return 0;
+ }
+
+ return m_proFiles.count();
+}
+
+int ProEditorModel::columnCount(const QModelIndex &) const
+{
+ return 1;
+}
+
+QVariant ProEditorModel::data(const QModelIndex &index, int role) const
+{
+ ProItem *item = proItem(index);
+ if (!item) {
+ return QVariant();
+ }
+
+ if (item->kind() == ProItem::BlockKind) {
+ ProBlock *block = static_cast<ProBlock*>(item);
+ if (block->blockKind() & ProBlock::ProFileKind) {
+ ProFile *pf = static_cast<ProFile*>(item);
+ if (role == Qt::DisplayRole) {
+ if (m_proFiles.count() > 1)
+ return QVariant(pf->displayFileName());
+ else
+ return QVariant(tr("<Global Scope>"));
+ } else if (role == Qt::DecorationRole) {
+ return QIcon(":/proparser/images/profile.png");
+ }
+ } else if (block->blockKind() & ProBlock::ScopeKind) {
+ if (role == Qt::DisplayRole)
+ return QVariant(blockName(block));
+ else if (role == Qt::DecorationRole)
+ return QIcon(":/proparser/images/scope.png");
+ else if (role == Qt::EditRole)
+ return QVariant(expressionToString(block));
+ } else if (block->blockKind() & ProBlock::VariableKind) {
+ ProVariable *var = static_cast<ProVariable *>(block);
+ if (role == Qt::DisplayRole) {
+ return QVariant(blockName(block));
+ } else if (role == Qt::DecorationRole) {
+ if (var->variableOperator() == ProVariable::AddOperator)
+ return QIcon(":/proparser/images/append.png");
+ else if (var->variableOperator() == ProVariable::RemoveOperator)
+ return QIcon(":/proparser/images/remove.png");
+ else
+ return QIcon(":/proparser/images/set.png");
+ } else if (role == Qt::EditRole) {
+ return QVariant(var->variable());
+ }
+ } else {
+ if (role == Qt::DisplayRole)
+ return QVariant(blockName(block));
+ else if (role == Qt::DecorationRole)
+ return QIcon(":/proparser/images/other.png");
+ else if (role == Qt::EditRole)
+ return QVariant(expressionToString(block));
+ }
+ } else if (item->kind() == ProItem::ValueKind) {
+ ProValue *value = static_cast<ProValue*>(item);
+ if (role == Qt::DisplayRole) {
+ ProVariable *var = proVariable(index.parent());
+ if (var && m_infomanager) {
+ if (ProVariableInfo *varinfo = m_infomanager->variable(var->variable())) {
+ if (ProValueInfo *valinfo = varinfo->value(value->value()))
+ return QVariant(valinfo->name());
+ }
+ }
+ return QVariant(value->value());
+ } else if (role == Qt::DecorationRole) {
+ return QIcon(":/proparser/images/value.png");
+ } else if (role == Qt::EditRole) {
+ return QVariant(value->value());
+ }
+ }
+
+ return QVariant();
+}
+
+bool ProEditorModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ static bool block = false;
+
+ if (block)
+ return false;
+
+ if (role != Qt::EditRole)
+ return false;
+
+ ProItem *item = proItem(index);
+ if (!item)
+ return false;
+
+ if (item->kind() == ProItem::ValueKind) {
+ ProValue *val = static_cast<ProValue *>(item);
+ if (val->value() == value.toString())
+ return false;
+
+ block = true;
+ m_cmdmanager->beginGroup(tr("Change Item"));
+ bool result = m_cmdmanager->command(new ProRemoveCommand(this, index));
+ if (result) {
+ ProValue *item = new ProValue(value.toString(), proVariable(index.parent()));
+ result = m_cmdmanager->command(new ProAddCommand(this, item, index.row(), index.parent()));
+ }
+ block = false;
+
+ m_cmdmanager->endGroup();
+ markProFileModified(index);
+ emit dataChanged(index,index);
+ return result;
+ } else if (item->kind() == ProItem::BlockKind) {
+ ProBlock *block = proBlock(index);
+ if (block->blockKind() & ProBlock::VariableKind) {
+ ProVariable *var = static_cast<ProVariable *>(block);
+ if (value.type() == QVariant::Int) {
+ if ((int)var->variableOperator() == value.toInt())
+ return false;
+
+ m_cmdmanager->beginGroup(tr("Change Variable Assignment"));
+ m_cmdmanager->command(new ChangeProVariableOpCommand(this, var,
+ (ProVariable::VariableOperator)value.toInt()));
+ m_cmdmanager->endGroup();
+ markProFileModified(index);
+ emit dataChanged(index,index);
+ return true;
+ } else {
+ if (var->variable() == value.toString())
+ return false;
+
+ m_cmdmanager->beginGroup(tr("Change Variable Type"));
+ m_cmdmanager->command(new ChangeProVariableIdCommand(this, var,
+ value.toString()));
+ m_cmdmanager->endGroup();
+ markProFileModified(index);
+ emit dataChanged(index,index);
+ return true;
+ }
+ } else if (block->blockKind() & ProBlock::ScopeContentsKind) {
+ ProBlock *scope = block->parent();
+ QString oldExp = expressionToString(scope);
+ if (oldExp == value.toString())
+ return false;
+
+ m_cmdmanager->beginGroup(tr("Change Scope Condition"));
+ m_cmdmanager->command(new ChangeProScopeCommand(this, scope, value.toString()));
+ m_cmdmanager->endGroup();
+ markProFileModified(index);
+ emit dataChanged(index,index);
+ return true;
+ } else if (block->blockKind() & ProBlock::ProFileKind) {
+ return false;
+ } else {
+ QString oldExp = expressionToString(block);
+ if (oldExp == value.toString())
+ return false;
+
+ m_cmdmanager->beginGroup(tr("Change Expression"));
+ m_cmdmanager->command(new ChangeProAdvancedCommand(this, block, value.toString()));
+ m_cmdmanager->endGroup();
+ markProFileModified(index);
+ emit dataChanged(index,index);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Qt::ItemFlags ProEditorModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return 0;
+
+ Qt::ItemFlags res = QAbstractItemModel::flags(index);
+ ProItem *item = proItem(index);
+ if (item->kind() == ProItem::BlockKind) {
+ ProBlock *block = static_cast<ProBlock*>(item);
+ if (block->blockKind() == ProBlock::ProFileKind)
+ return res;
+ }
+
+ return res | Qt::ItemIsEditable;
+}
+
+QMimeData *ProEditorModel::mimeData(const QModelIndexList &indexes) const
+{
+ QModelIndex index = indexes.first();
+ ProItem *item = proItem(index);
+ QMimeData *data = new QMimeData();
+ QString xml = ProXmlParser::itemToString(item);
+ data->setText(xml);
+ return data;
+}
+
+bool ProEditorModel::moveItem(const QModelIndex &index, int row)
+{
+ if (!index.isValid())
+ return false;
+
+ int oldrow = index.row();
+ QModelIndex parentIndex = index.parent();
+
+ if (oldrow == row)
+ return false;
+
+ ProItem *item = proItem(index);
+
+ m_cmdmanager->beginGroup(tr("Move Item"));
+ bool result = m_cmdmanager->command(new ProRemoveCommand(this, index, false));
+ if (result)
+ result = m_cmdmanager->command(new ProAddCommand(this, item, row, parentIndex, false));
+ m_cmdmanager->endGroup();
+ markProFileModified(index);
+
+ return result;
+}
+
+bool ProEditorModel::removeModelItem(const QModelIndex &index)
+{
+ if (!index.isValid())
+ return false;
+
+ int row = index.row();
+ QModelIndex parentIndex = index.parent();
+
+ if (!parentIndex.isValid())
+ return false;
+
+ // get the pro items
+ ProBlock *block = proBlock(parentIndex);
+ if (!block)
+ return false;
+
+ QList<ProItem *> proitems = block->items();
+ proitems.takeAt(row);
+
+ beginRemoveRows(parentIndex, row, row);
+ block->setItems(proitems);
+ endRemoveRows();
+ markProFileModified(index);
+
+ return true;
+}
+
+bool ProEditorModel::removeItem(const QModelIndex &index)
+{
+ bool creategroup = !m_cmdmanager->hasGroup();
+ if (creategroup)
+ m_cmdmanager->beginGroup(tr("Remove Item"));
+
+ bool result = m_cmdmanager->command(new ProRemoveCommand(this, index));
+
+ if (creategroup)
+ m_cmdmanager->endGroup();
+ markProFileModified(index);
+ return result;
+}
+
+bool ProEditorModel::insertModelItem(ProItem *item, int row, const QModelIndex &parent)
+{
+ if (!parent.isValid())
+ return false;
+
+ ProBlock *block = proBlock(parent);
+ if (!item || !block)
+ return false;
+
+ QList<ProItem *> proitems = block->items();
+ proitems.insert(row, item);
+
+ if ((block->blockKind() & ProBlock::VariableKind)
+ && item->kind() != ProItem::ValueKind)
+ return false;
+
+ if (item->kind() == ProItem::BlockKind) {
+ static_cast<ProBlock*>(item)->setParent(block);
+ } else if (item->kind() == ProItem::ValueKind) {
+ if (!(block->blockKind() & ProBlock::VariableKind))
+ return false;
+ static_cast<ProValue*>(item)->
+ setVariable(static_cast<ProVariable*>(block));
+ } else {
+ return false;
+ }
+
+ beginInsertRows(parent, row, row);
+ block->setItems(proitems);
+ endInsertRows();
+
+ markProFileModified(parent);
+ return true;
+}
+
+bool ProEditorModel::insertItem(ProItem *item, int row, const QModelIndex &parent)
+{
+ bool creategroup = !m_cmdmanager->hasGroup();
+ if (creategroup)
+ m_cmdmanager->beginGroup(tr("Insert Item"));
+
+ bool result = m_cmdmanager->command(new ProAddCommand(this, item, row, parent));
+
+ if (creategroup)
+ m_cmdmanager->endGroup();
+ markProFileModified(parent);
+ return result;
+}
+
+void ProEditorModel::markProFileModified(QModelIndex index)
+{
+ while (index.isValid()) {
+ if (proItem(index)->kind() == ProItem::BlockKind) {
+ ProBlock * block = proBlock(index);
+ if (block->blockKind() == ProBlock::ProFileKind) {
+ ProFile * file = static_cast<ProFile *>(block);
+ file->setModified(true);
+ return;
+ }
+ }
+ index = index.parent();
+ }
+}
+
+ProItem *ProEditorModel::proItem(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return 0;
+ return reinterpret_cast<ProItem*>(index.internalPointer());
+}
+
+ProVariable *ProEditorModel::proVariable(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return 0;
+
+ ProItem *item = proItem(index);
+ if (item->kind() != ProItem::BlockKind)
+ return 0;
+
+ ProBlock *block = static_cast<ProBlock *>(item);
+ if (block->blockKind() != ProBlock::VariableKind)
+ return 0;
+
+ return static_cast<ProVariable*>(block);
+}
+
+ProBlock *ProEditorModel::proBlock(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return 0;
+
+ ProItem *item = proItem(index);
+ if (item->kind() != ProItem::BlockKind)
+ return 0;
+
+ ProBlock *block = static_cast<ProBlock *>(item);
+ if (block->blockKind() & ProBlock::ScopeKind)
+ block = scopeContents(block);
+
+ return block;
+}
+
+QString ProEditorModel::expressionToString(ProBlock *block, bool display) const
+{
+ QString result;
+ QList<ProItem*> items = block->items();
+ for (int i = 0; i < items.count(); ++i) {
+ ProItem *item = items.at(i);
+ switch (item->kind()) {
+ case ProItem::FunctionKind: {
+ ProFunction *v = static_cast<ProFunction*>(item);
+ result += v->text();
+ break; }
+ case ProItem::ConditionKind: {
+ ProCondition *v = static_cast<ProCondition*>(item);
+ if (m_infomanager && display) {
+ if (ProScopeInfo *info = m_infomanager->scope(v->text()))
+ result += info->name();
+ else
+ result += v->text();
+ } else {
+ result += v->text();
+ }
+ break;
+ }
+ case ProItem::OperatorKind: {
+ ProOperator *v = static_cast<ProOperator*>(item);
+ if (v->operatorKind() == ProOperator::NotOperator)
+ result += QLatin1Char('!');
+ else
+ result += QLatin1Char('|');
+ break;
+ }
+ case ProItem::ValueKind:
+ case ProItem::BlockKind:
+ break; // ### unhandled
+ }
+ }
+
+ return result;
+}
+
+ProItem *ProEditorModel::createExpressionItem(QString &str) const
+{
+ ProItem *item = 0;
+
+ str = str.trimmed();
+ if (str.endsWith(')'))
+ item = new ProFunction(str);
+ else if (!str.isEmpty())
+ item = new ProCondition(str);
+
+ str.clear();
+ return item;
+}
+
+
+QList<ProItem *> ProEditorModel::stringToExpression(const QString &exp) const
+{
+ QList<ProItem*> result;
+ int p = 0;
+ bool c = false;
+
+ QString tmpstr;
+ for (int i = 0; i < exp.length(); ++i) {
+ QChar tmpchar = exp.at(i);
+ if (tmpchar == '(') ++p;
+ else if (tmpchar == ')') --p;
+ else if (tmpchar == '\'' || tmpchar == '\"') c = !c;
+ else if (!c && !p) {
+ if (tmpchar == '|') {
+ if (ProItem *item = createExpressionItem(tmpstr))
+ result << item;
+ result << new ProOperator(ProOperator::OrOperator);
+ continue;
+ } else if (tmpchar == '!') {
+ if (ProItem *item = createExpressionItem(tmpstr))
+ result << item;
+ result << new ProOperator(ProOperator::NotOperator);
+ continue;
+ }
+ }
+ tmpstr += tmpchar;
+ }
+
+ if (ProItem *item = createExpressionItem(tmpstr))
+ result << item;
+
+ return result;
+}
+
+ProBlock *ProEditorModel::scopeContents(ProBlock *block) const
+{
+ if (!(block->blockKind() & ProBlock::ScopeKind))
+ return 0;
+
+ ProItem *item = block->items().last();
+ if (item->kind() != ProItem::BlockKind)
+ return 0;
+ ProBlock *scope = static_cast<ProBlock*>(item);
+ if (!(scope->blockKind() & ProBlock::ScopeContentsKind))
+ return 0;
+ return scope;
+}
+
+ProScopeFilter::ProScopeFilter(QObject *parent)
+ : QSortFilterProxyModel(parent)
+{
+ m_checkable = ProScopeFilter::None;
+}
+
+void ProScopeFilter::setVariableFilter(const QStringList &vars)
+{
+ m_vars = vars;
+}
+
+void ProScopeFilter::setCheckable(CheckableType ct)
+{
+ m_checkable = ct;
+}
+
+QList<QModelIndex> ProScopeFilter::checkedIndexes() const
+{
+ return m_checkStates.keys(true);
+}
+
+Qt::ItemFlags ProScopeFilter::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags srcflags = sourceModel()->flags(mapToSource(index));
+ srcflags &= ~Qt::ItemIsDragEnabled; //disable drag
+
+ if (m_checkable == ProScopeFilter::None)
+ return srcflags;
+
+ return (srcflags|Qt::ItemIsUserCheckable);
+}
+
+QVariant ProScopeFilter::data(const QModelIndex &index, int role) const
+{
+ bool checkable =
+ m_checkable == ProScopeFilter::Blocks
+ || m_checkable == ProScopeFilter::Variable && sourceVariable(index);
+
+ if (checkable && role == Qt::CheckStateRole) {
+ QModelIndex srcindex = mapToSource(index);
+ if (m_checkStates.value(srcindex, false))
+ return Qt::Checked;
+ else
+ return Qt::Unchecked;
+ }
+
+ return QSortFilterProxyModel::data(index, role);
+}
+
+bool ProScopeFilter::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ // map to source
+ if (m_checkable != ProScopeFilter::None && role == Qt::CheckStateRole) {
+ if (m_checkable == ProScopeFilter::Blocks
+ || (m_checkable == ProScopeFilter::Variable && sourceVariable(index))) {
+ QModelIndex srcindex = mapToSource(index);
+ if (value.toInt() == Qt::Checked && !m_checkStates.value(srcindex, false)) {
+ m_checkStates.insert(srcindex, true);
+ emit dataChanged(index, index);
+ } else if (m_checkStates.value(srcindex, true)) {
+ m_checkStates.insert(srcindex, false);
+ emit dataChanged(index, index);
+ }
+ return true;
+ }
+ }
+
+ return QSortFilterProxyModel::setData(index, value, role);
+}
+
+ProVariable *ProScopeFilter::sourceVariable(const QModelIndex &index) const
+{
+ ProEditorModel *model = qobject_cast<ProEditorModel*>(sourceModel());
+ return model->proVariable(mapToSource(index));
+}
+
+bool ProScopeFilter::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
+{
+ ProEditorModel *model = qobject_cast<ProEditorModel*>(sourceModel());
+ if (!model)
+ return true;
+
+ QModelIndex index = model->index(source_row, 0, source_parent);
+ ProItem *item = model->proItem(index);
+ if (item->kind() != ProItem::BlockKind)
+ return false;
+
+ ProBlock *block = static_cast<ProBlock *>(item);
+
+ if (m_vars.isEmpty())
+ return (block->blockKind() & ProBlock::ScopeKind || block->blockKind() & ProBlock::ProFileKind);
+
+ if (block->blockKind() & ProBlock::VariableKind
+ || block->blockKind() & ProBlock::ScopeKind
+ || block->blockKind() & ProBlock::ProFileKind)
+ return !model->findVariables(m_vars, index).isEmpty();
+
+ return false;
+}
diff --git a/src/shared/proparser/proeditormodel.h b/src/shared/proparser/proeditormodel.h
new file mode 100644
index 0000000000..22f6c87e3d
--- /dev/null
+++ b/src/shared/proparser/proeditormodel.h
@@ -0,0 +1,156 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef PROEDITORMODEL_H
+#define PROEDITORMODEL_H
+
+#include "namespace_global.h"
+
+#include <QtCore/QAbstractItemModel>
+#include <QtCore/QList>
+#include <QtCore/QSet>
+#include <QtCore/QStringList>
+#include <QtGui/QSortFilterProxyModel>
+
+QT_BEGIN_NAMESPACE
+class ProBlock;
+class ProFile;
+class ProItem;
+class ProVariable;
+QT_END_NAMESPACE
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProCommandManager;
+class ProItemInfoManager;
+
+class ProEditorModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ ProEditorModel(QObject *parent = 0);
+ ~ProEditorModel();
+
+ void setInfoManager(ProItemInfoManager *infomanager);
+ ProItemInfoManager *infoManager() const;
+ ProCommandManager *cmdManager() const;
+
+ void setProFiles(QList<ProFile*> proFiles);
+ QList<ProFile*> proFiles() const;
+
+ QList<QModelIndex> findVariables(const QStringList &varname, const QModelIndex &parent = QModelIndex()) const;
+ QList<QModelIndex> findBlocks(const QModelIndex &parent = QModelIndex()) const;
+
+ bool moveItem(const QModelIndex &index, int row);
+ bool insertItem(ProItem *item, int row, const QModelIndex &parent);
+ bool removeItem(const QModelIndex &index);
+
+ ProItem *proItem(const QModelIndex &index) const;
+ ProBlock *proBlock(const QModelIndex &index) const;
+ ProVariable *proVariable(const QModelIndex &index) const;
+
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &index) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ QMimeData *mimeData(const QModelIndexList &indexes) const;
+
+ inline QList<ProFile*> changed() const { return m_changed.toList(); }
+protected:
+ ProItem *createExpressionItem(QString &str) const;
+
+ QString blockName(ProBlock *block) const;
+ ProBlock *scopeContents(ProBlock *block) const;
+
+ QString expressionToString(ProBlock *block, bool display = false) const;
+ QList<ProItem *> stringToExpression(const QString &exp) const;
+
+ bool insertModelItem(ProItem *item, int row, const QModelIndex &parent);
+ bool removeModelItem(const QModelIndex &index);
+
+private:
+ void markProFileModified(QModelIndex index);
+ ProCommandManager *m_cmdmanager;
+ QList<ProFile*> m_proFiles;
+ QSet<ProFile*> m_changed;
+ ProItemInfoManager *m_infomanager;
+
+ friend class ProAddCommand;
+ friend class ProRemoveCommand;
+ friend class ChangeProScopeCommand;
+ friend class ChangeProAdvancedCommand;
+};
+
+class ProScopeFilter : public QSortFilterProxyModel
+{
+ Q_OBJECT
+
+public:
+ enum CheckableType {
+ None,
+ Variable,
+ Blocks
+ };
+
+ void setVariableFilter(const QStringList &vars);
+ void setCheckable( CheckableType ct );
+
+ // returns the checked (source) indexes
+ QList<QModelIndex> checkedIndexes() const;
+
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ ProScopeFilter(QObject *parent);
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+
+protected:
+ ProVariable *sourceVariable(const QModelIndex &index) const;
+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
+
+private:
+ CheckableType m_checkable;
+ QStringList m_vars;
+ QMap<QModelIndex, bool> m_checkStates;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // PROEDITORMODEL_H
+
diff --git a/src/shared/proparser/profileevaluator.cpp b/src/shared/proparser/profileevaluator.cpp
new file mode 100644
index 0000000000..790edab457
--- /dev/null
+++ b/src/shared/proparser/profileevaluator.cpp
@@ -0,0 +1,2340 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "profileevaluator.h"
+#include "proparserutils.h"
+#include "proitems.h"
+
+#include <QtCore/QByteArray>
+#include <QtCore/QDateTime>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QList>
+#include <QtCore/QRegExp>
+#include <QtCore/QSet>
+#include <QtCore/QStack>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QTextStream>
+
+#ifdef Q_OS_UNIX
+#include <unistd.h>
+#include <sys/utsname.h>
+#elif defined(Q_OS_WIN32)
+#include <Windows.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef Q_OS_WIN32
+#define QT_POPEN _popen
+#else
+#define QT_POPEN popen
+#endif
+
+QT_BEGIN_NAMESPACE
+
+///////////////////////////////////////////////////////////////////////
+//
+// Option
+//
+///////////////////////////////////////////////////////////////////////
+
+QString
+Option::fixString(QString string, uchar flags)
+{
+ // XXX Ripped out caching, so this will be slow. Should not matter for current uses.
+
+ //fix the environment variables
+ if (flags & Option::FixEnvVars) {
+ int rep;
+ QRegExp reg_variableName(QLatin1String("\\$\\(.*\\)"));
+ reg_variableName.setMinimal(true);
+ while ((rep = reg_variableName.indexIn(string)) != -1)
+ string.replace(rep, reg_variableName.matchedLength(),
+ QString::fromLocal8Bit(qgetenv(string.mid(rep + 2, reg_variableName.matchedLength() - 3).toLatin1().constData()).constData()));
+ }
+
+ //canonicalize it (and treat as a path)
+ if (flags & Option::FixPathCanonicalize) {
+#if 0
+ string = QFileInfo(string).canonicalFilePath();
+#endif
+ string = QDir::cleanPath(string);
+ }
+
+ if (string.length() > 2 && string[0].isLetter() && string[1] == QLatin1Char(':'))
+ string[0] = string[0].toLower();
+
+ //fix separators
+ Q_ASSERT(!((flags & Option::FixPathToLocalSeparators) && (flags & Option::FixPathToTargetSeparators)));
+ if (flags & Option::FixPathToLocalSeparators) {
+#if defined(Q_OS_WIN32)
+ string = string.replace(QLatin1Char('/'), QLatin1Char('\\'));
+#else
+ string = string.replace(QLatin1Char('\\'), QLatin1Char('/'));
+#endif
+ } else if (flags & Option::FixPathToTargetSeparators) {
+ string = string.replace(QLatin1Char('/'), Option::dir_sep)
+ .replace(QLatin1Char('\\'), Option::dir_sep);
+ }
+
+ if ((string.startsWith(QLatin1Char('"')) && string.endsWith(QLatin1Char('"'))) ||
+ (string.startsWith(QLatin1Char('\'')) && string.endsWith(QLatin1Char('\''))))
+ string = string.mid(1, string.length() - 2);
+
+ return string;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// ProFileEvaluator::Private
+//
+///////////////////////////////////////////////////////////////////////
+
+class ProFileEvaluator::Private : public AbstractProItemVisitor
+{
+public:
+ Private(ProFileEvaluator *q_);
+
+ ProFileEvaluator *q;
+ int m_lineNo; // Error reporting
+ bool m_verbose;
+
+ /////////////// Reading pro file
+
+ bool read(ProFile *pro);
+
+ ProBlock *currentBlock();
+ void updateItem();
+ bool parseLine(const QString &line);
+ void insertVariable(const QString &line, int *i);
+ void insertOperator(const char op);
+ void insertComment(const QString &comment);
+ void enterScope(bool multiLine);
+ void leaveScope();
+ void finalizeBlock();
+
+ QStack<ProBlock *> m_blockstack;
+ ProBlock *m_block;
+
+ ProItem *m_commentItem;
+ QString m_proitem;
+ QString m_pendingComment;
+ bool m_syntaxError;
+ bool m_contNextLine;
+
+ /////////////// Evaluating pro file contents
+
+ // implementation of AbstractProItemVisitor
+ bool visitBeginProBlock(ProBlock *block);
+ bool visitEndProBlock(ProBlock *block);
+ bool visitBeginProVariable(ProVariable *variable);
+ bool visitEndProVariable(ProVariable *variable);
+ bool visitBeginProFile(ProFile *value);
+ bool visitEndProFile(ProFile *value);
+ bool visitProValue(ProValue *value);
+ bool visitProFunction(ProFunction *function);
+ bool visitProOperator(ProOperator *oper);
+ bool visitProCondition(ProCondition *condition);
+
+ QStringList valuesDirect(const QString &variableName) const { return m_valuemap[variableName]; }
+ QStringList values(const QString &variableName) const;
+ QStringList values(const QString &variableName, const ProFile *pro) const;
+ QStringList values(const QString &variableName, const QHash<QString, QStringList> &place,
+ const ProFile *pro) const;
+ QString propertyValue(const QString &val) const;
+
+ bool isActiveConfig(const QString &config, bool regex = false);
+ QStringList expandPattern(const QString &pattern);
+ void expandPatternHelper(const QString &relName, const QString &absName,
+ QStringList &sources_out);
+ QStringList expandVariableReferences(const QString &value);
+ QStringList evaluateExpandFunction(const QString &function, const QString &arguments);
+ QString format(const char *format) const;
+
+ QString currentFileName() const;
+ QString currentDirectory() const;
+ ProFile *currentProFile() const;
+
+ bool evaluateConditionalFunction(const QString &function, const QString &arguments, bool *result);
+ bool evaluateFile(const QString &fileName, bool *result);
+ bool evaluateFeatureFile(const QString &fileName, bool *result);
+
+ QStringList qmakeFeaturePaths();
+
+ enum { ConditionTrue, ConditionFalse, ConditionElse };
+ int m_condition;
+ int m_prevCondition;
+ bool m_updateCondition;
+ bool m_invertNext;
+ int m_skipLevel;
+ bool m_cumulative;
+ QString m_lastVarName;
+ ProVariable::VariableOperator m_variableOperator;
+ QString m_origfile;
+ QString m_oldPath; // To restore the current path to the path
+ QStack<ProFile*> m_profileStack; // To handle 'include(a.pri), so we can track back to 'a.pro' when finished with 'a.pri'
+
+ QHash<QString, QStringList> m_valuemap; // VariableName must be us-ascii, the content however can be non-us-ascii.
+ QHash<const ProFile*, QHash<QString, QStringList> > m_filevaluemap; // Variables per include file
+ QHash<QString, QString> m_properties;
+ QString m_outputDir;
+
+ int m_prevLineNo; // Checking whether we're assigning the same TARGET
+ ProFile *m_prevProFile; // See m_prevLineNo
+};
+
+ProFileEvaluator::Private::Private(ProFileEvaluator *q_)
+ : q(q_)
+{
+ m_prevLineNo = 0;
+ m_prevProFile = 0;
+ m_verbose = true;
+ m_block = 0;
+ m_commentItem = 0;
+ m_syntaxError = 0;
+ m_lineNo = 0;
+ m_contNextLine = false;
+ m_cumulative = true;
+ m_updateCondition = false;
+ m_condition = ConditionFalse;
+ m_invertNext = false;
+ m_skipLevel = 0;
+}
+
+bool ProFileEvaluator::Private::read(ProFile *pro)
+{
+ QFile file(pro->fileName());
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ q->errorMessage(format("%1 not readable.").arg(pro->fileName()));
+ return false;
+ }
+
+ m_syntaxError = false;
+ m_lineNo = 1;
+ m_blockstack.push(pro);
+
+ QTextStream ts(&file);
+ while (!ts.atEnd()) {
+ QString line = ts.readLine();
+ if (!parseLine(line)) {
+ q->errorMessage(format(".pro parse failure."));
+ return false;
+ }
+ ++m_lineNo;
+ }
+ return true;
+}
+
+bool ProFileEvaluator::Private::parseLine(const QString &line0)
+{
+ if (m_blockstack.isEmpty())
+ return false;
+
+ ushort quote = 0;
+ int parens = 0;
+ bool contNextLine = false;
+ QString line = line0.simplified();
+
+ for (int i = 0; !m_syntaxError && i < line.length(); ++i) {
+ ushort c = line.at(i).unicode();
+ if (quote && c == quote)
+ quote = 0;
+ else if (c == '(')
+ ++parens;
+ else if (c == ')')
+ --parens;
+ else if (c == '"' && (i == 0 || line.at(i - 1).unicode() != '\\'))
+ quote = c;
+ else if (!parens && !quote) {
+ if (c == '#') {
+ insertComment(line.mid(i + 1));
+ contNextLine = m_contNextLine;
+ break;
+ }
+ if (c == '\\' && i >= line.count() - 1) {
+ updateItem();
+ contNextLine = true;
+ continue;
+ }
+ if (m_block && (m_block->blockKind() & ProBlock::VariableKind)) {
+ if (c == ' ')
+ updateItem();
+ else
+ m_proitem += c;
+ continue;
+ }
+ if (c == ':') {
+ enterScope(false);
+ continue;
+ }
+ if (c == '{') {
+ enterScope(true);
+ continue;
+ }
+ if (c == '}') {
+ leaveScope();
+ continue;
+ }
+ if (c == '=') {
+ insertVariable(line, &i);
+ continue;
+ }
+ if (c == '|' || c == '!') {
+ insertOperator(c);
+ continue;
+ }
+ }
+
+ m_proitem += c;
+ }
+ m_contNextLine = contNextLine;
+
+ if (!m_syntaxError) {
+ updateItem();
+ if (!m_contNextLine)
+ finalizeBlock();
+ }
+ return !m_syntaxError;
+}
+
+void ProFileEvaluator::Private::finalizeBlock()
+{
+ if (m_blockstack.isEmpty()) {
+ m_syntaxError = true;
+ } else {
+ if (m_blockstack.top()->blockKind() & ProBlock::SingleLine)
+ leaveScope();
+ m_block = 0;
+ m_commentItem = 0;
+ }
+}
+
+void ProFileEvaluator::Private::insertVariable(const QString &line, int *i)
+{
+ ProVariable::VariableOperator opkind;
+
+ switch (m_proitem.at(m_proitem.length() - 1).unicode()) {
+ case '+':
+ m_proitem.chop(1);
+ opkind = ProVariable::AddOperator;
+ break;
+ case '-':
+ m_proitem.chop(1);
+ opkind = ProVariable::RemoveOperator;
+ break;
+ case '*':
+ m_proitem.chop(1);
+ opkind = ProVariable::UniqueAddOperator;
+ break;
+ case '~':
+ m_proitem.chop(1);
+ opkind = ProVariable::ReplaceOperator;
+ break;
+ default:
+ opkind = ProVariable::SetOperator;
+ }
+
+ ProBlock *block = m_blockstack.top();
+ m_proitem = m_proitem.trimmed();
+ ProVariable *variable = new ProVariable(m_proitem, block);
+ variable->setLineNumber(m_lineNo);
+ variable->setVariableOperator(opkind);
+ block->appendItem(variable);
+ m_block = variable;
+
+ if (!m_pendingComment.isEmpty()) {
+ m_block->setComment(m_pendingComment);
+ m_pendingComment.clear();
+ }
+ m_commentItem = variable;
+
+ m_proitem.clear();
+
+ if (opkind == ProVariable::ReplaceOperator) {
+ // skip util end of line or comment
+ while (1) {
+ ++(*i);
+
+ // end of line?
+ if (*i >= line.count())
+ break;
+
+ // comment?
+ if (line.at(*i).unicode() == '#') {
+ --(*i);
+ break;
+ }
+
+ m_proitem += line.at(*i);
+ }
+ m_proitem = m_proitem.trimmed();
+ }
+}
+
+void ProFileEvaluator::Private::insertOperator(const char op)
+{
+ updateItem();
+
+ ProOperator::OperatorKind opkind;
+ switch (op) {
+ case '!':
+ opkind = ProOperator::NotOperator;
+ break;
+ case '|':
+ opkind = ProOperator::OrOperator;
+ break;
+ default:
+ opkind = ProOperator::OrOperator;
+ }
+
+ ProBlock * const block = currentBlock();
+ ProOperator * const proOp = new ProOperator(opkind);
+ proOp->setLineNumber(m_lineNo);
+ block->appendItem(proOp);
+ m_commentItem = proOp;
+}
+
+void ProFileEvaluator::Private::insertComment(const QString &comment)
+{
+ updateItem();
+
+ QString strComment;
+ if (!m_commentItem)
+ strComment = m_pendingComment;
+ else
+ strComment = m_commentItem->comment();
+
+ if (strComment.isEmpty())
+ strComment = comment;
+ else {
+ strComment += QLatin1Char('\n');
+ strComment += comment.trimmed();
+ }
+
+ strComment = strComment.trimmed();
+
+ if (!m_commentItem)
+ m_pendingComment = strComment;
+ else
+ m_commentItem->setComment(strComment);
+}
+
+void ProFileEvaluator::Private::enterScope(bool multiLine)
+{
+ updateItem();
+
+ ProBlock *parent = currentBlock();
+ ProBlock *block = new ProBlock(parent);
+ block->setLineNumber(m_lineNo);
+ parent->setBlockKind(ProBlock::ScopeKind);
+
+ parent->appendItem(block);
+
+ if (multiLine)
+ block->setBlockKind(ProBlock::ScopeContentsKind);
+ else
+ block->setBlockKind(ProBlock::ScopeContentsKind|ProBlock::SingleLine);
+
+ m_blockstack.push(block);
+ m_block = 0;
+}
+
+void ProFileEvaluator::Private::leaveScope()
+{
+ updateItem();
+ m_blockstack.pop();
+ finalizeBlock();
+}
+
+ProBlock *ProFileEvaluator::Private::currentBlock()
+{
+ if (m_block)
+ return m_block;
+
+ ProBlock *parent = m_blockstack.top();
+ m_block = new ProBlock(parent);
+ m_block->setLineNumber(m_lineNo);
+ parent->appendItem(m_block);
+
+ if (!m_pendingComment.isEmpty()) {
+ m_block->setComment(m_pendingComment);
+ m_pendingComment.clear();
+ }
+
+ m_commentItem = m_block;
+
+ return m_block;
+}
+
+void ProFileEvaluator::Private::updateItem()
+{
+ m_proitem = m_proitem.trimmed();
+ if (m_proitem.isEmpty())
+ return;
+
+ ProBlock *block = currentBlock();
+ if (block->blockKind() & ProBlock::VariableKind) {
+ m_commentItem = new ProValue(m_proitem, static_cast<ProVariable*>(block));
+ } else if (m_proitem.endsWith(QLatin1Char(')'))) {
+ m_commentItem = new ProFunction(m_proitem);
+ } else {
+ m_commentItem = new ProCondition(m_proitem);
+ }
+ m_commentItem->setLineNumber(m_lineNo);
+ block->appendItem(m_commentItem);
+
+ m_proitem.clear();
+}
+
+
+bool ProFileEvaluator::Private::visitBeginProBlock(ProBlock *block)
+{
+ if (block->blockKind() == ProBlock::ScopeKind) {
+ m_updateCondition = true;
+ if (!m_skipLevel) {
+ m_prevCondition = m_condition;
+ m_condition = ConditionFalse;
+ } else {
+ Q_ASSERT(m_condition != ConditionTrue);
+ }
+ } else if (block->blockKind() & ProBlock::ScopeContentsKind) {
+ m_updateCondition = false;
+ if (m_condition != ConditionTrue)
+ ++m_skipLevel;
+ else
+ Q_ASSERT(!m_skipLevel);
+ }
+ return true;
+}
+
+bool ProFileEvaluator::Private::visitEndProBlock(ProBlock *block)
+{
+ if (block->blockKind() & ProBlock::ScopeContentsKind) {
+ if (m_skipLevel) {
+ Q_ASSERT(m_condition != ConditionTrue);
+ --m_skipLevel;
+ } else {
+ // Conditionals contained inside this block may have changed the state.
+ // So we reset it here to make an else following us do the right thing.
+ m_condition = ConditionTrue;
+ }
+ }
+ return true;
+}
+
+bool ProFileEvaluator::Private::visitBeginProVariable(ProVariable *variable)
+{
+ m_lastVarName = variable->variable();
+ m_variableOperator = variable->variableOperator();
+ return true;
+}
+
+bool ProFileEvaluator::Private::visitEndProVariable(ProVariable *variable)
+{
+ Q_UNUSED(variable);
+ m_lastVarName.clear();
+ return true;
+}
+
+bool ProFileEvaluator::Private::visitProOperator(ProOperator *oper)
+{
+ m_invertNext = (oper->operatorKind() == ProOperator::NotOperator);
+ return true;
+}
+
+bool ProFileEvaluator::Private::visitProCondition(ProCondition *cond)
+{
+ if (!m_skipLevel) {
+ if (cond->text().toLower() == QLatin1String("else")) {
+ // The state ConditionElse makes sure that subsequential elses are ignored.
+ // That's braindead, but qmake is like that.
+ if (m_prevCondition == ConditionTrue)
+ m_condition = ConditionElse;
+ else if (m_prevCondition == ConditionFalse)
+ m_condition = ConditionTrue;
+ } else if (m_condition == ConditionFalse) {
+ if (isActiveConfig(cond->text(), true) ^ m_invertNext)
+ m_condition = ConditionTrue;
+ }
+ }
+ m_invertNext = false;
+ return true;
+}
+
+bool ProFileEvaluator::Private::visitBeginProFile(ProFile * pro)
+{
+ PRE(pro);
+ bool ok = true;
+ m_lineNo = pro->lineNumber();
+
+ if (m_origfile.isEmpty())
+ m_origfile = pro->fileName();
+ if (m_oldPath.isEmpty()) {
+ // change the working directory for the initial profile we visit, since
+ // that is *the* profile. All the other times we reach this function will be due to
+ // include(file) or load(file)
+
+ m_oldPath = QDir::currentPath();
+
+ m_profileStack.push(pro);
+
+ const QString mkspecDirectory = propertyValue(QLatin1String("QMAKE_MKSPECS"));
+ if (!mkspecDirectory.isEmpty()) {
+ bool cumulative = m_cumulative;
+ m_cumulative = false;
+ // This is what qmake does, everything set in the mkspec is also set
+ // But this also creates a lot of problems
+ evaluateFile(mkspecDirectory + QLatin1String("/default/qmake.conf"), &ok);
+ evaluateFile(mkspecDirectory + QLatin1String("/features/default_pre.prf"), &ok);
+ m_cumulative = cumulative;
+ }
+
+ ok = QDir::setCurrent(pro->directoryName());
+ }
+
+ return ok;
+}
+
+bool ProFileEvaluator::Private::visitEndProFile(ProFile * pro)
+{
+ PRE(pro);
+ bool ok = true;
+ m_lineNo = pro->lineNumber();
+ if (m_profileStack.count() == 1 && !m_oldPath.isEmpty()) {
+ const QString &mkspecDirectory = propertyValue(QLatin1String("QMAKE_MKSPECS"));
+ if (!mkspecDirectory.isEmpty()) {
+ bool cumulative = m_cumulative;
+ m_cumulative = false;
+
+ evaluateFile(mkspecDirectory + QLatin1String("/features/default_post.prf"), &ok);
+
+ QSet<QString> processed;
+ forever {
+ bool finished = true;
+ QStringList configs = valuesDirect(QLatin1String("CONFIG"));
+ for (int i = configs.size() - 1; i >= 0; --i) {
+ const QString config = configs[i].toLower();
+ if (!processed.contains(config)) {
+ processed.insert(config);
+ evaluateFile(mkspecDirectory + QLatin1String("/features/")
+ + config + QLatin1String(".prf"), &ok);
+ if (ok) {
+ finished = false;
+ break;
+ }
+ }
+ }
+ if (finished)
+ break;
+ }
+
+ m_cumulative = cumulative;
+ }
+
+ m_profileStack.pop();
+ ok = QDir::setCurrent(m_oldPath);
+ }
+ return ok;
+}
+
+static void replaceInList(QStringList *varlist,
+ const QRegExp &regexp, const QString &replace, bool global)
+{
+ for (QStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) {
+ if ((*varit).contains(regexp)) {
+ (*varit).replace(regexp, replace);
+ if ((*varit).isEmpty())
+ varit = varlist->erase(varit);
+ else
+ ++varit;
+ if(!global)
+ break;
+ } else {
+ ++varit;
+ }
+ }
+}
+
+bool ProFileEvaluator::Private::visitProValue(ProValue *value)
+{
+ PRE(value);
+ m_lineNo = value->lineNumber();
+ QString val = value->value();
+
+ QString varName = m_lastVarName;
+
+ QStringList v = expandVariableReferences(val);
+
+ // Since qmake combines different values for the TARGET variable, we join
+ // TARGET values that are on the same line. We can't do this later with all
+ // values because this parser isn't scope-aware, so we'd risk joining
+ // scope-specific targets together.
+ if (varName == QLatin1String("TARGET")
+ && m_lineNo == m_prevLineNo
+ && currentProFile() == m_prevProFile) {
+ QStringList targets = m_valuemap.value(QLatin1String("TARGET"));
+ m_valuemap.remove(QLatin1String("TARGET"));
+ QStringList lastTarget(targets.takeLast());
+ lastTarget << v.join(QLatin1String(" "));
+ targets.push_back(lastTarget.join(QLatin1String(" ")));
+ v = targets;
+ }
+ m_prevLineNo = m_lineNo;
+ m_prevProFile = currentProFile();
+
+ // The following two blocks fix bug 180128 by making all "interesting"
+ // file name absolute in each .pro file, not just the top most one
+ if (varName == QLatin1String("SOURCES")
+ || varName == QLatin1String("HEADERS")
+ || varName == QLatin1String("INTERFACES")
+ || varName == QLatin1String("FORMS")
+ || varName == QLatin1String("FORMS3")
+ || varName == QLatin1String("RESOURCES")) {
+ // matches only existent files, expand certain(?) patterns
+ QStringList vv;
+ for (int i = v.count(); --i >= 0; )
+ vv << expandPattern(v[i]);
+ v = vv;
+ }
+
+ if (varName == QLatin1String("TRANSLATIONS")) {
+ // also matches non-existent files, but does not expand pattern
+ QString dir = QFileInfo(currentFileName()).absolutePath();
+ dir += QLatin1Char('/');
+ for (int i = v.count(); --i >= 0; )
+ v[i] = QFileInfo(dir, v[i]).absoluteFilePath();
+ }
+
+ switch (m_variableOperator) {
+ case ProVariable::SetOperator: // =
+ if (!m_cumulative) {
+ if (!m_skipLevel) {
+ m_valuemap[varName] = v;
+ m_filevaluemap[currentProFile()][varName] = v;
+ }
+ } else {
+ // We are greedy for values.
+ m_valuemap[varName] += v;
+ m_filevaluemap[currentProFile()][varName] += v;
+ }
+ break;
+ case ProVariable::UniqueAddOperator: // *=
+ if (!m_skipLevel || m_cumulative) {
+ insertUnique(&m_valuemap, varName, v);
+ insertUnique(&m_filevaluemap[currentProFile()], varName, v);
+ }
+ break;
+ case ProVariable::AddOperator: // +=
+ if (!m_skipLevel || m_cumulative) {
+ m_valuemap[varName] += v;
+ m_filevaluemap[currentProFile()][varName] += v;
+ }
+ break;
+ case ProVariable::RemoveOperator: // -=
+ if (!m_cumulative) {
+ if (!m_skipLevel) {
+ removeEach(&m_valuemap, varName, v);
+ removeEach(&m_filevaluemap[currentProFile()], varName, v);
+ }
+ } else if (!m_skipLevel) {
+ // this is a hack for the moment to fix the
+ // CONFIG -= app_bundle problem on Mac (add it to a variable -CONFIG as was done before)
+ insertUnique(&m_valuemap, QString("-%1").arg(varName), v);
+ insertUnique(&m_filevaluemap[currentProFile()], QString("-%1").arg(varName), v);
+ } else {
+ // We are stingy with our values, too.
+ }
+ break;
+ case ProVariable::ReplaceOperator: // ~=
+ {
+ // DEFINES ~= s/a/b/?[gqi]
+
+ // FIXME: qmake variable-expands val first.
+ if (val.length() < 4 || val[0] != QLatin1Char('s')) {
+ q->logMessage(format("the ~= operator can handle only the s/// function."));
+ return false;
+ }
+ QChar sep = val.at(1);
+ QStringList func = val.split(sep);
+ if (func.count() < 3 || func.count() > 4) {
+ q->logMessage(format("the s/// function expects 3 or 4 arguments."));
+ return false;
+ }
+
+ bool global = false, quote = false, case_sense = false;
+ if (func.count() == 4) {
+ global = func[3].indexOf(QLatin1Char('g')) != -1;
+ case_sense = func[3].indexOf(QLatin1Char('i')) == -1;
+ quote = func[3].indexOf(QLatin1Char('q')) != -1;
+ }
+ QString pattern = func[1];
+ QString replace = func[2];
+ if (quote)
+ pattern = QRegExp::escape(pattern);
+
+ QRegExp regexp(pattern, case_sense ? Qt::CaseSensitive : Qt::CaseInsensitive);
+
+ if (!m_skipLevel || m_cumulative) {
+ // We could make a union of modified and unmodified values,
+ // but this will break just as much as it fixes, so leave it as is.
+ replaceInList(&m_valuemap[varName], regexp, replace, global);
+ replaceInList(&m_filevaluemap[currentProFile()][varName], regexp, replace, global);
+ }
+ }
+ break;
+
+ }
+ return true;
+}
+
+bool ProFileEvaluator::Private::visitProFunction(ProFunction *func)
+{
+ if (!m_updateCondition || m_condition == ConditionFalse) {
+ QString text = func->text();
+ int lparen = text.indexOf(QLatin1Char('('));
+ int rparen = text.lastIndexOf(QLatin1Char(')'));
+ Q_ASSERT(lparen < rparen);
+ QString arguments = text.mid(lparen + 1, rparen - lparen - 1);
+ QString funcName = text.left(lparen);
+ m_lineNo = func->lineNumber();
+ bool result;
+ if (!evaluateConditionalFunction(funcName.trimmed(), arguments, &result)) {
+ m_invertNext = false;
+ return false;
+ }
+ if (!m_skipLevel && (result ^ m_invertNext))
+ m_condition = ConditionTrue;
+ }
+ m_invertNext = false;
+ return true;
+}
+
+
+QStringList ProFileEvaluator::Private::qmakeFeaturePaths()
+{
+ QStringList concat;
+ {
+ const QString base_concat = QDir::separator() + QString(QLatin1String("features"));
+ concat << base_concat + QDir::separator() + QLatin1String("mac");
+ concat << base_concat + QDir::separator() + QLatin1String("macx");
+ concat << base_concat + QDir::separator() + QLatin1String("unix");
+ concat << base_concat + QDir::separator() + QLatin1String("win32");
+ concat << base_concat + QDir::separator() + QLatin1String("mac9");
+ concat << base_concat + QDir::separator() + QLatin1String("qnx6");
+ concat << base_concat;
+ }
+ const QString mkspecs_concat = QDir::separator() + QString(QLatin1String("mkspecs"));
+ QStringList feature_roots;
+ QByteArray mkspec_path = qgetenv("QMAKEFEATURES");
+ if (!mkspec_path.isNull())
+ feature_roots += splitPathList(QString::fromLocal8Bit(mkspec_path));
+ /*
+ if (prop)
+ feature_roots += splitPathList(prop->value("QMAKEFEATURES"));
+ if (!Option::mkfile::cachefile.isEmpty()) {
+ QString path;
+ int last_slash = Option::mkfile::cachefile.lastIndexOf(Option::dir_sep);
+ if (last_slash != -1)
+ path = Option::fixPathToLocalOS(Option::mkfile::cachefile.left(last_slash));
+ foreach (const QString &concat_it, concat)
+ feature_roots << (path + concat_it);
+ }
+ */
+
+ QByteArray qmakepath = qgetenv("QMAKEPATH");
+ if (!qmakepath.isNull()) {
+ const QStringList lst = splitPathList(QString::fromLocal8Bit(qmakepath));
+ foreach (const QString &item, lst) {
+ foreach (const QString &concat_it, concat)
+ feature_roots << (item + mkspecs_concat + concat_it);
+ }
+ }
+ //if (!Option::mkfile::qmakespec.isEmpty())
+ // feature_roots << Option::mkfile::qmakespec + QDir::separator() + "features";
+ //if (!Option::mkfile::qmakespec.isEmpty()) {
+ // QFileInfo specfi(Option::mkfile::qmakespec);
+ // QDir specdir(specfi.absoluteFilePath());
+ // while (!specdir.isRoot()) {
+ // if (!specdir.cdUp() || specdir.isRoot())
+ // break;
+ // if (QFile::exists(specdir.path() + QDir::separator() + "features")) {
+ // foreach (const QString &concat_it, concat)
+ // feature_roots << (specdir.path() + concat_it);
+ // break;
+ // }
+ // }
+ //}
+ foreach (const QString &concat_it, concat)
+ feature_roots << (propertyValue(QLatin1String("QT_INSTALL_PREFIX")) +
+ mkspecs_concat + concat_it);
+ foreach (const QString &concat_it, concat)
+ feature_roots << (propertyValue(QLatin1String("QT_INSTALL_DATA")) +
+ mkspecs_concat + concat_it);
+ return feature_roots;
+}
+
+QString ProFileEvaluator::Private::propertyValue(const QString &name) const
+{
+ if (m_properties.contains(name))
+ return m_properties.value(name);
+ if (name == QLatin1String("QT_INSTALL_PREFIX"))
+ return QLibraryInfo::location(QLibraryInfo::PrefixPath);
+ if (name == QLatin1String("QT_INSTALL_DATA"))
+ return QLibraryInfo::location(QLibraryInfo::DataPath);
+ if (name == QLatin1String("QT_INSTALL_DOCS"))
+ return QLibraryInfo::location(QLibraryInfo::DocumentationPath);
+ if (name == QLatin1String("QT_INSTALL_HEADERS"))
+ return QLibraryInfo::location(QLibraryInfo::HeadersPath);
+ if (name == QLatin1String("QT_INSTALL_LIBS"))
+ return QLibraryInfo::location(QLibraryInfo::LibrariesPath);
+ if (name == QLatin1String("QT_INSTALL_BINS"))
+ return QLibraryInfo::location(QLibraryInfo::BinariesPath);
+ if (name == QLatin1String("QT_INSTALL_PLUGINS"))
+ return QLibraryInfo::location(QLibraryInfo::PluginsPath);
+ if (name == QLatin1String("QT_INSTALL_TRANSLATIONS"))
+ return QLibraryInfo::location(QLibraryInfo::TranslationsPath);
+ if (name == QLatin1String("QT_INSTALL_CONFIGURATION"))
+ return QLibraryInfo::location(QLibraryInfo::SettingsPath);
+ if (name == QLatin1String("QT_INSTALL_EXAMPLES"))
+ return QLibraryInfo::location(QLibraryInfo::ExamplesPath);
+ if (name == QLatin1String("QT_INSTALL_DEMOS"))
+ return QLibraryInfo::location(QLibraryInfo::DemosPath);
+ if (name == QLatin1String("QMAKE_MKSPECS"))
+ return qmake_mkspec_paths().join(Option::dirlist_sep);
+ if (name == QLatin1String("QMAKE_VERSION"))
+ return QLatin1String("1.0"); //### FIXME
+ //return qmake_version();
+#ifdef QT_VERSION_STR
+ if (name == QLatin1String("QT_VERSION"))
+ return QLatin1String(QT_VERSION_STR);
+#endif
+ return QLatin1String("UNKNOWN"); //###
+}
+
+ProFile *ProFileEvaluator::Private::currentProFile() const
+{
+ if (m_profileStack.count() > 0)
+ return m_profileStack.top();
+ return 0;
+}
+
+QString ProFileEvaluator::Private::currentFileName() const
+{
+ ProFile *pro = currentProFile();
+ if (pro)
+ return pro->fileName();
+ return QString();
+}
+
+QString ProFileEvaluator::Private::currentDirectory() const
+{
+ ProFile *cur = m_profileStack.top();
+ return cur->directoryName();
+}
+
+QStringList ProFileEvaluator::Private::expandVariableReferences(const QString &str)
+{
+ bool fOK;
+ bool *ok = &fOK;
+ QStringList ret;
+ if (ok)
+ *ok = true;
+ if (str.isEmpty())
+ return ret;
+
+ const ushort LSQUARE = '[';
+ const ushort RSQUARE = ']';
+ const ushort LCURLY = '{';
+ const ushort RCURLY = '}';
+ const ushort LPAREN = '(';
+ const ushort RPAREN = ')';
+ const ushort DOLLAR = '$';
+ const ushort BACKSLASH = '\\';
+ const ushort UNDERSCORE = '_';
+ const ushort DOT = '.';
+ const ushort SPACE = ' ';
+ const ushort TAB = '\t';
+
+ const QChar *str_data = str.data();
+ const int str_len = str.length();
+
+ ushort term;
+ QString var, args;
+
+ int replaced = 0;
+ QString current;
+ for (int i = 0; i < str_len; ++i) {
+ ushort c = str_data[i].unicode();
+ const int start_var = i;
+ if (c == BACKSLASH) {
+ bool escape = false;
+ const char *symbols = "[]{}()$\\";
+ for (const char *s = symbols; *s; ++s) {
+ if (str_data[i+1] == (ushort)*s) {
+ i++;
+ escape = true;
+ if (!(replaced++))
+ current = str.left(start_var);
+ current.append(str.at(i));
+ break;
+ }
+ }
+ if (!escape && replaced)
+ current.append(QChar(c));
+ continue;
+ }
+ if (c == SPACE || c == TAB) {
+ c = 0;
+ if (!current.isEmpty()) {
+ unquote(&current);
+ ret.append(current);
+ current.clear();
+ }
+ } else if (c == DOLLAR && str_len > i+2) {
+ c = str_data[++i].unicode();
+ if (c == DOLLAR) {
+ term = 0;
+ var.clear();
+ args.clear();
+ enum { VAR, ENVIRON, FUNCTION, PROPERTY } var_type = VAR;
+ c = str_data[++i].unicode();
+ if (c == LSQUARE) {
+ c = str_data[++i].unicode();
+ term = RSQUARE;
+ var_type = PROPERTY;
+ } else if (c == LCURLY) {
+ c = str_data[++i].unicode();
+ var_type = VAR;
+ term = RCURLY;
+ } else if (c == LPAREN) {
+ c = str_data[++i].unicode();
+ var_type = ENVIRON;
+ term = RPAREN;
+ }
+ while (1) {
+ if (!(c & (0xFF<<8)) &&
+ c != DOT && c != UNDERSCORE &&
+ (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9'))
+ break;
+ var.append(QChar(c));
+ if (++i == str_len)
+ break;
+ c = str_data[i].unicode();
+ }
+ if (var_type == VAR && c == LPAREN) {
+ var_type = FUNCTION;
+ int depth = 0;
+ while (1) {
+ if (++i == str_len)
+ break;
+ c = str_data[i].unicode();
+ if (c == LPAREN) {
+ depth++;
+ } else if (c == RPAREN) {
+ if (!depth)
+ break;
+ --depth;
+ }
+ args.append(QChar(c));
+ }
+ if (i < str_len-1)
+ c = str_data[++i].unicode();
+ else
+ c = 0;
+ }
+ if (term) {
+ if (c != term) {
+ q->logMessage(format("Missing %1 terminator [found %2]")
+ .arg(QChar(term)).arg(QChar(c)));
+ if (ok)
+ *ok = false;
+ return QStringList();
+ }
+ c = 0;
+ } else if (i > str_len-1) {
+ c = 0;
+ }
+
+ QStringList replacement;
+ if (var_type == ENVIRON) {
+ replacement << QString::fromLocal8Bit(qgetenv(var.toLocal8Bit().constData()));
+ } else if (var_type == PROPERTY) {
+ replacement << propertyValue(var);
+ //if (prop)
+ // replacement = QStringList(prop->value(var));
+ } else if (var_type == FUNCTION) {
+ replacement << evaluateExpandFunction(var, args);
+ } else if (var_type == VAR) {
+ replacement += values(var);
+ }
+ if (!(replaced++) && start_var)
+ current = str.left(start_var);
+ if (!replacement.isEmpty()) {
+ /* If a list is beteen two strings make sure it expands in such a way
+ * that the string to the left is prepended to the first string and
+ * the string to the right is appended to the last string, example:
+ * LIST = a b c
+ * V3 = x/$$LIST/f.cpp
+ * message($$member(V3,0)) # Outputs "x/a"
+ * message($$member(V3,1)) # Outputs "b"
+ * message($$member(V3,2)) # Outputs "c/f.cpp"
+ */
+ current.append(replacement.at(0));
+ for (int i = 1; i < replacement.count(); ++i) {
+ unquote(&current);
+ ret.append(current);
+ current = replacement.at(i);
+ }
+ }
+ } else {
+ if (replaced)
+ current.append(QLatin1Char('$'));
+ }
+ }
+ if (replaced && c != 0)
+ current.append(QChar(c));
+ }
+ if (!replaced) {
+ current = str;
+ unquote(&current);
+ ret.append(current);
+ } else if (!current.isEmpty()) {
+ unquote(&current);
+ ret.append(current);
+ }
+ return ret;
+}
+
+bool ProFileEvaluator::Private::isActiveConfig(const QString &config, bool regex)
+{
+ // magic types for easy flipping
+ if (config == QLatin1String("true"))
+ return true;
+ if (config == QLatin1String("false"))
+ return false;
+
+ // mkspecs
+ if ((Option::target_mode == Option::TARG_MACX_MODE
+ || Option::target_mode == Option::TARG_QNX6_MODE
+ || Option::target_mode == Option::TARG_UNIX_MODE)
+ && config == QLatin1String("unix"))
+ return true;
+ if (Option::target_mode == Option::TARG_MACX_MODE && config == QLatin1String("macx"))
+ return true;
+ if (Option::target_mode == Option::TARG_QNX6_MODE && config == QLatin1String("qnx6"))
+ return true;
+ if (Option::target_mode == Option::TARG_MAC9_MODE && config == QLatin1String("mac9"))
+ return true;
+ if ((Option::target_mode == Option::TARG_MAC9_MODE
+ || Option::target_mode == Option::TARG_MACX_MODE)
+ && config == QLatin1String("mac"))
+ return true;
+ if (Option::target_mode == Option::TARG_WIN_MODE && config == QLatin1String("win32"))
+ return true;
+
+ QRegExp re(config, Qt::CaseSensitive, QRegExp::Wildcard);
+ QString spec = Option::qmakespec;
+ if ((regex && re.exactMatch(spec)) || (!regex && spec == config))
+ return true;
+
+ return false;
+}
+
+QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &func, const QString &arguments)
+{
+ QStringList argumentsList = split_arg_list(arguments);
+ QStringList args;
+ for (int i = 0; i < argumentsList.count(); ++i)
+ args += expandVariableReferences(argumentsList[i]);
+
+ enum ExpandFunc { E_MEMBER=1, E_FIRST, E_LAST, E_CAT, E_FROMFILE, E_EVAL, E_LIST,
+ E_SPRINTF, E_JOIN, E_SPLIT, E_BASENAME, E_DIRNAME, E_SECTION,
+ E_FIND, E_SYSTEM, E_UNIQUE, E_QUOTE, E_ESCAPE_EXPAND,
+ E_UPPER, E_LOWER, E_FILES, E_PROMPT, E_RE_ESCAPE,
+ E_REPLACE };
+
+ static QHash<QString, int> *expands = 0;
+ if (!expands) {
+ expands = new QHash<QString, int>;
+ expands->insert(QLatin1String("member"), E_MEMBER);
+ expands->insert(QLatin1String("first"), E_FIRST);
+ expands->insert(QLatin1String("last"), E_LAST);
+ expands->insert(QLatin1String("cat"), E_CAT);
+ expands->insert(QLatin1String("fromfile"), E_FROMFILE); // implementation disabled (see comment below)
+ expands->insert(QLatin1String("eval"), E_EVAL);
+ expands->insert(QLatin1String("list"), E_LIST);
+ expands->insert(QLatin1String("sprintf"), E_SPRINTF);
+ expands->insert(QLatin1String("join"), E_JOIN);
+ expands->insert(QLatin1String("split"), E_SPLIT);
+ expands->insert(QLatin1String("basename"), E_BASENAME);
+ expands->insert(QLatin1String("dirname"), E_DIRNAME);
+ expands->insert(QLatin1String("section"), E_SECTION);
+ expands->insert(QLatin1String("find"), E_FIND);
+ expands->insert(QLatin1String("system"), E_SYSTEM);
+ expands->insert(QLatin1String("unique"), E_UNIQUE);
+ expands->insert(QLatin1String("quote"), E_QUOTE);
+ expands->insert(QLatin1String("escape_expand"), E_ESCAPE_EXPAND);
+ expands->insert(QLatin1String("upper"), E_UPPER);
+ expands->insert(QLatin1String("lower"), E_LOWER);
+ expands->insert(QLatin1String("re_escape"), E_RE_ESCAPE);
+ expands->insert(QLatin1String("files"), E_FILES);
+ expands->insert(QLatin1String("prompt"), E_PROMPT); // interactive, so cannot be implemented
+ expands->insert(QLatin1String("replace"), E_REPLACE);
+ }
+ ExpandFunc func_t = ExpandFunc(expands->value(func.toLower()));
+
+ QStringList ret;
+
+ switch (func_t) {
+ case E_BASENAME:
+ case E_DIRNAME:
+ case E_SECTION: {
+ bool regexp = false;
+ QString sep, var;
+ int beg = 0;
+ int end = -1;
+ if (func_t == E_SECTION) {
+ if (args.count() != 3 && args.count() != 4) {
+ q->logMessage(format("%1(var) section(var, sep, begin, end) "
+ "requires three or four arguments.").arg(func));
+ } else {
+ var = args[0];
+ sep = args[1];
+ beg = args[2].toInt();
+ if (args.count() == 4)
+ end = args[3].toInt();
+ }
+ } else {
+ if (args.count() != 1) {
+ q->logMessage(format("%1(var) requires one argument.").arg(func));
+ } else {
+ var = args[0];
+ regexp = true;
+ sep = QLatin1String("[\\\\/]");
+ if (func_t == E_DIRNAME)
+ end = -2;
+ else
+ beg = -1;
+ }
+ }
+ if (!var.isNull()) {
+ foreach (const QString str, values(var)) {
+ if (regexp)
+ ret += str.section(QRegExp(sep), beg, end);
+ else
+ ret += str.section(sep, beg, end);
+ }
+ }
+ break;
+ }
+ case E_SPRINTF:
+ if(args.count() < 1) {
+ q->logMessage(format("sprintf(format, ...) requires at least one argument"));
+ } else {
+ QString tmp = args.at(0);
+ for (int i = 1; i < args.count(); ++i)
+ tmp = tmp.arg(args.at(i));
+ ret = split_value_list(tmp);
+ }
+ break;
+ case E_JOIN: {
+ if (args.count() < 1 || args.count() > 4) {
+ q->logMessage(format("join(var, glue, before, after) requires one to four arguments."));
+ } else {
+ QString glue, before, after;
+ if (args.count() >= 2)
+ glue = args[1];
+ if (args.count() >= 3)
+ before = args[2];
+ if (args.count() == 4)
+ after = args[3];
+ const QStringList &var = values(args.first());
+ if (!var.isEmpty())
+ ret.append(before + var.join(glue) + after);
+ }
+ break;
+ }
+ case E_SPLIT: {
+ if (args.count() != 2) {
+ q->logMessage(format("split(var, sep) requires one or two arguments"));
+ } else {
+ const QString &sep = (args.count() == 2) ? args[1] : QString(Option::field_sep);
+ foreach (const QString &var, values(args.first()))
+ foreach (const QString &splt, var.split(sep))
+ ret.append(splt);
+ }
+ break;
+ }
+ case E_MEMBER: {
+ if (args.count() < 1 || args.count() > 3) {
+ q->logMessage(format("member(var, start, end) requires one to three arguments."));
+ } else {
+ bool ok = true;
+ const QStringList var = values(args.first());
+ int start = 0, end = 0;
+ if (args.count() >= 2) {
+ QString start_str = args[1];
+ start = start_str.toInt(&ok);
+ if (!ok) {
+ if (args.count() == 2) {
+ int dotdot = start_str.indexOf(QLatin1String(".."));
+ if (dotdot != -1) {
+ start = start_str.left(dotdot).toInt(&ok);
+ if (ok)
+ end = start_str.mid(dotdot+2).toInt(&ok);
+ }
+ }
+ if (!ok)
+ q->logMessage(format("member() argument 2 (start) '%2' invalid.")
+ .arg(start_str));
+ } else {
+ end = start;
+ if (args.count() == 3)
+ end = args[2].toInt(&ok);
+ if (!ok)
+ q->logMessage(format("member() argument 3 (end) '%2' invalid.\n")
+ .arg(args[2]));
+ }
+ }
+ if (ok) {
+ if (start < 0)
+ start += var.count();
+ if (end < 0)
+ end += var.count();
+ if (start < 0 || start >= var.count() || end < 0 || end >= var.count()) {
+ //nothing
+ } else if (start < end) {
+ for (int i = start; i <= end && var.count() >= i; i++)
+ ret.append(var[i]);
+ } else {
+ for (int i = start; i >= end && var.count() >= i && i >= 0; i--)
+ ret += var[i];
+ }
+ }
+ }
+ break;
+ }
+ case E_FIRST:
+ case E_LAST: {
+ if (args.count() != 1) {
+ q->logMessage(format("%1(var) requires one argument.").arg(func));
+ } else {
+ const QStringList var = values(args.first());
+ if (!var.isEmpty()) {
+ if (func_t == E_FIRST)
+ ret.append(var[0]);
+ else
+ ret.append(var.last());
+ }
+ }
+ break;
+ }
+ case E_CAT:
+ if (args.count() < 1 || args.count() > 2) {
+ q->logMessage(format("cat(file, singleline=true) requires one or two arguments."));
+ } else {
+ QString file = args[0];
+ file = Option::fixPathToLocalOS(file);
+
+ bool singleLine = true;
+ if (args.count() > 1)
+ singleLine = (args[1].toLower() == QLatin1String("true"));
+
+ QFile qfile(file);
+ if (qfile.open(QIODevice::ReadOnly)) {
+ QTextStream stream(&qfile);
+ while (!stream.atEnd()) {
+ ret += split_value_list(stream.readLine().trimmed());
+ if (!singleLine)
+ ret += QLatin1String("\n");
+ }
+ qfile.close();
+ }
+ }
+ break;
+#if 0 // Used only by Qt's configure for caching
+ case E_FROMFILE:
+ if (args.count() != 2) {
+ q->logMessage(format("fromfile(file, variable) requires two arguments."));
+ } else {
+ QString file = args[0], seek_variableName = args[1];
+
+ ProFile pro(Option::fixPathToLocalOS(file));
+
+ ProFileEvaluator visitor;
+ visitor.setVerbose(m_verbose);
+ visitor.setCumulative(m_cumulative);
+
+ if (!visitor.queryProFile(&pro))
+ break;
+
+ if (!visitor.accept(&pro))
+ break;
+
+ ret = visitor.values(seek_variableName);
+ }
+ break;
+#endif
+ case E_EVAL: {
+ if (args.count() != 1) {
+ q->logMessage(format("eval(variable) requires one argument"));
+
+ } else {
+ ret += values(args.at(0));
+ }
+ break; }
+ case E_LIST: {
+ static int x = 0;
+ QString tmp;
+ tmp.sprintf(".QMAKE_INTERNAL_TMP_variableName_%d", x++);
+ ret = QStringList(tmp);
+ QStringList lst;
+ foreach (const QString &arg, args)
+ lst += split_value_list(arg);
+ m_valuemap[tmp] = lst;
+ break; }
+ case E_FIND:
+ if (args.count() != 2) {
+ q->logMessage(format("find(var, str) requires two arguments."));
+ } else {
+ QRegExp regx(args[1]);
+ foreach (const QString &val, values(args.first()))
+ if (regx.indexIn(val) != -1)
+ ret += val;
+ }
+ break;
+#if 0 // Disabled, as it is relatively useless, too slow and dangerous.
+ case E_SYSTEM:
+ if (!m_skipLevel) { // FIXME: should exec only if the result is being used
+ // (i.e., if this is nested into an assignment) - these
+ // are less likely to have side effects
+ if (args.count() < 1 || args.count() > 2) {
+ q->logMessage(format("system(execute) requires one or two arguments."));
+ } else {
+ char buff[256];
+ FILE *proc = QT_POPEN(args[0].toLatin1(), "r");
+ bool singleLine = true;
+ if (args.count() > 1)
+ singleLine = (args[1].toLower() == QLatin1String("true"));
+ QString output;
+ while (proc && !feof(proc)) {
+ int read_in = int(fread(buff, 1, 255, proc));
+ if (!read_in)
+ break;
+ for (int i = 0; i < read_in; i++) {
+ if ((singleLine && buff[i] == '\n') || buff[i] == '\t')
+ buff[i] = ' ';
+ }
+ buff[read_in] = '\0';
+ output += QLatin1String(buff);
+ }
+ ret += split_value_list(output);
+ }
+ }
+ break;
+#endif
+ case E_UNIQUE:
+ if(args.count() != 1) {
+ q->logMessage(format("unique(var) requires one argument."));
+ } else {
+ foreach (const QString &var, values(args.first()))
+ if (!ret.contains(var))
+ ret.append(var);
+ }
+ break;
+ case E_QUOTE:
+ for (int i = 0; i < args.count(); ++i)
+ ret += QStringList(args.at(i));
+ break;
+ case E_ESCAPE_EXPAND:
+ for (int i = 0; i < args.size(); ++i) {
+ QChar *i_data = args[i].data();
+ int i_len = args[i].length();
+ for (int x = 0; x < i_len; ++x) {
+ if (*(i_data+x) == QLatin1Char('\\') && x < i_len-1) {
+ if (*(i_data+x+1) == QLatin1Char('\\')) {
+ ++x;
+ } else {
+ struct {
+ char in, out;
+ } mapped_quotes[] = {
+ { 'n', '\n' },
+ { 't', '\t' },
+ { 'r', '\r' },
+ { 0, 0 }
+ };
+ for (int i = 0; mapped_quotes[i].in; ++i) {
+ if (*(i_data+x+1) == QLatin1Char(mapped_quotes[i].in)) {
+ *(i_data+x) = QLatin1Char(mapped_quotes[i].out);
+ if (x < i_len-2)
+ memmove(i_data+x+1, i_data+x+2, (i_len-x-2)*sizeof(QChar));
+ --i_len;
+ break;
+ }
+ }
+ }
+ }
+ }
+ ret.append(QString(i_data, i_len));
+ }
+ break;
+ case E_RE_ESCAPE:
+ for (int i = 0; i < args.size(); ++i)
+ ret += QRegExp::escape(args[i]);
+ break;
+ case E_UPPER:
+ case E_LOWER:
+ for (int i = 0; i < args.count(); ++i)
+ if (func_t == E_UPPER)
+ ret += args[i].toUpper();
+ else
+ ret += args[i].toLower();
+ break;
+ case E_FILES:
+ if (args.count() != 1 && args.count() != 2) {
+ q->logMessage(format("files(pattern, recursive=false) requires one or two arguments"));
+ } else {
+ bool recursive = false;
+ if (args.count() == 2)
+ recursive = (args[1].toLower() == QLatin1String("true") || args[1].toInt());
+ QStringList dirs;
+ QString r = Option::fixPathToLocalOS(args[0]);
+ int slash = r.lastIndexOf(QDir::separator());
+ if (slash != -1) {
+ dirs.append(r.left(slash));
+ r = r.mid(slash+1);
+ } else {
+ dirs.append(QString());
+ }
+
+ const QRegExp regex(r, Qt::CaseSensitive, QRegExp::Wildcard);
+ for (int d = 0; d < dirs.count(); d++) {
+ QString dir = dirs[d];
+ if (!dir.isEmpty() && !dir.endsWith(Option::dir_sep))
+ dir += QLatin1Char('/');
+
+ QDir qdir(dir);
+ for (int i = 0; i < (int)qdir.count(); ++i) {
+ if (qdir[i] == QLatin1String(".") || qdir[i] == QLatin1String(".."))
+ continue;
+ QString fname = dir + qdir[i];
+ if (QFileInfo(fname).isDir()) {
+ if (recursive)
+ dirs.append(fname);
+ }
+ if (regex.exactMatch(qdir[i]))
+ ret += fname;
+ }
+ }
+ }
+ break;
+ case E_REPLACE:
+ if(args.count() != 3 ) {
+ q->logMessage(format("replace(var, before, after) requires three arguments"));
+ } else {
+ const QRegExp before(args[1]);
+ const QString after(args[2]);
+ foreach (QString val, values(args.first()))
+ ret += val.replace(before, after);
+ }
+ break;
+ case 0:
+ q->logMessage(format("'%1' is not a recognized replace function").arg(func));
+ break;
+ default:
+ q->logMessage(format("Function '%1' is not implemented").arg(func));
+ break;
+ }
+
+ return ret;
+}
+
+bool ProFileEvaluator::Private::evaluateConditionalFunction(const QString &function,
+ const QString &arguments, bool *result)
+{
+ QStringList argumentsList = split_arg_list(arguments);
+ QString sep;
+ sep.append(Option::field_sep);
+
+ QStringList args;
+ for (int i = 0; i < argumentsList.count(); ++i)
+ args += expandVariableReferences(argumentsList[i]).join(sep);
+
+ enum TestFunc { T_REQUIRES=1, T_GREATERTHAN, T_LESSTHAN, T_EQUALS,
+ T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM,
+ T_RETURN, T_BREAK, T_NEXT, T_DEFINED, T_CONTAINS, T_INFILE,
+ T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_MESSAGE, T_IF };
+
+ static QHash<QString, int> *functions = 0;
+ if (!functions) {
+ functions = new QHash<QString, int>;
+ functions->insert(QLatin1String("requires"), T_REQUIRES);
+ functions->insert(QLatin1String("greaterThan"), T_GREATERTHAN);
+ functions->insert(QLatin1String("lessThan"), T_LESSTHAN);
+ functions->insert(QLatin1String("equals"), T_EQUALS);
+ functions->insert(QLatin1String("isEqual"), T_EQUALS);
+ functions->insert(QLatin1String("exists"), T_EXISTS);
+ functions->insert(QLatin1String("export"), T_EXPORT);
+ functions->insert(QLatin1String("clear"), T_CLEAR);
+ functions->insert(QLatin1String("unset"), T_UNSET);
+ functions->insert(QLatin1String("eval"), T_EVAL);
+ functions->insert(QLatin1String("CONFIG"), T_CONFIG);
+ functions->insert(QLatin1String("if"), T_IF);
+ functions->insert(QLatin1String("isActiveConfig"), T_CONFIG);
+ functions->insert(QLatin1String("system"), T_SYSTEM);
+ functions->insert(QLatin1String("return"), T_RETURN);
+ functions->insert(QLatin1String("break"), T_BREAK);
+ functions->insert(QLatin1String("next"), T_NEXT);
+ functions->insert(QLatin1String("defined"), T_DEFINED);
+ functions->insert(QLatin1String("contains"), T_CONTAINS);
+ functions->insert(QLatin1String("infile"), T_INFILE);
+ functions->insert(QLatin1String("count"), T_COUNT);
+ functions->insert(QLatin1String("isEmpty"), T_ISEMPTY);
+ functions->insert(QLatin1String("load"), T_LOAD); //v
+ functions->insert(QLatin1String("include"), T_INCLUDE); //v
+ functions->insert(QLatin1String("debug"), T_DEBUG);
+ functions->insert(QLatin1String("message"), T_MESSAGE); //v
+ functions->insert(QLatin1String("warning"), T_MESSAGE); //v
+ functions->insert(QLatin1String("error"), T_MESSAGE); //v
+ }
+
+ bool cond = false;
+ bool ok = true;
+
+ TestFunc func_t = (TestFunc)functions->value(function);
+
+ switch (func_t) {
+#if 0
+ case T_INFILE:
+ case T_REQUIRES:
+ case T_GREATERTHAN:
+ case T_LESSTHAN:
+ case T_EQUALS:
+ case T_EXPORT:
+ case T_CLEAR:
+ case T_UNSET:
+ case T_EVAL:
+ case T_IF:
+ case T_RETURN:
+ case T_BREAK:
+ case T_NEXT:
+ case T_DEFINED:
+#endif
+ case T_CONFIG: {
+ if (args.count() < 1 || args.count() > 2) {
+ q->logMessage(format("CONFIG(config) requires one or two arguments."));
+ ok = false;
+ break;
+ }
+ if (args.count() == 1) {
+ //cond = isActiveConfig(args.first()); XXX
+ break;
+ }
+ const QStringList mutuals = args[1].split(QLatin1Char('|'));
+ const QStringList &configs = valuesDirect(QLatin1String("CONFIG"));
+ for (int i = configs.size() - 1 && ok; i >= 0; i--) {
+ for (int mut = 0; mut < mutuals.count(); mut++) {
+ if (configs[i] == mutuals[mut].trimmed()) {
+ cond = (configs[i] == args[0]);
+ break;
+ }
+ }
+ }
+ break;
+ }
+ case T_CONTAINS: {
+ if (args.count() < 2 || args.count() > 3) {
+ q->logMessage(format("contains(var, val) requires two or three arguments."));
+ ok = false;
+ break;
+ }
+
+ QRegExp regx(args[1]);
+ const QStringList &l = values(args.first());
+ if (args.count() == 2) {
+ for (int i = 0; i < l.size(); ++i) {
+ const QString val = l[i];
+ if (regx.exactMatch(val) || val == args[1]) {
+ cond = true;
+ break;
+ }
+ }
+ } else {
+ const QStringList mutuals = args[2].split(QLatin1Char('|'));
+ for (int i = l.size() - 1; i >= 0; i--) {
+ const QString val = l[i];
+ for (int mut = 0; mut < mutuals.count(); mut++) {
+ if (val == mutuals[mut].trimmed()) {
+ cond = (regx.exactMatch(val) || val == args[1]);
+ break;
+ }
+ }
+ }
+ }
+
+ break;
+ }
+ case T_COUNT: {
+ if (args.count() != 2 && args.count() != 3) {
+ q->logMessage(format("count(var, count, op=\"equals\") requires two or three arguments."));
+ ok = false;
+ break;
+ }
+ if (args.count() == 3) {
+ QString comp = args[2];
+ if (comp == QLatin1String(">") || comp == QLatin1String("greaterThan")) {
+ cond = values(args.first()).count() > args[1].toInt();
+ } else if (comp == QLatin1String(">=")) {
+ cond = values(args.first()).count() >= args[1].toInt();
+ } else if (comp == QLatin1String("<") || comp == QLatin1String("lessThan")) {
+ cond = values(args.first()).count() < args[1].toInt();
+ } else if (comp == QLatin1String("<=")) {
+ cond = values(args.first()).count() <= args[1].toInt();
+ } else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual") || comp == QLatin1String("=") || comp == QLatin1String("==")) {
+ cond = values(args.first()).count() == args[1].toInt();
+ } else {
+ ok = false;
+ q->logMessage(format("unexpected modifier to count(%2)").arg(comp));
+ }
+ break;
+ }
+ cond = values(args.first()).count() == args[1].toInt();
+ break;
+ }
+ case T_INCLUDE: {
+ if (m_skipLevel && !m_cumulative)
+ break;
+ QString parseInto;
+ if (args.count() == 2) {
+ parseInto = args[1];
+ } else if (args.count() != 1) {
+ q->logMessage(format("include(file) requires one or two arguments."));
+ ok = false;
+ break;
+ }
+ QString fileName = args.first();
+ // ### this breaks if we have include(c:/reallystupid.pri) but IMHO that's really bad style.
+ QDir currentProPath(currentDirectory());
+ fileName = QDir::cleanPath(currentProPath.absoluteFilePath(fileName));
+ ok = evaluateFile(fileName, &ok);
+ break;
+ }
+ case T_LOAD: {
+ if (m_skipLevel && !m_cumulative)
+ break;
+ QString parseInto;
+ bool ignore_error = false;
+ if (args.count() == 2) {
+ QString sarg = args[1];
+ ignore_error = (sarg.toLower() == QLatin1String("true") || sarg.toInt());
+ } else if (args.count() != 1) {
+ q->logMessage(format("load(feature) requires one or two arguments."));
+ ok = false;
+ break;
+ }
+ ok = evaluateFeatureFile( args.first(), &cond);
+ break;
+ }
+ case T_DEBUG:
+ // Yup - do nothing. Nothing is going to enable debug output anyway.
+ break;
+ case T_MESSAGE: {
+ if (args.count() != 1) {
+ q->logMessage(format("%1(message) requires one argument.").arg(function));
+ ok = false;
+ break;
+ }
+ QString msg = fixEnvVariables(args.first());
+ if (function == QLatin1String("error")) {
+ QStringList parents;
+ foreach (ProFile *proFile, m_profileStack)
+ parents.append(proFile->fileName());
+ if (!parents.isEmpty())
+ parents.takeLast();
+ if (parents.isEmpty())
+ q->fileMessage(format("Project ERROR: %1").arg(msg));
+ else
+ q->fileMessage(format("Project ERROR: %1. File was included from: '%2'")
+ .arg(msg).arg(parents.join(QLatin1String("', '"))));
+ } else {
+ q->fileMessage(format("Project MESSAGE: %1").arg(msg));
+ }
+ break;
+ }
+#if 0 // Way too dangerous to enable.
+ case T_SYSTEM: {
+ if (args.count() != 1) {
+ q->logMessage(format("system(exec) requires one argument."));
+ ok = false;
+ break;
+ }
+ ok = system(args.first().toLatin1().constData()) == 0;
+ break;
+ }
+#endif
+ case T_ISEMPTY: {
+ if (args.count() != 1) {
+ q->logMessage(format("isEmpty(var) requires one argument."));
+ ok = false;
+ break;
+ }
+ QStringList sl = values(args.first());
+ if (sl.count() == 0) {
+ cond = true;
+ } else if (sl.count() > 0) {
+ QString var = sl.first();
+ cond = (var.isEmpty());
+ }
+ break;
+ }
+ case T_EXISTS: {
+ if (args.count() != 1) {
+ q->logMessage(format("exists(file) requires one argument."));
+ ok = false;
+ break;
+ }
+ QString file = args.first();
+ file = Option::fixPathToLocalOS(file);
+
+ if (QFile::exists(file)) {
+ cond = true;
+ break;
+ }
+ //regular expression I guess
+ QString dirstr = currentDirectory();
+ int slsh = file.lastIndexOf(Option::dir_sep);
+ if (slsh != -1) {
+ dirstr = file.left(slsh+1);
+ file = file.right(file.length() - slsh - 1);
+ }
+ cond = QDir(dirstr).entryList(QStringList(file)).count();
+
+ break;
+ }
+ case 0:
+ // This is too chatty currently (missing defineTest and defineReplace)
+ //q->logMessage(format("'%1' is not a recognized test function").arg(function));
+ break;
+ default:
+ q->logMessage(format("Function '%1' is not implemented").arg(function));
+ break;
+ }
+
+ if (result)
+ *result = cond;
+
+ return ok;
+}
+
+QStringList ProFileEvaluator::Private::values(const QString &variableName,
+ const QHash<QString, QStringList> &place,
+ const ProFile *pro) const
+{
+ if (variableName == QLatin1String("LITERAL_WHITESPACE")) //a real space in a token
+ return QStringList(QLatin1String("\t"));
+ if (variableName == QLatin1String("LITERAL_DOLLAR")) //a real $
+ return QStringList(QLatin1String("$"));
+ if (variableName == QLatin1String("LITERAL_HASH")) //a real #
+ return QStringList(QLatin1String("#"));
+ if (variableName == QLatin1String("OUT_PWD")) //the out going dir
+ return QStringList(m_outputDir);
+ if (variableName == QLatin1String("PWD") || //current working dir (of _FILE_)
+ variableName == QLatin1String("IN_PWD"))
+ return QStringList(currentDirectory());
+ if (variableName == QLatin1String("DIR_SEPARATOR"))
+ return QStringList(Option::dir_sep);
+ if (variableName == QLatin1String("DIRLIST_SEPARATOR"))
+ return QStringList(Option::dirlist_sep);
+ if (variableName == QLatin1String("_LINE_")) //parser line number
+ return QStringList(QString::number(m_lineNo));
+ if (variableName == QLatin1String("_FILE_")) //parser file; qmake is a bit weird here
+ return QStringList(m_profileStack.size() == 1 ? pro->fileName() : QFileInfo(pro->fileName()).fileName());
+ if (variableName == QLatin1String("_DATE_")) //current date/time
+ return QStringList(QDateTime::currentDateTime().toString());
+ if (variableName == QLatin1String("_PRO_FILE_"))
+ return QStringList(m_origfile);
+ if (variableName == QLatin1String("_PRO_FILE_PWD_"))
+ return QStringList(QFileInfo(m_origfile).absolutePath());
+ if (variableName == QLatin1String("_QMAKE_CACHE_"))
+ return QStringList(); // FIXME?
+ if (variableName.startsWith(QLatin1String("QMAKE_HOST."))) {
+ QString ret, type = variableName.mid(11);
+#if defined(Q_OS_WIN32)
+ if (type == QLatin1String("os")) {
+ ret = QLatin1String("Windows");
+ } else if (type == QLatin1String("name")) {
+ DWORD name_length = 1024;
+ TCHAR name[1024];
+ if (GetComputerName(name, &name_length))
+ ret = QString::fromUtf16((ushort*)name, name_length);
+ } else if (type == QLatin1String("version") || type == QLatin1String("version_string")) {
+ QSysInfo::WinVersion ver = QSysInfo::WindowsVersion;
+ if (type == QLatin1String("version"))
+ ret = QString::number(ver);
+ else if (ver == QSysInfo::WV_Me)
+ ret = QLatin1String("WinMe");
+ else if (ver == QSysInfo::WV_95)
+ ret = QLatin1String("Win95");
+ else if (ver == QSysInfo::WV_98)
+ ret = QLatin1String("Win98");
+ else if (ver == QSysInfo::WV_NT)
+ ret = QLatin1String("WinNT");
+ else if (ver == QSysInfo::WV_2000)
+ ret = QLatin1String("Win2000");
+ else if (ver == QSysInfo::WV_2000)
+ ret = QLatin1String("Win2003");
+ else if (ver == QSysInfo::WV_XP)
+ ret = QLatin1String("WinXP");
+ else if (ver == QSysInfo::WV_VISTA)
+ ret = QLatin1String("WinVista");
+ else
+ ret = QLatin1String("Unknown");
+ } else if (type == QLatin1String("arch")) {
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+ switch(info.wProcessorArchitecture) {
+#ifdef PROCESSOR_ARCHITECTURE_AMD64
+ case PROCESSOR_ARCHITECTURE_AMD64:
+ ret = QLatin1String("x86_64");
+ break;
+#endif
+ case PROCESSOR_ARCHITECTURE_INTEL:
+ ret = QLatin1String("x86");
+ break;
+ case PROCESSOR_ARCHITECTURE_IA64:
+#ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
+ case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
+#endif
+ ret = QLatin1String("IA64");
+ break;
+ default:
+ ret = QLatin1String("Unknown");
+ break;
+ }
+ }
+#elif defined(Q_OS_UNIX)
+ struct utsname name;
+ if (!uname(&name)) {
+ if (type == QLatin1String("os"))
+ ret = QString::fromLatin1(name.sysname);
+ else if (type == QLatin1String("name"))
+ ret = QString::fromLatin1(name.nodename);
+ else if (type == QLatin1String("version"))
+ ret = QString::fromLatin1(name.release);
+ else if (type == QLatin1String("version_string"))
+ ret = QString::fromLatin1(name.version);
+ else if (type == QLatin1String("arch"))
+ ret = QString::fromLatin1(name.machine);
+ }
+#endif
+ return QStringList(ret);
+ }
+
+ QStringList result = place[variableName];
+ if (result.isEmpty()) {
+ if (variableName == QLatin1String("TARGET")) {
+ result.append(QFileInfo(m_origfile).baseName());
+ } else if (variableName == QLatin1String("TEMPLATE")) {
+ result.append(QLatin1String("app"));
+ } else if (variableName == QLatin1String("QMAKE_DIR_SEP")) {
+ result.append(Option::dirlist_sep);
+ }
+ }
+ return result;
+}
+
+QStringList ProFileEvaluator::Private::values(const QString &variableName) const
+{
+ return values(variableName, m_valuemap, currentProFile());
+}
+
+QStringList ProFileEvaluator::Private::values(const QString &variableName, const ProFile *pro) const
+{
+ return values(variableName, m_filevaluemap[pro], pro);
+}
+
+ProFile *ProFileEvaluator::parsedProFile(const QString &fileName)
+{
+ QFileInfo fi(fileName);
+ if (fi.exists()) {
+ ProFile *pro = new ProFile(fi.absoluteFilePath());
+ if (d->read(pro))
+ return pro;
+ delete pro;
+ }
+ return 0;
+}
+
+void ProFileEvaluator::releaseParsedProFile(ProFile *proFile)
+{
+ delete proFile;
+}
+
+bool ProFileEvaluator::Private::evaluateFile(const QString &fileName, bool *result)
+{
+ bool ok = true;
+ ProFile *pro = q->parsedProFile(fileName);
+ if (pro) {
+ m_profileStack.push(pro);
+ ok = (currentProFile() ? pro->Accept(this) : false);
+ m_profileStack.pop();
+ q->releaseParsedProFile(pro);
+
+ if (result)
+ *result = true;
+ } else {
+ if (result)
+ *result = false;
+ }
+/* if (ok && readFeatures) {
+ QStringList configs = values("CONFIG");
+ QSet<QString> processed;
+ foreach (const QString &fn, configs) {
+ if (!processed.contains(fn)) {
+ processed.insert(fn);
+ evaluateFeatureFile(fn, 0);
+ }
+ }
+ } */
+
+ return ok;
+}
+
+bool ProFileEvaluator::Private::evaluateFeatureFile(const QString &fileName, bool *result)
+{
+ QString fn;
+ foreach (const QString &path, qmakeFeaturePaths()) {
+ QString fname = path + QLatin1Char('/') + fileName;
+ if (QFileInfo(fname).exists()) {
+ fn = fname;
+ break;
+ }
+ fname += QLatin1String(".prf");
+ if (QFileInfo(fname).exists()) {
+ fn = fname;
+ break;
+ }
+ }
+ if (fn.isEmpty())
+ return false;
+ bool cumulative = m_cumulative;
+ m_cumulative = false;
+ bool ok = evaluateFile(fn, result);
+ m_cumulative = cumulative;
+ return ok;
+}
+
+void ProFileEvaluator::Private::expandPatternHelper(const QString &relName, const QString &absName,
+ QStringList &sources_out)
+{
+ const QStringList vpaths = values(QLatin1String("VPATH"))
+ + values(QLatin1String("QMAKE_ABSOLUTE_SOURCE_PATH"))
+ + values(QLatin1String("DEPENDPATH"))
+ + values(QLatin1String("VPATH_SOURCES"));
+
+ QFileInfo fi(absName);
+ bool found = fi.exists();
+ // Search in all vpaths
+ if (!found) {
+ foreach (const QString &vpath, vpaths) {
+ fi.setFile(vpath + QDir::separator() + relName);
+ if (fi.exists()) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ sources_out += fi.absoluteFilePath(); // Not resolving symlinks
+ } else {
+ QString val = relName;
+ QString dir;
+ QString wildcard = val;
+ QString real_dir;
+ if (wildcard.lastIndexOf(QLatin1Char('/')) != -1) {
+ dir = wildcard.left(wildcard.lastIndexOf(QLatin1Char('/')) + 1);
+ real_dir = dir;
+ wildcard = wildcard.right(wildcard.length() - dir.length());
+ }
+
+ if (real_dir.isEmpty() || QFileInfo(real_dir).exists()) {
+ QStringList files = QDir(real_dir).entryList(QStringList(wildcard));
+ if (files.isEmpty()) {
+ q->logMessage(format("Failure to find %1").arg(val));
+ } else {
+ QString a;
+ for (int i = files.count() - 1; i >= 0; --i) {
+ if (files[i] == QLatin1String(".") || files[i] == QLatin1String(".."))
+ continue;
+ a = dir + files[i];
+ sources_out += a;
+ }
+ }
+ } else {
+ q->logMessage(format("Cannot match %1/%2, as %3 does not exist.")
+ .arg(real_dir).arg(wildcard).arg(real_dir));
+ }
+ }
+}
+
+
+/*
+ * Lookup of files are done in this order:
+ * 1. look in pwd
+ * 2. look in vpaths
+ * 3. expand wild card files relative from the profiles folder
+ **/
+
+// FIXME: This code supports something that I'd consider a flaw in .pro file syntax
+// which is not even documented. So arguably this can be ditched completely...
+QStringList ProFileEvaluator::Private::expandPattern(const QString& pattern)
+{
+ if (!currentProFile())
+ return QStringList();
+
+ QStringList sources_out;
+ const QString absName = QDir::cleanPath(QDir::current().absoluteFilePath(pattern));
+
+ expandPatternHelper(pattern, absName, sources_out);
+ return sources_out;
+}
+
+QString ProFileEvaluator::Private::format(const char *fmt) const
+{
+ ProFile *pro = currentProFile();
+ QString fileName = pro ? pro->fileName() : QLatin1String("Not a file");
+ int lineNumber = pro ? m_lineNo : 0;
+ return QString::fromLatin1("%1(%2):").arg(fileName).arg(lineNumber) + QString::fromAscii(fmt);
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// ProFileEvaluator
+//
+///////////////////////////////////////////////////////////////////////
+
+ProFileEvaluator::ProFileEvaluator()
+ : d(new Private(this))
+{
+ Option::init();
+}
+
+ProFileEvaluator::~ProFileEvaluator()
+{
+ delete d;
+}
+
+bool ProFileEvaluator::contains(const QString &variableName) const
+{
+ return d->m_valuemap.contains(variableName);
+}
+
+inline QStringList fixEnvVariables(const QStringList &x)
+{
+ QStringList ret;
+ foreach (const QString &str, x)
+ ret << Option::fixString(str, Option::FixEnvVars);
+ return ret;
+}
+
+
+QStringList ProFileEvaluator::values(const QString &variableName) const
+{
+ return fixEnvVariables(d->values(variableName));
+}
+
+QStringList ProFileEvaluator::values(const QString &variableName, const ProFile *pro) const
+{
+ return fixEnvVariables(d->values(variableName, pro));
+}
+
+ProFileEvaluator::TemplateType ProFileEvaluator::templateType()
+{
+ QStringList templ = values(QLatin1String("TEMPLATE"));
+ if (templ.count() >= 1) {
+ QString t = templ.last().toLower();
+ if (t == QLatin1String("app"))
+ return TT_Application;
+ if (t == QLatin1String("lib"))
+ return TT_Library;
+ if (t == QLatin1String("script"))
+ return TT_Script;
+ if (t == QLatin1String("subdirs"))
+ return TT_Subdirs;
+ }
+ return TT_Unknown;
+}
+
+bool ProFileEvaluator::queryProFile(ProFile *pro)
+{
+ return d->read(pro);
+}
+
+bool ProFileEvaluator::accept(ProFile *pro)
+{
+ return pro->Accept(d);
+}
+
+QString ProFileEvaluator::propertyValue(const QString &name) const
+{
+ return d->propertyValue(name);
+}
+
+namespace {
+ template<class K, class T> void insert(QHash<K,T> *out, const QHash<K,T> &in)
+ {
+ typename QHash<K,T>::const_iterator i = in.begin();
+ while (i != in.end()) {
+ out->insert(i.key(), i.value());
+ ++i;
+ }
+ }
+} // anon namespace
+
+void ProFileEvaluator::addVariables(const QHash<QString, QStringList> &variables)
+{
+ insert(&(d->m_valuemap), variables);
+}
+
+void ProFileEvaluator::addProperties(const QHash<QString, QString> &properties)
+{
+ insert(&(d->m_properties), properties);
+}
+
+void ProFileEvaluator::logMessage(const QString &message)
+{
+ if (d->m_verbose && !d->m_skipLevel)
+ qWarning("%s", qPrintable(message));
+}
+
+void ProFileEvaluator::fileMessage(const QString &message)
+{
+ if (!d->m_skipLevel)
+ qWarning("%s", qPrintable(message));
+}
+
+void ProFileEvaluator::errorMessage(const QString &message)
+{
+ if (!d->m_skipLevel)
+ qWarning("%s", qPrintable(message));
+}
+
+void ProFileEvaluator::setVerbose(bool on)
+{
+ d->m_verbose = on;
+}
+
+void ProFileEvaluator::setCumulative(bool on)
+{
+ d->m_cumulative = on;
+}
+
+void ProFileEvaluator::setOutputDir(const QString &dir)
+{
+ d->m_outputDir = dir;
+}
+
+void evaluateProFile(const ProFileEvaluator &visitor, QHash<QByteArray, QStringList> *varMap)
+{
+ QStringList sourceFiles;
+ QString codecForTr;
+ QString codecForSource;
+ QStringList tsFileNames;
+
+ // app/lib template
+ sourceFiles += visitor.values(QLatin1String("SOURCES"));
+ sourceFiles += visitor.values(QLatin1String("HEADERS"));
+ tsFileNames = visitor.values(QLatin1String("TRANSLATIONS"));
+
+ QStringList trcodec = visitor.values(QLatin1String("CODEC"))
+ + visitor.values(QLatin1String("DEFAULTCODEC"))
+ + visitor.values(QLatin1String("CODECFORTR"));
+ if (!trcodec.isEmpty())
+ codecForTr = trcodec.last();
+
+ QStringList srccodec = visitor.values(QLatin1String("CODECFORSRC"));
+ if (!srccodec.isEmpty())
+ codecForSource = srccodec.last();
+
+ QStringList forms = visitor.values(QLatin1String("INTERFACES"))
+ + visitor.values(QLatin1String("FORMS"))
+ + visitor.values(QLatin1String("FORMS3"));
+ sourceFiles << forms;
+
+#if QT_VERSION >= 0x040500
+ sourceFiles.sort();
+ sourceFiles.removeDuplicates();
+ tsFileNames.sort();
+ tsFileNames.removeDuplicates();
+#else
+ sourceFiles = sourceFiles.toSet().toList();
+ sourceFiles.sort();
+ tsFileNames = tsFileNames.toSet().toList();
+ tsFileNames.sort();
+#endif
+
+ varMap->insert("SOURCES", sourceFiles);
+ varMap->insert("CODECFORTR", QStringList() << codecForTr);
+ varMap->insert("CODECFORSRC", QStringList() << codecForSource);
+ varMap->insert("TRANSLATIONS", tsFileNames);
+}
+
+bool evaluateProFile(const QString &fileName, bool verbose, QHash<QByteArray, QStringList> *varMap)
+{
+ QFileInfo fi(fileName);
+ if (!fi.exists())
+ return false;
+
+ ProFile pro(fi.absoluteFilePath());
+
+ ProFileEvaluator visitor;
+ visitor.setVerbose(verbose);
+
+ if (!visitor.queryProFile(&pro))
+ return false;
+
+ if (!visitor.accept(&pro))
+ return false;
+
+ evaluateProFile(visitor, varMap);
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/shared/proparser/profileevaluator.h b/src/shared/proparser/profileevaluator.h
new file mode 100644
index 0000000000..a0b860dba0
--- /dev/null
+++ b/src/shared/proparser/profileevaluator.h
@@ -0,0 +1,96 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef PROFILEEVALUATOR_H
+#define PROFILEEVALUATOR_H
+
+#include "proitems.h"
+#include "abstractproitemvisitor.h"
+
+#include <QtCore/QIODevice>
+#include <QtCore/QHash>
+#include <QtCore/QStringList>
+#include <QtCore/QStack>
+
+QT_BEGIN_NAMESPACE
+
+class ProFile;
+class ProFileEvaluator;
+
+void evaluateProFile(const ProFileEvaluator &visitor, QHash<QByteArray, QStringList> *varMap);
+bool evaluateProFile(const QString &fileName, bool verbose, QHash<QByteArray, QStringList> *varMap);
+
+class ProFileEvaluator
+{
+public:
+ enum TemplateType {
+ TT_Unknown = 0,
+ TT_Application,
+ TT_Library,
+ TT_Script,
+ TT_Subdirs
+ };
+
+ ProFileEvaluator();
+ virtual ~ProFileEvaluator();
+
+ ProFileEvaluator::TemplateType templateType();
+ virtual bool contains(const QString &variableName) const;
+ void setVerbose(bool on); // Default is false
+ void setCumulative(bool on); // Default is true!
+ void setOutputDir(const QString &dir); // Default is empty
+
+ bool queryProFile(ProFile *pro);
+ bool accept(ProFile *pro);
+
+ void addVariables(const QHash<QString, QStringList> &variables);
+ void addProperties(const QHash<QString, QString> &properties);
+ QStringList values(const QString &variableName) const;
+ QStringList values(const QString &variableName, const ProFile *pro) const;
+ QString propertyValue(const QString &val) const;
+
+ // for our descendents
+ virtual ProFile *parsedProFile(const QString &fileName);
+ virtual void releaseParsedProFile(ProFile *proFile);
+ virtual void logMessage(const QString &msg);
+ virtual void errorMessage(const QString &msg); // .pro parse errors
+ virtual void fileMessage(const QString &msg); // error() and message() from .pro file
+
+private:
+ class Private;
+ Private *d;
+};
+
+QT_END_NAMESPACE
+
+#endif // PROFILEEVALUATOR_H
diff --git a/src/shared/proparser/proiteminfo.cpp b/src/shared/proparser/proiteminfo.cpp
new file mode 100644
index 0000000000..7ada47a301
--- /dev/null
+++ b/src/shared/proparser/proiteminfo.cpp
@@ -0,0 +1,241 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "proiteminfo.h"
+
+#include <QtCore/QFile>
+
+using namespace Qt4ProjectManager::Internal;
+
+ProItemInfo::ProItemInfo(ProItemInfoKind kind)
+ : m_kind(kind)
+{ }
+
+ProItemInfo::ProItemInfoKind ProItemInfo::kind() const
+{
+ return m_kind;
+}
+
+void ProItemInfo::setId(const QString &id)
+{
+ m_id = id;
+}
+
+void ProItemInfo::setName(const QString &name)
+{
+ m_name = name;
+}
+
+void ProItemInfo::setDescription(const QString &desc)
+{
+ m_description = desc;
+}
+
+QString ProItemInfo::id() const
+{
+ return m_id;
+}
+
+QString ProItemInfo::name() const
+{
+ return m_name;
+}
+
+QString ProItemInfo::description() const
+{
+ return m_description;
+}
+
+ProScopeInfo::ProScopeInfo()
+ : ProItemInfo(ProItemInfo::Scope)
+{ }
+
+ProValueInfo::ProValueInfo()
+ : ProItemInfo(ProItemInfo::Value)
+{ }
+
+ProVariableInfo::ProVariableInfo()
+ : ProItemInfo(ProItemInfo::Variable)
+{
+ m_operator = ProVariable::SetOperator;
+}
+
+ProVariableInfo::~ProVariableInfo()
+{
+ qDeleteAll(m_values.values());
+}
+
+void ProVariableInfo::addValue(ProValueInfo *value)
+{
+ m_values.insert(value->id(), value);
+}
+
+void ProVariableInfo::setMultiple(bool multiple)
+{
+ m_multiple = multiple;
+}
+
+void ProVariableInfo::setDefaultOperator(ProVariable::VariableOperator op)
+{
+ m_operator = op;
+}
+
+ProValueInfo *ProVariableInfo::value(const QString &id) const
+{
+ return m_values.value(id, 0);
+}
+
+QList<ProValueInfo *> ProVariableInfo::values() const
+{
+ return m_values.values();
+}
+
+bool ProVariableInfo::multiple() const
+{
+ return m_multiple;
+}
+
+ProVariable::VariableOperator ProVariableInfo::defaultOperator() const
+{
+ return m_operator;
+}
+
+ProItemInfoManager::ProItemInfoManager(QObject *parent)
+ : QObject(parent)
+{
+ load(QLatin1String(":/proparser/proiteminfo.xml"));
+}
+
+ProItemInfoManager::~ProItemInfoManager()
+{
+ qDeleteAll(m_variables.values());
+ qDeleteAll(m_scopes.values());
+}
+
+void ProItemInfoManager::addVariable(ProVariableInfo *variable)
+{
+ m_variables.insert(variable->id(), variable);
+}
+
+void ProItemInfoManager::addScope(ProScopeInfo *scope)
+{
+ m_scopes.insert(scope->id(), scope);
+}
+
+ProVariableInfo *ProItemInfoManager::variable(const QString &id) const
+{
+ return m_variables.value(id, 0);
+}
+
+ProScopeInfo *ProItemInfoManager::scope(const QString &id) const
+{
+ return m_scopes.value(id, 0);
+}
+
+QList<ProScopeInfo *> ProItemInfoManager::scopes() const
+{
+ return m_scopes.values();
+}
+
+QList<ProVariableInfo *> ProItemInfoManager::variables() const
+{
+ return m_variables.values();
+}
+
+bool ProItemInfoManager::load(const QString &filename)
+{
+ QFile file(filename);
+ if (!file.open(QIODevice::ReadOnly))
+ return false;
+
+ QDomDocument doc;
+ if (!doc.setContent(&file))
+ return false;
+
+ QDomElement root = doc.documentElement();
+ if (root.nodeName() != QLatin1String("proiteminfo"))
+ return false;
+
+ QDomElement child = root.firstChildElement();
+ for (; !child.isNull(); child = child.nextSiblingElement()) {
+ if (child.nodeName() == QLatin1String("scope"))
+ readScope(child);
+ else if (child.nodeName() == QLatin1String("variable"))
+ readVariable(child);
+ }
+
+ file.close();
+ return true;
+}
+
+void ProItemInfoManager::readItem(ProItemInfo *item, const QDomElement &data)
+{
+ QDomElement child = data.firstChildElement();
+ for (; !child.isNull(); child = child.nextSiblingElement()) {
+ if (child.nodeName() == QLatin1String("id"))
+ item->setId(child.text());
+ else if (child.nodeName() == QLatin1String("name"))
+ item->setName(child.text());
+ else if (child.nodeName() == QLatin1String("description"))
+ item->setDescription(child.text());
+ }
+}
+
+void ProItemInfoManager::readScope(const QDomElement &data)
+{
+ ProScopeInfo *scope = new ProScopeInfo();
+ readItem(scope, data);
+ addScope(scope);
+}
+
+void ProItemInfoManager::readVariable(const QDomElement &data)
+{
+ ProVariableInfo *var = new ProVariableInfo();
+ readItem(var, data);
+
+ var->setMultiple(data.attribute(QLatin1String("multiple"), QLatin1String("false")) == QLatin1String("true"));
+ var->setDefaultOperator((ProVariable::VariableOperator)data.attribute(QLatin1String("operator"),
+ QLatin1String("3")).toInt());
+
+ QDomElement child = data.firstChildElement();
+ for (; !child.isNull(); child = child.nextSiblingElement()) {
+ if (child.nodeName() == QLatin1String("value")) {
+ ProValueInfo *val = new ProValueInfo();
+ readItem(val, child);
+ var->addValue(val);
+ }
+ }
+
+ addVariable(var);
+}
+
diff --git a/src/shared/proparser/proiteminfo.h b/src/shared/proparser/proiteminfo.h
new file mode 100644
index 0000000000..01be6a4f83
--- /dev/null
+++ b/src/shared/proparser/proiteminfo.h
@@ -0,0 +1,137 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef PROITEMINFO_H
+#define PROITEMINFO_H
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QMap>
+#include <QtXml/QDomElement>
+
+#include "proitems.h"
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProItemInfo
+{
+public:
+ enum ProItemInfoKind {
+ Scope,
+ Value,
+ Variable
+ };
+
+ ProItemInfo(ProItemInfoKind kind);
+
+ ProItemInfoKind kind() const;
+ void setId(const QString &id);
+ void setName(const QString &name);
+ void setDescription(const QString &desc);
+
+ QString id() const;
+ QString name() const;
+ QString description() const;
+
+private:
+ QString m_id;
+ QString m_name;
+ QString m_description;
+ ProItemInfoKind m_kind;
+};
+
+class ProScopeInfo : public ProItemInfo
+{
+public:
+ ProScopeInfo();
+};
+
+class ProValueInfo : public ProItemInfo
+{
+public:
+ ProValueInfo();
+};
+
+class ProVariableInfo : public ProItemInfo
+{
+public:
+ ProVariableInfo();
+ ~ProVariableInfo();
+
+ void addValue(ProValueInfo *value);
+ void setMultiple(bool multiple);
+ void setDefaultOperator(ProVariable::VariableOperator op);
+
+ ProValueInfo *value(const QString &id) const;
+
+ QList<ProValueInfo *> values() const;
+ bool multiple() const;
+ ProVariable::VariableOperator defaultOperator() const;
+
+private:
+ ProVariable::VariableOperator m_operator;
+ bool m_multiple;
+ QMap<QString, ProValueInfo *> m_values;
+};
+
+class ProItemInfoManager : public QObject {
+ Q_OBJECT
+
+public:
+ ProItemInfoManager(QObject *parent);
+ ~ProItemInfoManager();
+
+ ProVariableInfo *variable(const QString &id) const;
+ ProScopeInfo *scope(const QString &id) const;
+
+ QList<ProScopeInfo *> scopes() const;
+ QList<ProVariableInfo *> variables() const;
+
+private:
+ bool load(const QString &filename);
+ void addVariable(ProVariableInfo *variable);
+ void addScope(ProScopeInfo *scope);
+ void readItem(ProItemInfo *item, const QDomElement &data);
+ void readScope(const QDomElement &data);
+ void readVariable(const QDomElement &data);
+
+ QMap<QString, ProScopeInfo *> m_scopes;
+ QMap<QString, ProVariableInfo *> m_variables;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // PROITEMINFO_H
diff --git a/src/shared/proparser/proiteminfo.xml b/src/shared/proparser/proiteminfo.xml
new file mode 100644
index 0000000000..1425c37150
--- /dev/null
+++ b/src/shared/proparser/proiteminfo.xml
@@ -0,0 +1,110 @@
+<!DOCTYPE ProItemInfo>
+<proiteminfo>
+ <scope>
+ <id>win32</id>
+ <name>Windows</name>
+ </scope>
+
+ <scope>
+ <id>unix</id>
+ <name>Unix</name>
+ </scope>
+
+ <scope>
+ <id>mac</id>
+ <name>Mac</name>
+ </scope>
+
+ <variable multiple="false">
+ <id>TARGET</id>
+ <name>Output Target</name>
+ <description>This specifies the name of the target file.</description>
+ </variable>
+
+ <variable multiple="false">
+ <id>TEMPLATE</id>
+ <name>Output Template</name>
+ <description>This variable contains the name of the template to use when generating the project.</description>
+ <value>
+ <id>app</id>
+ <name>Application</name>
+ </value>
+ <value>
+ <id>lib</id>
+ <name>Library</name>
+ </value>
+ <value>
+ <id>subdirs</id>
+ <name>Subdirectories</name>
+ </value>
+ </variable>
+
+ <variable multiple="true" operator="0">
+ <id>HEADERS</id>
+ <name>Header Files</name>
+ <description>Defines the header files for the project</description>
+ </variable>
+
+ <variable multiple="true" operator="0">
+ <id>SOURCES</id>
+ <name>Source Files</name>
+ <description>Defines the source files for the project</description>
+ </variable>
+
+ <variable multiple="true" operator="0">
+ <id>INCLUDEPATH</id>
+ <name>Include Path</name>
+ <description>Defines the include path for the project</description>
+ </variable>
+
+ <variable multiple="true" operator="0">
+ <id>FORMS</id>
+ <name>Form Files</name>
+ <description>Defines the form files for the project</description>
+ </variable>
+
+ <variable multiple="true" operator="0">
+ <id>RESOURCES</id>
+ <name>Resource Files</name>
+ <description>Defines the resource files for the project</description>
+ </variable>
+
+ <variable multiple="true" operator="0">
+ <id>QT</id>
+ <name>Qt Modules</name>
+ <description>The values stored in the QT variable control which of the Qt modules are used by your project.</description>
+ <value>
+ <id>core</id>
+ <name>QtCore module</name>
+ </value>
+ <value>
+ <id>gui</id>
+ <name>QtGui module</name>
+ </value>
+ <value>
+ <id>network</id>
+ <name>QtNetwork module</name>
+ </value>
+ <value>
+ <id>opengl</id>
+ <name>QtOpenGL module</name>
+ </value>
+ <value>
+ <id>sql</id>
+ <name>QtSql module</name>
+ </value>
+ <value>
+ <id>svg</id>
+ <name>QtSvg module</name>
+ </value>
+ <value>
+ <id>xml</id>
+ <name>QtXml module</name>
+ </value>
+ <value>
+ <id>qt3support</id>
+ <name>Qt3Support module</name>
+ </value>
+ </variable>
+
+</proiteminfo>
diff --git a/src/shared/proparser/proitems.cpp b/src/shared/proparser/proitems.cpp
new file mode 100644
index 0000000000..60c5b29b71
--- /dev/null
+++ b/src/shared/proparser/proitems.cpp
@@ -0,0 +1,320 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "proitems.h"
+#include "abstractproitemvisitor.h"
+
+#include <QtCore/QFileInfo>
+
+QT_BEGIN_NAMESPACE
+
+// --------------- ProItem ------------
+void ProItem::setComment(const QString &comment)
+{
+ m_comment = comment;
+}
+
+QString ProItem::comment() const
+{
+ return m_comment;
+}
+
+// --------------- ProBlock ----------------
+ProBlock::ProBlock(ProBlock *parent)
+{
+ m_blockKind = 0;
+ m_parent = parent;
+}
+
+ProBlock::~ProBlock()
+{
+ qDeleteAll(m_proitems);
+}
+
+void ProBlock::appendItem(ProItem *proitem)
+{
+ m_proitems << proitem;
+}
+
+void ProBlock::setItems(const QList<ProItem *> &proitems)
+{
+ m_proitems = proitems;
+}
+
+QList<ProItem *> ProBlock::items() const
+{
+ return m_proitems;
+}
+
+void ProBlock::setBlockKind(int blockKind)
+{
+ m_blockKind = blockKind;
+}
+
+int ProBlock::blockKind() const
+{
+ return m_blockKind;
+}
+
+void ProBlock::setParent(ProBlock *parent)
+{
+ m_parent = parent;
+}
+
+ProBlock *ProBlock::parent() const
+{
+ return m_parent;
+}
+
+ProItem::ProItemKind ProBlock::kind() const
+{
+ return ProItem::BlockKind;
+}
+
+bool ProBlock::Accept(AbstractProItemVisitor *visitor)
+{
+ visitor->visitBeginProBlock(this);
+ foreach (ProItem *item, m_proitems) {
+ if (!item->Accept(visitor))
+ return false;
+ }
+ return visitor->visitEndProBlock(this);
+}
+
+// --------------- ProVariable ----------------
+ProVariable::ProVariable(const QString &name, ProBlock *parent)
+ : ProBlock(parent)
+{
+ setBlockKind(ProBlock::VariableKind);
+ m_variable = name;
+ m_variableKind = SetOperator;
+}
+
+void ProVariable::setVariableOperator(VariableOperator variableKind)
+{
+ m_variableKind = variableKind;
+}
+
+ProVariable::VariableOperator ProVariable::variableOperator() const
+{
+ return m_variableKind;
+}
+
+void ProVariable::setVariable(const QString &name)
+{
+ m_variable = name;
+}
+
+QString ProVariable::variable() const
+{
+ return m_variable;
+}
+
+bool ProVariable::Accept(AbstractProItemVisitor *visitor)
+{
+ visitor->visitBeginProVariable(this);
+ foreach (ProItem *item, m_proitems) {
+ if (!item->Accept(visitor))
+ return false;
+ }
+ return visitor->visitEndProVariable(this);
+}
+
+// --------------- ProValue ----------------
+ProValue::ProValue(const QString &value, ProVariable *variable)
+{
+ m_variable = variable;
+ m_value = value;
+}
+
+void ProValue::setValue(const QString &value)
+{
+ m_value = value;
+}
+
+QString ProValue::value() const
+{
+ return m_value;
+}
+
+void ProValue::setVariable(ProVariable *variable)
+{
+ m_variable = variable;
+}
+
+ProVariable *ProValue::variable() const
+{
+ return m_variable;
+}
+
+ProItem::ProItemKind ProValue::kind() const
+{
+ return ProItem::ValueKind;
+}
+
+bool ProValue::Accept(AbstractProItemVisitor *visitor)
+{
+ return visitor->visitProValue(this);
+}
+
+// --------------- ProFunction ----------------
+ProFunction::ProFunction(const QString &text)
+{
+ m_text = text;
+}
+
+void ProFunction::setText(const QString &text)
+{
+ m_text = text;
+}
+
+QString ProFunction::text() const
+{
+ return m_text;
+}
+
+ProItem::ProItemKind ProFunction::kind() const
+{
+ return ProItem::FunctionKind;
+}
+
+bool ProFunction::Accept(AbstractProItemVisitor *visitor)
+{
+ return visitor->visitProFunction(this);
+}
+
+// --------------- ProCondition ----------------
+ProCondition::ProCondition(const QString &text)
+{
+ m_text = text;
+}
+
+void ProCondition::setText(const QString &text)
+{
+ m_text = text;
+}
+
+QString ProCondition::text() const
+{
+ return m_text;
+}
+
+ProItem::ProItemKind ProCondition::kind() const
+{
+ return ProItem::ConditionKind;
+}
+
+bool ProCondition::Accept(AbstractProItemVisitor *visitor)
+{
+ return visitor->visitProCondition(this);
+}
+
+// --------------- ProOperator ----------------
+ProOperator::ProOperator(OperatorKind operatorKind)
+{
+ m_operatorKind = operatorKind;
+}
+
+void ProOperator::setOperatorKind(OperatorKind operatorKind)
+{
+ m_operatorKind = operatorKind;
+}
+
+ProOperator::OperatorKind ProOperator::operatorKind() const
+{
+ return m_operatorKind;
+}
+
+ProItem::ProItemKind ProOperator::kind() const
+{
+ return ProItem::OperatorKind;
+}
+
+bool ProOperator::Accept(AbstractProItemVisitor *visitor)
+{
+ return visitor->visitProOperator(this);
+}
+
+// --------------- ProFile ----------------
+ProFile::ProFile(const QString &fileName)
+ : ProBlock(0)
+{
+ m_modified = false;
+ setBlockKind(ProBlock::ProFileKind);
+ m_fileName = fileName;
+
+ QFileInfo fi(fileName);
+ m_displayFileName = fi.fileName();
+ m_directoryName = fi.absolutePath();
+}
+
+ProFile::~ProFile()
+{
+}
+
+QString ProFile::displayFileName() const
+{
+ return m_displayFileName;
+}
+
+QString ProFile::fileName() const
+{
+ return m_fileName;
+}
+
+QString ProFile::directoryName() const
+{
+ return m_directoryName;
+}
+
+void ProFile::setModified(bool modified)
+{
+ m_modified = modified;
+}
+
+bool ProFile::isModified() const
+{
+ return m_modified;
+}
+
+bool ProFile::Accept(AbstractProItemVisitor *visitor)
+{
+ visitor->visitBeginProFile(this);
+ foreach (ProItem *item, m_proitems) {
+ if (!item->Accept(visitor))
+ return false;
+ }
+ return visitor->visitEndProFile(this);
+}
+
+QT_END_NAMESPACE
diff --git a/src/shared/proparser/proitems.h b/src/shared/proparser/proitems.h
new file mode 100644
index 0000000000..9e53147934
--- /dev/null
+++ b/src/shared/proparser/proitems.h
@@ -0,0 +1,228 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef PROITEMS_H
+#define PROITEMS_H
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+
+struct AbstractProItemVisitor;
+
+class ProItem
+{
+public:
+ enum ProItemKind {
+ ValueKind,
+ FunctionKind,
+ ConditionKind,
+ OperatorKind,
+ BlockKind
+ };
+
+ ProItem() : m_lineNumber(0) {}
+ virtual ~ProItem() {}
+
+ virtual ProItemKind kind() const = 0;
+
+ void setComment(const QString &comment);
+ QString comment() const;
+
+ virtual bool Accept(AbstractProItemVisitor *visitor) = 0;
+ int lineNumber() const { return m_lineNumber; }
+ void setLineNumber(int lineNumber) { m_lineNumber = lineNumber; }
+
+private:
+ QString m_comment;
+ int m_lineNumber;
+};
+
+class ProBlock : public ProItem
+{
+public:
+ enum ProBlockKind {
+ NormalKind = 0x00,
+ ScopeKind = 0x01,
+ ScopeContentsKind = 0x02,
+ VariableKind = 0x04,
+ ProFileKind = 0x08,
+ SingleLine = 0x10
+ };
+
+ ProBlock(ProBlock *parent);
+ ~ProBlock();
+
+ void appendItem(ProItem *proitem);
+ void setItems(const QList<ProItem *> &proitems);
+ QList<ProItem *> items() const;
+
+ void setBlockKind(int blockKind);
+ int blockKind() const;
+
+ void setParent(ProBlock *parent);
+ ProBlock *parent() const;
+
+ ProItem::ProItemKind kind() const;
+
+ virtual bool Accept(AbstractProItemVisitor *visitor);
+protected:
+ QList<ProItem *> m_proitems;
+private:
+ ProBlock *m_parent;
+ int m_blockKind;
+};
+
+class ProVariable : public ProBlock
+{
+public:
+ enum VariableOperator {
+ AddOperator = 0,
+ RemoveOperator = 1,
+ ReplaceOperator = 2,
+ SetOperator = 3,
+ UniqueAddOperator = 4
+ };
+
+ ProVariable(const QString &name, ProBlock *parent);
+
+ void setVariableOperator(VariableOperator variableKind);
+ VariableOperator variableOperator() const;
+
+ void setVariable(const QString &name);
+ QString variable() const;
+
+ virtual bool Accept(AbstractProItemVisitor *visitor);
+private:
+ VariableOperator m_variableKind;
+ QString m_variable;
+};
+
+class ProValue : public ProItem
+{
+public:
+ ProValue(const QString &value, ProVariable *variable);
+
+ void setValue(const QString &value);
+ QString value() const;
+
+ void setVariable(ProVariable *variable);
+ ProVariable *variable() const;
+
+ ProItem::ProItemKind kind() const;
+
+ virtual bool Accept(AbstractProItemVisitor *visitor);
+private:
+ QString m_value;
+ ProVariable *m_variable;
+};
+
+class ProFunction : public ProItem
+{
+public:
+ explicit ProFunction(const QString &text);
+
+ void setText(const QString &text);
+ QString text() const;
+
+ ProItem::ProItemKind kind() const;
+
+ virtual bool Accept(AbstractProItemVisitor *visitor);
+private:
+ QString m_text;
+};
+
+class ProCondition : public ProItem
+{
+public:
+ explicit ProCondition(const QString &text);
+
+ void setText(const QString &text);
+ QString text() const;
+
+ ProItem::ProItemKind kind() const;
+
+ virtual bool Accept(AbstractProItemVisitor *visitor);
+private:
+ QString m_text;
+};
+
+class ProOperator : public ProItem
+{
+public:
+ enum OperatorKind {
+ OrOperator = 1,
+ NotOperator = 2
+ };
+
+ explicit ProOperator(OperatorKind operatorKind);
+
+ void setOperatorKind(OperatorKind operatorKind);
+ OperatorKind operatorKind() const;
+
+ ProItem::ProItemKind kind() const;
+
+ virtual bool Accept(AbstractProItemVisitor *visitor);
+private:
+ OperatorKind m_operatorKind;
+};
+
+class ProFile : public QObject, public ProBlock
+{
+ Q_OBJECT
+
+public:
+ explicit ProFile(const QString &fileName);
+ ~ProFile();
+
+ QString displayFileName() const;
+ QString fileName() const;
+ QString directoryName() const;
+
+ void setModified(bool modified);
+ bool isModified() const;
+
+ virtual bool Accept(AbstractProItemVisitor *visitor);
+
+private:
+ QString m_fileName;
+ QString m_displayFileName;
+ QString m_directoryName;
+ bool m_modified;
+};
+
+QT_END_NAMESPACE
+
+#endif // PROITEMS_H
diff --git a/src/shared/proparser/proparser.pri b/src/shared/proparser/proparser.pri
new file mode 100644
index 0000000000..78b43d5901
--- /dev/null
+++ b/src/shared/proparser/proparser.pri
@@ -0,0 +1,35 @@
+VPATH += $$PWD
+QT += xml
+
+INCLUDEPATH *= $$PWD $$PWD/..
+
+# Input
+HEADERS += \
+ abstractproitemvisitor.h \
+ procommandmanager.h \
+ proeditor.h \
+ proeditormodel.h \
+ profileevaluator.h \
+ proiteminfo.h \
+ proitems.h \
+ proparserutils.h \
+ prowriter.h \
+ proxml.h \
+ valueeditor.h \
+ $$PWD/../namespace_global.h
+
+SOURCES += \
+ procommandmanager.cpp \
+ proeditor.cpp \
+ proeditormodel.cpp \
+ profileevaluator.cpp \
+ proiteminfo.cpp \
+ proitems.cpp \
+ prowriter.cpp \
+ proxml.cpp \
+ valueeditor.cpp
+
+FORMS += proeditor.ui \
+ valueeditor.ui
+
+RESOURCES += proparser.qrc
diff --git a/src/shared/proparser/proparser.qrc b/src/shared/proparser/proparser.qrc
new file mode 100644
index 0000000000..e6dde343df
--- /dev/null
+++ b/src/shared/proparser/proparser.qrc
@@ -0,0 +1,12 @@
+<RCC>
+ <qresource prefix="/proparser" >
+ <file>images/profile.png</file>
+ <file>images/scope.png</file>
+ <file>images/value.png</file>
+ <file>images/other.png</file>
+ <file>images/set.png</file>
+ <file>images/append.png</file>
+ <file>images/remove.png</file>
+ <file>proiteminfo.xml</file>
+ </qresource>
+</RCC>
diff --git a/src/shared/proparser/proparserutils.h b/src/shared/proparser/proparserutils.h
new file mode 100644
index 0000000000..7c751c9c27
--- /dev/null
+++ b/src/shared/proparser/proparserutils.h
@@ -0,0 +1,302 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef PROPARSERUTILS_H
+#define PROPARSERUTILS_H
+
+#include <QtCore/QDir>
+#include <QtCore/QLibraryInfo>
+
+QT_BEGIN_NAMESPACE
+
+// Pre- and postcondition macros
+#define PRE(cond) do {if(!(cond))qt_assert(#cond,__FILE__,__LINE__);} while (0)
+#define POST(cond) do {if(!(cond))qt_assert(#cond,__FILE__,__LINE__);} while (0)
+
+// This struct is from qmake, but we are not using everything.
+struct Option
+{
+ //simply global convenience
+ //static QString libtool_ext;
+ //static QString pkgcfg_ext;
+ //static QString prf_ext;
+ //static QString prl_ext;
+ //static QString ui_ext;
+ //static QStringList h_ext;
+ //static QStringList cpp_ext;
+ //static QString h_moc_ext;
+ //static QString cpp_moc_ext;
+ //static QString obj_ext;
+ //static QString lex_ext;
+ //static QString yacc_ext;
+ //static QString h_moc_mod;
+ //static QString cpp_moc_mod;
+ //static QString lex_mod;
+ //static QString yacc_mod;
+ static QString dir_sep;
+ static QString dirlist_sep;
+ static QString qmakespec;
+ static QChar field_sep;
+
+ enum TARG_MODE { TARG_UNIX_MODE, TARG_WIN_MODE, TARG_MACX_MODE, TARG_MAC9_MODE, TARG_QNX6_MODE };
+ static TARG_MODE target_mode;
+ //static QString pro_ext;
+ //static QString res_ext;
+
+ static void init()
+ {
+#ifdef Q_OS_WIN
+ Option::dirlist_sep = QLatin1Char(';');
+ Option::dir_sep = QLatin1Char('\\');
+#else
+ Option::dirlist_sep = QLatin1Char(':');
+ Option::dir_sep = QLatin1Char(QLatin1Char('/'));
+#endif
+ Option::qmakespec = QString::fromLatin1(qgetenv("QMAKESPEC").data());
+ Option::field_sep = QLatin1Char(' ');
+ }
+
+ enum StringFixFlags {
+ FixNone = 0x00,
+ FixEnvVars = 0x01,
+ FixPathCanonicalize = 0x02,
+ FixPathToLocalSeparators = 0x04,
+ FixPathToTargetSeparators = 0x08
+ };
+ static QString fixString(QString string, uchar flags);
+
+ inline static QString fixPathToLocalOS(const QString &in, bool fix_env = true, bool canonical = true)
+ {
+ uchar flags = FixPathToLocalSeparators;
+ if (fix_env)
+ flags |= FixEnvVars;
+ if (canonical)
+ flags |= FixPathCanonicalize;
+ return fixString(in, flags);
+ }
+};
+#if defined(Q_OS_WIN32)
+Option::TARG_MODE Option::target_mode = Option::TARG_WIN_MODE;
+#elif defined(Q_OS_MAC)
+Option::TARG_MODE Option::target_mode = Option::TARG_MACX_MODE;
+#elif defined(Q_OS_QNX6)
+Option::TARG_MODE Option::target_mode = Option::TARG_QNX6_MODE;
+#else
+Option::TARG_MODE Option::target_mode = Option::TARG_UNIX_MODE;
+#endif
+
+QString Option::qmakespec;
+QString Option::dirlist_sep;
+QString Option::dir_sep;
+QChar Option::field_sep;
+
+static void unquote(QString *string)
+{
+ PRE(string);
+ if ( (string->startsWith(QLatin1Char('\"')) && string->endsWith(QLatin1Char('\"')))
+ || (string->startsWith(QLatin1Char('\'')) && string->endsWith(QLatin1Char('\''))) )
+ {
+ string->remove(0,1);
+ string->remove(string->length() - 1,1);
+ }
+}
+
+static void insertUnique(QHash<QString, QStringList> *map,
+ const QString &key, const QStringList &value)
+{
+ QStringList &sl = (*map)[key];
+ foreach (const QString &str, value)
+ if (!sl.contains(str))
+ sl.append(str);
+}
+
+static void removeEach(QHash<QString, QStringList> *map,
+ const QString &key, const QStringList &value)
+{
+ QStringList &sl = (*map)[key];
+ foreach (const QString &str, value)
+ sl.removeAll(str);
+}
+
+/*
+ See ProFileEvaluator::Private::visitProValue(...)
+
+static QStringList replaceInList(const QStringList &varList, const QRegExp &regexp,
+ const QString &replace, bool global)
+{
+ QStringList resultList = varList;
+
+ for (QStringList::Iterator varit = resultList.begin(); varit != resultList.end();) {
+ if (varit->contains(regexp)) {
+ *varit = varit->replace(regexp, replace);
+ if (varit->isEmpty())
+ varit = resultList.erase(varit);
+ else
+ ++varit;
+ if (!global)
+ break;
+ } else {
+ ++varit;
+ }
+ }
+ return resultList;
+}
+*/
+
+inline QString fixEnvVariables(const QString &x)
+{
+ return Option::fixString(x, Option::FixEnvVars);
+}
+
+inline QStringList splitPathList(const QString &paths)
+{
+ return paths.split(Option::dirlist_sep);
+}
+
+static QStringList split_arg_list(QString params)
+{
+ int quote = 0;
+ QStringList args;
+
+ const ushort LPAREN = '(';
+ const ushort RPAREN = ')';
+ const ushort SINGLEQUOTE = '\'';
+ const ushort DOUBLEQUOTE = '"';
+ const ushort COMMA = ',';
+ const ushort SPACE = ' ';
+ //const ushort TAB = '\t';
+
+ ushort unicode;
+ const QChar *params_data = params.data();
+ const int params_len = params.length();
+ int last = 0;
+ while (last < params_len && ((params_data+last)->unicode() == SPACE
+ /*|| (params_data+last)->unicode() == TAB*/))
+ ++last;
+ for (int x = last, parens = 0; x <= params_len; x++) {
+ unicode = (params_data+x)->unicode();
+ if (x == params_len) {
+ while (x && (params_data+(x-1))->unicode() == SPACE)
+ --x;
+ QString mid(params_data+last, x-last);
+ if (quote) {
+ if (mid[0] == quote && mid[(int)mid.length()-1] == quote)
+ mid = mid.mid(1, mid.length()-2);
+ quote = 0;
+ }
+ args << mid;
+ break;
+ }
+ if (unicode == LPAREN) {
+ --parens;
+ } else if (unicode == RPAREN) {
+ ++parens;
+ } else if (quote && unicode == quote) {
+ quote = 0;
+ } else if (!quote && (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE)) {
+ quote = unicode;
+ } else if (!parens && !quote && unicode == COMMA) {
+ QString mid = params.mid(last, x - last).trimmed();
+ args << mid;
+ last = x+1;
+ while (last < params_len && ((params_data+last)->unicode() == SPACE
+ /*|| (params_data+last)->unicode() == TAB*/))
+ ++last;
+ }
+ }
+ for (int i = 0; i < args.count(); i++)
+ unquote(&args[i]);
+ return args;
+}
+
+static QStringList split_value_list(const QString &vals, bool do_semicolon=false)
+{
+ QString build;
+ QStringList ret;
+ QStack<QChar> quote;
+
+ const QChar LPAREN = QLatin1Char('(');
+ const QChar RPAREN = QLatin1Char(')');
+ const QChar SINGLEQUOTE = QLatin1Char('\'');
+ const QChar DOUBLEQUOTE = QLatin1Char('"');
+ const QChar BACKSLASH = QLatin1Char('\\');
+ const QChar SEMICOLON = QLatin1Char(';');
+
+ const QChar *vals_data = vals.data();
+ const int vals_len = vals.length();
+ for (int x = 0, parens = 0; x < vals_len; x++) {
+ QChar c = vals_data[x];
+ if (x != vals_len-1 && c == BACKSLASH &&
+ vals_data[x+1].unicode() == '\'' || vals_data[x+1] == DOUBLEQUOTE) {
+ build += vals_data[x++]; // get that 'escape'
+ } else if (!quote.isEmpty() && c == quote.top()) {
+ quote.pop();
+ } else if (c == SINGLEQUOTE || c == DOUBLEQUOTE) {
+ quote.push(c);
+ } else if (c == RPAREN) {
+ --parens;
+ } else if (c == LPAREN) {
+ ++parens;
+ }
+
+ if (!parens && quote.isEmpty() && ((do_semicolon && c == SEMICOLON) ||
+ vals_data[x] == Option::field_sep)) {
+ ret << build;
+ build.clear();
+ } else {
+ build += vals_data[x];
+ }
+ }
+ if (!build.isEmpty())
+ ret << build;
+ return ret;
+}
+
+static QStringList qmake_mkspec_paths()
+{
+ QStringList ret;
+ const QString concat = QDir::separator() + QString(QLatin1String("mkspecs"));
+ QByteArray qmakepath = qgetenv("QMAKEPATH");
+ if (!qmakepath.isEmpty()) {
+ const QStringList lst = splitPathList(QString::fromLocal8Bit(qmakepath));
+ for (QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it)
+ ret << ((*it) + concat);
+ }
+ ret << QLibraryInfo::location(QLibraryInfo::DataPath) + concat;
+
+ return ret;
+}
+
+QT_END_NAMESPACE
+
+#endif // PROPARSERUTILS_H
diff --git a/src/shared/proparser/prowriter.cpp b/src/shared/proparser/prowriter.cpp
new file mode 100644
index 0000000000..d5558e9b8c
--- /dev/null
+++ b/src/shared/proparser/prowriter.cpp
@@ -0,0 +1,208 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "proitems.h"
+#include "prowriter.h"
+
+#include <QtCore/QFile>
+
+using namespace Qt4ProjectManager::Internal;
+
+bool ProWriter::write(ProFile *profile, const QString &fileName)
+{
+ QFile data(fileName);
+ if (!data.open(QFile::WriteOnly|QFile::Text))
+ return false;
+
+ m_writeState = 0;
+ m_comment.clear();
+ m_out.setDevice(&data);
+ writeItem(profile, QString());
+ data.close();
+
+ return true;
+}
+
+QString ProWriter::contents(ProFile *profile)
+{
+ QString result;
+
+ m_writeState = 0;
+ m_comment.clear();
+ m_out.setString(&result, QIODevice::WriteOnly);
+ writeItem(profile, QString());
+
+ return result;
+}
+
+QString ProWriter::fixComment(const QString &comment, const QString &indent) const
+{
+ QString result = comment;
+ result = result.replace(QLatin1Char('\n'),
+ QLatin1Char('\n') + indent + QLatin1String("# "));
+ return QLatin1String("# ") + result;
+}
+
+void ProWriter::writeValue(ProValue *value, const QString &indent)
+{
+ if (m_writeState & NewLine) {
+ m_out << indent << QLatin1String(" ");
+ m_writeState &= ~NewLine;
+ }
+
+ m_out << value->value();
+
+ if (!(m_writeState & LastItem))
+ m_out << QLatin1String(" \\");
+
+ if (!value->comment().isEmpty())
+ m_out << QLatin1Char(' ') << fixComment(value->comment(), indent);
+
+ m_out << endl;
+ m_writeState |= NewLine;
+}
+
+void ProWriter::writeOther(ProItem *item, const QString &indent)
+{
+ if (m_writeState & NewLine) {
+ m_out << indent;
+ m_writeState &= ~NewLine;
+ }
+
+ if (item->kind() == ProItem::FunctionKind) {
+ ProFunction *v = static_cast<ProFunction*>(item);
+ m_out << v->text();
+ } else if (item->kind() == ProItem::ConditionKind) {
+ ProCondition *v = static_cast<ProCondition*>(item);
+ m_out << v->text();
+ } else if (item->kind() == ProItem::OperatorKind) {
+ ProOperator *v = static_cast<ProOperator*>(item);
+ if (v->operatorKind() == ProOperator::OrOperator)
+ m_out << QLatin1Char('|');
+ else
+ m_out << QLatin1Char('!');
+ }
+
+ if (!item->comment().isEmpty()) {
+ if (!m_comment.isEmpty())
+ m_comment += QLatin1Char('\n');
+ m_comment += item->comment();
+ }
+}
+
+void ProWriter::writeBlock(ProBlock *block, const QString &indent)
+{
+ if (m_writeState & NewLine) {
+ m_out << indent;
+ m_writeState &= ~NewLine;
+ }
+
+ if (!block->comment().isEmpty()) {
+ if (!(m_writeState & FirstItem))
+ m_out << endl << indent;
+ m_out << fixComment(block->comment(), indent) << endl << indent;
+ }
+
+ QString newindent = indent;
+ if (block->blockKind() & ProBlock::VariableKind) {
+ ProVariable *v = static_cast<ProVariable*>(block);
+ m_out << v->variable();
+ switch (v->variableOperator()) {
+ case ProVariable::AddOperator:
+ m_out << QLatin1String(" += "); break;
+ case ProVariable::RemoveOperator:
+ m_out << QLatin1String(" -= "); break;
+ case ProVariable::ReplaceOperator:
+ m_out << QLatin1String(" ~= "); break;
+ case ProVariable::SetOperator:
+ m_out << QLatin1String(" = "); break;
+ case ProVariable::UniqueAddOperator:
+ m_out << QLatin1String(" *= "); break;
+ }
+ } else if (block->blockKind() & ProBlock::ScopeContentsKind) {
+ if (block->items().count() > 1) {
+ newindent = indent + QLatin1String(" ");
+ m_out << QLatin1String(" { ");
+ if (!m_comment.isEmpty()) {
+ m_out << fixComment(m_comment, indent);
+ m_comment.clear();
+ }
+ m_out << endl;
+ m_writeState |= NewLine;
+ } else {
+ m_out << QLatin1Char(':');
+ }
+ }
+
+ QList<ProItem*> items = block->items();
+ for (int i = 0; i < items.count(); ++i) {
+ m_writeState &= ~LastItem;
+ m_writeState &= ~FirstItem;
+ if (i == 0)
+ m_writeState |= FirstItem;
+ if (i == items.count() - 1)
+ m_writeState |= LastItem;
+ writeItem(items.at(i), newindent);
+ }
+
+ if ((block->blockKind() & ProBlock::ScopeContentsKind) && (block->items().count() > 1)) {
+ if (m_writeState & NewLine) {
+ m_out << indent;
+ m_writeState &= ~NewLine;
+ }
+ m_out << QLatin1Char('}');
+ }
+
+ if (!m_comment.isEmpty()) {
+ m_out << fixComment(m_comment, indent);
+ m_out << endl;
+ m_writeState |= NewLine;
+ m_comment.clear();
+ }
+
+ if (!(m_writeState & NewLine)) {
+ m_out << endl;
+ m_writeState |= NewLine;
+ }
+}
+
+void ProWriter::writeItem(ProItem *item, const QString &indent)
+{
+ if (item->kind() == ProItem::ValueKind) {
+ writeValue(static_cast<ProValue*>(item), indent);
+ } else if (item->kind() == ProItem::BlockKind) {
+ writeBlock(static_cast<ProBlock*>(item), indent);
+ } else {
+ writeOther(item, indent);
+ }
+}
diff --git a/src/shared/proparser/prowriter.h b/src/shared/proparser/prowriter.h
new file mode 100644
index 0000000000..a2282b357e
--- /dev/null
+++ b/src/shared/proparser/prowriter.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef PROWRITER_H
+#define PROWRITER_H
+
+#include "namespace_global.h"
+
+#include <QtCore/QTextStream>
+
+QT_BEGIN_NAMESPACE
+class ProFile;
+class ProValue;
+class ProItem;
+class ProBlock;
+QT_END_NAMESPACE
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProWriter
+{
+public:
+ bool write(ProFile *profile, const QString &fileName);
+ QString contents(ProFile *profile);
+
+protected:
+ QString fixComment(const QString &comment, const QString &indent) const;
+ void writeValue(ProValue *value, const QString &indent);
+ void writeOther(ProItem *item, const QString &indent);
+ void writeBlock(ProBlock *block, const QString &indent);
+ void writeItem(ProItem *item, const QString &indent);
+
+private:
+ enum ProWriteState {
+ NewLine = 0x01,
+ FirstItem = 0x02,
+ LastItem = 0x04
+ };
+
+ QTextStream m_out;
+ int m_writeState;
+ QString m_comment;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // PROWRITER_H
diff --git a/src/shared/proparser/proxml.cpp b/src/shared/proparser/proxml.cpp
new file mode 100644
index 0000000000..96091436ee
--- /dev/null
+++ b/src/shared/proparser/proxml.cpp
@@ -0,0 +1,208 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "proxml.h"
+#include "proitems.h"
+
+using namespace Qt4ProjectManager::Internal;
+
+QString ProXmlParser::itemToString(ProItem *item)
+{
+ ProXmlParser xmlparser;
+ QDomDocument doc("ProItem");
+ QDomNode itemNode = xmlparser.createItemNode(doc, item);
+
+ if (itemNode.isNull())
+ return QString();
+
+ doc.appendChild(itemNode);
+
+ return doc.toString();
+}
+
+QDomNode ProXmlParser::createItemNode(QDomDocument doc, ProItem *item) const
+{
+
+ QDomElement tag;
+ if (item->kind() == ProItem::ValueKind) {
+ tag = doc.createElement(QLatin1String("value"));
+ ProValue *v = static_cast<ProValue*>(item);
+ QDomText text = doc.createTextNode(v->value());
+ tag.appendChild(text);
+ }
+
+ if (item->kind() == ProItem::FunctionKind) {
+ tag = doc.createElement(QLatin1String("function"));
+ ProFunction *v = static_cast<ProFunction*>(item);
+ QDomText text = doc.createTextNode(v->text());
+ tag.appendChild(text);
+ }
+
+ if (item->kind() == ProItem::ConditionKind) {
+ tag = doc.createElement(QLatin1String("condition"));
+ ProCondition *v = static_cast<ProCondition*>(item);
+ QDomText text = doc.createTextNode(v->text());
+ tag.appendChild(text);
+ }
+
+ if (item->kind() == ProItem::OperatorKind) {
+ tag = doc.createElement(QLatin1String("operator"));
+ ProOperator *v = static_cast<ProOperator*>(item);
+ tag.setAttribute(QLatin1String("type"), (int)v->operatorKind());
+ }
+
+ if (tag.isNull() && item->kind() != ProItem::BlockKind) {
+ qDebug() << "*** Warning: Found unknown item!";
+ return tag;
+ }
+
+ if (tag.isNull()) {
+ ProBlock *block = static_cast<ProBlock*>(item);
+
+ if (block->blockKind() & ProBlock::ProFileKind) {
+ tag = doc.createElement(QLatin1String("file"));
+ } else if (block->blockKind() & ProBlock::VariableKind) {
+ tag = doc.createElement(QLatin1String("variable"));
+ ProVariable *v = static_cast<ProVariable*>(block);
+ tag.setAttribute(QLatin1String("name"), QString(v->variable()));
+ tag.setAttribute(QLatin1String("type"), (int)v->variableOperator());
+ } else if (block->blockKind() & ProBlock::ScopeKind) {
+ tag = doc.createElement(QLatin1String("scope"));
+ } else if (block->blockKind() & ProBlock::ScopeContentsKind) {
+ tag = doc.createElement(QLatin1String("scopecontents"));
+ } else {
+ tag = doc.createElement(QLatin1String("block"));
+ }
+
+ foreach (ProItem *child, block->items()) {
+ QDomNode childNode = createItemNode(doc, child);
+ if (!childNode.isNull())
+ tag.appendChild(childNode);
+ }
+ }
+
+ QString comment = item->comment();
+ comment = comment.replace('\\', QLatin1String("\\\\"));
+ comment = comment.replace('\n', QLatin1String("\\n"));
+
+ if (!comment.isEmpty())
+ tag.setAttribute(QLatin1String("comment"), comment);
+
+ return tag;
+}
+
+ProItem *ProXmlParser::parseItemNode(QDomDocument doc, QDomNode node) const
+{
+ QDomElement tag = node.toElement();
+ if (tag.isNull()) {
+ qDebug() << "*** Warning: Failed while parsing XML";
+ return 0;
+ }
+
+ ProItem *item = 0;
+ if (tag.tagName() == QLatin1String("value")) {
+ item = new ProValue(tag.text(), 0);
+ } else if (tag.tagName() == QLatin1String("function")) {
+ item = new ProFunction(tag.text());
+ } else if (tag.tagName() == QLatin1String("condition")) {
+ item = new ProCondition(tag.text());
+ } else if (tag.tagName() == QLatin1String("operator")) {
+ int optype = tag.attribute(QLatin1String("type")).toInt();
+ item = new ProOperator((ProOperator::OperatorKind)optype);
+ } else if (tag.tagName() == QLatin1String("variable")) {
+ QString name = tag.attribute(QLatin1String("name"));
+ int vartype = tag.attribute(QLatin1String("type")).toInt();
+ ProVariable::VariableOperator varop = ProVariable::VariableOperator(vartype);
+ ProVariable *v = new ProVariable(name, 0);
+ v->setVariableOperator(varop);
+ item = v;
+ } else if (tag.tagName() == QLatin1String("file")) {
+ ProFile *v = new ProFile(QString());
+ item = v;
+ } else if (tag.tagName() == QLatin1String("scope")) {
+ ProBlock *v = new ProBlock(0);
+ v->setBlockKind(ProBlock::ScopeKind);
+ item = v;
+ } else if (tag.tagName() == QLatin1String("scopecontents")) {
+ ProBlock *v = new ProBlock(0);
+ v->setBlockKind(ProBlock::ScopeContentsKind);
+ item = v;
+ } else if (tag.tagName() == QLatin1String("block")) {
+ item = new ProBlock(0);
+ }
+
+ if (!item) {
+ qDebug() << "*** Warning: Could not create item!";
+ return 0;
+ }
+
+ QString comment = tag.attribute(QLatin1String("comment"));
+ if (!comment.isEmpty()) {
+ //### fix multiple lines
+ item->setComment(comment);
+ }
+
+ if (item->kind() != ProItem::BlockKind)
+ return item;
+
+ ProBlock *block = static_cast<ProBlock *>(item);
+ ProVariable *variable = 0;
+ if (block->blockKind() & ProBlock::VariableKind)
+ variable = static_cast<ProVariable *>(block);
+
+ QDomNodeList children = tag.childNodes();
+ for (int i=0; i<children.count(); ++i) {
+ ProItem *childItem = parseItemNode(doc, children.at(i));
+ if (!childItem)
+ continue;
+
+ if (variable && childItem->kind() == ProItem::ValueKind)
+ static_cast<ProValue*>(childItem)->setVariable(variable);
+ else if (childItem->kind() == ProItem::BlockKind)
+ static_cast<ProBlock*>(childItem)->setParent(block);
+
+ block->appendItem(childItem);
+ }
+
+ return item;
+}
+
+ProItem *ProXmlParser::stringToItem(const QString &xml)
+{
+ ProXmlParser xmlparser;
+ QDomDocument doc("ProItem");
+
+ doc.setContent(xml);
+
+ return xmlparser.parseItemNode(doc, doc.documentElement());
+}
diff --git a/src/shared/proparser/proxml.h b/src/shared/proparser/proxml.h
new file mode 100644
index 0000000000..f343c703cf
--- /dev/null
+++ b/src/shared/proparser/proxml.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef PROXML_H
+#define PROXML_H
+
+#include "namespace_global.h"
+
+#include <QtXml>
+
+QT_BEGIN_NAMESPACE
+class ProItem;
+QT_END_NAMESPACE
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProXmlParser {
+public:
+ static QString itemToString(ProItem *item);
+ static ProItem *stringToItem(const QString &xml);
+private:
+ QDomNode createItemNode(QDomDocument doc, ProItem *item) const;
+ ProItem *parseItemNode(QDomDocument doc, QDomNode node) const;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // PROXML_H
diff --git a/src/shared/proparser/valueeditor.cpp b/src/shared/proparser/valueeditor.cpp
new file mode 100644
index 0000000000..b85d70cf2a
--- /dev/null
+++ b/src/shared/proparser/valueeditor.cpp
@@ -0,0 +1,500 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "valueeditor.h"
+#include "proitems.h"
+#include "proeditormodel.h"
+#include "proiteminfo.h"
+
+#include <QtGui/QMenu>
+#include <QtGui/QKeyEvent>
+
+using namespace Qt4ProjectManager::Internal;
+
+ValueEditor::ValueEditor(QWidget *parent)
+ : QWidget(parent),
+ m_model(0),
+ m_handleModelChanges(true),
+ m_infomanager(0)
+{
+ setupUi(this);
+}
+
+ValueEditor::~ValueEditor()
+{
+}
+
+void ValueEditor::initialize(ProEditorModel *model, ProItemInfoManager *infomanager)
+{
+ m_model = model;
+ m_infomanager = infomanager;
+ initialize();
+}
+
+void ValueEditor::hideVariable()
+{
+ m_varGroupBox->setVisible(false);
+}
+
+void ValueEditor::showVariable(bool advanced)
+{
+ m_varComboBoxLabel->setVisible(!advanced);
+ m_varComboBox->setVisible(!advanced);
+
+ m_varLineEditLabel->setVisible(advanced);
+ m_varLineEdit->setVisible(advanced);
+
+ m_assignComboBoxLabel->setVisible(advanced);
+ m_assignComboBox->setVisible(advanced);
+
+ m_varGroupBox->setVisible(true);
+}
+
+void ValueEditor::setItemEditType(ItemEditType type)
+{
+ m_editStackWidget->setCurrentIndex(type);
+}
+
+void ValueEditor::setDescription(ItemEditType type, const QString &header, const QString &description)
+{
+ switch (type) {
+ case MultiUndefined:
+ m_multiUndefinedGroupBox->setTitle(header);
+ m_multiUndefinedDescriptionLabel->setVisible(!description.isEmpty());
+ m_multiUndefinedDescriptionLabel->setText(description);
+ break;
+ case MultiDefined:
+ m_multiDefinedGroupBox->setTitle(header);
+ m_multiDefinedDescriptionLabel->setVisible(!description.isEmpty());
+ m_multiDefinedDescriptionLabel->setText(description);
+ break;
+ case SingleUndefined:
+ m_singleUndefinedGroupBox->setTitle(header);
+ m_singleUndefinedDescriptionLabel->setVisible(!description.isEmpty());
+ m_singleUndefinedDescriptionLabel->setText(description);
+ break;
+ default:
+ m_singleDefinedGroupBox->setTitle(header);
+ m_singleDefinedDescriptionLabel->setVisible(!description.isEmpty());
+ m_singleDefinedDescriptionLabel->setText(description);
+ break;
+ }
+}
+
+void ValueEditor::initialize()
+{
+ hideVariable();
+ setItemEditType(MultiUndefined);
+
+ m_itemListView->setModel(m_model);
+ m_itemListView->setRootIndex(QModelIndex());
+
+ connect(m_itemAddButton, SIGNAL(clicked()),
+ this, SLOT(addItem()));
+ connect(m_itemRemoveButton, SIGNAL(clicked()),
+ this, SLOT(removeItem()));
+
+ connect(m_itemListView->selectionModel(),
+ SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
+ this, SLOT(updateItemList(const QModelIndex &)));
+
+ connect(m_itemListWidget, SIGNAL(itemChanged(QListWidgetItem *)),
+ this, SLOT(updateItemChanges(QListWidgetItem *)));
+
+ foreach (ProVariableInfo *varinfo, m_infomanager->variables()) {
+ m_varComboBox->addItem(varinfo->name(), varinfo->id());
+ }
+
+ connect(m_varLineEdit, SIGNAL(editingFinished()), this, SLOT(updateVariableId()));
+ connect(m_varComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateVariableId(int)));
+ connect(m_assignComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateVariableOp(int)));
+
+ connect(m_itemLineEdit, SIGNAL(editingFinished()), this, SLOT(updateItemId()));
+ connect(m_itemComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateItemId(int)));
+
+ connect(m_model, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
+ this, SLOT(modelChanged(const QModelIndex &)));
+
+ connect(m_model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
+ this, SLOT(modelChanged(const QModelIndex &)));
+
+ connect(m_model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
+ this, SLOT(modelChanged(const QModelIndex &)));
+
+ updateItemList(QModelIndex());
+}
+
+void ValueEditor::modelChanged(const QModelIndex &index)
+{
+ if (m_handleModelChanges) {
+ if (m_currentIndex == index || m_currentIndex == index.parent())
+ editIndex(m_currentIndex);
+ }
+}
+
+void ValueEditor::editIndex(const QModelIndex &index)
+{
+ if (!m_model)
+ return;
+ m_currentIndex = index;
+ ProBlock *block = m_model->proBlock(index);
+
+ m_varGroupBox->setEnabled(block != 0);
+ m_editStackWidget->setEnabled(block != 0);
+
+ if (!block)
+ return;
+
+ if (block->blockKind() & ProBlock::ScopeContentsKind) {
+ showScope(block);
+ } else if (block->blockKind() & ProBlock::VariableKind) {
+ showVariable(static_cast<ProVariable*>(block));
+ } else {
+ showOther(block);
+ }
+}
+
+ValueEditor::ItemEditType ValueEditor::itemType(bool defined, bool multiple) const
+{
+ if (defined) {
+ if (multiple)
+ return MultiDefined;
+ else
+ return SingleDefined;
+ } else {
+ if (multiple)
+ return MultiUndefined;
+ else
+ return SingleUndefined;
+ }
+}
+
+void ValueEditor::showVariable(ProVariable *variable)
+{
+ if (!m_model)
+ return;
+ ProVariableInfo *info = m_infomanager->variable(variable->variable());
+
+ const bool advanced = (!m_model->infoManager() || (info == 0));
+ bool defined = false;
+ bool multiple = true;
+
+ QSet<QString> values;
+ foreach(ProItem *proitem, variable->items()) {
+ if (proitem->kind() == ProItem::ValueKind) {
+ ProValue *val = static_cast<ProValue *>(proitem);
+ values.insert(val->value());
+ }
+ }
+
+ if (!advanced && info) {
+ defined = !info->values().isEmpty();
+
+ // check if all values are known
+ foreach(QString val, values) {
+ if (!info->value(val)) {
+ defined = false;
+ break;
+ }
+ }
+
+ multiple = info->multiple();
+ }
+
+ if (values.count() > 1)
+ multiple = true;
+
+ bool wasblocked;
+
+ if (!advanced) {
+ const int index = m_varComboBox->findData(variable->variable(), Qt::UserRole, Qt::MatchExactly);
+ wasblocked = m_varComboBox->blockSignals(true);
+ m_varComboBox->setCurrentIndex(index);
+ m_varComboBox->blockSignals(wasblocked);
+ } else {
+ wasblocked = m_varLineEdit->blockSignals(true);
+ m_varLineEdit->setText(variable->variable());
+ m_varLineEdit->blockSignals(wasblocked);
+ }
+
+ ItemEditType type = itemType(defined, multiple);
+
+ wasblocked = m_assignComboBox->blockSignals(true);
+ m_assignComboBox->setCurrentIndex(variable->variableOperator());
+ m_assignComboBox->blockSignals(wasblocked);
+
+ QString header = tr("Edit Values");
+ QString desc;
+ if (info) {
+ header = tr("Edit %1").arg(info->name());
+ desc = info->description();
+ }
+ setDescription(type, header, desc);
+
+ m_itemListWidget->clear();
+
+ switch (type) {
+ case MultiUndefined: {
+ const QModelIndex parent = m_currentIndex;
+ m_itemListView->setRootIndex(parent);
+ m_itemListView->setCurrentIndex(m_model->index(0,0,parent));
+ }
+ break;
+ case MultiDefined:
+ wasblocked = m_itemListWidget->blockSignals(true);
+
+ foreach(ProValueInfo *valinfo, info->values()) {
+ QListWidgetItem *item = new QListWidgetItem(m_itemListWidget);
+ item->setText(valinfo->name());
+ item->setData(Qt::UserRole, valinfo->id());
+
+ if (values.contains(valinfo->id()))
+ item->setCheckState(Qt::Checked);
+ else
+ item->setCheckState(Qt::Unchecked);
+ }
+
+ m_itemListWidget->blockSignals(wasblocked);
+ break;
+ case SingleUndefined:
+ wasblocked = m_itemLineEdit->blockSignals(true);
+ if (values.isEmpty())
+ m_itemLineEdit->setText(QString());
+ else
+ m_itemLineEdit->setText(values.toList().first());
+ m_itemLineEdit->blockSignals(wasblocked);
+ break;
+ case SingleDefined:
+ wasblocked = m_itemComboBox->blockSignals(true);
+ m_itemComboBox->clear();
+
+ foreach(ProValueInfo *valinfo, info->values()) {
+ m_itemComboBox->addItem(valinfo->name(), valinfo->id());
+ }
+
+ int index = -1;
+ if (!values.isEmpty()) {
+ const QString id = values.toList().first();
+ index = m_itemComboBox->findData(id, Qt::UserRole, Qt::MatchExactly);
+ }
+
+ m_itemComboBox->setCurrentIndex(index);
+ m_itemComboBox->blockSignals(wasblocked);
+ break;
+ }
+
+ showVariable(advanced);
+ setItemEditType(type);
+}
+
+void ValueEditor::showScope(ProBlock *)
+{
+ if (!m_model)
+ return;
+ const bool wasblocked = m_itemLineEdit->blockSignals(true);
+ m_itemLineEdit->setText(m_model->data(m_currentIndex, Qt::EditRole).toString());
+ m_itemLineEdit->blockSignals(wasblocked);
+
+ setDescription(SingleUndefined, tr("Edit Scope"));
+
+ hideVariable();
+ setItemEditType(SingleUndefined);
+}
+
+void ValueEditor::showOther(ProBlock *)
+{
+ if (!m_model)
+ return;
+ const bool wasblocked = m_itemLineEdit->blockSignals(true);
+ m_itemLineEdit->setText(m_model->data(m_currentIndex, Qt::EditRole).toString());
+ m_itemLineEdit->blockSignals(wasblocked);
+
+ setDescription(SingleUndefined, tr("Edit Advanced Expression"));
+
+ hideVariable();
+ setItemEditType(SingleUndefined);
+}
+
+void ValueEditor::addItem(QString value)
+{
+ if (!m_model)
+ return;
+ QModelIndex parent = m_currentIndex;
+ ProVariable *var = static_cast<ProVariable *>(m_model->proBlock(parent));
+
+ if (value.isEmpty()) {
+ value = QLatin1String("...");
+
+ if (ProVariableInfo *varinfo = m_infomanager->variable(var->variable())) {
+ const QList<ProValueInfo *> vals = varinfo->values();
+ if (!vals.isEmpty())
+ value = vals.first()->id();
+ }
+ }
+
+ m_handleModelChanges = false;
+ m_model->insertItem(new ProValue(value, var),
+ m_model->rowCount(parent), parent);
+
+ const QModelIndex idx = m_model->index(m_model->rowCount(parent)-1, 0, parent);
+ m_itemListView->setCurrentIndex(idx);
+ m_itemListView->edit(idx);
+ m_itemListView->scrollToBottom();
+ m_handleModelChanges = true;
+}
+
+void ValueEditor::removeItem()
+{
+ if (!m_model)
+ return;
+ m_handleModelChanges = false;
+ const QModelIndex idx = m_itemListView->currentIndex();
+ m_itemListView->closePersistentEditor(idx);
+ m_model->removeItem(idx);
+ m_handleModelChanges = true;
+}
+
+void ValueEditor::updateItemList(const QModelIndex &)
+{
+ if (!m_model)
+ return;
+ m_itemRemoveButton->setEnabled(m_model->rowCount(m_currentIndex));
+}
+
+QModelIndex ValueEditor::findValueIndex(const QString &id) const
+{
+ if (!m_model)
+ return QModelIndex();
+ const QModelIndex parent = m_currentIndex;
+ const int rows = m_model->rowCount(parent);
+
+ for (int row=0; row<rows; ++row) {
+ const QModelIndex index = m_model->index(row, 0, parent);
+ ProItem *item = m_model->proItem(index);
+ if (!item || item->kind() != ProItem::ValueKind)
+ continue;
+
+ if (static_cast<ProValue*>(item)->value() == id)
+ return index;
+ }
+
+ return QModelIndex();
+}
+
+void ValueEditor::updateItemChanges(QListWidgetItem *item)
+{
+ if (!m_model)
+ return;
+ const QModelIndex parent = m_currentIndex;
+ ProBlock *block = m_model->proBlock(parent);
+
+ if (!block || !(block->blockKind() & ProBlock::VariableKind))
+ return;
+
+ ProVariable *var = static_cast<ProVariable *>(block);
+ const QString id = item->data(Qt::UserRole).toString();
+
+ m_handleModelChanges = false;
+ const QModelIndex index = findValueIndex(id);
+ if (item->checkState() == Qt::Checked && !index.isValid()) {
+ m_model->insertItem(new ProValue(id, var),
+ m_model->rowCount(parent), m_currentIndex);
+ } else if (item->checkState() != Qt::Checked && index.isValid()) {
+ m_model->removeItem(index);
+ }
+ m_handleModelChanges = true;
+}
+
+void ValueEditor::updateVariableId()
+{
+ if (!m_model)
+ return;
+ m_handleModelChanges = false;
+ m_model->setData(m_currentIndex, QVariant(m_varLineEdit->text()));
+ m_handleModelChanges = true;
+}
+
+void ValueEditor::updateVariableId(int index)
+{
+ if (!m_model)
+ return;
+ ProVariableInfo *info = m_infomanager->variable(m_varComboBox->itemData(index).toString());
+
+ m_model->setData(m_currentIndex, info->id());
+ m_model->setData(m_currentIndex, info->defaultOperator());
+}
+
+void ValueEditor::updateVariableOp(int index)
+{
+ if (!m_model)
+ return;
+ m_handleModelChanges = false;
+ m_model->setData(m_currentIndex, QVariant(index));
+ m_handleModelChanges = true;
+}
+
+void ValueEditor::updateItemId()
+{
+ if (!m_model)
+ return;
+ QModelIndex index = m_currentIndex;
+ if (m_varGroupBox->isVisible()) {
+ index = m_model->index(0,0,index);
+ if (!index.isValid()) {
+ addItem(m_itemLineEdit->text());
+ return;
+ }
+ }
+
+ m_handleModelChanges = false;
+ m_model->setData(index, QVariant(m_itemLineEdit->text()));
+ m_handleModelChanges = true;
+}
+
+void ValueEditor::updateItemId(int index)
+{
+ if (!m_model)
+ return;
+ QModelIndex idx = m_currentIndex;
+ if (m_varGroupBox->isVisible()) {
+ idx = m_model->index(0,0,idx);
+ if (!idx.isValid()) {
+ addItem(m_itemComboBox->itemData(index).toString());
+ return;
+ }
+ }
+
+ m_handleModelChanges = false;
+ m_model->setData(idx, m_itemComboBox->itemData(index));
+ m_handleModelChanges = true;
+}
diff --git a/src/shared/proparser/valueeditor.h b/src/shared/proparser/valueeditor.h
new file mode 100644
index 0000000000..5ed6cbea2b
--- /dev/null
+++ b/src/shared/proparser/valueeditor.h
@@ -0,0 +1,119 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef VALUEEDITOR_H
+#define VALUEEDITOR_H
+
+#include "namespace_global.h"
+#include "ui_valueeditor.h"
+
+#include <QtCore/QList>
+#include <QtGui/QWidget>
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+class ProBlock;
+class ProVariable;
+QT_END_NAMESPACE
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ProEditorModel;
+class ProItemInfoManager;
+
+class ValueEditor : public QWidget, protected Ui::ValueEditor
+{
+ Q_OBJECT
+
+public:
+ ValueEditor(QWidget *parent = 0);
+ ~ValueEditor();
+
+ void initialize(ProEditorModel *model, ProItemInfoManager *infomanager);
+
+public slots:
+ void editIndex(const QModelIndex &index);
+
+protected slots:
+ void modelChanged(const QModelIndex &index);
+
+ void addItem(QString value = QString());
+ void removeItem();
+
+ void updateItemList(const QModelIndex &item);
+ void updateItemChanges(QListWidgetItem *item);
+
+ void updateVariableId();
+ void updateVariableId(int index);
+ void updateVariableOp(int index);
+
+ void updateItemId();
+ void updateItemId(int index);
+
+private:
+ enum ItemEditType {
+ SingleDefined = 0,
+ SingleUndefined = 1,
+ MultiDefined = 2,
+ MultiUndefined = 3
+ };
+
+ void hideVariable();
+ void showVariable(bool advanced);
+ void setItemEditType(ItemEditType type);
+ void setDescription(ItemEditType type, const QString &header, const QString &desc = QString());
+
+ void initialize();
+
+ void showVariable(ProVariable *variable);
+ void showScope(ProBlock *scope);
+ void showOther(ProBlock *block);
+
+ ItemEditType itemType(bool defined, bool multiple) const;
+ QModelIndex findValueIndex(const QString &id) const;
+
+protected:
+ QPointer<ProEditorModel> m_model;
+
+private:
+ bool m_handleModelChanges;
+
+ QModelIndex m_currentIndex;
+ ProItemInfoManager *m_infomanager;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // VALUEEDITOR_H
diff --git a/src/shared/proparser/valueeditor.ui b/src/shared/proparser/valueeditor.ui
new file mode 100644
index 0000000000..9a281035d2
--- /dev/null
+++ b/src/shared/proparser/valueeditor.ui
@@ -0,0 +1,384 @@
+<ui version="4.0" >
+ <class>Qt4ProjectManager::Internal::ValueEditor</class>
+ <widget class="QWidget" name="Qt4ProjectManager::Internal::ValueEditor" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>621</width>
+ <height>557</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="m_varGroupBox" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>Edit Variable</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="1" >
+ <widget class="QComboBox" name="m_varComboBox" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="m_varLineEditLabel" >
+ <property name="text" >
+ <string>Variable Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="m_assignComboBoxLabel" >
+ <property name="text" >
+ <string>Assignment Operator:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="m_varLineEdit" />
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="m_varComboBoxLabel" >
+ <property name="text" >
+ <string>Variable:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QComboBox" name="m_assignComboBox" >
+ <item>
+ <property name="text" >
+ <string>Append (+=)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Remove (-=)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Replace (~=)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Set (=)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Unique (*=)</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QStackedWidget" name="m_editStackWidget" >
+ <property name="currentIndex" >
+ <number>2</number>
+ </property>
+ <widget class="QWidget" name="m_singleDefinedPage" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="m_singleDefinedGroupBox" >
+ <property name="title" >
+ <string>Select Item</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="m_singleDefinedDescriptionLabel" >
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="m_itemComboBox" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="m_singleUndefinedPage" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="m_singleUndefinedGroupBox" >
+ <property name="title" >
+ <string>Edit Item</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="m_singleUndefinedDescriptionLabel" >
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="m_itemLineEdit" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="m_multiDefinedPage" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="m_multiDefinedGroupBox" >
+ <property name="title" >
+ <string>Select Items</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="m_multiDefinedDescriptionLabel" >
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QListWidget" name="m_itemListWidget" />
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="m_multiUndefinedPage" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="m_multiUndefinedGroupBox" >
+ <property name="title" >
+ <string>Edit Items</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="m_multiUndefinedDescriptionLabel" >
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QListView" name="m_itemListView" >
+ <property name="uniformItemSizes" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QToolButton" name="m_itemAddButton" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>New</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="m_itemRemoveButton" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>44</width>
+ <height>128</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/shared/qrceditor/qrceditor.cpp b/src/shared/qrceditor/qrceditor.cpp
new file mode 100644
index 0000000000..e4f04c9762
--- /dev/null
+++ b/src/shared/qrceditor/qrceditor.cpp
@@ -0,0 +1,402 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qrceditor.h"
+#include "undocommands_p.h"
+
+#include <QtCore/QDebug>
+#include <QtGui/QMenu>
+#include <QtGui/QFileDialog>
+#include <QtGui/QMessageBox>
+
+namespace SharedTools {
+
+QrcEditor::QrcEditor(QWidget *parent)
+ : QWidget(parent),
+ m_treeview(new ResourceView(&m_history)),
+ m_addFileAction(0)
+{
+ m_ui.setupUi(this);
+ QHBoxLayout *layout = new QHBoxLayout;
+ layout->setSpacing(0);
+ layout->setMargin(0);
+ m_ui.centralWidget->setLayout(layout);
+
+ m_treeview->enableContextMenu(false);
+ layout->addWidget(m_treeview);
+ connect(m_ui.removeButton, SIGNAL(clicked()), this, SLOT(onRemove()));
+
+ // 'Add' button with menu
+ QMenu *addMenu = new QMenu(this);
+ m_addFileAction = addMenu->addAction(tr("Add Files"), this, SLOT(onAddFiles()));
+ addMenu->addAction(tr("Add Prefix"), this, SLOT(onAddPrefix()));
+ m_ui.addButton->setMenu(addMenu);
+
+ connect(m_treeview, SIGNAL(addPrefixTriggered()), this, SLOT(onAddPrefix()));
+ connect(m_treeview, SIGNAL(addFilesTriggered(QString)), this, SLOT(onAddFiles()));
+ connect(m_treeview, SIGNAL(removeItem()), this, SLOT(onRemove()));
+ connect(m_treeview, SIGNAL(currentIndexChanged()), this, SLOT(updateCurrent()));
+ connect(m_treeview, SIGNAL(dirtyChanged(bool)), this, SIGNAL(dirtyChanged(bool)));
+ m_treeview->setFocus();
+
+ connect(m_ui.aliasText, SIGNAL(textEdited(QString)),
+ this, SLOT(onAliasChanged(QString)));
+ connect(m_ui.prefixText, SIGNAL(textEdited(QString)),
+ this, SLOT(onPrefixChanged(QString)));
+ connect(m_ui.languageText, SIGNAL(textEdited(QString)),
+ this, SLOT(onLanguageChanged(QString)));
+
+ // Prevent undo command merging after a switch of focus:
+ // (0) The initial text is "Green".
+ // (1) The user appends " is a color." --> text is "Green is a color."
+ // (2) The user clicks into some other line edit --> loss of focus
+ // (3) The user gives focuse again and substitutes "Green" with "Red"
+ // --> text now is "Red is a color."
+ // (4) The user hits undo --> text now is "Green is a color."
+ // Without calling advanceMergeId() it would have been "Green", instead.
+ connect(m_ui.aliasText, SIGNAL(editingFinished()),
+ m_treeview, SLOT(advanceMergeId()));
+ connect(m_ui.prefixText, SIGNAL(editingFinished()),
+ m_treeview, SLOT(advanceMergeId()));
+ connect(m_ui.languageText, SIGNAL(editingFinished()),
+ m_treeview, SLOT(advanceMergeId()));
+
+ connect(m_treeview, SIGNAL(addFilesTriggered(const QString&)),
+ this, SIGNAL(addFilesTriggered(const QString&)));
+
+ connect(&m_history, SIGNAL(canRedoChanged(bool)), this, SLOT(updateHistoryControls()));
+ connect(&m_history, SIGNAL(canUndoChanged(bool)), this, SLOT(updateHistoryControls()));
+ connect(&m_history, SIGNAL(canRedoChanged(bool)), this, SLOT(updateCurrent()));
+ connect(&m_history, SIGNAL(canUndoChanged(bool)), this, SLOT(updateCurrent()));
+ updateHistoryControls();
+ updateCurrent();
+}
+
+QrcEditor::~QrcEditor()
+{
+}
+
+QString QrcEditor::fileName() const
+{
+ return m_treeview->fileName();
+}
+
+void QrcEditor::setFileName(const QString &fileName)
+{
+ m_treeview->setFileName(fileName);
+}
+
+bool QrcEditor::load(const QString &fileName)
+{
+ const bool success = m_treeview->load(fileName);
+ if (success) {
+ // Set "focus"
+ m_treeview->setCurrentIndex(m_treeview->model()->index(0,0));
+
+ // Expand prefix nodes
+ m_treeview->expandAll();
+ }
+ return success;
+}
+
+bool QrcEditor::save()
+{
+ return m_treeview->save();
+}
+
+bool QrcEditor::isDirty()
+{
+ return m_treeview->isDirty();
+}
+
+void QrcEditor::setDirty(bool dirty)
+{
+ m_treeview->setDirty(dirty);
+}
+
+// Propagates a change of selection in the tree
+// to the alias/prefix/language edit controls
+void QrcEditor::updateCurrent()
+{
+ const bool isValid = m_treeview->currentIndex().isValid();
+ const bool isPrefix = m_treeview->isPrefix(m_treeview->currentIndex()) && isValid;
+ const bool isFile = !isPrefix && isValid;
+
+ m_ui.aliasLabel->setEnabled(isFile);
+ m_ui.aliasText->setEnabled(isFile);
+ m_currentAlias = m_treeview->currentAlias();
+ m_ui.aliasText->setText(m_currentAlias);
+
+ m_ui.prefixLabel->setEnabled(isPrefix);
+ m_ui.prefixText->setEnabled(isPrefix);
+ m_currentPrefix = m_treeview->currentPrefix();
+ m_ui.prefixText->setText(m_currentPrefix);
+
+ m_ui.languageLabel->setEnabled(isPrefix);
+ m_ui.languageText->setEnabled(isPrefix);
+ m_currentLanguage = m_treeview->currentLanguage();
+ m_ui.languageText->setText(m_currentLanguage);
+
+ m_ui.addButton->setEnabled(true);
+ m_addFileAction->setEnabled(isValid);
+ m_ui.removeButton->setEnabled(isValid);
+}
+
+void QrcEditor::updateHistoryControls()
+{
+ emit undoStackChanged(m_history.canUndo(), m_history.canRedo());
+}
+
+void QrcEditor::resolveLocationIssues(QStringList &files)
+{
+ const QDir dir = QFileInfo(m_treeview->fileName()).absoluteDir();
+ const QString dotdotSlash = QLatin1String("../");
+ int i = 0;
+ int count = files.count();
+
+ // Find first troublesome file
+ for (; i < count; i++) {
+ QString const &file = files.at(i);
+ const QString relativePath = dir.relativeFilePath(file);
+ if (relativePath.startsWith(dotdotSlash))
+ break;
+ }
+
+ // All paths fine -> no interaction needed
+ if (i == count) {
+ return;
+ }
+
+ // Interact with user from now on
+ bool abort = false;
+ for (; i < count; i++) {
+ // Path fine -> skip file
+ QString const &file = files.at(i);
+ QString const relativePath = dir.relativeFilePath(file);
+ if (!relativePath.startsWith(dotdotSlash)) {
+ continue;
+ }
+
+ // Path troublesome and aborted -> remove file
+ if (abort) {
+ files.removeAt(i);
+ count--;
+ i--;
+ continue;
+ } else {
+ // Path troublesome -> query user
+ QMessageBox message(this);
+ message.setWindowTitle(tr("Invalid file"));
+ message.setIcon(QMessageBox::Warning);
+ QPushButton * const continueButton = message.addButton(tr("Add anyway"), QMessageBox::AcceptRole);
+ QPushButton * const copyButton = message.addButton(tr("Copy"), QMessageBox::ActionRole);
+ QPushButton * const skipButton = message.addButton(tr("Don't add"), QMessageBox::DestructiveRole);
+ QPushButton * const abortButton = message.addButton(tr("Abort"), QMessageBox::RejectRole);
+ message.setDefaultButton(copyButton);
+ message.setEscapeButton(skipButton);
+ message.setText(tr("The file %1 is not in a subdirectory of the resource file. Continuing will result in an invalid resource file.")
+ .arg(QDir::toNativeSeparators(file)));
+ message.exec();
+ if (message.clickedButton() == continueButton) {
+ continue;
+ } else if (message.clickedButton() == skipButton) {
+ files.removeAt(i);
+ count--;
+ i--; // Compensate i++
+ } else if (message.clickedButton() == copyButton) {
+ const QFileInfo fi(file);
+ const QFileInfo suggestion(dir, fi.fileName());
+ const QString copyName = QFileDialog::getSaveFileName(this, tr("Choose copy location"),
+ suggestion.absoluteFilePath());
+ if (!copyName.isEmpty()) {
+ if (QFile::exists(copyName)) {
+ if (!QFile::remove(copyName)) {
+ QMessageBox::critical(this, tr("Overwrite failed"),
+ tr("Could not overwrite file %1.")
+ .arg(QDir::toNativeSeparators(copyName)));
+ // Remove file
+ files.removeAt(i);
+ count--;
+ i--; // Compensate i++
+ continue;
+ }
+ }
+ if (!QFile::copy(file, copyName)) {
+ QMessageBox::critical(this, tr("Copying failed"),
+ tr("Could not copy the file to %1.")
+ .arg(QDir::toNativeSeparators(copyName)));
+ // Remove file
+ files.removeAt(i);
+ count--;
+ i--; // Compensate i++
+ continue;
+ }
+ files[i] = copyName;
+ } else {
+ // Remove file
+ files.removeAt(i);
+ count--;
+ i--; // Compensate i++
+ }
+ } else if (message.clickedButton() == abortButton) {
+ abort = true;
+
+ files.removeAt(i);
+ count--;
+ i--; // Compensate i++
+ }
+ }
+ }
+}
+
+void QrcEditor::setResourceDragEnabled(bool e)
+{
+ m_treeview->setResourceDragEnabled(e);
+}
+
+bool QrcEditor::resourceDragEnabled() const
+{
+ return m_treeview->resourceDragEnabled();
+}
+
+void QrcEditor::setDefaultAddFileEnabled(bool enable)
+{
+ m_treeview->setDefaultAddFileEnabled(enable);
+}
+
+bool QrcEditor::defaultAddFileEnabled() const
+{
+ return m_treeview->defaultAddFileEnabled();
+}
+
+void QrcEditor::addFile(const QString &prefix, const QString &file)
+{
+ // TODO: make this function UNDO / REDO aware
+ m_treeview->addFile(prefix, file);
+}
+
+/*
+void QrcEditor::removeFile(const QString &prefix, const QString &file)
+{
+ m_treeview->removeFile(prefix, file);
+}
+*/
+// Slot for change of line edit content 'alias'
+void QrcEditor::onAliasChanged(const QString &alias)
+{
+ const QString &before = m_currentAlias;
+ const QString &after = alias;
+ m_treeview->setCurrentAlias(before, after);
+ m_currentAlias = alias;
+ updateHistoryControls();
+}
+
+// Slot for change of line edit content 'prefix'
+void QrcEditor::onPrefixChanged(const QString &prefix)
+{
+ const QString &before = m_currentPrefix;
+ const QString &after = prefix;
+ m_treeview->setCurrentPrefix(before, after);
+ m_currentPrefix = prefix;
+ updateHistoryControls();
+}
+
+// Slot for change of line edit content 'language'
+void QrcEditor::onLanguageChanged(const QString &language)
+{
+ const QString &before = m_currentLanguage;
+ const QString &after = language;
+ m_treeview->setCurrentLanguage(before, after);
+ m_currentLanguage = language;
+ updateHistoryControls();
+}
+
+// Slot for 'Remove' button
+void QrcEditor::onRemove()
+{
+ // Find current item, push and execute command
+ const QModelIndex current = m_treeview->currentIndex();
+ int afterDeletionArrayIndex = current.row();
+ QModelIndex afterDeletionParent = current.parent();
+ m_treeview->findSamePlacePostDeletionModelIndex(afterDeletionArrayIndex, afterDeletionParent);
+ QUndoCommand * const removeCommand = new RemoveEntryCommand(m_treeview, current);
+ m_history.push(removeCommand);
+ const QModelIndex afterDeletionModelIndex
+ = m_treeview->model()->index(afterDeletionArrayIndex, 0, afterDeletionParent);
+ m_treeview->setCurrentIndex(afterDeletionModelIndex);
+ updateHistoryControls();
+}
+
+// Slot for 'Add File' button
+void QrcEditor::onAddFiles()
+{
+ QModelIndex const current = m_treeview->currentIndex();
+ int const currentIsPrefixNode = m_treeview->isPrefix(current);
+ int const prefixArrayIndex = currentIsPrefixNode ? current.row()
+ : m_treeview->model()->parent(current).row();
+ int const cursorFileArrayIndex = currentIsPrefixNode ? 0 : current.row();
+ QStringList fileNames = m_treeview->fileNamesToAdd();
+ resolveLocationIssues(fileNames);
+ if (fileNames.isEmpty())
+ return;
+ QUndoCommand * const addFilesCommand = new AddFilesCommand(
+ m_treeview, prefixArrayIndex, cursorFileArrayIndex, fileNames);
+ m_history.push(addFilesCommand);
+ updateHistoryControls();
+}
+
+// Slot for 'Add Prefix' button
+void QrcEditor::onAddPrefix()
+{
+ QUndoCommand * const addEmptyPrefixCommand = new AddEmptyPrefixCommand(m_treeview);
+ m_history.push(addEmptyPrefixCommand);
+ updateHistoryControls();
+}
+
+// Slot for 'Undo' button
+void QrcEditor::onUndo()
+{
+ m_history.undo();
+ updateCurrent();
+ updateHistoryControls();
+}
+
+// Slot for 'Redo' button
+void QrcEditor::onRedo()
+{
+ m_history.redo();
+ updateCurrent();
+ updateHistoryControls();
+}
+
+} // namespace SharedTools
diff --git a/src/shared/qrceditor/qrceditor.h b/src/shared/qrceditor/qrceditor.h
new file mode 100644
index 0000000000..44eab56623
--- /dev/null
+++ b/src/shared/qrceditor/qrceditor.h
@@ -0,0 +1,109 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef QRCEDITOR_H
+#define QRCEDITOR_H
+
+#include "ui_qrceditor.h"
+#include "resourceview.h"
+
+#include <QtGui/QWidget>
+#include <QtGui/QUndoStack>
+
+namespace SharedTools {
+
+class QrcEditor : public QWidget
+{
+ Q_OBJECT
+
+public:
+ QrcEditor(QWidget *parent = 0);
+ virtual ~QrcEditor();
+
+ bool load(const QString &fileName);
+ bool save();
+
+ bool isDirty();
+ void setDirty(bool dirty);
+
+ QString fileName() const;
+ void setFileName(const QString &fileName);
+
+ void setResourceDragEnabled(bool e);
+ bool resourceDragEnabled() const;
+
+ void setDefaultAddFileEnabled(bool enable);
+ bool defaultAddFileEnabled() const;
+
+ void addFile(const QString &prefix, const QString &file);
+// void removeFile(const QString &prefix, const QString &file);
+
+signals:
+ void dirtyChanged(bool dirty);
+ void addFilesTriggered(const QString &prefix);
+
+private slots:
+ void updateCurrent();
+ void updateHistoryControls();
+
+private:
+ void resolveLocationIssues(QStringList &files);
+
+private slots:
+ void onAliasChanged(const QString &alias);
+ void onPrefixChanged(const QString &prefix);
+ void onLanguageChanged(const QString &language);
+ void onRemove();
+ void onAddFiles();
+ void onAddPrefix();
+
+signals:
+ void undoStackChanged(bool canUndo, bool canRedo);
+
+public slots:
+ void onUndo();
+ void onRedo();
+
+private:
+ Ui::QrcEditor m_ui;
+ QUndoStack m_history;
+ ResourceView *m_treeview;
+ QAction *m_addFileAction;
+
+ QString m_currentAlias;
+ QString m_currentPrefix;
+ QString m_currentLanguage;
+};
+
+}
+
+#endif
diff --git a/src/shared/qrceditor/qrceditor.pri b/src/shared/qrceditor/qrceditor.pri
new file mode 100644
index 0000000000..3efd26553f
--- /dev/null
+++ b/src/shared/qrceditor/qrceditor.pri
@@ -0,0 +1,28 @@
+QT_BUILD_TREE=$$(QT_BUILD_TREE)
+isEmpty(QT_BUILD_TREE):QT_BUILD_TREE=$$(QTDIR)
+QT_QRC_BUILD_TREE = $$fromfile($$QT_BUILD_TREE/.qmake.cache,QT_SOURCE_TREE)
+
+INCLUDEPATH *= $$QT_QRC_BUILD_TREE/tools/designer/src/lib/shared
+INCLUDEPATH *= $$PWD $$PWD/..
+
+QT *= xml
+
+DEFINES *= QT_NO_SHARED_EXPORT
+
+# Input
+SOURCES += \
+ $$PWD/resourcefile.cpp \
+ $$PWD/resourceview.cpp \
+ $$PWD/qrceditor.cpp \
+ $$PWD/undocommands.cpp \
+
+HEADERS += \
+ $$PWD/resourcefile_p.h \
+ $$PWD/resourceview.h \
+ $$PWD/qrceditor.h \
+ $$PWD/undocommands_p.h \
+ \
+ $$PWD/../namespace_global.h \
+
+FORMS += $$PWD/qrceditor.ui
+
diff --git a/src/shared/qrceditor/qrceditor.ui b/src/shared/qrceditor/qrceditor.ui
new file mode 100644
index 0000000000..02b5780f54
--- /dev/null
+++ b/src/shared/qrceditor/qrceditor.ui
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QrcEditor</class>
+ <widget class="QWidget" name="QrcEditor">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>491</width>
+ <height>381</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="spacing">
+ <number>-1</number>
+ </property>
+ <property name="margin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="centralWidget" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>200</width>
+ <height>200</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="addButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeButton">
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Properties</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QGridLayout">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="aliasText"/>
+ </item>
+ <item row="1" column="1" rowspan="2">
+ <widget class="QLineEdit" name="prefixText"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="prefixLabel">
+ <property name="text">
+ <string>Prefix:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="languageLabel">
+ <property name="text">
+ <string>Language:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="languageText"/>
+ </item>
+ <item row="0" column="0" rowspan="2">
+ <widget class="QLabel" name="aliasLabel">
+ <property name="text">
+ <string>Alias:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ <zorder>centralWidget</zorder>
+ <zorder>groupBox</zorder>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/shared/qrceditor/resourcefile.cpp b/src/shared/qrceditor/resourcefile.cpp
new file mode 100644
index 0000000000..b88444c6e1
--- /dev/null
+++ b/src/shared/qrceditor/resourcefile.cpp
@@ -0,0 +1,985 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "resourcefile_p.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QMimeData>
+#include <QtCore/QtAlgorithms>
+#include <QtCore/QTextStream>
+
+#include <QtGui/QIcon>
+#include <QtGui/QImageReader>
+
+#include <QtXml/QDomDocument>
+
+QT_BEGIN_NAMESPACE
+
+/*
+TRANSLATOR qdesigner_internal::ResourceModel
+*/
+
+namespace qdesigner_internal {
+
+/******************************************************************************
+** ResourceFile
+*/
+
+ResourceFile::ResourceFile(const QString &file_name)
+{
+ setFileName(file_name);
+}
+
+ResourceFile::~ResourceFile()
+{
+ clearPrefixList();
+}
+
+bool ResourceFile::load()
+{
+ m_error_message.clear();
+
+ if (m_file_name.isEmpty()) {
+ m_error_message = QCoreApplication::translate("Designer", "file name is empty");
+ return false;
+ }
+
+ QFile file(m_file_name);
+ if (!file.open(QIODevice::ReadOnly)) {
+ m_error_message = file.errorString();
+ return false;
+ }
+
+ clearPrefixList();
+
+ QDomDocument doc;
+
+ QString error_msg;
+ int error_line, error_col;
+ if (!doc.setContent(&file, &error_msg, &error_line, &error_col)) {
+ m_error_message = QCoreApplication::translate("Designer", "XML error on line %1, col %2: %3")
+ .arg(error_line).arg(error_col).arg(error_msg);
+ return false;
+ }
+
+ QDomElement root = doc.firstChildElement(QLatin1String("RCC"));
+ if (root.isNull()) {
+ m_error_message = QCoreApplication::translate("Designer", "no <RCC> root element");
+ return false;
+ }
+
+ QDomElement relt = root.firstChildElement(QLatin1String("qresource"));
+ for (; !relt.isNull(); relt = relt.nextSiblingElement(QLatin1String("qresource"))) {
+
+ QString prefix = fixPrefix(relt.attribute(QLatin1String("prefix")));
+ if (prefix.isEmpty())
+ prefix = QString(QLatin1Char('/'));
+ const QString language = relt.attribute(QLatin1String("lang"));
+
+ const int idx = indexOfPrefix(prefix);
+ Prefix * p = 0;
+ if (idx == -1) {
+ p = new Prefix(prefix, language);
+ m_prefix_list.append(p);
+ } else {
+ p = m_prefix_list[idx];
+ }
+ Q_ASSERT(p);
+
+ QDomElement felt = relt.firstChildElement(QLatin1String("file"));
+ for (; !felt.isNull(); felt = felt.nextSiblingElement(QLatin1String("file"))) {
+ const QString fileName = absolutePath(felt.text());
+ const QString alias = felt.attribute(QLatin1String("alias"));
+ File * const file = new File(p, fileName, alias);
+ p->file_list.append(file);
+ }
+ }
+
+ return true;
+}
+
+bool ResourceFile::save()
+{
+ m_error_message.clear();
+
+ if (m_file_name.isEmpty()) {
+ m_error_message = QCoreApplication::translate("Designer", "file name is empty");
+ return false;
+ }
+
+ QFile file(m_file_name);
+ if (!file.open(QIODevice::WriteOnly)) {
+ m_error_message = file.errorString();
+ return false;
+ }
+
+ QDomDocument doc;
+ QDomElement root = doc.createElement(QLatin1String("RCC"));
+ doc.appendChild(root);
+
+ const QStringList name_list = prefixList();
+
+ foreach (const QString &name, name_list) {
+ FileList file_list;
+ QString lang;
+ foreach (Prefix *pref, m_prefix_list) {
+ if (pref->name == name){
+ file_list += pref->file_list;
+ lang = pref->lang;
+ }
+ }
+
+ QDomElement relt = doc.createElement(QLatin1String("qresource"));
+ root.appendChild(relt);
+ relt.setAttribute(QLatin1String("prefix"), name);
+ if (!lang.isEmpty())
+ relt.setAttribute(QLatin1String("lang"), lang);
+
+ foreach (const File *f, file_list) {
+ const File &file = *f;
+ QDomElement felt = doc.createElement(QLatin1String("file"));
+ relt.appendChild(felt);
+ const QString conv_file = relativePath(file.name).replace(QDir::separator(), QLatin1Char('/'));
+ const QDomText text = doc.createTextNode(conv_file);
+ felt.appendChild(text);
+ if (!file.alias.isEmpty())
+ felt.setAttribute(QLatin1String("alias"), file.alias);
+ }
+ }
+
+ QTextStream stream(&file);
+ doc.save(stream, 4);
+
+ return true;
+}
+
+bool ResourceFile::split(const QString &_path, QString *prefix, QString *file) const
+{
+ prefix->clear();
+ file->clear();
+
+ QString path = _path;
+ if (!path.startsWith(QLatin1Char(':')))
+ return false;
+ path = path.mid(1);
+
+ for (int i = 0; i < m_prefix_list.size(); ++i) {
+ Prefix const * const &pref = m_prefix_list.at(i);
+ if (!path.startsWith(pref->name))
+ continue;
+
+ *prefix = pref->name;
+ if (pref->name == QString(QLatin1Char('/')))
+ *file = path.mid(1);
+ else
+ *file = path.mid(pref->name.size() + 1);
+
+ const QString filePath = absolutePath(*file);
+
+ for (int j = 0; j < pref->file_list.count(); j++) {
+ File const * const &f = pref->file_list.at(j);
+ if (!f->alias.isEmpty()) {
+ if (absolutePath(f->alias) == filePath) {
+ *file = f->name;
+ return true;
+ }
+ } else if (f->name == filePath)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+QString ResourceFile::resolvePath(const QString &path) const
+{
+ QString prefix, file;
+ if (split(path, &prefix, &file))
+ return absolutePath(file);
+
+ return QString();
+}
+
+QStringList ResourceFile::prefixList() const
+{
+ QStringList result;
+ for (int i = 0; i < m_prefix_list.size(); ++i)
+ result.append(m_prefix_list.at(i)->name);
+ return result;
+}
+
+bool ResourceFile::isEmpty() const
+{
+ return m_file_name.isEmpty() && m_prefix_list.isEmpty();
+}
+
+QStringList ResourceFile::fileList(int pref_idx) const
+{
+ QStringList result;
+ Q_ASSERT(pref_idx >= 0 && pref_idx < m_prefix_list.count());
+ const FileList &abs_file_list = m_prefix_list.at(pref_idx)->file_list;
+ foreach (const File *abs_file, abs_file_list)
+ result.append(relativePath(abs_file->name));
+ return result;
+}
+
+void ResourceFile::addFile(int prefix_idx, const QString &file, int file_idx)
+{
+ Prefix * const p = m_prefix_list[prefix_idx];
+ Q_ASSERT(p);
+ FileList &files = p->file_list;
+ Q_ASSERT(file_idx >= -1 && file_idx <= files.size());
+ if (file_idx == -1)
+ file_idx = files.size();
+ files.insert(file_idx, new File(p, absolutePath(file)));
+}
+
+void ResourceFile::addPrefix(const QString &prefix, int prefix_idx)
+{
+ QString fixed_prefix = fixPrefix(prefix);
+ if (indexOfPrefix(fixed_prefix) != -1)
+ return;
+
+ Q_ASSERT(prefix_idx >= -1 && prefix_idx <= m_prefix_list.size());
+ if (prefix_idx == -1)
+ prefix_idx = m_prefix_list.size();
+ m_prefix_list.insert(prefix_idx, new Prefix(fixed_prefix));
+}
+
+void ResourceFile::removePrefix(int prefix_idx)
+{
+ Q_ASSERT(prefix_idx >= 0 && prefix_idx < m_prefix_list.count());
+ Prefix * const p = m_prefix_list.at(prefix_idx);
+ delete p;
+ m_prefix_list.removeAt(prefix_idx);
+}
+
+void ResourceFile::removeFile(int prefix_idx, int file_idx)
+{
+ Q_ASSERT(prefix_idx >= 0 && prefix_idx < m_prefix_list.count());
+ FileList &fileList = m_prefix_list[prefix_idx]->file_list;
+ Q_ASSERT(file_idx >= 0 && file_idx < fileList.count());
+ delete fileList.at(file_idx);
+ fileList.removeAt(file_idx);
+}
+
+void ResourceFile::replacePrefix(int prefix_idx, const QString &prefix)
+{
+ Q_ASSERT(prefix_idx >= 0 && prefix_idx < m_prefix_list.count());
+ m_prefix_list[prefix_idx]->name = fixPrefix(prefix);
+}
+
+void ResourceFile::replaceLang(int prefix_idx, const QString &lang)
+{
+ Q_ASSERT(prefix_idx >= 0 && prefix_idx < m_prefix_list.count());
+ m_prefix_list[prefix_idx]->lang = lang;
+}
+
+void ResourceFile::replaceAlias(int prefix_idx, int file_idx, const QString &alias)
+{
+ Q_ASSERT(prefix_idx >= 0 && prefix_idx < m_prefix_list.count());
+ FileList &fileList = m_prefix_list.at(prefix_idx)->file_list;
+ Q_ASSERT(file_idx >= 0 && file_idx < fileList.count());
+ fileList[file_idx]->alias = alias;
+}
+
+
+void ResourceFile::replaceFile(int pref_idx, int file_idx, const QString &file)
+{
+ Q_ASSERT(pref_idx >= 0 && pref_idx < m_prefix_list.count());
+ FileList &fileList = m_prefix_list.at(pref_idx)->file_list;
+ Q_ASSERT(file_idx >= 0 && file_idx < fileList.count());
+ fileList[file_idx]->name = file;
+}
+
+int ResourceFile::indexOfPrefix(const QString &prefix) const
+{
+ QString fixed_prefix = fixPrefix(prefix);
+ for (int i = 0; i < m_prefix_list.size(); ++i) {
+ if (m_prefix_list.at(i)->name == fixed_prefix)
+ return i;
+ }
+ return -1;
+}
+
+int ResourceFile::indexOfFile(int pref_idx, const QString &file) const
+{
+ Q_ASSERT(pref_idx >= 0 && pref_idx < m_prefix_list.count());
+ Prefix * const p = m_prefix_list.at(pref_idx);
+ File equalFile(p, absolutePath(file));
+ return p->file_list.indexOf(&equalFile);
+}
+
+QString ResourceFile::relativePath(const QString &abs_path) const
+{
+ if (m_file_name.isEmpty() || QFileInfo(abs_path).isRelative())
+ return abs_path;
+
+ QFileInfo fileInfo(m_file_name);
+ return fileInfo.absoluteDir().relativeFilePath(abs_path);
+}
+
+QString ResourceFile::absolutePath(const QString &rel_path) const
+{
+ const QFileInfo fi(rel_path);
+ if (fi.isAbsolute())
+ return rel_path;
+
+ QString rc = QFileInfo(m_file_name).path();
+ rc += QDir::separator();
+ rc += rel_path;
+ return QDir::cleanPath(rc);
+}
+
+bool ResourceFile::contains(const QString &prefix, const QString &file) const
+{
+ int pref_idx = indexOfPrefix(prefix);
+ if (pref_idx == -1)
+ return false;
+ if (file.isEmpty())
+ return true;
+ Q_ASSERT(pref_idx >= 0 && pref_idx < m_prefix_list.count());
+ Prefix * const p = m_prefix_list.at(pref_idx);
+ Q_ASSERT(p);
+ File equalFile(p, absolutePath(file));
+ return p->file_list.contains(&equalFile);
+}
+
+bool ResourceFile::contains(int pref_idx, const QString &file) const
+{
+ Q_ASSERT(pref_idx >= 0 && pref_idx < m_prefix_list.count());
+ Prefix * const p = m_prefix_list.at(pref_idx);
+ File equalFile(p, absolutePath(file));
+ return p->file_list.contains(&equalFile);
+}
+
+/*static*/ QString ResourceFile::fixPrefix(const QString &prefix)
+{
+ const QChar slash = QLatin1Char('/');
+ QString result = QString(slash);
+ for (int i = 0; i < prefix.size(); ++i) {
+ const QChar c = prefix.at(i);
+ if (c == slash && result.at(result.size() - 1) == slash)
+ continue;
+ result.append(c);
+ }
+
+ if (result.size() > 1 && result.endsWith(slash))
+ result = result.mid(0, result.size() - 1);
+
+ return result;
+}
+
+int ResourceFile::prefixCount() const
+{
+ return m_prefix_list.size();
+}
+
+QString ResourceFile::prefix(int idx) const
+{
+ Q_ASSERT((idx >= 0) && (idx < m_prefix_list.count()));
+ return m_prefix_list.at(idx)->name;
+}
+
+QString ResourceFile::lang(int idx) const
+{
+ Q_ASSERT(idx >= 0 && idx < m_prefix_list.count());
+ return m_prefix_list.at(idx)->lang;
+}
+
+int ResourceFile::fileCount(int prefix_idx) const
+{
+ Q_ASSERT(prefix_idx >= 0 && prefix_idx < m_prefix_list.count());
+ return m_prefix_list.at(prefix_idx)->file_list.size();
+}
+
+QString ResourceFile::file(int prefix_idx, int file_idx) const
+{
+ Q_ASSERT(prefix_idx >= 0 && prefix_idx < m_prefix_list.count());
+ FileList &fileList = m_prefix_list.at(prefix_idx)->file_list;
+ Q_ASSERT(file_idx >= 0 && file_idx < fileList.count());
+ return fileList.at(file_idx)->name;
+}
+
+QString ResourceFile::alias(int prefix_idx, int file_idx) const
+{
+ Q_ASSERT(prefix_idx >= 0 && prefix_idx < m_prefix_list.count());
+ FileList &fileList = m_prefix_list.at(prefix_idx)->file_list;
+ Q_ASSERT(file_idx >= 0 && file_idx < fileList.count());
+ return fileList.at(file_idx)->alias;
+}
+
+void * ResourceFile::prefixPointer(int prefixIndex) const
+{
+ Q_ASSERT(prefixIndex >= 0 && prefixIndex < m_prefix_list.count());
+ return m_prefix_list.at(prefixIndex);
+}
+
+void * ResourceFile::filePointer(int prefixIndex, int fileIndex) const
+{
+ Q_ASSERT(prefixIndex >= 0 && prefixIndex < m_prefix_list.count());
+ FileList &fileList = m_prefix_list.at(prefixIndex)->file_list;
+ Q_ASSERT(fileIndex >= 0 && fileIndex < fileList.count());
+ return fileList.at(fileIndex);
+}
+
+int ResourceFile::prefixPointerIndex(const Prefix *prefix) const
+{
+ int const count = m_prefix_list.count();
+ for (int i = 0; i < count; i++) {
+ Prefix * const other = m_prefix_list.at(i);
+ if (*other == *prefix)
+ return i;
+ }
+ return -1;
+}
+
+void ResourceFile::clearPrefixList()
+{
+ qDeleteAll(m_prefix_list);
+ m_prefix_list.clear();
+}
+
+/******************************************************************************
+** ResourceModel
+*/
+
+ResourceModel::ResourceModel(const ResourceFile &resource_file, QObject *parent)
+ : QAbstractItemModel(parent), m_resource_file(resource_file), m_dirty(false)
+{
+ // Only action that works for QListWidget and the like.
+ setSupportedDragActions(Qt::CopyAction);
+}
+
+void ResourceModel::setDirty(bool b)
+{
+ if (b == m_dirty)
+ return;
+
+ m_dirty = b;
+ emit dirtyChanged(b);
+}
+
+QModelIndex ResourceModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (column != 0)
+ return QModelIndex();
+
+ void * internalPointer = 0;
+ if (parent.isValid()) {
+ void * const pip = parent.internalPointer();
+ if (pip == 0)
+ return QModelIndex();
+
+ // File node
+ Node * const node = reinterpret_cast<Node *>(pip);
+ Prefix * const prefix = node->prefix();
+ Q_ASSERT(prefix);
+ if (row < 0 || row >= prefix->file_list.count())
+ return QModelIndex();
+ const int prefixIndex = m_resource_file.prefixPointerIndex(prefix);
+ const int fileIndex = row;
+ internalPointer = m_resource_file.filePointer(prefixIndex, fileIndex);
+ } else {
+ // Prefix node
+ if (row < 0 || row >= m_resource_file.prefixCount())
+ return QModelIndex();
+ internalPointer = m_resource_file.prefixPointer(row);
+ }
+ Q_ASSERT(internalPointer);
+ return createIndex(row, 0, internalPointer);
+}
+
+QModelIndex ResourceModel::parent(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QModelIndex();
+
+ void * const internalPointer = index.internalPointer();
+ if (internalPointer == 0)
+ return QModelIndex();
+ Node * const node = reinterpret_cast<Node *>(internalPointer);
+ Prefix * const prefix = node->prefix();
+ Q_ASSERT(prefix);
+ bool const isFileNode = (prefix != node);
+
+ if (isFileNode) {
+ const int row = m_resource_file.prefixPointerIndex(prefix);
+ Q_ASSERT(row >= 0);
+ return createIndex(row, 0, prefix);
+ } else {
+ return QModelIndex();
+ }
+}
+
+int ResourceModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid()) {
+ void * const internalPointer = parent.internalPointer();
+ Node * const node = reinterpret_cast<Node *>(internalPointer);
+ Prefix * const prefix = node->prefix();
+ Q_ASSERT(prefix);
+ bool const isFileNode = (prefix != node);
+
+ if (isFileNode) {
+ return 0;
+ } else {
+ return prefix->file_list.count();
+ }
+ } else {
+ return m_resource_file.prefixCount();
+ }
+}
+
+int ResourceModel::columnCount(const QModelIndex &) const
+{
+ return 1;
+}
+
+bool ResourceModel::hasChildren(const QModelIndex &parent) const
+{
+ return rowCount(parent) != 0;
+}
+
+bool ResourceModel::iconFileExtension(const QString &path)
+{
+ static QStringList ext_list;
+ if (ext_list.isEmpty()) {
+ const QList<QByteArray> _ext_list = QImageReader::supportedImageFormats();
+ foreach (const QByteArray &ext, _ext_list) {
+ QString dotExt = QString(QLatin1Char('.'));
+ dotExt += QString::fromAscii(ext);
+ ext_list.append(dotExt);
+ }
+ }
+
+ foreach (QString ext, ext_list) {
+ if (path.endsWith(ext, Qt::CaseInsensitive))
+ return true;
+ }
+
+ return false;
+}
+
+static inline void appendParenthesized(const QString &what, QString &s)
+{
+ s += QLatin1String(" (");
+ s += what;
+ s += QLatin1Char(')');
+}
+
+QVariant ResourceModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ void * const internalPointer = index.internalPointer();
+ Node * const node = reinterpret_cast<Node *>(internalPointer);
+ Prefix const * const prefix = node->prefix();
+ File const * const file = node->file();
+ Q_ASSERT(prefix);
+ bool const isFileNode = (prefix != node);
+
+ QVariant result;
+
+ switch (role) {
+ case Qt::DisplayRole:
+ {
+ QString stringRes;
+ if (!isFileNode) {
+ // Prefix node
+ stringRes = prefix->name;
+ const QString &lang = prefix->lang;
+ if (!lang.isEmpty())
+ appendParenthesized(lang, stringRes);
+ } else {
+ // File node
+ Q_ASSERT(file);
+ stringRes = QFileInfo(file->name).fileName();
+ const QString alias = file->alias;
+ if (!alias.isEmpty())
+ appendParenthesized(alias, stringRes);
+ }
+ result = stringRes;
+ }
+ break;
+ case Qt::DecorationRole:
+ if (isFileNode) {
+ // File node
+ Q_ASSERT(file);
+ const QString path = m_resource_file.absolutePath(file->name);
+ if (iconFileExtension(path)) {
+ const QIcon icon(path);
+ if (!icon.isNull())
+ result = icon;
+ }
+ }
+ break;
+ case Qt::ToolTipRole:
+ if (isFileNode) {
+ // File node
+ Q_ASSERT(file);
+ QString conv_file = m_resource_file.relativePath(file->name);
+ QString stringRes = conv_file.replace(QDir::separator(), QLatin1Char('/'));
+ const QString &alias_file = file->alias;
+ if (!alias_file.isEmpty())
+ appendParenthesized(alias_file, stringRes);
+
+ result = stringRes;
+ result = "Qt::ToolTipRole " + stringRes;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return result;
+}
+
+void ResourceModel::getItem(const QModelIndex &index, QString &prefix, QString &file) const
+{
+ prefix.clear();
+ file.clear();
+
+ if (!index.isValid())
+ return;
+
+ void * const internalPointer = index.internalPointer();
+ Node * const node = reinterpret_cast<Node *>(internalPointer);
+ Prefix * const p = node->prefix();
+ Q_ASSERT(p);
+ bool const isFileNode = (p != node);
+
+ if (isFileNode) {
+ File *const f = node->file();
+ Q_ASSERT(f);
+ if (!f->alias.isEmpty())
+ file = f->alias;
+ else
+ file = f->name;
+ } else {
+ prefix = p->name;
+ }
+}
+
+QString ResourceModel::lang(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QString();
+
+ return m_resource_file.lang(index.row());
+}
+
+QString ResourceModel::alias(const QModelIndex &index) const
+{
+ if (!index.isValid() || !index.parent().isValid())
+ return QString();
+ return m_resource_file.alias(index.parent().row(), index.row());
+}
+
+QString ResourceModel::file(const QModelIndex &index) const
+{
+ if (!index.isValid() || !index.parent().isValid())
+ return QString();
+ return m_resource_file.file(index.parent().row(), index.row());
+}
+
+QModelIndex ResourceModel::getIndex(const QString &prefixed_file)
+{
+ QString prefix, file;
+ if (!m_resource_file.split(prefixed_file, &prefix, &file))
+ return QModelIndex();
+ return getIndex(prefix, file);
+}
+
+QModelIndex ResourceModel::getIndex(const QString &prefix, const QString &file)
+{
+ if (prefix.isEmpty())
+ return QModelIndex();
+
+ const int pref_idx = m_resource_file.indexOfPrefix(prefix);
+ if (pref_idx == -1)
+ return QModelIndex();
+
+ const QModelIndex pref_model_idx = index(pref_idx, 0, QModelIndex());
+ if (file.isEmpty())
+ return pref_model_idx;
+
+ const int file_idx = m_resource_file.indexOfFile(pref_idx, file);
+ if (file_idx == -1)
+ return QModelIndex();
+
+ return index(file_idx, 0, pref_model_idx);
+}
+
+QModelIndex ResourceModel::prefixIndex(const QModelIndex &sel_idx) const
+{
+ if (!sel_idx.isValid())
+ return QModelIndex();
+ const QModelIndex parentIndex = parent(sel_idx);
+ return parentIndex.isValid() ? parentIndex : sel_idx;
+}
+
+QModelIndex ResourceModel::addNewPrefix()
+{
+ const QString format = QLatin1String("/new/prefix%1");
+ int i = 1;
+ QString prefix = format.arg(i);
+ for ( ; m_resource_file.contains(prefix); i++)
+ prefix = format.arg(i);
+
+ i = rowCount(QModelIndex());
+ beginInsertRows(QModelIndex(), i, i);
+ m_resource_file.addPrefix(prefix);
+ endInsertRows();
+
+ setDirty(true);
+
+ return index(i, 0, QModelIndex());
+}
+
+QModelIndex ResourceModel::addFiles(const QModelIndex &model_idx, const QStringList &file_list)
+{
+ const QModelIndex prefixModelIndex = prefixIndex(model_idx);
+ const int prefixArrayIndex = prefixModelIndex.row();
+ const int cursorFileArrayIndex = (prefixModelIndex == model_idx) ? 0 : model_idx.row();
+ int dummy;
+ int lastFileArrayIndex;
+ addFiles(prefixArrayIndex, file_list, cursorFileArrayIndex, dummy, lastFileArrayIndex);
+ return index(lastFileArrayIndex, 0, prefixModelIndex);
+}
+
+void ResourceModel::addFiles(int prefixIndex, const QStringList &fileNames, int cursorFile,
+ int &firstFile, int &lastFile)
+{
+ Q_UNUSED(cursorFile);
+ const QModelIndex prefix_model_idx = index(prefixIndex, 0, QModelIndex());
+ const QStringList &file_list = fileNames;
+ firstFile = -1;
+ lastFile = -1;
+
+ if (!prefix_model_idx.isValid()) {
+ return;
+ }
+ const int prefix_idx = prefixIndex;
+
+ QStringList unique_list;
+ foreach (QString file, file_list) {
+ if (!m_resource_file.contains(prefix_idx, file) && !unique_list.contains(file))
+ unique_list.append(file);
+ }
+
+ if (unique_list.isEmpty()) {
+ return;
+ }
+ const int cnt = m_resource_file.fileCount(prefix_idx);
+ beginInsertRows(prefix_model_idx, cnt, cnt + unique_list.count() - 1); // ### FIXME
+
+ foreach (QString file, file_list)
+ m_resource_file.addFile(prefix_idx, file);
+
+ const QFileInfo fi(file_list.last());
+ m_lastResourceDir = fi.absolutePath();
+
+ endInsertRows();
+ setDirty(true);
+
+ firstFile = cnt;
+ lastFile = cnt + unique_list.count() - 1;
+}
+
+
+void ResourceModel::insertPrefix(int prefixIndex, const QString &prefix,
+ const QString &lang)
+{
+ beginInsertRows(QModelIndex(), prefixIndex, prefixIndex);
+ m_resource_file.addPrefix(prefix, prefixIndex);
+ m_resource_file.replaceLang(prefixIndex, lang);
+ endInsertRows();
+ setDirty(true);
+}
+
+void ResourceModel::insertFile(int prefixIndex, int fileIndex,
+ const QString &fileName, const QString &alias)
+{
+ const QModelIndex parent = index(prefixIndex, 0, QModelIndex());
+ beginInsertRows(parent, fileIndex, fileIndex);
+ m_resource_file.addFile(prefixIndex, fileName, fileIndex);
+ m_resource_file.replaceAlias(prefixIndex, fileIndex, alias);
+ endInsertRows();
+ setDirty(true);
+}
+
+void ResourceModel::changePrefix(const QModelIndex &model_idx, const QString &prefix)
+{
+ if (!model_idx.isValid())
+ return;
+
+ const QModelIndex prefix_model_idx = prefixIndex(model_idx);
+ const int prefix_idx = model_idx.row();
+ if (m_resource_file.prefix(prefix_idx) == ResourceFile::fixPrefix(prefix))
+ return;
+
+ if (m_resource_file.contains(prefix))
+ return;
+
+ m_resource_file.replacePrefix(prefix_idx, prefix);
+ emit dataChanged(prefix_model_idx, prefix_model_idx);
+ setDirty(true);
+}
+
+void ResourceModel::changeLang(const QModelIndex &model_idx, const QString &lang)
+{
+ if (!model_idx.isValid())
+ return;
+
+ const QModelIndex prefix_model_idx = prefixIndex(model_idx);
+ const int prefix_idx = model_idx.row();
+ if (m_resource_file.lang(prefix_idx) == lang)
+ return;
+
+ m_resource_file.replaceLang(prefix_idx, lang);
+ emit dataChanged(prefix_model_idx, prefix_model_idx);
+ setDirty(true);
+}
+
+void ResourceModel::changeAlias(const QModelIndex &index, const QString &alias)
+{
+ if (!index.parent().isValid())
+ return;
+
+ if (m_resource_file.alias(index.parent().row(), index.row()) == alias)
+ return;
+ m_resource_file.replaceAlias(index.parent().row(), index.row(), alias);
+ emit dataChanged(index, index);
+ setDirty(true);
+}
+
+QModelIndex ResourceModel::deleteItem(const QModelIndex &idx)
+{
+ if (!idx.isValid())
+ return QModelIndex();
+
+ QString dummy, file;
+ getItem(idx, dummy, file);
+ int prefix_idx = -1;
+ int file_idx = -1;
+
+ beginRemoveRows(parent(idx), idx.row(), idx.row());
+ if (file.isEmpty()) {
+ // Remove prefix
+ prefix_idx = idx.row();
+ m_resource_file.removePrefix(prefix_idx);
+ if (prefix_idx == m_resource_file.prefixCount())
+ --prefix_idx;
+ } else {
+ // Remove file
+ prefix_idx = prefixIndex(idx).row();
+ file_idx = idx.row();
+ m_resource_file.removeFile(prefix_idx, file_idx);
+ if (file_idx == m_resource_file.fileCount(prefix_idx))
+ --file_idx;
+ }
+ endRemoveRows();
+
+ setDirty(true);
+
+ if (prefix_idx == -1)
+ return QModelIndex();
+ const QModelIndex prefix_model_idx = index(prefix_idx, 0, QModelIndex());
+ if (file_idx == -1)
+ return prefix_model_idx;
+ return index(file_idx, 0, prefix_model_idx);
+}
+
+bool ResourceModel::reload()
+{
+ const bool result = m_resource_file.load();
+ if (result)
+ setDirty(false);
+ return result;
+}
+
+bool ResourceModel::save()
+{
+ const bool result = m_resource_file.save();
+ if (result)
+ setDirty(false);
+ return result;
+}
+
+QString ResourceModel::lastResourceOpenDirectory() const
+{
+ if (m_lastResourceDir.isEmpty())
+ return absolutePath(QString());
+ return m_lastResourceDir;
+}
+
+// Create a resource path 'prefix:/file'
+QString ResourceModel::resourcePath(const QString &prefix, const QString &file)
+{
+ QString rc = QString(QLatin1Char(':'));
+ rc += prefix;
+ rc += QLatin1Char('/');
+ rc += file;
+ return QDir::cleanPath(rc);
+}
+
+QMimeData *ResourceModel::mimeData(const QModelIndexList &indexes) const
+{
+ if (indexes.size() != 1)
+ return 0;
+
+ QString prefix, file;
+ getItem(indexes.front(), prefix, file);
+ if (prefix.isEmpty() || file.isEmpty())
+ return 0;
+
+ // DnD format of Designer 4.4
+ QDomDocument doc;
+ QDomElement elem = doc.createElement(QLatin1String("resource"));
+ elem.setAttribute(QLatin1String("type"), QLatin1String("image"));
+ elem.setAttribute(QLatin1String("file"), resourcePath(prefix, file));
+ doc.appendChild(elem);
+
+ QMimeData *rc = new QMimeData;
+ rc->setText(doc.toString());
+ return rc;
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/src/shared/qrceditor/resourcefile_p.h b/src/shared/qrceditor/resourcefile_p.h
new file mode 100644
index 0000000000..61b6c594b6
--- /dev/null
+++ b/src/shared/qrceditor/resourcefile_p.h
@@ -0,0 +1,269 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef RESOURCEFILE_P_H
+#define RESOURCEFILE_P_H
+
+#include "namespace_global.h"
+
+#include <QtCore/QAbstractItemModel>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+
+#include "shared_global_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+#ifdef BUILD_VSIP
+# define RESOURCE_EXPORT
+#else
+# define RESOURCE_EXPORT QDESIGNER_SHARED_EXPORT
+#endif
+
+struct File;
+struct Prefix;
+
+/*!
+ \class Node
+
+ Forms the base class for nodes in a \l ResourceFile tree.
+*/
+class Node
+{
+protected:
+ Node(File *file, Prefix *prefix) : m_file(file), m_prefix(prefix)
+ {
+ Q_ASSERT(m_prefix);
+ }
+public:
+ File *file() { return m_file; }
+ Prefix *prefix() { return m_prefix; }
+private:
+ File *m_file;
+ Prefix *m_prefix;
+};
+
+/*!
+ \class File
+
+ Represents a file node in a \l ResourceFile tree.
+*/
+struct File : public Node {
+ File(Prefix *prefix, const QString &_name = QString(), const QString &_alias = QString())
+ : Node(this, prefix), name(_name), alias(_alias) {}
+ bool operator < (const File &other) const { return name < other.name; }
+ bool operator == (const File &other) const { return name == other.name; }
+ bool operator != (const File &other) const { return name != other.name; }
+ QString name;
+ QString alias;
+};
+typedef QList<File *> FileList;
+
+/*!
+ \class Prefix
+
+ Represents a prefix node in a \l ResourceFile tree.
+*/
+struct Prefix : public Node
+{
+ Prefix(const QString &_name = QString(), const QString &_lang = QString(), const FileList &_file_list = FileList())
+ : Node(NULL, this), name(_name), lang(_lang), file_list(_file_list) {}
+ ~Prefix()
+ {
+ qDeleteAll(file_list);
+ file_list.clear();
+ }
+ bool operator == (const Prefix &other) const { return (name == other.name) && (lang == other.lang); }
+ QString name;
+ QString lang;
+ FileList file_list;
+};
+typedef QList<Prefix *> PrefixList;
+
+/*!
+ \class ResourceFile
+
+ Represents the structure of a Qt Resource File (.qrc) file.
+*/
+class RESOURCE_EXPORT ResourceFile
+{
+public:
+ ResourceFile(const QString &file_name = QString());
+ ~ResourceFile();
+
+ void setFileName(const QString &file_name) { m_file_name = file_name; }
+ QString fileName() const { return m_file_name; }
+ bool load();
+ bool save();
+ QString errorMessage() const { return m_error_message; }
+
+private:
+ QString resolvePath(const QString &path) const;
+ QStringList prefixList() const;
+ QStringList fileList(int pref_idx) const;
+
+public:
+ int prefixCount() const;
+ QString prefix(int idx) const;
+ QString lang(int idx) const;
+
+ int fileCount(int prefix_idx) const;
+
+ QString file(int prefix_idx, int file_idx) const;
+ QString alias(int prefix_idx, int file_idx) const;
+
+ void addFile(int prefix_idx, const QString &file, int file_idx = -1);
+ void addPrefix(const QString &prefix, int prefix_idx = -1);
+
+ void removePrefix(int prefix_idx);
+ void removeFile(int prefix_idx, int file_idx);
+
+ void replacePrefix(int prefix_idx, const QString &prefix);
+ void replaceLang(int prefix_idx, const QString &lang);
+ void replaceAlias(int prefix_idx, int file_idx, const QString &alias);
+
+private:
+ void replaceFile(int pref_idx, int file_idx, const QString &file);
+public:
+ int indexOfPrefix(const QString &prefix) const;
+ int indexOfFile(int pref_idx, const QString &file) const;
+
+ bool contains(const QString &prefix, const QString &file = QString()) const;
+ bool contains(int pref_idx, const QString &file) const;
+
+ QString relativePath(const QString &abs_path) const;
+ QString absolutePath(const QString &rel_path) const;
+
+ static QString fixPrefix(const QString &prefix);
+ bool split(const QString &path, QString *prefix, QString *file) const;
+
+private:
+ bool isEmpty() const;
+
+private:
+ PrefixList m_prefix_list;
+ QString m_file_name;
+ QString m_error_message;
+
+public:
+ void * prefixPointer(int prefixIndex) const;
+ void * filePointer(int prefixIndex, int fileIndex) const;
+ int prefixPointerIndex(const Prefix *prefix) const;
+
+private:
+ void clearPrefixList();
+};
+
+/*!
+ \class ResourceModel
+
+ Wraps a \l ResourceFile as a single-column tree model.
+*/
+class RESOURCE_EXPORT ResourceModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ ResourceModel(const ResourceFile &resource_file, QObject *parent = 0);
+
+ QModelIndex index(int row, int column,
+ const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &index) const;
+ int rowCount(const QModelIndex &parent) const;
+ int columnCount(const QModelIndex &parent) const;
+ bool hasChildren(const QModelIndex &parent) const;
+
+protected:
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+public:
+ QString fileName() const { return m_resource_file.fileName(); }
+ void setFileName(const QString &file_name) { m_resource_file.setFileName(file_name); }
+ void getItem(const QModelIndex &index, QString &prefix, QString &file) const;
+
+ QString lang(const QModelIndex &index) const;
+ QString alias(const QModelIndex &index) const;
+ QString file(const QModelIndex &index) const;
+
+ virtual QModelIndex addNewPrefix();
+ virtual QModelIndex addFiles(const QModelIndex &idx, const QStringList &file_list);
+ void addFiles(int prefixIndex, const QStringList &fileNames, int cursorFile, int &firstFile, int &lastFile);
+ void insertPrefix(int prefixIndex, const QString &prefix, const QString &lang);
+ void insertFile(int prefixIndex, int fileIndex, const QString &fileName, const QString &alias);
+ virtual void changePrefix(const QModelIndex &idx, const QString &prefix);
+ virtual void changeLang(const QModelIndex &idx, const QString &lang);
+ virtual void changeAlias(const QModelIndex &idx, const QString &alias);
+ virtual QModelIndex deleteItem(const QModelIndex &idx);
+ QModelIndex getIndex(const QString &prefix, const QString &file);
+ QModelIndex getIndex(const QString &prefixed_file);
+ QModelIndex prefixIndex(const QModelIndex &sel_idx) const;
+
+ QString absolutePath(const QString &path) const
+ { return m_resource_file.absolutePath(path); }
+
+private:
+ QString relativePath(const QString &path) const
+ { return m_resource_file.relativePath(path); }
+ QString lastResourceOpenDirectory() const;
+
+public:
+ virtual bool reload();
+ virtual bool save();
+ // QString errorMessage() const { return m_resource_file.errorMessage(); }
+
+ bool dirty() const { return m_dirty; }
+ void setDirty(bool b);
+
+private:
+ virtual QMimeData *mimeData (const QModelIndexList & indexes) const;
+
+ static bool iconFileExtension(const QString &path);
+ static QString resourcePath(const QString &prefix, const QString &file);
+
+signals:
+ void dirtyChanged(bool b);
+
+private:
+ ResourceFile m_resource_file;
+ bool m_dirty;
+ QString m_lastResourceDir;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // RESOURCEFILE_P_H
diff --git a/src/shared/qrceditor/resourceview.cpp b/src/shared/qrceditor/resourceview.cpp
new file mode 100644
index 0000000000..ee9c507337
--- /dev/null
+++ b/src/shared/qrceditor/resourceview.cpp
@@ -0,0 +1,663 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "resourceview.h"
+
+#include "undocommands_p.h"
+
+#include <QtCore/QDebug>
+
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QFileDialog>
+#include <QtGui/QHeaderView>
+#include <QtGui/QInputDialog>
+#include <QtGui/QMenu>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QUndoStack>
+
+namespace SharedTools {
+
+/*!
+ \class FileEntryBackup
+
+ Backups a file node.
+*/
+class FileEntryBackup : public EntryBackup
+{
+private:
+ int m_fileIndex;
+ QString m_alias;
+
+public:
+ FileEntryBackup(ResourceModel &model, int prefixIndex, int fileIndex,
+ const QString &fileName, const QString &alias)
+ : EntryBackup(model, prefixIndex, fileName), m_fileIndex(fileIndex),
+ m_alias(alias) { }
+ void restore() const;
+};
+
+void FileEntryBackup::restore() const
+{
+ m_model->insertFile(m_prefixIndex, m_fileIndex, m_name, m_alias);
+}
+
+/*!
+ \class PrefixEntryBackup
+
+ Backups a prefix node including children.
+*/
+class PrefixEntryBackup : public EntryBackup
+{
+private:
+ QString m_language;
+ QList<FileEntryBackup> m_files;
+
+public:
+ PrefixEntryBackup(ResourceModel &model, int prefixIndex, const QString &prefix,
+ const QString &language, const QList<FileEntryBackup> &files)
+ : EntryBackup(model, prefixIndex, prefix), m_language(language), m_files(files) { }
+ void restore() const;
+};
+
+void PrefixEntryBackup::restore() const
+{
+ m_model->insertPrefix(m_prefixIndex, m_name, m_language);
+ foreach (const FileEntryBackup &entry, m_files) {
+ entry.restore();
+ }
+}
+
+namespace Internal {
+
+class RelativeResourceModel : public ResourceModel
+{
+public:
+ RelativeResourceModel(const ResourceFile &resource_file, QObject *parent = 0);
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
+ {
+ if (!index.isValid())
+ return QVariant();
+/*
+ void const * const internalPointer = index.internalPointer();
+
+ if ((role == Qt::DisplayRole) && (internalPointer != NULL))
+ return ResourceModel::data(index, Qt::ToolTipRole);
+*/
+ return ResourceModel::data(index, role);
+ }
+
+ void setResourceDragEnabled(bool e) { m_resourceDragEnabled = e; }
+ bool resourceDragEnabled() const { return m_resourceDragEnabled; }
+
+ virtual Qt::ItemFlags flags(const QModelIndex &index) const;
+
+ EntryBackup * removeEntry(const QModelIndex &index);
+
+private:
+ bool m_resourceDragEnabled;
+};
+
+RelativeResourceModel::RelativeResourceModel(const ResourceFile &resource_file, QObject *parent) :
+ ResourceModel(resource_file, parent),
+ m_resourceDragEnabled(false)
+{
+}
+
+Qt::ItemFlags RelativeResourceModel::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags rc = ResourceModel::flags(index);
+ if ((rc & Qt::ItemIsEnabled) && m_resourceDragEnabled)
+ rc |= Qt::ItemIsDragEnabled;
+ return rc;
+}
+
+EntryBackup * RelativeResourceModel::removeEntry(const QModelIndex &index)
+{
+ const QModelIndex prefixIndex = this->prefixIndex(index);
+ const bool isPrefixNode = (prefixIndex == index);
+
+ // Create backup, remove, return backup
+ if (isPrefixNode) {
+ QString dummy;
+ QString prefixBackup;
+ getItem(index, prefixBackup, dummy);
+ const QString languageBackup = lang(index);
+ const int childCount = rowCount(index);
+ QList<FileEntryBackup> filesBackup;
+ for (int i = 0; i < childCount; i++) {
+ const QModelIndex childIndex = this->index(i, 0, index);
+ const QString fileNameBackup = file(childIndex);
+ const QString aliasBackup = alias(childIndex);
+ FileEntryBackup entry(*this, index.row(), i, fileNameBackup, aliasBackup);
+ filesBackup << entry;
+ }
+ deleteItem(index);
+ return new PrefixEntryBackup(*this, index.row(), prefixBackup, languageBackup, filesBackup);
+ } else {
+ const QString fileNameBackup = file(index);
+ const QString aliasBackup = alias(index);
+ deleteItem(index);
+ return new FileEntryBackup(*this, prefixIndex.row(), index.row(), fileNameBackup, aliasBackup);
+ }
+}
+
+} // namespace Internal
+
+ResourceView::ResourceView(QUndoStack *history, QWidget *parent) :
+ QTreeView(parent),
+ m_qrcModel(new Internal::RelativeResourceModel(m_qrcFile, this)),
+ m_addFile(0),
+ m_editAlias(0),
+ m_removeItem(0),
+ m_addPrefix(0),
+ m_editPrefix(0),
+ m_editLang(0),
+ m_viewMenu(0),
+ m_defaultAddFile(false),
+ m_history(history),
+ m_mergeId(-1)
+{
+ advanceMergeId();
+ setModel(m_qrcModel);
+
+ header()->hide();
+
+ connect(m_qrcModel, SIGNAL(dirtyChanged(bool)),
+ this, SIGNAL(dirtyChanged(bool)));
+
+ setupMenu();
+
+ setDefaultAddFileEnabled(true);
+ enableContextMenu(true);
+}
+
+ResourceView::~ResourceView(void)
+{
+
+}
+
+void ResourceView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+ emit currentIndexChanged();
+}
+
+bool ResourceView::isDirty() const
+{
+ return m_qrcModel->dirty();
+}
+
+void ResourceView::setDirty(bool dirty)
+{
+ m_qrcModel->setDirty(dirty);
+}
+
+void ResourceView::setDefaultAddFileEnabled(bool enable)
+{
+ m_defaultAddFile = enable;
+}
+
+bool ResourceView::defaultAddFileEnabled() const
+{
+ return m_defaultAddFile;
+}
+
+void ResourceView::findSamePlacePostDeletionModelIndex(int &row, QModelIndex &parent) const
+{
+ // Concept:
+ // - Make selection stay on same Y level
+ // - Enable user to hit delete several times in row
+ const bool hasLowerBrother = m_qrcModel->hasIndex(row + 1,
+ 0, parent);
+ if (hasLowerBrother) {
+ // First or mid child -> lower brother
+ // o
+ // +--o
+ // +-[o] <-- deleted
+ // +--o <-- chosen
+ // o
+ // --> return unmodified
+ } else {
+ if (parent == QModelIndex()) {
+ // Last prefix node
+ if (row == 0) {
+ // Last and only prefix node
+ // [o] <-- deleted
+ // +--o
+ // +--o
+ row = -1;
+ parent = QModelIndex();
+ } else {
+ const QModelIndex upperBrother = m_qrcModel->index(row - 1,
+ 0, parent);
+ if (m_qrcModel->hasChildren(upperBrother)) {
+ // o
+ // +--o <-- selected
+ // [o] <-- deleted
+ row = m_qrcModel->rowCount(upperBrother) - 1;
+ parent = upperBrother;
+ } else {
+ // o
+ // o <-- selected
+ // [o] <-- deleted
+ row--;
+ }
+ }
+ } else {
+ // Last file node
+ const bool hasPrefixBelow = m_qrcModel->hasIndex(parent.row() + 1,
+ parent.column(), QModelIndex());
+ if (hasPrefixBelow) {
+ // Last child or parent with lower brother -> lower brother of parent
+ // o
+ // +--o
+ // +-[o] <-- deleted
+ // o <-- chosen
+ row = parent.row() + 1;
+ parent = QModelIndex();
+ } else {
+ const bool onlyChild = row == 0;
+ if (onlyChild) {
+ // Last and only child of last parent -> parent
+ // o <-- chosen
+ // +-[o] <-- deleted
+ row = parent.row();
+ parent = m_qrcModel->parent(parent);
+ } else {
+ // Last child of last parent -> upper brother
+ // o
+ // +--o <-- chosen
+ // +-[o] <-- deleted
+ row--;
+ }
+ }
+ }
+ }
+}
+
+EntryBackup * ResourceView::removeEntry(const QModelIndex &index)
+{
+ Q_ASSERT(m_qrcModel);
+ return m_qrcModel->removeEntry(index);
+}
+
+void ResourceView::addFiles(int prefixIndex, const QStringList &fileNames, int cursorFile,
+ int &firstFile, int &lastFile)
+{
+ Q_ASSERT(m_qrcModel);
+ m_qrcModel->addFiles(prefixIndex, fileNames, cursorFile, firstFile, lastFile);
+
+ // Expand prefix node
+ const QModelIndex prefixModelIndex = m_qrcModel->index(prefixIndex, 0, QModelIndex());
+ if (prefixModelIndex.isValid()) {
+ this->setExpanded(prefixModelIndex, true);
+ }
+}
+
+void ResourceView::removeFiles(int prefixIndex, int firstFileIndex, int lastFileIndex)
+{
+ Q_ASSERT(prefixIndex >= 0 && prefixIndex < m_qrcModel->rowCount(QModelIndex()));
+ const QModelIndex prefixModelIndex = m_qrcModel->index(prefixIndex, 0, QModelIndex());
+ Q_ASSERT(prefixModelIndex != QModelIndex());
+ Q_ASSERT(firstFileIndex >= 0 && firstFileIndex < m_qrcModel->rowCount(prefixModelIndex));
+ Q_ASSERT(lastFileIndex >= 0 && lastFileIndex < m_qrcModel->rowCount(prefixModelIndex));
+
+ for (int i = lastFileIndex; i >= firstFileIndex; i--) {
+ const QModelIndex index = m_qrcModel->index(i, 0, prefixModelIndex);
+ delete removeEntry(index);
+ }
+}
+
+void ResourceView::enableContextMenu(bool enable)
+{
+ if (enable) {
+ connect(this, SIGNAL(clicked(const QModelIndex &)),
+ this, SLOT(popupMenu(const QModelIndex &)));
+ } else {
+ disconnect(this, SIGNAL(clicked(const QModelIndex &)),
+ this, SLOT(popupMenu(const QModelIndex &)));
+ }
+}
+
+void ResourceView::setupMenu()
+{
+ m_viewMenu = new QMenu(this);
+/*
+ m_addFile = m_viewMenu->addAction(tr("Add Files..."), this, SIGNAL(addFiles()));
+ m_editAlias = m_viewMenu->addAction(tr("Change Alias..."), this, SLOT(onEditAlias()));
+ m_addPrefix = m_viewMenu->addAction(tr("Add Prefix..."), this, SLOT(addPrefix()));
+ m_editPrefix = m_viewMenu->addAction(tr("Change Prefix..."), this, SLOT(onEditPrefix()));
+ m_editLang = m_viewMenu->addAction(tr("Change Language..."), this, SLOT(onEditLang()));
+ m_viewMenu->addSeparator();
+ m_removeItem = m_viewMenu->addAction(tr("Remove Item"), this, SLOT(removeItem()));
+*/
+ m_addFile = m_viewMenu->addAction(tr("Add Files..."), this, SLOT(onAddFiles()));
+ m_editAlias = m_viewMenu->addAction(tr("Change Alias..."), this, SLOT(onEditAlias()));
+ m_addPrefix = m_viewMenu->addAction(tr("Add Prefix..."), this, SIGNAL(addPrefixTriggered()));
+ m_editPrefix = m_viewMenu->addAction(tr("Change Prefix..."), this, SLOT(onEditPrefix()));
+ m_editLang = m_viewMenu->addAction(tr("Change Language..."), this, SLOT(onEditLang()));
+ m_viewMenu->addSeparator();
+ m_removeItem = m_viewMenu->addAction(tr("Remove Item"), this, SIGNAL(removeItem()));
+}
+
+void ResourceView::mouseReleaseEvent(QMouseEvent *e)
+{
+ m_releasePos = e->globalPos();
+ if (e->button() != Qt::RightButton)
+ m_releasePos = QPoint();
+
+ QTreeView::mouseReleaseEvent(e);
+}
+
+void ResourceView::popupMenu(const QModelIndex &index)
+{
+ if (!m_releasePos.isNull()) {
+ m_addFile->setEnabled(index.isValid());
+ m_editPrefix->setEnabled(index.isValid());
+ m_editLang->setEnabled(index.isValid());
+ m_removeItem->setEnabled(index.isValid());
+
+ m_viewMenu->popup(m_releasePos);
+ }
+}
+
+QModelIndex ResourceView::addPrefix()
+{
+ const QModelIndex idx = m_qrcModel->addNewPrefix();
+ selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
+ return idx;
+}
+
+QStringList ResourceView::fileNamesToAdd()
+{
+ return QFileDialog::getOpenFileNames(this, tr("Open file"),
+ m_qrcModel->absolutePath(QString()),
+ tr("All files (*.*)"));
+}
+
+void ResourceView::onAddFiles()
+{
+ emit addFilesTriggered(currentPrefix());
+}
+
+void ResourceView::addFiles(QStringList fileList, const QModelIndex &index)
+{
+ if (fileList.isEmpty())
+ return;
+ QModelIndex idx = index;
+ if (!m_qrcModel->hasChildren(QModelIndex())) {
+ idx = addPrefix();
+ expand(idx);
+ }
+
+ idx = m_qrcModel->addFiles(idx, fileList);
+
+ if (idx.isValid()) {
+ const QModelIndex preindex = m_qrcModel->prefixIndex(index);
+ setExpanded(preindex, true);
+ selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
+ QString prefix, file;
+ m_qrcModel->getItem(preindex, prefix, file);
+// XXX emit filesAdded(prefix, fileList);
+ }
+}
+
+void ResourceView::addFile(const QString &prefix, const QString &file)
+{
+ const QModelIndex preindex = m_qrcModel->getIndex(prefix, QString());
+ addFiles(QStringList(file), preindex);
+}
+
+/*
+void ResourceView::removeItem()
+{
+ const QModelIndex index = currentIndex();
+ m_qrcModel->deleteItem(index);
+}
+
+void ResourceView::removeFile(const QString &prefix, const QString &file)
+{
+ const QModelIndex index = m_qrcModel->getIndex(prefix, file);
+ if (index.isValid())
+ m_qrcModel->deleteItem(index);
+}
+*/
+void ResourceView::onEditPrefix()
+{
+ QModelIndex index = currentIndex();
+ changePrefix(index);
+}
+
+void ResourceView::onEditLang()
+{
+ const QModelIndex index = currentIndex();
+ changeLang(index);
+}
+
+void ResourceView::onEditAlias()
+{
+ const QModelIndex index = currentIndex();
+ changeAlias(index);
+}
+
+bool ResourceView::load(QString fileName)
+{
+ const QFileInfo fi(fileName);
+ m_qrcModel->setFileName(fi.absoluteFilePath());
+
+ if (!fi.exists())
+ return false;
+
+ const bool result = m_qrcModel->reload();
+ reset();
+ return result;
+}
+
+bool ResourceView::save(void)
+{
+ return m_qrcModel->save();
+}
+
+void ResourceView::changePrefix(const QModelIndex &index)
+{
+ bool ok = false;
+ const QModelIndex preindex = m_qrcModel->prefixIndex(index);
+
+ QString prefixBefore;
+ QString dummy;
+ m_qrcModel->getItem(preindex, prefixBefore, dummy);
+
+ QString const prefixAfter = QInputDialog::getText(this, tr("Change Prefix"), tr("Input Prefix:"),
+ QLineEdit::Normal, prefixBefore, &ok);
+
+ if (ok)
+ addUndoCommand(preindex, PrefixProperty, prefixBefore, prefixAfter);
+}
+
+void ResourceView::changeLang(const QModelIndex &index)
+{
+ bool ok = false;
+ const QModelIndex preindex = m_qrcModel->prefixIndex(index);
+
+ QString const langBefore = m_qrcModel->lang(preindex);
+ QString const langAfter = QInputDialog::getText(this, tr("Change Language"), tr("Language:"),
+ QLineEdit::Normal, langBefore, &ok);
+
+ if (ok) {
+ addUndoCommand(preindex, LanguageProperty, langBefore, langAfter);
+ }
+}
+
+void ResourceView::changeAlias(const QModelIndex &index)
+{
+ if (!index.parent().isValid())
+ return;
+
+ bool ok = false;
+
+ QString const aliasBefore = m_qrcModel->alias(index);
+ QString const aliasAfter = QInputDialog::getText(this, tr("Change File Alias"), tr("Alias:"),
+ QLineEdit::Normal, aliasBefore, &ok);
+
+ if (ok)
+ addUndoCommand(index, AliasProperty, aliasBefore, aliasAfter);
+}
+
+QString ResourceView::currentAlias() const
+{
+ const QModelIndex current = currentIndex();
+ if (!current.isValid())
+ return QString();
+ return m_qrcModel->alias(current);
+}
+
+QString ResourceView::currentPrefix() const
+{
+ const QModelIndex current = currentIndex();
+ if (!current.isValid())
+ return QString();
+ const QModelIndex preindex = m_qrcModel->prefixIndex(current);
+ QString prefix, file;
+ m_qrcModel->getItem(preindex, prefix, file);
+ return prefix;
+}
+
+QString ResourceView::currentLanguage() const
+{
+ const QModelIndex current = currentIndex();
+ if (!current.isValid())
+ return QString();
+ const QModelIndex preindex = m_qrcModel->prefixIndex(current);
+ return m_qrcModel->lang(preindex);
+}
+
+QString ResourceView::getCurrentValue(NodeProperty property) const
+{
+ switch (property) {
+ case AliasProperty: return currentAlias();
+ case PrefixProperty: return currentPrefix();
+ case LanguageProperty: return currentLanguage();
+ default: Q_ASSERT(false); return QString(); // Kill warning
+ }
+}
+
+void ResourceView::changeValue(const QModelIndex &nodeIndex, NodeProperty property,
+ const QString &value)
+{
+ switch (property) {
+ case AliasProperty: m_qrcModel->changeAlias(nodeIndex, value); return;
+ case PrefixProperty: m_qrcModel->changePrefix(nodeIndex, value); return;
+ case LanguageProperty: m_qrcModel->changeLang(nodeIndex, value); return;
+ default: Q_ASSERT(false);
+ }
+}
+
+void ResourceView::advanceMergeId()
+{
+ m_mergeId++;
+ if (m_mergeId < 0)
+ m_mergeId = 0;
+}
+
+void ResourceView::addUndoCommand(const QModelIndex &nodeIndex, NodeProperty property,
+ const QString &before, const QString &after)
+{
+ QUndoCommand * const command = new ModifyPropertyCommand(this, nodeIndex, property,
+ m_mergeId, before, after);
+ m_history->push(command);
+}
+
+void ResourceView::setCurrentAlias(const QString &before, const QString &after)
+{
+ const QModelIndex current = currentIndex();
+ if (!current.isValid())
+ return;
+
+ addUndoCommand(current, AliasProperty, before, after);
+}
+
+void ResourceView::setCurrentPrefix(const QString &before, const QString &after)
+{
+ const QModelIndex current = currentIndex();
+ if (!current.isValid())
+ return;
+ const QModelIndex preindex = m_qrcModel->prefixIndex(current);
+
+ addUndoCommand(preindex, PrefixProperty, before, after);
+}
+
+void ResourceView::setCurrentLanguage(const QString &before, const QString &after)
+{
+ const QModelIndex current = currentIndex();
+ if (!current.isValid())
+ return;
+ const QModelIndex preindex = m_qrcModel->prefixIndex(current);
+
+ addUndoCommand(preindex, LanguageProperty, before, after);
+}
+
+bool ResourceView::isPrefix(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return false;
+ const QModelIndex preindex = m_qrcModel->prefixIndex(index);
+ if (preindex == index)
+ return true;
+ return false;
+}
+
+QString ResourceView::fileName() const
+{
+ return m_qrcModel->fileName();
+}
+
+void ResourceView::setFileName(const QString &fileName)
+{
+ m_qrcModel->setFileName(fileName);
+}
+
+void ResourceView::setResourceDragEnabled(bool e)
+{
+ setDragEnabled(e);
+ m_qrcModel->setResourceDragEnabled(e);
+}
+
+bool ResourceView::resourceDragEnabled() const
+{
+ return m_qrcModel->resourceDragEnabled();
+}
+
+} // namespace SharedTools
diff --git a/src/shared/qrceditor/resourceview.h b/src/shared/qrceditor/resourceview.h
new file mode 100644
index 0000000000..ae11b2db93
--- /dev/null
+++ b/src/shared/qrceditor/resourceview.h
@@ -0,0 +1,186 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef RESOURCEVIEW_H
+#define RESOURCEVIEW_H
+
+#include "namespace_global.h"
+
+#include "resourcefile_p.h"
+
+#include <QtGui/QTreeView>
+#include <QtCore/QPoint>
+
+using namespace qdesigner_internal;
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QMenu;
+class QMouseEvent;
+class QUndoStack;
+QT_END_NAMESPACE
+
+namespace SharedTools {
+
+/*!
+ \class EntryBackup
+
+ Holds the backup of a tree node including children.
+*/
+class EntryBackup
+{
+protected:
+ ResourceModel *m_model;
+ int m_prefixIndex;
+ QString m_name;
+
+ EntryBackup(ResourceModel &model, int prefixIndex, const QString &name)
+ : m_model(&model), m_prefixIndex(prefixIndex), m_name(name) { }
+
+public:
+ virtual void restore() const = 0;
+ virtual ~EntryBackup() { }
+};
+
+namespace Internal {
+ class RelativeResourceModel;
+}
+
+class ResourceView : public QTreeView
+{
+ Q_OBJECT
+
+public:
+ enum NodeProperty {
+ AliasProperty,
+ PrefixProperty,
+ LanguageProperty
+ };
+
+ ResourceView(QUndoStack *history, QWidget *parent = 0);
+ ~ResourceView(void);
+
+ bool load(QString fileName);
+ bool save(void);
+ QString fileName() const;
+ void setFileName(const QString &fileName);
+
+ bool isDirty() const;
+ void setDirty(bool dirty);
+
+ void enableContextMenu(bool enable);
+
+ void addFiles(QStringList fileList, const QModelIndex &index);
+
+ void addFile(const QString &prefix, const QString &file);
+// void removeFile(const QString &prefix, const QString &file);
+
+ bool isPrefix(const QModelIndex &index) const;
+
+ QString currentAlias() const;
+ QString currentPrefix() const;
+ QString currentLanguage() const;
+
+ void setResourceDragEnabled(bool e);
+ bool resourceDragEnabled() const;
+
+ void setDefaultAddFileEnabled(bool enable);
+ bool defaultAddFileEnabled() const;
+
+ void findSamePlacePostDeletionModelIndex(int &row, QModelIndex &parent) const;
+ EntryBackup * removeEntry(const QModelIndex &index);
+ void addFiles(int prefixIndex, const QStringList &fileNames, int cursorFile,
+ int &firstFile, int &lastFile);
+ void removeFiles(int prefixIndex, int firstFileIndex, int lastFileIndex);
+ QStringList fileNamesToAdd();
+ QModelIndex addPrefix();
+
+public slots:
+ void onAddFiles();
+ void setCurrentAlias(const QString &before, const QString &after);
+ void setCurrentPrefix(const QString &before, const QString &after);
+ void setCurrentLanguage(const QString &before, const QString &after);
+ void advanceMergeId();
+
+protected:
+ void setupMenu();
+ void changePrefix(const QModelIndex &index);
+ void changeLang(const QModelIndex &index);
+ void changeAlias(const QModelIndex &index);
+ void mouseReleaseEvent(QMouseEvent *e);
+
+signals:
+ void removeItem();
+ void dirtyChanged(bool b);
+ void currentIndexChanged();
+
+ void addFilesTriggered(const QString &prefix);
+ void addPrefixTriggered();
+
+protected slots:
+ void currentChanged(const QModelIndex &current, const QModelIndex &previous);
+
+private slots:
+ void onEditAlias();
+ void onEditPrefix();
+ void onEditLang();
+ void popupMenu(const QModelIndex &index);
+
+public:
+ QString getCurrentValue(NodeProperty property) const;
+ void changeValue(const QModelIndex &nodeIndex, NodeProperty property, const QString &value);
+
+private:
+ void addUndoCommand(const QModelIndex &nodeIndex, NodeProperty property, const QString &before,
+ const QString &after);
+
+ QPoint m_releasePos;
+
+ qdesigner_internal::ResourceFile m_qrcFile;
+ Internal::RelativeResourceModel *m_qrcModel;
+
+ QAction *m_addFile;
+ QAction *m_editAlias;
+ QAction *m_removeItem;
+ QAction *m_addPrefix;
+ QAction *m_editPrefix;
+ QAction *m_editLang;
+ QMenu *m_viewMenu;
+ bool m_defaultAddFile;
+ QUndoStack *m_history;
+ int m_mergeId;
+};
+
+} // namespace SharedTools
+
+#endif // RESOURCEVIEW_H
diff --git a/src/shared/qrceditor/test/main.cpp b/src/shared/qrceditor/test/main.cpp
new file mode 100644
index 0000000000..481a3b09e7
--- /dev/null
+++ b/src/shared/qrceditor/test/main.cpp
@@ -0,0 +1,43 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qrceditor.h"
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ MainWindow mw;
+ mw.show();
+ return app.exec();
+}
diff --git a/src/shared/qrceditor/test/mainwindow.cpp b/src/shared/qrceditor/test/mainwindow.cpp
new file mode 100644
index 0000000000..22941ca59a
--- /dev/null
+++ b/src/shared/qrceditor/test/mainwindow.cpp
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "mainwindow.h"
+#include "qrceditor.h"
+
+#include <QAction>
+#include <QDebug>
+#include <QFileDialog>
+#include <QMenuBar>
+#include <QStatusBar>
+#include <QVBoxLayout>
+
+MainWindow::MainWindow() :
+ m_qrcEditor(new SharedTools::QrcEditor())
+{
+ m_qrcEditor->setResourceDragEnabled(true);
+ setWindowTitle(tr("Test resource editor"));
+ QMenu* fMenu = menuBar()->addMenu(tr("File"));
+
+ QAction* oa = fMenu->addAction(tr("Open..."));
+ connect(oa, SIGNAL(triggered()), this, SLOT(slotOpen()));
+
+ QAction* sa = fMenu->addAction(tr("Save"));
+ connect(sa, SIGNAL(triggered()), this, SLOT(slotSave()));
+
+ QAction* xa = fMenu->addAction(tr("Exit!"));
+ connect(xa, SIGNAL(triggered()), this, SLOT(close()));
+
+
+ QWidget *cw = new QWidget();
+ setCentralWidget(cw);
+ QVBoxLayout *lt = new QVBoxLayout(cw);
+ lt->addWidget(m_qrcEditor);
+ setMinimumSize(QSize(500, 500));
+}
+
+void MainWindow::slotOpen()
+{
+ const QString fileName = QFileDialog::getOpenFileName(this, tr("Choose resource file"),
+ QString(),
+ tr("Resource files (*.qrc)"));
+ if (fileName.isEmpty())
+ return;
+
+ if (m_qrcEditor->load(fileName))
+ statusBar()->showMessage(tr("%1 opened").arg(fileName));
+ else
+ statusBar()->showMessage(tr("Unable to open %1!").arg(fileName));
+}
+
+void MainWindow::slotSave()
+{
+ const QString oldFileName = m_qrcEditor->fileName();
+ QString fileName = oldFileName;
+
+ if (fileName.isEmpty()) {
+ fileName = QFileDialog::getSaveFileName(this, tr("Save resource file"),
+ QString(),
+ tr("Resource files (*.qrc)"));
+ if (fileName.isEmpty())
+ return;
+ }
+
+ m_qrcEditor->setFileName(fileName);
+ if (m_qrcEditor->save())
+ statusBar()->showMessage(tr("%1 written").arg(fileName));
+ else {
+ statusBar()->showMessage(tr("Unable to write %1!").arg(fileName));
+ m_qrcEditor->setFileName(oldFileName);
+ }
+}
diff --git a/src/shared/qrceditor/test/mainwindow.h b/src/shared/qrceditor/test/mainwindow.h
new file mode 100644
index 0000000000..fec9d01402
--- /dev/null
+++ b/src/shared/qrceditor/test/mainwindow.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+namespace SharedTools {
+ class QrcEditor;
+}
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow();
+
+private slots:
+ void slotOpen();
+ void slotSave();
+
+private:
+ SharedTools::QrcEditor *m_qrcEditor;
+};
+
+#endif // MAINWINDOW_H
diff --git a/src/shared/qrceditor/test/test.pro b/src/shared/qrceditor/test/test.pro
new file mode 100644
index 0000000000..aae1b39461
--- /dev/null
+++ b/src/shared/qrceditor/test/test.pro
@@ -0,0 +1,11 @@
+######################################################################
+# Automatically generated by qmake (1.07a) Mon Mar 19 11:10:13 2007
+######################################################################
+
+TEMPLATE = app
+
+QT += gui
+
+include(../qrceditor.pri)
+SOURCES += main.cpp mainwindow.cpp
+HEADERS += mainwindow.h
diff --git a/src/shared/qrceditor/undocommands.cpp b/src/shared/qrceditor/undocommands.cpp
new file mode 100644
index 0000000000..171fffafa7
--- /dev/null
+++ b/src/shared/qrceditor/undocommands.cpp
@@ -0,0 +1,193 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "undocommands_p.h"
+
+#include <QtCore/QModelIndex>
+
+namespace SharedTools {
+
+ViewCommand::ViewCommand(ResourceView *view)
+ : m_view(view)
+{ }
+
+ViewCommand::~ViewCommand()
+{ }
+
+ModelIndexViewCommand::ModelIndexViewCommand(ResourceView *view)
+ : ViewCommand(view)
+{ }
+
+ModelIndexViewCommand::~ModelIndexViewCommand()
+{ }
+
+void ModelIndexViewCommand::storeIndex(const QModelIndex &index)
+{
+ if (m_view->isPrefix(index)) {
+ m_prefixArrayIndex = index.row();
+ m_fileArrayIndex = -1;
+ } else {
+ m_fileArrayIndex = index.row();
+ m_prefixArrayIndex = m_view->model()->parent(index).row();
+ }
+}
+
+QModelIndex ModelIndexViewCommand::makeIndex() const
+{
+ const QModelIndex prefixModelIndex
+ = m_view->model()->index(m_prefixArrayIndex, 0, QModelIndex());
+ if (m_fileArrayIndex != -1) {
+ // File node
+ const QModelIndex fileModelIndex
+ = m_view->model()->index(m_fileArrayIndex, 0, prefixModelIndex);
+ return fileModelIndex;
+ } else {
+ // Prefix node
+ return prefixModelIndex;
+ }
+}
+
+
+
+ModifyPropertyCommand::ModifyPropertyCommand(ResourceView *view, const QModelIndex &nodeIndex,
+ ResourceView::NodeProperty property, const int mergeId, const QString &before,
+ const QString &after)
+ : ModelIndexViewCommand(view), m_property(property), m_before(before), m_after(after),
+ m_mergeId(mergeId)
+{
+ storeIndex(nodeIndex);
+}
+
+bool ModifyPropertyCommand::mergeWith(const QUndoCommand * command)
+{
+ const ModifyPropertyCommand * const brother
+ = dynamic_cast<const ModifyPropertyCommand *>(command);
+ if (command == 0 || m_property != brother->m_property)
+ return false;
+
+ // Choose older command (this) and forgot the other
+ return true;
+}
+
+void ModifyPropertyCommand::undo()
+{
+ Q_ASSERT(m_view);
+
+ // Save current text in m_after for redo()
+ m_after = m_view->getCurrentValue(m_property);
+
+ // Reset text to m_before
+ m_view->changeValue(makeIndex(), m_property, m_before);
+}
+
+void ModifyPropertyCommand::redo()
+{
+ // Prevent execution from within QUndoStack::push
+ if (m_after.isNull())
+ return;
+
+ // Bring back text before undo
+ Q_ASSERT(m_view);
+ m_view->changeValue(makeIndex(), m_property, m_after);
+}
+
+RemoveEntryCommand::RemoveEntryCommand(ResourceView *view, const QModelIndex &index)
+ : ModelIndexViewCommand(view), m_entry(0), m_isExpanded(true)
+{
+ storeIndex(index);
+}
+
+RemoveEntryCommand::~RemoveEntryCommand()
+{
+ freeEntry();
+}
+
+void RemoveEntryCommand::redo()
+{
+ freeEntry();
+ const QModelIndex index = makeIndex();
+ m_isExpanded = m_view->isExpanded(index);
+ m_entry = m_view->removeEntry(index);
+}
+
+void RemoveEntryCommand::undo()
+{
+ if (m_entry == 0) {
+ m_entry->restore();
+ Q_ASSERT(m_view != 0);
+ const QModelIndex index = makeIndex();
+ m_view->setExpanded(index, m_isExpanded);
+ m_view->setCurrentIndex(index);
+ freeEntry();
+ }
+}
+
+void RemoveEntryCommand::freeEntry()
+{
+ delete m_entry;
+ m_entry = 0;
+}
+
+AddFilesCommand::AddFilesCommand(ResourceView *view, int prefixIndex, int cursorFileIndex,
+ const QStringList &fileNames)
+ : ViewCommand(view), m_prefixIndex(prefixIndex), m_cursorFileIndex(cursorFileIndex),
+ m_fileNames(fileNames)
+{ }
+
+void AddFilesCommand::redo()
+{
+ m_view->addFiles(m_prefixIndex, m_fileNames, m_cursorFileIndex, m_firstFile, m_lastFile);
+}
+
+void AddFilesCommand::undo()
+{
+ m_view->removeFiles(m_prefixIndex, m_firstFile, m_lastFile);
+}
+
+AddEmptyPrefixCommand::AddEmptyPrefixCommand(ResourceView *view)
+ : ViewCommand(view)
+{ }
+
+void AddEmptyPrefixCommand::redo()
+{
+ m_prefixArrayIndex = m_view->addPrefix().row();
+}
+
+void AddEmptyPrefixCommand::undo()
+{
+ const QModelIndex prefixModelIndex = m_view->model()->index(
+ m_prefixArrayIndex, 0, QModelIndex());
+ delete m_view->removeEntry(prefixModelIndex);
+}
+
+} // namespace SharedTools
diff --git a/src/shared/qrceditor/undocommands_p.h b/src/shared/qrceditor/undocommands_p.h
new file mode 100644
index 0000000000..5a6f5af9a2
--- /dev/null
+++ b/src/shared/qrceditor/undocommands_p.h
@@ -0,0 +1,165 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef UNDO_COMMANDS_H
+#define UNDO_COMMANDS_H
+
+#include "resourceview.h"
+
+#include <QtCore/QString>
+#include <QtGui/QUndoCommand>
+
+QT_BEGIN_NAMESPACE
+class QModelIndex;
+QT_END_NAMESPACE
+
+namespace SharedTools {
+
+/*!
+ \class ViewCommand
+
+ Provides a base for \l ResourceView-related commands.
+*/
+class ViewCommand : public QUndoCommand
+{
+protected:
+ ResourceView *m_view;
+
+ ViewCommand(ResourceView *view);
+ virtual ~ViewCommand();
+};
+
+/*!
+ \class ModelIndexViewCommand
+
+ Provides a mean to store/restore a \l QModelIndex as it cannot
+ be stored savely in most cases. This is an abstract class.
+*/
+class ModelIndexViewCommand : public ViewCommand
+{
+ int m_prefixArrayIndex;
+ int m_fileArrayIndex;
+
+protected:
+ ModelIndexViewCommand(ResourceView *view);
+ virtual ~ModelIndexViewCommand();
+ void storeIndex(const QModelIndex &index);
+ QModelIndex makeIndex() const;
+};
+
+/*!
+ \class ModifyPropertyCommand
+
+ Modifies the name/prefix/language property of a prefix/file node.
+*/
+class ModifyPropertyCommand : public ModelIndexViewCommand
+{
+ ResourceView::NodeProperty m_property;
+ QString m_before;
+ QString m_after;
+ int m_mergeId;
+
+public:
+ ModifyPropertyCommand(ResourceView *view, const QModelIndex &nodeIndex,
+ ResourceView::NodeProperty property, const int mergeId, const QString &before,
+ const QString &after = QString());
+
+private:
+ int id() const { return m_mergeId; }
+ bool mergeWith(const QUndoCommand * command);
+ void undo();
+ void redo();
+};
+
+/*!
+ \class RemoveEntryCommand
+
+ Removes a \l QModelIndex including all children from a \l ResourceView.
+*/
+class RemoveEntryCommand : public ModelIndexViewCommand
+{
+ EntryBackup *m_entry;
+ bool m_isExpanded;
+
+public:
+ RemoveEntryCommand(ResourceView *view, const QModelIndex &index);
+ ~RemoveEntryCommand();
+
+private:
+ void redo();
+ void undo();
+ void freeEntry();
+};
+
+/*!
+ \class AddFilesCommand
+
+ Adds a list of files to a given prefix node.
+*/
+class AddFilesCommand : public ViewCommand
+{
+ int m_prefixIndex;
+ int m_cursorFileIndex;
+ int m_firstFile;
+ int m_lastFile;
+ const QStringList m_fileNames;
+
+public:
+ AddFilesCommand(ResourceView *view, int prefixIndex, int cursorFileIndex,
+ const QStringList &fileNames);
+
+private:
+ void redo();
+ void undo();
+};
+
+/*!
+ \class AddEmptyPrefixCommand
+
+ Adds a new, empty prefix node.
+*/
+class AddEmptyPrefixCommand : public ViewCommand
+{
+ int m_prefixArrayIndex;
+
+public:
+ AddEmptyPrefixCommand(ResourceView *view);
+
+private:
+ void redo();
+ void undo();
+};
+
+} // namespace SharedTools
+
+#endif // UNDO_COMMANDS_H
diff --git a/src/shared/qscripthighlighter/README b/src/shared/qscripthighlighter/README
new file mode 100644
index 0000000000..220e01228e
--- /dev/null
+++ b/src/shared/qscripthighlighter/README
@@ -0,0 +1,3 @@
+Syntax highlighter for Qt script courtesy of Simon.
+
+Exists as a duplicate in Designer.
diff --git a/src/shared/qscripthighlighter/qscripthighlighter.cpp b/src/shared/qscripthighlighter/qscripthighlighter.cpp
new file mode 100644
index 0000000000..390e3ca466
--- /dev/null
+++ b/src/shared/qscripthighlighter/qscripthighlighter.cpp
@@ -0,0 +1,482 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qscripthighlighter.h"
+
+#include <QtCore/QSet>
+#include <QtCore/QtAlgorithms>
+
+static const QSet<QString> &qscriptKeywords() {
+ static QSet<QString> keywords;
+ if (keywords.empty()) {
+ keywords.insert(QLatin1String("Infinity"));
+ keywords.insert(QLatin1String("NaN"));
+ keywords.insert(QLatin1String("abstract"));
+ keywords.insert(QLatin1String("boolean"));
+ keywords.insert(QLatin1String("break"));
+ keywords.insert(QLatin1String("byte"));
+ keywords.insert(QLatin1String("case"));
+ keywords.insert(QLatin1String("catch"));
+ keywords.insert(QLatin1String("char"));
+ keywords.insert(QLatin1String("class"));
+ keywords.insert(QLatin1String("const"));
+ keywords.insert(QLatin1String("constructor"));
+ keywords.insert(QLatin1String("continue"));
+ keywords.insert(QLatin1String("debugger"));
+ keywords.insert(QLatin1String("default"));
+ keywords.insert(QLatin1String("delete"));
+ keywords.insert(QLatin1String("do"));
+ keywords.insert(QLatin1String("double"));
+ keywords.insert(QLatin1String("else"));
+ keywords.insert(QLatin1String("enum"));
+ keywords.insert(QLatin1String("export"));
+ keywords.insert(QLatin1String("extends"));
+ keywords.insert(QLatin1String("false"));
+ keywords.insert(QLatin1String("final"));
+ keywords.insert(QLatin1String("finally"));
+ keywords.insert(QLatin1String("float"));
+ keywords.insert(QLatin1String("for"));
+ keywords.insert(QLatin1String("function"));
+ keywords.insert(QLatin1String("goto"));
+ keywords.insert(QLatin1String("if"));
+ keywords.insert(QLatin1String("implements"));
+ keywords.insert(QLatin1String("import"));
+ keywords.insert(QLatin1String("in"));
+ keywords.insert(QLatin1String("instanceof"));
+ keywords.insert(QLatin1String("int"));
+ keywords.insert(QLatin1String("interface"));
+ keywords.insert(QLatin1String("long"));
+ keywords.insert(QLatin1String("native"));
+ keywords.insert(QLatin1String("new"));
+ keywords.insert(QLatin1String("package"));
+ keywords.insert(QLatin1String("private"));
+ keywords.insert(QLatin1String("protected"));
+ keywords.insert(QLatin1String("public"));
+ keywords.insert(QLatin1String("return"));
+ keywords.insert(QLatin1String("short"));
+ keywords.insert(QLatin1String("static"));
+ keywords.insert(QLatin1String("super"));
+ keywords.insert(QLatin1String("switch"));
+ keywords.insert(QLatin1String("synchronized"));
+ keywords.insert(QLatin1String("this"));
+ keywords.insert(QLatin1String("throw"));
+ keywords.insert(QLatin1String("throws"));
+ keywords.insert(QLatin1String("transient"));
+ keywords.insert(QLatin1String("true"));
+ keywords.insert(QLatin1String("try"));
+ keywords.insert(QLatin1String("typeof"));
+ keywords.insert(QLatin1String("undefined"));
+ keywords.insert(QLatin1String("var"));
+ keywords.insert(QLatin1String("void"));
+ keywords.insert(QLatin1String("volatile"));
+ keywords.insert(QLatin1String("while"));
+ keywords.insert(QLatin1String("with")); // end
+ }
+ return keywords;
+}
+
+
+namespace SharedTools {
+
+QScriptHighlighter::QScriptHighlighter(QTextDocument *parent)
+ : QSyntaxHighlighter(parent)
+{
+ setFormats(defaultFormats());
+}
+
+void QScriptHighlighter::highlightBlock(const QString &text)
+{
+ // states
+ enum {
+ StateStandard,
+ StateCommentStart1,
+ StateCCommentStart2,
+ StateCppCommentStart2,
+ StateCComment,
+ StateCppComment,
+ StateCCommentEnd1,
+ StateCCommentEnd2,
+ StateStringStart,
+ StateString,
+ StateStringEnd,
+ StateString2Start,
+ StateString2,
+ StateString2End,
+ StateNumber,
+ StatePreProcessor,
+ NumStates
+ };
+ // tokens
+ enum {
+ InputAlpha,
+ InputNumber,
+ InputAsterix,
+ InputSlash,
+ InputParen,
+ InputSpace,
+ InputHash,
+ InputQuotation,
+ InputApostrophe,
+ InputSep,
+ NumInputs
+ };
+
+ static const uchar table[NumStates][NumInputs] = {
+ { StateStandard, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateStandard
+ { StateStandard, StateNumber, StateCCommentStart2, StateCppCommentStart2, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateCommentStart1
+ { StateCComment, StateCComment, StateCCommentEnd1, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCCommentStart2
+ { StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment }, // CppCommentStart2
+ { StateCComment, StateCComment, StateCCommentEnd1, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCComment
+ { StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment }, // StateCppComment
+ { StateCComment, StateCComment, StateCCommentEnd1, StateCCommentEnd2, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCCommentEnd1
+ { StateStandard, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateCCommentEnd2
+ { StateString, StateString, StateString, StateString, StateString, StateString, StateString, StateStringEnd, StateString, StateString }, // StateStringStart
+ { StateString, StateString, StateString, StateString, StateString, StateString, StateString, StateStringEnd, StateString, StateString }, // StateString
+ { StateStandard, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateStringEnd
+ { StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2End, StateString2 }, // StateString2Start
+ { StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2End, StateString2 }, // StateString2
+ { StateStandard, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateString2End
+ { StateNumber, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateNumber
+ { StatePreProcessor, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard } // StatePreProcessor
+ };
+
+ QString buffer;
+ buffer.reserve(text.length());
+ QTextCharFormat emptyFormat;
+
+ int state = onBlockStart();
+ if (text.isEmpty()) {
+ onBlockEnd(state, 0);
+ return;
+ }
+
+ int input = -1;
+ int i = 0;
+ bool lastWasBackSlash = false;
+ bool makeLastStandard = false;
+
+ static const QString alphabeth = QLatin1String("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ static const QString mathChars = QString::fromLatin1("xXeE");
+ static const QString numbers = QString::fromLatin1("0123456789");
+ bool questionMark = false;
+ QChar lastChar;
+
+ int firstNonSpace = -1;
+ int lastNonSpace = -1;
+
+ forever {
+ const QChar c = text.at(i);
+
+ if (lastWasBackSlash) {
+ input = InputSep;
+ } else {
+ switch (c.toLatin1()) {
+ case '*':
+ input = InputAsterix;
+ break;
+ case '/':
+ input = InputSlash;
+ break;
+ case '(': case '[': case '{':
+ input = InputParen;
+ if (state == StateStandard
+ || state == StateNumber
+ || state == StatePreProcessor
+ || state == StateCCommentEnd2
+ || state == StateCCommentEnd1
+ || state == StateString2End
+ || state == StateStringEnd
+ )
+ onOpeningParenthesis(c, i);
+ break;
+ case ')': case ']': case '}':
+ input = InputParen;
+ if (state == StateStandard
+ || state == StateNumber
+ || state == StatePreProcessor
+ || state == StateCCommentEnd2
+ || state == StateCCommentEnd1
+ || state == StateString2End
+ || state == StateStringEnd
+ ) {
+ onClosingParenthesis(c, i);
+ }
+ break;
+ case '#':
+ input = InputHash;
+ break;
+ case '"':
+ input = InputQuotation;
+ break;
+ case '\'':
+ input = InputApostrophe;
+ break;
+ case ' ':
+ input = InputSpace;
+ break;
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9': case '0':
+ if (alphabeth.contains(lastChar)
+ && (!mathChars.contains(lastChar) || !numbers.contains(text.at(i - 1)))) {
+ input = InputAlpha;
+ } else {
+ if (input == InputAlpha && numbers.contains(lastChar))
+ input = InputAlpha;
+ else
+ input = InputNumber;
+ }
+ break;
+ case ':': {
+ input = InputAlpha;
+ QChar nextChar = ' ';
+ if (i < text.length() - 1)
+ nextChar = text.at(i + 1);
+ if (state == StateStandard && !questionMark &&
+ lastChar != ':' && nextChar != ':') {
+ for (int j = 0; j < i; ++j) {
+ if (format(j) == emptyFormat)
+ setFormat(j, 1, m_formats[LabelFormat]);
+ }
+ }
+ break;
+ }
+ default: {
+ if (!questionMark && c == QLatin1Char('?'))
+ questionMark = true;
+ if (c.isLetter() || c == QLatin1Char('_'))
+ input = InputAlpha;
+ else
+ input = InputSep;
+ } break;
+ }
+ }
+
+ if (input != InputSpace) {
+ if (firstNonSpace < 0)
+ firstNonSpace = i;
+ lastNonSpace = i;
+ }
+
+ lastWasBackSlash = !lastWasBackSlash && c == QLatin1Char('\\');
+
+ if (input == InputAlpha)
+ buffer += c;
+
+ state = table[state][input];
+
+ switch (state) {
+ case StateStandard: {
+ setFormat(i, 1, emptyFormat);
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ if (!buffer.isEmpty() && input != InputAlpha ) {
+ highlightKeyword(i, buffer);
+ buffer.clear();
+ }
+ } break;
+ case StateCommentStart1:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = true;
+ buffer.resize(0);
+ break;
+ case StateCCommentStart2:
+ setFormat(i - 1, 2, m_formats[CommentFormat]);
+ makeLastStandard = false;
+ buffer.resize(0);
+ break;
+ case StateCppCommentStart2:
+ setFormat(i - 1, 2, m_formats[CommentFormat]);
+ makeLastStandard = false;
+ buffer.resize(0);
+ break;
+ case StateCComment:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_formats[CommentFormat]);
+ buffer.resize(0);
+ break;
+ case StateCppComment:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_formats[CommentFormat]);
+ buffer.resize(0);
+ break;
+ case StateCCommentEnd1:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_formats[CommentFormat]);
+ buffer.resize(0);
+ break;
+ case StateCCommentEnd2:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_formats[CommentFormat]);
+ buffer.resize(0);
+ break;
+ case StateStringStart:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, emptyFormat);
+ buffer.resize(0);
+ break;
+ case StateString:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_formats[StringFormat]);
+ buffer.resize(0);
+ break;
+ case StateStringEnd:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, emptyFormat);
+ buffer.resize(0);
+ break;
+ case StateString2Start:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, emptyFormat);
+ buffer.resize(0);
+ break;
+ case StateString2:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_formats[StringFormat]);
+ buffer.resize(0);
+ break;
+ case StateString2End:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, emptyFormat);
+ buffer.resize(0);
+ break;
+ case StateNumber:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat( i, 1, m_formats[NumberFormat]);
+ buffer.resize(0);
+ break;
+ case StatePreProcessor:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_formats[PreProcessorFormat]);
+ buffer.resize(0);
+ break;
+ }
+
+ lastChar = c;
+ i++;
+ if (i >= text.length())
+ break;
+ }
+
+ highlightKeyword(text.length(), buffer);
+
+ if (state == StateCComment
+ || state == StateCCommentEnd1
+ || state == StateCCommentStart2
+ ) {
+ state = StateCComment;
+ } else if (state == StateString) {
+ state = StateString;
+ } else if (state == StateString2) {
+ state = StateString2;
+ } else {
+ state = StateStandard;
+ }
+
+ onBlockEnd(state, firstNonSpace);
+}
+
+void QScriptHighlighter::highlightKeyword(int currentPos, const QString &buffer)
+{
+ if (buffer.isEmpty())
+ return;
+
+ if (buffer.at(0) == QLatin1Char('Q')) {
+ setFormat(currentPos - buffer.length(), buffer.length(), m_formats[TypeFormat]);
+ } else {
+ if (qscriptKeywords().contains(buffer))
+ setFormat(currentPos - buffer.length(), buffer.length(), m_formats[KeywordFormat]);
+ }
+}
+
+const QVector<QTextCharFormat> &QScriptHighlighter::defaultFormats()
+{
+ static QVector<QTextCharFormat> rc;
+ if (rc.empty()) {
+ rc.resize(NumFormats);
+ rc[NumberFormat].setForeground(Qt::blue);
+ rc[StringFormat].setForeground(Qt::darkGreen);
+ rc[TypeFormat].setForeground(Qt::darkMagenta);
+ rc[KeywordFormat].setForeground(Qt::darkYellow);
+ rc[LabelFormat].setForeground(Qt::darkRed);
+ rc[CommentFormat].setForeground(Qt::red);
+ rc[CommentFormat].setFontItalic(true);
+ rc[PreProcessorFormat].setForeground(Qt::darkBlue);
+ }
+ return rc;
+}
+
+void QScriptHighlighter::setFormats(const QVector<QTextCharFormat> &s)
+{
+ qCopy(s.constBegin(), s.constEnd(), m_formats);
+}
+
+int QScriptHighlighter::onBlockStart()
+{
+ int state = 0;
+ int previousState = previousBlockState();
+ if (previousState != -1)
+ state = previousState;
+ return state;
+}
+void QScriptHighlighter::onOpeningParenthesis(QChar, int) {}
+void QScriptHighlighter::onClosingParenthesis(QChar, int) {}
+void QScriptHighlighter::onBlockEnd(int state, int) { return setCurrentBlockState(state); }
+
+} // namespace SharedTools
+
diff --git a/src/shared/qscripthighlighter/qscripthighlighter.h b/src/shared/qscripthighlighter/qscripthighlighter.h
new file mode 100644
index 0000000000..332026c77c
--- /dev/null
+++ b/src/shared/qscripthighlighter/qscripthighlighter.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef QSCRIPTSYNTAXHIGHLIGHTER_H
+#define QSCRIPTSYNTAXHIGHLIGHTER_H
+
+#include <QVector>
+#include <QtGui/QSyntaxHighlighter>
+
+namespace SharedTools {
+
+class QScriptHighlighter : public QSyntaxHighlighter
+{
+ Q_OBJECT
+public:
+ QScriptHighlighter(QTextDocument *parent = 0);
+ virtual void highlightBlock(const QString &text);
+
+ enum { NumberFormat, StringFormat, TypeFormat,
+ KeywordFormat, PreProcessorFormat, LabelFormat, CommentFormat,
+ NumFormats };
+
+ // MS VC 6 compatible, still.
+ void setFormats(const QVector<QTextCharFormat> &s);
+ static const QVector<QTextCharFormat> &defaultFormats();
+
+private:
+ // The functions are notified whenever parentheses are encountered.
+ // Custom behaviour can be added, for example storing info for indenting.
+ virtual int onBlockStart(); // returns the blocks initial state
+ virtual void onOpeningParenthesis(QChar parenthesis, int pos);
+ virtual void onClosingParenthesis(QChar parenthesis, int pos);
+ // sets the enriched user state, or simply calls setCurrentBlockState(state);
+ virtual void onBlockEnd(int state, int firstNonSpace);
+
+ void highlightKeyword(int currentPos, const QString &buffer);
+
+ QTextCharFormat m_formats[NumFormats];
+};
+
+} // namespace SharedTools
+
+#endif // QSCRIPTSYNTAXHIGHLIGHTER_H
diff --git a/src/shared/qscripthighlighter/qscripthighlighter.pri b/src/shared/qscripthighlighter/qscripthighlighter.pri
new file mode 100644
index 0000000000..577bed10a6
--- /dev/null
+++ b/src/shared/qscripthighlighter/qscripthighlighter.pri
@@ -0,0 +1,4 @@
+INCLUDEPATH *= $$PWD
+
+SOURCES += $$PWD/qscripthighlighter.cpp
+HEADERS += $$PWD/qscripthighlighter.h
diff --git a/src/shared/qscripthighlighter/test/main.cpp b/src/shared/qscripthighlighter/test/main.cpp
new file mode 100644
index 0000000000..9bfdf22d28
--- /dev/null
+++ b/src/shared/qscripthighlighter/test/main.cpp
@@ -0,0 +1,50 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qscripthighlighter.h"
+
+#include <QTextEdit>
+#include <QMainWindow>
+#include <QApplication>
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ QMainWindow mw;
+
+ QTextEdit *textEdit = new QTextEdit;
+ new SharedTools::QScriptHighlighter(textEdit->document());
+ mw.setCentralWidget(textEdit);
+ mw.show();
+ return app.exec();
+}
diff --git a/src/shared/qscripthighlighter/test/test.pro b/src/shared/qscripthighlighter/test/test.pro
new file mode 100644
index 0000000000..4962411032
--- /dev/null
+++ b/src/shared/qscripthighlighter/test/test.pro
@@ -0,0 +1,10 @@
+######################################################################
+# Automatically generated by qmake (2.01a) Mon Apr 16 13:02:01 2007
+######################################################################
+
+TEMPLATE = app
+
+QT += gui
+
+include(../qscripthighlighter.pri)
+SOURCES += main.cpp
diff --git a/src/shared/qtextended_integration.h b/src/shared/qtextended_integration.h
new file mode 100644
index 0000000000..fe2bf5ad67
--- /dev/null
+++ b/src/shared/qtextended_integration.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef QTEXTENDED_INTEGRATION
+#define QTEXTENDED_INTEGRATION
+
+// Enable support for QBuild style project parsing
+//#define QTEXTENDED_QBUILD_SUPPORT
+
+/*
+This file is intended to be the 'communication channel' for Qt-Extended (aka Qtopia) integration issues.
+
+*** The first step in the integration is to add support for QBuild to the IDE ***
+
+QBuild is the build system used in Qt-Extended 4.4 and onwards. QBuild is a replacement for qmake+make.
+The reasons for the replacement go a bit beyond this page, but in short:
+- there's only one qbuild instance running v.s. MANY qmake instances.
+- implements proper management of dependencies between files. Regardless of where you are in the source tree ... a 'make' will always result in all dependencies (that have changed) being rebuild in the correct sequence. This is something that was a major issue with Qt-Extended development in the past.
+- solves many Qt-Extended build/deployment issues
+- separates build logic (specific for Qt-Extended) from the script runner logic
+- fully supports TeamBuilder and can trottle build, moc, and IO tasks differently.
+- is fast!!!!
+
+QBuild is a bootstrapping solution, i.e. the only thing you need to do to build Qt-Extended is:
+ configure <options>
+ make
+ make image
+
+Configure will build QBuild, and QBuild will produce very small Makefile's that basically re-direct all make calls back to QBuild. The configuration options are saved in a cache file that is read by QBuild upon any invocation.
+
+Within QBuild, all pro files are named qbuild.pro and there's no need to create template pro files for "SUBDIRS". QBuild will always traverse through the complete source tree and will discover all 'real' projects.
+QBuild .pro files are also different from QMake .pro files in that the first can contain scripting language that define the project specific logic.
+
+So far one class has been modified:
+- qt4project.cpp/h -> basically the mechanism to discover project files needs to be adapted to QBuild.
+There's a bit of nastiness in the code that I'd like to see fixed, esp the ugly global boolean, but I'm not familar enough with the code to do that properly.
+
+How to use?
+- You should get yourself a copy of //depot/qtopia/main (from the Brisbane p4.trolltech.com.au:866 server)
+- The actual contents of Qtopia are irrelevant at this stage, i.e. you don't need to sync every day. We only use it as a sample of a large project containing qbuild stuff.
+- hack the ~/depot/qtopia/main/qbuild.pro file and set "SUBDIRS=examples etc/themes" (we don't want too much stuff at this stage), i.e. make sure you're not scanning 'src' as well.
+- build and run Qt Creator and make sure you have your Qt Creator IDE as the FIRST open project (or whatever you use for testing)
+- then do a project "Open Project/Session" on ~/depot/qtopia/main/qbuild.pro
+
+What you should get is the usual IDE project tree and then a second one below with the Qtopia stuff.
+The Qtopia tree however doesn't show much projects: just the base and then examples.pro and themes.pro (and this depends on these old files still lying around in the depot).
+
+To activate Qbuild support:
+- Compile Qt Creator with QTEXTENDED_QBUILD_SUPPORT defined (see top of this file)
+- rebuild and run Qt Creator
+
+What you should get is the usual IDE project tree and then a second one below with the Qtopia stuff but this time with approx 15 qbuild.pro projects.
+Issues:
+* Every project file is still named 'qbuild.pro', I hacked ProFile::ProFile() to set m_displayFileName to the base dir name when it's a qbuild.pro file (i.e. src/applications/addressbook/qbuild.pro should become 'addressbook' instead of'qbuild.pro'), but that doesn't seem to work. Also ProFile is a copy from Qt? so I can't really modify it.
+* The tree is (obviously) not showing much depth. This is because there are no .pro files in directories such as src/examples. So what we would need is a way to create virtual projects or something similar.
+Any suggestions how to fix this?
+
+*** Future steps ***
+- running configure, make, make image
+- defining configuration options (i.e. supporting multiple shadow builds)
+- running QtExtended on qvfb
+- debugging QtExtended on qvfb
+- running QtExtended on a device
+- debugging QtExtended on a device
+- and probably more
+
+*/
+
+#endif
diff --git a/src/shared/qtlockedfile/README.txt b/src/shared/qtlockedfile/README.txt
new file mode 100644
index 0000000000..6fcf2fd295
--- /dev/null
+++ b/src/shared/qtlockedfile/README.txt
@@ -0,0 +1,10 @@
+This is the src directory of the QtLockedFile
+solution integrated over from addons/main/utils/qtlockedfile/src .
+
+namespace.patch was applied to introduce the SharedTools namespace.
+
+It is required by the QtSingleApplication solution.
+
+History:
+
+16.05.2008 Integrated
diff --git a/src/shared/qtlockedfile/namespace.patch b/src/shared/qtlockedfile/namespace.patch
new file mode 100644
index 0000000000..eb894a3700
--- /dev/null
+++ b/src/shared/qtlockedfile/namespace.patch
@@ -0,0 +1,70 @@
+
+--- qtlockedfile.cpp 1970-01-01 01:00:00.000000000
++++ qtlockedfile.cpp 2008/05/16 10:51:19.000000000
+@@ -1,5 +1,7 @@
+ #include "qtlockedfile.h"
+
++namespace SharedTools {
++
+ /*!
+ \class QtLockedFile
+
+@@ -123,3 +125,5 @@
+
+ Destroys the \e QtLockedFile object. If any locks were held, they are released.
+ */
++
++}
+
+--- qtlockedfile.h 1970-01-01 01:00:00.000000000
++++ qtlockedfile.h 2008/05/16 10:51:19.000000000
+@@ -19,6 +19,8 @@
+ # define QT_QTLOCKEDFILE_EXPORT
+ #endif
+
++namespace SharedTools {
++
+ class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile
+ {
+ public:
+@@ -41,4 +43,6 @@
+ LockMode m_lock_mode;
+ };
+
++}
++
+ #endif
+
+--- qtlockedfile_unix.cpp 1970-01-01 01:00:00.000000000
++++ qtlockedfile_unix.cpp 2008/05/16 10:51:19.000000000
+@@ -5,6 +5,8 @@
+
+ #include "qtlockedfile.h"
+
++namespace SharedTools {
++
+ bool QtLockedFile::lock(LockMode mode, bool block)
+ {
+ if (!isOpen()) {
+@@ -73,3 +75,4 @@
+ unlock();
+ }
+
++}
+
+--- qtlockedfile_win.cpp 1970-01-01 01:00:00.000000000
++++ qtlockedfile_win.cpp 2008/05/16 10:51:19.000000000
+@@ -2,6 +2,8 @@
+ #include <qt_windows.h>
+ #include <QtCore/QFileInfo>
+
++namespace SharedTools {
++
+ #define SEMAPHORE_PREFIX "QtLockedFile semaphore "
+ #define MUTEX_PREFIX "QtLockedFile mutex "
+ #define SEMAPHORE_MAX 100
+@@ -168,3 +170,4 @@
+ }
+ }
+
++}
diff --git a/src/shared/qtlockedfile/qtlockedfile.cpp b/src/shared/qtlockedfile/qtlockedfile.cpp
new file mode 100644
index 0000000000..fe2acfd612
--- /dev/null
+++ b/src/shared/qtlockedfile/qtlockedfile.cpp
@@ -0,0 +1,162 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qtlockedfile.h"
+
+namespace SharedTools {
+
+/*!
+ \class QtLockedFile
+
+ \brief The QtLockedFile class extends QFile with advisory locking functions.
+
+ A file may be locked in read or write mode. Multiple instances of
+ \e QtLockedFile, created in multiple processes running on the same
+ machine, may have a file locked in read mode. Exactly one instance
+ may have it locked in write mode. A read and a write lock cannot
+ exist simultaneously on the same file.
+
+ The file locks are advisory. This means that nothing prevents
+ another process from manipulating a locked file using QFile or
+ file system functions offered by the OS. Serialization is only
+ guaranteed if all processes that access the file use
+ QtLockedFile. Also, while holding a lock on a file, a process
+ must not open the same file again (through any API), or locks
+ can be unexpectedly lost.
+
+ The lock provided by an instance of \e QtLockedFile is released
+ whenever the program terminates. This is true even when the
+ program crashes and no destructors are called.
+*/
+
+/*! \enum QtLockedFile::LockMode
+
+ This enum describes the available lock modes.
+
+ \value ReadLock A read lock.
+ \value WriteLock A write lock.
+ \value NoLock Neither a read lock nor a write lock.
+*/
+
+/*!
+ Constructs an unlocked \e QtLockedFile object. This constructor behaves in the same way
+ as \e QFile::QFile().
+
+ \sa QFile::QFile()
+*/
+QtLockedFile::QtLockedFile()
+ : QFile()
+{
+#ifdef Q_OS_WIN
+ m_semaphore_hnd = 0;
+ m_mutex_hnd = 0;
+#endif
+ m_lock_mode = NoLock;
+}
+
+/*!
+ Constructs an unlocked QtLockedFile object with file \a name. This constructor behaves in
+ the same way as \e QFile::QFile(const QString&).
+
+ \sa QFile::QFile()
+*/
+QtLockedFile::QtLockedFile(const QString &name)
+ : QFile(name)
+{
+#ifdef Q_OS_WIN
+ m_semaphore_hnd = 0;
+ m_mutex_hnd = 0;
+#endif
+ m_lock_mode = NoLock;
+}
+
+/*!
+ Returns \e true if this object has a in read or write lock;
+ otherwise returns \e false.
+
+ \sa lockMode()
+*/
+bool QtLockedFile::isLocked() const
+{
+ return m_lock_mode != NoLock;
+}
+
+/*!
+ Returns the type of lock currently held by this object, or \e QtLockedFile::NoLock.
+
+ \sa isLocked()
+*/
+QtLockedFile::LockMode QtLockedFile::lockMode() const
+{
+ return m_lock_mode;
+}
+
+/*!
+ \fn bool QtLockedFile::lock(LockMode mode, bool block = true)
+
+ Obtains a lock of type \a mode.
+
+ If \a block is true, this
+ function will block until the lock is aquired. If \a block is
+ false, this function returns \e false immediately if the lock cannot
+ be aquired.
+
+ If this object already has a lock of type \a mode, this function returns \e true immediately. If this object has a lock of a different type than \a mode, the lock
+ is first released and then a new lock is obtained.
+
+ This function returns \e true if, after it executes, the file is locked by this object,
+ and \e false otherwise.
+
+ \sa unlock(), isLocked(), lockMode()
+*/
+
+/*!
+ \fn bool QtLockedFile::unlock()
+
+ Releases a lock.
+
+ If the object has no lock, this function returns immediately.
+
+ This function returns \e true if, after it executes, the file is not locked by
+ this object, and \e false otherwise.
+
+ \sa lock(), isLocked(), lockMode()
+*/
+
+/*!
+ \fn QtLockedFile::~QtLockedFile()
+
+ Destroys the \e QtLockedFile object. If any locks were held, they are released.
+*/
+
+} // namespace SharedTools
diff --git a/src/shared/qtlockedfile/qtlockedfile.h b/src/shared/qtlockedfile/qtlockedfile.h
new file mode 100644
index 0000000000..abf44fa452
--- /dev/null
+++ b/src/shared/qtlockedfile/qtlockedfile.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef QTLOCKEDFILE_H
+#define QTLOCKEDFILE_H
+
+#include <QtCore/QFile>
+
+#if defined(Q_WS_WIN)
+# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT)
+# define QT_QTLOCKEDFILE_EXPORT
+# elif defined(QT_QTLOCKEDFILE_IMPORT)
+# if defined(QT_QTLOCKEDFILE_EXPORT)
+# undef QT_QTLOCKEDFILE_EXPORT
+# endif
+# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport)
+# elif defined(QT_QTLOCKEDFILE_EXPORT)
+# undef QT_QTLOCKEDFILE_EXPORT
+# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport)
+# endif
+#else
+# define QT_QTLOCKEDFILE_EXPORT
+#endif
+
+namespace SharedTools {
+
+class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile
+{
+public:
+ enum LockMode { NoLock = 0, ReadLock, WriteLock };
+
+ QtLockedFile();
+ QtLockedFile(const QString &name);
+ ~QtLockedFile();
+
+ bool lock(LockMode mode, bool block = true);
+ bool unlock();
+ bool isLocked() const;
+ LockMode lockMode() const;
+
+private:
+#ifdef Q_OS_WIN
+ Qt::HANDLE m_semaphore_hnd;
+ Qt::HANDLE m_mutex_hnd;
+#endif
+ LockMode m_lock_mode;
+};
+
+} // namespace SharedTools
+
+#endif // QTLOCKEDFILE_H
diff --git a/src/shared/qtlockedfile/qtlockedfile.pri b/src/shared/qtlockedfile/qtlockedfile.pri
new file mode 100644
index 0000000000..46d1f1a12a
--- /dev/null
+++ b/src/shared/qtlockedfile/qtlockedfile.pri
@@ -0,0 +1,13 @@
+INCLUDEPATH += $$PWD
+DEPENDPATH += $$PWD
+HEADERS += $$PWD/qtlockedfile.h
+SOURCES += $$PWD/qtlockedfile.cpp
+
+unix:SOURCES += $$PWD/qtlockedfile_unix.cpp
+win32:SOURCES += $$PWD/qtlockedfile_win.cpp
+
+win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
+ DEFINES += QT_QTLOCKEDFILE_EXPORT=__declspec(dllexport)
+}
+
+
diff --git a/src/shared/qtlockedfile/qtlockedfile_unix.cpp b/src/shared/qtlockedfile/qtlockedfile_unix.cpp
new file mode 100644
index 0000000000..10ae8f69c3
--- /dev/null
+++ b/src/shared/qtlockedfile/qtlockedfile_unix.cpp
@@ -0,0 +1,111 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qtlockedfile.h"
+
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+namespace SharedTools {
+
+bool QtLockedFile::lock(LockMode mode, bool block)
+{
+ if (!isOpen()) {
+ qWarning("QtLockedFile::lock(): file is not opened");
+ return false;
+ }
+
+ if (mode == NoLock)
+ return unlock();
+
+ if (mode == m_lock_mode)
+ return true;
+
+ if (m_lock_mode != NoLock)
+ unlock();
+
+ struct flock fl;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK;
+ int cmd = block ? F_SETLKW : F_SETLK;
+ int ret = fcntl(handle(), cmd, &fl);
+
+ if (ret == -1) {
+ if (errno != EINTR && errno != EAGAIN)
+ qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
+ return false;
+ }
+
+
+ m_lock_mode = mode;
+ return true;
+}
+
+
+bool QtLockedFile::unlock()
+{
+ if (!isOpen()) {
+ qWarning("QtLockedFile::unlock(): file is not opened");
+ return false;
+ }
+
+ if (!isLocked())
+ return true;
+
+ struct flock fl;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ fl.l_type = F_UNLCK;
+ int ret = fcntl(handle(), F_SETLKW, &fl);
+
+ if (ret == -1) {
+ qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
+ return false;
+ }
+
+ m_lock_mode = NoLock;
+ return true;
+}
+
+QtLockedFile::~QtLockedFile()
+{
+ if (isOpen())
+ unlock();
+}
+
+} // namespace SharedTools
diff --git a/src/shared/qtlockedfile/qtlockedfile_win.cpp b/src/shared/qtlockedfile/qtlockedfile_win.cpp
new file mode 100644
index 0000000000..f1d74e30fc
--- /dev/null
+++ b/src/shared/qtlockedfile/qtlockedfile_win.cpp
@@ -0,0 +1,207 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qtlockedfile.h"
+
+#include <qt_windows.h>
+#include <QtCore/QFileInfo>
+
+namespace SharedTools {
+
+#define SEMAPHORE_PREFIX "QtLockedFile semaphore "
+#define MUTEX_PREFIX "QtLockedFile mutex "
+#define SEMAPHORE_MAX 100
+
+static QString errorCodeToString(DWORD errorCode)
+{
+ QString result;
+ char *data = 0;
+ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ 0, errorCode, 0,
+ (char*)&data, 0, 0);
+ result = QString::fromLocal8Bit(data);
+ if (data != 0)
+ LocalFree(data);
+
+ if (result.endsWith("\n"))
+ result.truncate(result.length() - 1);
+
+ return result;
+}
+
+bool QtLockedFile::lock(LockMode mode, bool block)
+{
+ if (!isOpen()) {
+ qWarning("QtLockedFile::lock(): file is not opened");
+ return false;
+ }
+
+ if (mode == m_lock_mode)
+ return true;
+
+ if (m_lock_mode != 0)
+ unlock();
+
+ if (m_semaphore_hnd == 0) {
+ QFileInfo fi(*this);
+ QString sem_name = QString::fromLatin1(SEMAPHORE_PREFIX)
+ + fi.absoluteFilePath().toLower();
+
+ QT_WA( {
+ m_semaphore_hnd = CreateSemaphoreW(0, SEMAPHORE_MAX, SEMAPHORE_MAX,
+ (TCHAR*)sem_name.utf16());
+ } , {
+ m_semaphore_hnd = CreateSemaphoreA(0, SEMAPHORE_MAX, SEMAPHORE_MAX,
+ sem_name.toLocal8Bit().constData());
+ } );
+
+ if (m_semaphore_hnd == 0) {
+ qWarning("QtLockedFile::lock(): CreateSemaphore: %s",
+ errorCodeToString(GetLastError()).toLatin1().constData());
+ return false;
+ }
+ }
+
+ bool gotMutex = false;
+ int decrement;
+ if (mode == ReadLock) {
+ decrement = 1;
+ } else {
+ decrement = SEMAPHORE_MAX;
+ if (m_mutex_hnd == 0) {
+ QFileInfo fi(*this);
+ QString mut_name = QString::fromLatin1(MUTEX_PREFIX)
+ + fi.absoluteFilePath().toLower();
+ QT_WA( {
+ m_mutex_hnd = CreateMutexW(NULL, FALSE, (TCHAR*)mut_name.utf16());
+ } , {
+ m_mutex_hnd = CreateMutexA(NULL, FALSE, mut_name.toLocal8Bit().constData());
+ } );
+
+ if (m_mutex_hnd == 0) {
+ qWarning("QtLockedFile::lock(): CreateMutex: %s",
+ errorCodeToString(GetLastError()).toLatin1().constData());
+ return false;
+ }
+ }
+ DWORD res = WaitForSingleObject(m_mutex_hnd, block ? INFINITE : 0);
+ if (res == WAIT_TIMEOUT)
+ return false;
+ if (res == WAIT_FAILED) {
+ qWarning("QtLockedFile::lock(): WaitForSingleObject (mutex): %s",
+ errorCodeToString(GetLastError()).toLatin1().constData());
+ return false;
+ }
+ gotMutex = true;
+ }
+
+ for (int i = 0; i < decrement; ++i) {
+ DWORD res = WaitForSingleObject(m_semaphore_hnd, block ? INFINITE : 0);
+ if (res == WAIT_TIMEOUT) {
+ if (i) {
+ // A failed nonblocking rw locking. Undo changes to semaphore.
+ if (ReleaseSemaphore(m_semaphore_hnd, i, NULL) == 0) {
+ qWarning("QtLockedFile::unlock(): ReleaseSemaphore: %s",
+ errorCodeToString(GetLastError()).toLatin1().constData());
+ // Fall through
+ }
+ }
+ if (gotMutex)
+ ReleaseMutex(m_mutex_hnd);
+ return false;
+ }
+ if (res != WAIT_OBJECT_0) {
+ if (gotMutex)
+ ReleaseMutex(m_mutex_hnd);
+ qWarning("QtLockedFile::lock(): WaitForSingleObject (semaphore): %s",
+ errorCodeToString(GetLastError()).toLatin1().constData());
+ return false;
+ }
+ }
+
+ m_lock_mode = mode;
+ if (gotMutex)
+ ReleaseMutex(m_mutex_hnd);
+ return true;
+}
+
+bool QtLockedFile::unlock()
+{
+ if (!isOpen()) {
+ qWarning("QtLockedFile::unlock(): file is not opened");
+ return false;
+ }
+
+ if (!isLocked())
+ return true;
+
+ int increment;
+ if (m_lock_mode == ReadLock)
+ increment = 1;
+ else
+ increment = SEMAPHORE_MAX;
+
+ DWORD ret = ReleaseSemaphore(m_semaphore_hnd, increment, 0);
+ if (ret == 0) {
+ qWarning("QtLockedFile::unlock(): ReleaseSemaphore: %s",
+ errorCodeToString(GetLastError()).toLatin1().constData());
+ return false;
+ }
+
+ m_lock_mode = QtLockedFile::NoLock;
+ return true;
+}
+
+QtLockedFile::~QtLockedFile()
+{
+ if (isOpen())
+ unlock();
+ if (m_mutex_hnd != 0) {
+ DWORD ret = CloseHandle(m_mutex_hnd);
+ if (ret == 0) {
+ qWarning("QtLockedFile::~QtLockedFile(): CloseHandle (mutex): %s",
+ errorCodeToString(GetLastError()).toLatin1().constData());
+ }
+ m_mutex_hnd = 0;
+ }
+ if (m_semaphore_hnd != 0) {
+ DWORD ret = CloseHandle(m_semaphore_hnd);
+ if (ret == 0) {
+ qWarning("QtLockedFile::~QtLockedFile(): CloseHandle (semaphore): %s",
+ errorCodeToString(GetLastError()).toLatin1().constData());
+ }
+ m_semaphore_hnd = 0;
+ }
+}
+
+} // namespace SharedTools
diff --git a/src/shared/qtsingleapplication/README.txt b/src/shared/qtsingleapplication/README.txt
new file mode 100644
index 0000000000..1909a33fca
--- /dev/null
+++ b/src/shared/qtsingleapplication/README.txt
@@ -0,0 +1,10 @@
+This is the src directory of the QtSingleApplication solution
+integrated over from addons/main/utils/qtsingleapplication/src .
+
+namespace.patch was applied to introduce the SharedTools namespace.
+
+It additionally requires the QtLockedFile solution.
+
+History:
+
+16.05.2008 Integrated
diff --git a/src/shared/qtsingleapplication/namespace.patch b/src/shared/qtsingleapplication/namespace.patch
new file mode 100644
index 0000000000..2876e3a378
--- /dev/null
+++ b/src/shared/qtsingleapplication/namespace.patch
@@ -0,0 +1,133 @@
+
+--- qtlocalpeer.cpp 1970-01-01 01:00:00.000000000
++++ qtlocalpeer.cpp 2008/05/16 10:36:53.000000000
+@@ -13,6 +13,8 @@
+ #include <time.h>
+ #endif
+
++namespace SharedTools {
++
+ const char* QtLocalPeer::ack = "ack";
+
+ QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
+@@ -139,3 +141,5 @@
+ delete socket;
+ emit messageReceived(message); // ##(might take a long time to return)
+ }
++
++}
+
+--- qtlocalpeer.h 1970-01-01 01:00:00.000000000
++++ qtlocalpeer.h 2008/05/16 10:36:53.000000000
+@@ -1,9 +1,11 @@
+
++
+ #include <QtNetwork/QLocalServer>
+ #include <QtNetwork/QLocalSocket>
+ #include <QtCore/QDir>
+ #include <qtlockedfile.h>
+
++namespace SharedTools {
+
+ class QtLocalPeer : public QObject
+ {
+@@ -31,3 +33,5 @@
+ private:
+ static const char* ack;
+ };
++
++} // SharedTools
+
+--- qtsingleapplication.cpp 1970-01-01 01:00:00.000000000
++++ qtsingleapplication.cpp 2008/05/16 10:36:53.000000000
+@@ -3,6 +3,8 @@
+ #include "qtlocalpeer.h"
+ #include <QtGui/QWidget>
+
++namespace SharedTools {
++
+ void QtSingleApplication::sysInit(const QString &appId)
+ {
+ actWin = 0;
+@@ -95,3 +97,5 @@
+ actWin->activateWindow();
+ }
+ }
++
++}
+
+--- qtsingleapplication.h 1970-01-01 01:00:00.000000000
++++ qtsingleapplication.h 2008/05/16 10:36:53.000000000
+@@ -1,6 +1,8 @@
+
+ #include <QtGui/QApplication>
+
++namespace SharedTools {
++
+ class QtLocalPeer;
+
+ class QtSingleApplication : public QApplication
+@@ -47,3 +49,5 @@
+ QtLocalPeer *peer;
+ QWidget *actWin;
+ };
++
++}
+
+--- qtsingleapplication.pri 1970-01-01 01:00:00.000000000
++++ qtsingleapplication.pri 2008/05/16 10:36:53.000000000
+@@ -6,7 +6,7 @@
+ QT *= network
+
+ gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h)
+-isEmpty(gotqtlockedfile):include(../../qtlockedfile/src/qtlockedfile.pri)
++isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri)
+
+
+ win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
+
+--- qtsinglecoreapplication.cpp 1970-01-01 01:00:00.000000000
++++ qtsinglecoreapplication.cpp 2008/05/16 10:36:53.000000000
+@@ -2,6 +2,7 @@
+ #include "qtsinglecoreapplication.h"
+ #include "qtlocalpeer.h"
+
++namespace SharedTools {
+
+ QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
+ : QCoreApplication(argc, argv)
+@@ -36,3 +37,4 @@
+ return peer->applicationId();
+ }
+
++}
+
+--- qtsinglecoreapplication.h 1970-01-01 01:00:00.000000000
++++ qtsinglecoreapplication.h 2008/05/16 10:36:53.000000000
+@@ -1,6 +1,8 @@
+
+ #include <QtCore/QCoreApplication>
+
++namespace SharedTools {
++
+ class QtLocalPeer;
+
+ class QtSingleCoreApplication : public QCoreApplication
+@@ -25,3 +27,5 @@
+ private:
+ QtLocalPeer* peer;
+ };
++
++}
+
+--- qtsinglecoreapplication.pri 1970-01-01 01:00:00.000000000
++++ qtsinglecoreapplication.pri 2008/05/16 10:36:53.000000000
+@@ -6,7 +6,7 @@
+ QT *= network
+
+ gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h)
+-isEmpty(gotqtlockedfile):include(../../qtlockedfile/src/qtlockedfile.pri)
++isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri)
+
+
+ win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
diff --git a/src/shared/qtsingleapplication/qtlocalpeer.cpp b/src/shared/qtsingleapplication/qtlocalpeer.cpp
new file mode 100644
index 0000000000..4b68c67c3d
--- /dev/null
+++ b/src/shared/qtsingleapplication/qtlocalpeer.cpp
@@ -0,0 +1,176 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qtlocalpeer.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QTime>
+
+#if defined(Q_OS_WIN)
+#include <QtCore/QLibrary>
+#include <QtCore/qt_windows.h>
+typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
+static PProcessIdToSessionId pProcessIdToSessionId = 0;
+#endif
+
+#if defined(Q_OS_UNIX)
+#include <time.h>
+#include <unistd.h>
+#endif
+
+namespace SharedTools {
+
+const char *QtLocalPeer::ack = "ack";
+
+QtLocalPeer::QtLocalPeer(QObject *parent, const QString &appId)
+ : QObject(parent), id(appId)
+{
+ if (id.isEmpty())
+ id = QCoreApplication::applicationFilePath(); //### On win, check if this returns .../argv[0] without casefolding; .\MYAPP == .\myapp on Win
+
+ QByteArray idc = id.toUtf8();
+ quint16 idNum = qChecksum(idc.constData(), idc.size());
+ //### could do: two 16bit checksums over separate halves of id, for a 32bit result - improved uniqeness probability. Every-other-char split would be best.
+
+ socketName = QLatin1String("qtsingleapplication-")
+ + QString::number(idNum, 16);
+#if defined(Q_OS_WIN)
+ if (!pProcessIdToSessionId) {
+ QLibrary lib("kernel32");
+ pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
+ }
+ if (pProcessIdToSessionId) {
+ DWORD sessionId = 0;
+ pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
+ socketName += QLatin1Char('-') + QString::number(sessionId, 16);
+ }
+#else
+ socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
+#endif
+
+ server = new QLocalServer(this);
+ QString lockName = QDir(QDir::tempPath()).absolutePath()
+ + QLatin1Char('/') + socketName
+ + QLatin1String("-lockfile");
+ lockFile.setFileName(lockName);
+ lockFile.open(QIODevice::ReadWrite);
+}
+
+bool QtLocalPeer::isClient()
+{
+ if (lockFile.isLocked())
+ return false;
+
+ if (!lockFile.lock(QtLockedFile::WriteLock, false))
+ return true;
+
+ bool res = server->listen(socketName);
+ if (!res && server->serverError() == QAbstractSocket::AddressInUseError)
+ res = server->listen(socketName); // ### Workaround 4.4.0tp bug
+ if (!res)
+ qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
+ QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection()));
+ return false;
+}
+
+bool QtLocalPeer::sendMessage(const QString &message, int timeout)
+{
+ if (!isClient())
+ return false;
+
+ QLocalSocket socket;
+ bool connOk = false;
+ for (int i = 0; i < 2; i++) {
+ // Try twice, in case the other instance is just starting up
+ socket.connectToServer(socketName);
+ connOk = socket.waitForConnected(timeout/2);
+ if (connOk || i)
+ break;
+ int ms = 250;
+#if defined(Q_OS_WIN)
+ Sleep(DWORD(ms));
+#else
+ struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
+ nanosleep(&ts, NULL);
+#endif
+ }
+ if (!connOk)
+ return false;
+
+ QByteArray uMsg(message.toUtf8());
+ QDataStream ds(&socket);
+ ds.writeBytes(uMsg.constData(), uMsg.size());
+ bool res = socket.waitForBytesWritten(timeout);
+ res &= socket.waitForReadyRead(timeout); // wait for ack
+ res &= (socket.read(qstrlen(ack)) == ack);
+ return res;
+}
+
+void QtLocalPeer::receiveConnection()
+{
+ QLocalSocket* socket = server->nextPendingConnection();
+ if (!socket)
+ return;
+
+ // Why doesn't Qt have a blocking stream that takes care of this shait???
+ while (socket->bytesAvailable() < sizeof(quint32))
+ socket->waitForReadyRead();
+ QDataStream ds(socket);
+ QByteArray uMsg;
+ quint32 remaining;
+ ds >> remaining;
+ uMsg.resize(remaining);
+ int got = 0;
+ char* uMsgBuf = uMsg.data();
+ //qDebug() << "RCV: remaining" << remaining;
+ do {
+ got = ds.readRawData(uMsgBuf, remaining);
+ remaining -= got;
+ uMsgBuf += got;
+ //qDebug() << "RCV: got" << got << "remaining" << remaining;
+ } while (remaining && got >= 0 && socket->waitForReadyRead(2000));
+ //### error check: got<0
+ if (got < 0) {
+ qWarning() << "QtLocalPeer: Message reception failed" << socket->errorString();
+ delete socket;
+ return;
+ }
+ // ### async this
+ QString message(QString::fromUtf8(uMsg));
+ socket->write(ack, qstrlen(ack));
+ socket->waitForBytesWritten(1000);
+ delete socket;
+ emit messageReceived(message); // ##(might take a long time to return)
+}
+
+} // namespace SharedTools
diff --git a/src/shared/qtsingleapplication/qtlocalpeer.h b/src/shared/qtsingleapplication/qtlocalpeer.h
new file mode 100644
index 0000000000..e4021c9b12
--- /dev/null
+++ b/src/shared/qtsingleapplication/qtlocalpeer.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qtlockedfile.h"
+
+#include <QtNetwork/QLocalServer>
+#include <QtNetwork/QLocalSocket>
+#include <QtCore/QDir>
+
+namespace SharedTools {
+
+class QtLocalPeer : public QObject
+{
+ Q_OBJECT
+
+public:
+ QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
+ bool isClient();
+ bool sendMessage(const QString &message, int timeout);
+ QString applicationId() const
+ { return id; }
+
+Q_SIGNALS:
+ void messageReceived(const QString &message);
+
+protected Q_SLOTS:
+ void receiveConnection();
+
+protected:
+ QString id;
+ QString socketName;
+ QLocalServer* server;
+ QtLockedFile lockFile;
+
+private:
+ static const char* ack;
+};
+
+} // namespace SharedTools
diff --git a/src/shared/qtsingleapplication/qtsingleapplication.cpp b/src/shared/qtsingleapplication/qtsingleapplication.cpp
new file mode 100644
index 0000000000..8505d5b49c
--- /dev/null
+++ b/src/shared/qtsingleapplication/qtsingleapplication.cpp
@@ -0,0 +1,145 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qtsingleapplication.h"
+#include "qtlocalpeer.h"
+
+#include <QtGui/QWidget>
+#include <QtGui/QFileOpenEvent>
+
+namespace SharedTools {
+
+void QtSingleApplication::sysInit(const QString &appId)
+{
+ actWin = 0;
+ peer = new QtLocalPeer(this, appId);
+ connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
+}
+
+
+QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled)
+ : QApplication(argc, argv, GUIenabled)
+{
+ sysInit();
+}
+
+
+QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv)
+ : QApplication(argc, argv)
+{
+ sysInit(appId);
+}
+
+
+QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type)
+ : QApplication(argc, argv, type)
+{
+ sysInit();
+}
+
+
+#if defined(Q_WS_X11)
+QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE colormap)
+ : QApplication(dpy, visual, colormap)
+{
+ sysInit();
+}
+
+QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
+ : QApplication(dpy, argc, argv, visual, cmap)
+{
+ sysInit();
+}
+
+QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId,
+ int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE colormap)
+ : QApplication(dpy, argc, argv, visual, colormap)
+{
+ sysInit(appId);
+}
+#endif
+
+bool QtSingleApplication::event(QEvent *event)
+{
+ if (event->type() == QEvent::FileOpen) {
+ QFileOpenEvent *foe = static_cast<QFileOpenEvent*>(event);
+ emit fileOpenRequest(foe->file());
+ return true;
+ }
+ return QApplication::event(event);
+}
+
+bool QtSingleApplication::isRunning()
+{
+ return peer->isClient();
+}
+
+
+bool QtSingleApplication::sendMessage(const QString &message, int timeout)
+{
+ return peer->sendMessage(message, timeout);
+}
+
+
+QString QtSingleApplication::id() const
+{
+ return peer->applicationId();
+}
+
+
+void QtSingleApplication::setActivationWindow(QWidget *aw, bool activateOnMessage)
+{
+ actWin = aw;
+ if (activateOnMessage)
+ connect(peer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow()));
+ else
+ disconnect(peer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow()));
+}
+
+
+QWidget* QtSingleApplication::activationWindow() const
+{
+ return actWin;
+}
+
+
+void QtSingleApplication::activateWindow()
+{
+ if (actWin) {
+ actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized);
+ actWin->raise();
+ actWin->activateWindow();
+ }
+}
+
+} // namespace SharedTools
diff --git a/src/shared/qtsingleapplication/qtsingleapplication.h b/src/shared/qtsingleapplication/qtsingleapplication.h
new file mode 100644
index 0000000000..7e023ab981
--- /dev/null
+++ b/src/shared/qtsingleapplication/qtsingleapplication.h
@@ -0,0 +1,85 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include <QtGui/QApplication>
+
+namespace SharedTools {
+
+class QtLocalPeer;
+
+class QtSingleApplication : public QApplication
+{
+ Q_OBJECT
+
+public:
+ QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
+ QtSingleApplication(const QString &id, int &argc, char **argv);
+ QtSingleApplication(int &argc, char **argv, Type type);
+#if defined(Q_WS_X11)
+ QtSingleApplication(Display *dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
+ QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0);
+#endif
+
+ bool isRunning();
+ QString id() const;
+
+ void setActivationWindow(QWidget* aw, bool activateOnMessage = true);
+ QWidget* activationWindow() const;
+ bool event(QEvent *event);
+
+
+public Q_SLOTS:
+ bool sendMessage(const QString &message, int timeout = 5000);
+ void activateWindow();
+
+//Obsolete methods:
+public:
+ void initialize(bool = true)
+ { isRunning(); }
+
+#if defined(Q_WS_X11)
+ QtSingleApplication(Display* dpy, const QString &id, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
+#endif
+// end obsolete methods
+
+Q_SIGNALS:
+ void messageReceived(const QString &message);
+ void fileOpenRequest(const QString &file);
+
+private:
+ void sysInit(const QString &appId = QString());
+ QtLocalPeer *peer;
+ QWidget *actWin;
+};
+
+} // namespace SharedTools
diff --git a/src/shared/qtsingleapplication/qtsingleapplication.pri b/src/shared/qtsingleapplication/qtsingleapplication.pri
new file mode 100644
index 0000000000..f6d8462619
--- /dev/null
+++ b/src/shared/qtsingleapplication/qtsingleapplication.pri
@@ -0,0 +1,14 @@
+INCLUDEPATH += $$PWD
+DEPENDPATH += $$PWD
+HEADERS += $$PWD/qtsingleapplication.h $$PWD/qtlocalpeer.h
+SOURCES += $$PWD/qtsingleapplication.cpp $$PWD/qtlocalpeer.cpp
+
+QT *= network
+
+gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h)
+isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri)
+
+
+win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
+ DEFINES += QT_QTSINGLEAPPLICATION_EXPORT=__declspec(dllexport)
+}
diff --git a/src/shared/qtsingleapplication/qtsinglecoreapplication.cpp b/src/shared/qtsingleapplication/qtsinglecoreapplication.cpp
new file mode 100644
index 0000000000..c244459afb
--- /dev/null
+++ b/src/shared/qtsingleapplication/qtsinglecoreapplication.cpp
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "qtsinglecoreapplication.h"
+#include "qtlocalpeer.h"
+
+namespace SharedTools {
+
+QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
+ : QCoreApplication(argc, argv)
+{
+ peer = new QtLocalPeer(this);
+ connect(peer, SIGNAL(messageReceived(QString)), SIGNAL(messageReceived(QString)));
+}
+
+
+QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv)
+ : QCoreApplication(argc, argv)
+{
+ peer = new QtLocalPeer(this, appId);
+ connect(peer, SIGNAL(messageReceived(QString)), SIGNAL(messageReceived(QString)));
+}
+
+
+bool QtSingleCoreApplication::isRunning()
+{
+ return peer->isClient();
+}
+
+
+bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout)
+{
+ return peer->sendMessage(message, timeout);
+}
+
+
+QString QtSingleCoreApplication::id() const
+{
+ return peer->applicationId();
+}
+
+} // namespace SharedTools
diff --git a/src/shared/qtsingleapplication/qtsinglecoreapplication.h b/src/shared/qtsingleapplication/qtsinglecoreapplication.h
new file mode 100644
index 0000000000..a765c7d070
--- /dev/null
+++ b/src/shared/qtsingleapplication/qtsinglecoreapplication.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include <QtCore/QCoreApplication>
+
+namespace SharedTools {
+
+class QtLocalPeer;
+
+class QtSingleCoreApplication : public QCoreApplication
+{
+ Q_OBJECT
+
+public:
+ QtSingleCoreApplication(int &argc, char **argv);
+ QtSingleCoreApplication(const QString &id, int &argc, char **argv);
+
+ bool isRunning();
+ QString id() const;
+
+public Q_SLOTS:
+ bool sendMessage(const QString &message, int timeout = 5000);
+
+
+Q_SIGNALS:
+ void messageReceived(const QString &message);
+
+
+private:
+ QtLocalPeer* peer;
+};
+
+} // namespace SharedTools
diff --git a/src/shared/qtsingleapplication/qtsinglecoreapplication.pri b/src/shared/qtsingleapplication/qtsinglecoreapplication.pri
new file mode 100644
index 0000000000..3d6301b29c
--- /dev/null
+++ b/src/shared/qtsingleapplication/qtsinglecoreapplication.pri
@@ -0,0 +1,14 @@
+INCLUDEPATH += $$PWD
+DEPENDPATH += $$PWD
+HEADERS += $$PWD/qtsinglecoreapplication.h $$PWD/qtlocalpeer.h
+SOURCES += $$PWD/qtsinglecoreapplication.cpp $$PWD/qtlocalpeer.cpp
+
+QT *= network
+
+gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h)
+isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri)
+
+
+win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
+ DEFINES += QT_QTSINGLECOREAPPLICATION_EXPORT=__declspec(dllexport)
+}
diff --git a/src/shared/scriptwrapper/README b/src/shared/scriptwrapper/README
new file mode 100644
index 0000000000..dd7f4bf14a
--- /dev/null
+++ b/src/shared/scriptwrapper/README
@@ -0,0 +1,58 @@
+Some wrap helpers for Script support.
+
+How to wrap an interface:
+=========================
+
+1) Prototypes (preferred)
+-------------------------
+
+- Interface must inherit QObjectInterface and be qvariant-castable, that is,
+ declared as Q-MetaType.
+
+- Register a prototype with the engine for each interface:
+ - Provide an informative toString()-slot.
+ - Use properties and slots for everything, can be non-void as well
+ - Accessors to interfaces should be properties.
+
+- In the toScriptValue() function passed on to qScriptRegisterMetaType, create
+ an newQObject on the QObject obtained from the QObjectInterface and assign it the prototype
+ registered for the interface (obtained from the engine) using QScriptValue::setDefaultPrototype
+ The prototype can then qobject (-extension)-cast to the interface as each
+ implementing class returns 'this' as qObject() of QObjectInterface.
+
+- If sequences of the interface are used, declare them as Q-MetaType
+ and do qScriptRegisterSequenceMetaType().
+
+The template registerQObjectInterface does the magic.
+
+2) Manually bless a script value with properties
+------------------------------------------------
+
+Typically, a qobject-derived wrapper will be used
+that provides an accessor to the wrapped class.
+The wrapper contains a QScriptValue 'm_self' which
+typically is initialized using:
+
+- engine.newQObject(this, QScriptEngine::ScriptOwnership))
+ for interfaces that are always present.
+
+- m_self(engine.newQObject(this, QScriptEngine::QtOwnership)),
+ can be used when setting the qObject() of an QObjectInterface
+ as parent of the qobject-derived wrapper. If the QObject goes
+ out of scope while running the script, the script object
+ will stop working.
+
+A conversion cast to QScriptValue can then be provided.
+
+How to wrap functions:
+
+Most functions can then be implemented as slots, property-like
+things as such.
+
+The other functions have to be implemented via script-callbacks.
+(Parameter checking required).
+
+The templates in here can help in writing the wrapper
+objects. For examples, see
+
+src/plugins/core/scriptmanager/qworkbench_wrapper.h
diff --git a/src/shared/scriptwrapper/interface_wrap_helpers.h b/src/shared/scriptwrapper/interface_wrap_helpers.h
new file mode 100644
index 0000000000..8ec308fe7e
--- /dev/null
+++ b/src/shared/scriptwrapper/interface_wrap_helpers.h
@@ -0,0 +1,92 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef INTERFACE_WRAP_HELPERS_H
+#define INTERFACE_WRAP_HELPERS_H
+
+#include <QtScript/QScriptEngine>
+
+namespace SharedTools {
+
+// Convert a QObjectInterface to Scriptvalue
+// To be registered as a magic creation function with qScriptRegisterMetaType().
+// (see registerQObjectInterface)
+
+template <class QObjectInterface>
+static QScriptValue qObjectInterfaceToScriptValue(QScriptEngine *engine, QObjectInterface* const &qoif)
+{
+ if (!qoif)
+ return QScriptValue(engine, QScriptValue::NullValue);
+
+ QObject *qObject = const_cast<QObjectInterface *>(qoif);
+
+ const QScriptEngine::QObjectWrapOptions wrapOptions =
+ QScriptEngine::ExcludeChildObjects|QScriptEngine::ExcludeSuperClassMethods|QScriptEngine::ExcludeSuperClassProperties;
+ return engine->newQObject(qObject, QScriptEngine::QtOwnership, wrapOptions);
+}
+
+// Convert Scriptvalue back to QObjectInterface
+// To be registered as a magic conversion function with qScriptRegisterMetaType().
+// (see registerQObjectInterface)
+
+template <class QObjectInterface>
+static void scriptValueToQObjectInterface(const QScriptValue &sv, QObjectInterface *&p)
+{
+ QObject *qObject = sv.toQObject();
+ p = qobject_cast<QObjectInterface*>(qObject);
+}
+
+// Magically register a Workbench interface derived from
+// ExtensionSystem::QObjectInterface class with the engine.
+// To avoid lifecycle issues, the script value is created on the QObject returned
+// by ExtensionSystem::QObjectInterface::qObject() and given the specified
+// prototype. By convention, ExtensionSystem::QObjectInterface::qObject() returns an
+// QObject that implements the interface, so it can be casted to it.
+
+template <class QObjectInterface, class Prototype>
+static void registerQObjectInterface(QScriptEngine &engine)
+{
+ Prototype *protoType = new Prototype(&engine);
+ const QScriptValue scriptProtoType = engine.newQObject(protoType);
+
+ const int metaTypeId = qScriptRegisterMetaType<QObjectInterface*>(
+ &engine,
+ qObjectInterfaceToScriptValue<QObjectInterface>,
+ scriptValueToQObjectInterface<QObjectInterface>,
+ scriptProtoType);
+ Q_UNUSED(metaTypeId);
+}
+
+} // namespace SharedTools
+
+#endif // INTERFACE_WRAP_HELPERS_H
diff --git a/src/shared/scriptwrapper/scriptwrapper.pri b/src/shared/scriptwrapper/scriptwrapper.pri
new file mode 100644
index 0000000000..49c7d607cf
--- /dev/null
+++ b/src/shared/scriptwrapper/scriptwrapper.pri
@@ -0,0 +1,3 @@
+INCLUDEPATH *= $$PWD
+
+HEADERS += $$PWD/wrap_helpers.h
diff --git a/src/shared/scriptwrapper/wrap_helpers.h b/src/shared/scriptwrapper/wrap_helpers.h
new file mode 100644
index 0000000000..bba83728b9
--- /dev/null
+++ b/src/shared/scriptwrapper/wrap_helpers.h
@@ -0,0 +1,335 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#ifndef WRAP_HELPERS_H
+#define WRAP_HELPERS_H
+
+#include <QtScript/QScriptEngine>
+#include <QtScript/QScriptContext>
+#include <QtScript/QScriptValue>
+
+namespace SharedTools {
+
+// Strip a const ref from a type via template specialization trick.
+// Use for determining function call args
+
+template <class T>
+ struct RemoveConstRef {
+ typedef T Result;
+ };
+
+template <class T>
+ struct RemoveConstRef<const T &> {
+ typedef T Result;
+ };
+
+// Template that retrieves a QObject-derived class from a QScriptValue.
+
+template <class QObjectDerived>
+ QObjectDerived *qObjectFromScriptValue(const QScriptValue &v)
+{
+ if (!v.isQObject())
+ return 0;
+ QObject *o = v.toQObject();
+ return qobject_cast<QObjectDerived *>(o);
+}
+
+// Template that retrieves a wrapped object from a QScriptValue.
+// The wrapped object is accessed through an accessor of
+// the QObject-derived wrapper.
+
+template <class Wrapper, class Wrapped>
+ Wrapped *wrappedFromScriptValue(const QScriptValue &v,
+ Wrapped * (Wrapper::*wrappedAccessor) () const)
+{
+ Wrapper *wrapper = qObjectFromScriptValue<Wrapper>(v);
+ if (!wrapper)
+ return 0;
+ return (wrapper->*wrappedAccessor)();
+}
+
+// Template that retrieves a wrapped object from
+// a QObject-derived script wrapper object that is set as 'this' in
+// a script context via accessor.
+
+template <class Wrapper, class Wrapped>
+ static inline Wrapped *wrappedThisFromContext(QScriptContext *context,
+ Wrapped * (Wrapper::*wrappedAccessor) () const)
+{
+ Wrapped *wrapped = wrappedFromScriptValue(context->thisObject(), wrappedAccessor);
+ Q_ASSERT(wrapped);
+ return wrapped;
+}
+
+// Template that retrieves an object contained in a wrapped object
+// in a script getter call (namely the interfaces returned by
+// the core interface accessors). Mangles out the wrapper object from
+// thisObject(), accesses the wrapped object and returns the contained object.
+
+template <class Contained, class Wrapper, class Wrapped>
+ static inline Contained *containedFromContext(QScriptContext *context,
+ Wrapped * (Wrapper::*wrappedAccessor) () const,
+ Contained * (Wrapped::*containedAccessor)() const)
+{
+ Wrapped *wrapped = wrappedThisFromContext(context, wrappedAccessor);
+ return (wrapped->*containedAccessor)();
+}
+
+// Template that retrieves a contained QObject-type object
+// in a script getter call and creates a new script-object via engine->newQObject().
+// To be called from a script getter callback.
+
+template <class Contained, class Wrapper, class Wrapped>
+ static inline QScriptValue containedQObjectFromContextToScriptValue(QScriptContext *context, QScriptEngine *engine,
+ Wrapped * (Wrapper::*wrappedAccessor) () const,
+ Contained * (Wrapped::*containedAccessor)() const)
+{
+ return engine->newQObject(containedFromContext(context, wrappedAccessor, containedAccessor));
+}
+
+// Template that retrieves a contained Non-QObject-type object
+// in a script getter call and creates a new script-object by wrapping it into
+// a new instance of ContainedWrapper (which casts to QScriptValue).
+// To be called from a script getter callback.
+
+template <class ContainedWrapper, class Contained, class Wrapper, class Wrapped>
+ static inline QScriptValue wrapContainedFromContextAsScriptValue(QScriptContext *context, QScriptEngine *engine,
+ Wrapped * (Wrapper::*wrappedAccessor) () const,
+ Contained * (Wrapped::*containedAccessor)() const)
+{
+ Contained *c = containedFromContext(context, wrappedAccessor, containedAccessor);
+ if (!c)
+ return QScriptValue(engine, QScriptValue::NullValue);
+
+ ContainedWrapper *cw = new ContainedWrapper(*engine, c);
+ return *cw; // cast to QScriptValue
+}
+
+// Template that retrieves a wrapped object from context (this)
+// and calls a const-member function with no parameters.
+// To be called from a script getter callback.
+
+template <class Ret, class Wrapper, class Wrapped>
+ static inline QScriptValue scriptCallConstMember_0(QScriptContext *context, QScriptEngine *engine,
+ Wrapped * (Wrapper::*wrappedAccessor) () const,
+ Ret (Wrapped::*member)() const)
+{
+ Wrapped *wrapped = wrappedThisFromContext(context, wrappedAccessor);
+ return engine->toScriptValue( (wrapped->*member)() );
+}
+
+// Ditto for non-const
+
+template <class Ret, class Wrapper, class Wrapped>
+ static inline QScriptValue scriptCallMember_0(QScriptContext *context, QScriptEngine *engine,
+ Wrapped * (Wrapper::*wrappedAccessor) () const,
+ Ret (Wrapped::*member)())
+{
+ Wrapped *wrapped = wrappedThisFromContext(context, wrappedAccessor);
+ return engine->toScriptValue( (wrapped->*member)() );
+}
+
+// Template that retrieves a wrapped object from context (this)
+// and calls a const-member function with 1 parameter on it.
+// To be called from a script getter callback.
+
+template <class Ret, class Argument, class Wrapper, class Wrapped>
+ static inline QScriptValue scriptCallConstMember_1(QScriptContext *context, QScriptEngine *engine,
+ Wrapped * (Wrapper::*wrappedAccessor) () const,
+ Ret (Wrapped::*member)(Argument a1) const)
+{
+ const int argumentCount = context->argumentCount();
+ if ( argumentCount != 1)
+ return QScriptValue (engine, QScriptValue::NullValue);
+
+ Wrapped *wrapped = wrappedThisFromContext(context, wrappedAccessor);
+ // call member. If the argument is a const ref, strip it.
+ typedef typename RemoveConstRef<Argument>::Result ArgumentBase;
+ ArgumentBase a = qscriptvalue_cast<ArgumentBase>(context->argument(0));
+ return engine->toScriptValue( (wrapped->*member)(a) );
+}
+
+// Template that retrieves a wrapped object
+// and calls a member function with 1 parameter on it.
+// To be called from a script getter callback.
+
+template <class Ret, class Argument, class Wrapper, class Wrapped>
+ static inline QScriptValue scriptCallMember_1(QScriptContext *context, QScriptEngine *engine,
+ Wrapped * (Wrapper::*wrappedAccessor) () const,
+ Ret (Wrapped::*member)(Argument a1))
+{
+ const int argumentCount = context->argumentCount();
+ if ( argumentCount != 1)
+ return QScriptValue (engine, QScriptValue::NullValue);
+
+ Wrapped *wrapped = wrappedThisFromContext(context, wrappedAccessor);
+ // call member. If the argument is a const ref, strip it.
+ typedef typename RemoveConstRef<Argument>::Result ArgumentBase;
+ ArgumentBase a = qscriptvalue_cast<ArgumentBase>(context->argument(0));
+ return engine->toScriptValue( (wrapped->*member)(a) );
+}
+
+// Template that retrieves a wrapped object
+// and calls a void member function with 1 parameter that is a wrapper of
+// of some interface.
+// Typically used for something like 'setCurrentEditor(Editor*)'
+// To be called from a script callback.
+
+template <class ThisWrapper, class ThisWrapped, class ArgumentWrapper, class ArgumentWrapped>
+static QScriptValue scriptCallVoidMember_Wrapped1(QScriptContext *context, QScriptEngine *engine,
+ ThisWrapped * (ThisWrapper::*thisWrappedAccessor) () const,
+ ArgumentWrapped *(ArgumentWrapper::*argumentWrappedAccessor)() const,
+ void (ThisWrapped::*member)(ArgumentWrapped *a1),
+ bool acceptNullArgument = false)
+{
+ const QScriptValue voidRC = QScriptValue(engine, QScriptValue::UndefinedValue);
+ if (context->argumentCount() < 1)
+ return voidRC;
+
+ ThisWrapped *thisWrapped = wrappedThisFromContext(context, thisWrappedAccessor);
+ ArgumentWrapped *aw = wrappedFromScriptValue(context->argument(0), argumentWrappedAccessor);
+ if (acceptNullArgument || aw)
+ (thisWrapped->*member)(aw);
+ return voidRC;
+}
+
+// Macros that define the static functions to call members
+
+#define SCRIPT_CALL_CONST_MEMBER_0(funcName, accessor, member) \
+static QScriptValue funcName(QScriptContext *context, QScriptEngine *engine) \
+{ return SharedTools::scriptCallConstMember_0(context, engine, accessor, member); }
+
+#define SCRIPT_CALL_MEMBER_0(funcName, accessor, member) \
+static QScriptValue funcName(QScriptContext *context, QScriptEngine *engine) \
+{ return SharedTools::scriptCallMember_0(context, engine, accessor, member); }
+
+#define SCRIPT_CALL_CONST_MEMBER_1(funcName, accessor, member) \
+static QScriptValue funcName(QScriptContext *context, QScriptEngine *engine) \
+{ return SharedTools::scriptCallConstMember_1(context, engine, accessor, member); }
+
+#define SCRIPT_CALL_MEMBER_1(funcName, accessor, member) \
+static QScriptValue funcName(QScriptContext *context, QScriptEngine *engine) \
+{ return SharedTools::scriptCallMember_1(context, engine, accessor, member); }
+
+// Create a script list of wrapped non-qobjects by wrapping them.
+// Wrapper must cast to QScriptValue.
+
+template <class Wrapper, class Iterator>
+ static inline QScriptValue wrapObjectList( QScriptEngine *engine, Iterator i1, Iterator i2)
+{
+ QScriptValue rc = engine->newArray(i2 - i1); // Grrr!
+ quint32 i = 0;
+ for ( ; i1 != i2 ; ++i1, i++) {
+ Wrapper * wrapper = new Wrapper(*engine, *i1);
+ rc.setProperty(i, *wrapper);
+ }
+ return rc;
+}
+
+// Unwrap a list of wrapped objects from a script list.
+
+template <class Wrapper, class Wrapped>
+ static inline QList<Wrapped*> unwrapObjectList(const QScriptValue &v,
+ Wrapped *(Wrapper::*wrappedAccessor)() const)
+{
+ QList<Wrapped*> rc;
+
+ if (!v.isArray())
+ return rc;
+
+ const quint32 len = v.property(QLatin1String("length")).toUInt32();
+ if (!len)
+ return rc;
+
+ for (quint32 i = 0; i < len; i++) {
+ const QScriptValue e = v.property(i);
+ if (e.isQObject()) {
+ QObject *o = e.toQObject();
+ if (Wrapper * wrapper = qobject_cast<Wrapper *>(o))
+ rc.push_back((wrapper->*wrappedAccessor)());
+ }
+ }
+ return rc;
+}
+
+// Traditional registration of a prototype for an interface.
+// that can be converted via script value casts via Q_DECLARE_METATYPE.
+
+template <class Interface, class Prototype>
+ static void registerInterfaceWithDefaultPrototype(QScriptEngine &engine)
+{
+ Prototype *protoType = new Prototype(&engine);
+ const QScriptValue scriptProtoType = engine.newQObject(protoType);
+
+ engine.setDefaultPrototype(qMetaTypeId<Interface*>(), scriptProtoType);
+}
+
+// Convert a class derived from QObject to Scriptvalue via engine->newQObject() to make
+// the signals, slots and properties visible.
+// To be registered as a magic creation function with qScriptRegisterMetaType().
+// (see registerQObject()
+
+template <class SomeQObject>
+static QScriptValue qObjectToScriptValue(QScriptEngine *engine, SomeQObject * const &qo)
+{
+ return engine->newQObject(qo, QScriptEngine::QtOwnership, QScriptEngine::ExcludeChildObjects);
+}
+
+// Convert Scriptvalue back to a class derived from QObject via QScriptValue::toQObject()
+// To be registered as a magic conversion function with qScriptRegisterMetaType().
+// (see registerQObject)
+
+template <class SomeQObject>
+static void scriptValueToQObject(const QScriptValue &sv, SomeQObject * &p)
+{
+ QObject *qObject = sv.toQObject();
+ p = qobject_cast<SomeQObject*>(qObject);
+ Q_ASSERT(p);
+}
+
+// Register a QObject-derived class which has Q_DECLARE_METATYPE(Ptr*)
+// with the engine using qObjectToScriptValue/scriptValueToQObject as
+// conversion functions to make it possible to use for example
+// Q_PROPERTY(QMainWindow*).
+
+template <class SomeQObject>
+static void registerQObject(QScriptEngine &engine)
+{
+ qScriptRegisterMetaType<SomeQObject*>(&engine,
+ qObjectToScriptValue<SomeQObject>,
+ scriptValueToQObject<SomeQObject>);
+}
+
+} // namespace SharedTools
+
+#endif // WRAP_HELPERS_H