summaryrefslogtreecommitdiff
path: root/src/plugins/cpptools
diff options
context:
space:
mode:
authorcon <qtc-commiter@nokia.com>2008-12-02 12:01:29 +0100
committercon <qtc-commiter@nokia.com>2008-12-02 12:01:29 +0100
commit05c35356abc31549c5db6eba31fb608c0365c2a0 (patch)
treebe044530104267afaff13f8943889cb97f8c8bad /src/plugins/cpptools
downloadqt-creator-05c35356abc31549c5db6eba31fb608c0365c2a0.tar.gz
Initial import
Diffstat (limited to 'src/plugins/cpptools')
-rw-r--r--src/plugins/cpptools/CppTools.pluginspec12
-rw-r--r--src/plugins/cpptools/cppcodecompletion.cpp1040
-rw-r--r--src/plugins/cpptools/cppcodecompletion.h145
-rw-r--r--src/plugins/cpptools/cpphoverhandler.cpp243
-rw-r--r--src/plugins/cpptools/cpphoverhandler.h75
-rw-r--r--src/plugins/cpptools/cppmodelmanager.cpp740
-rw-r--r--src/plugins/cpptools/cppmodelmanager.h135
-rw-r--r--src/plugins/cpptools/cppmodelmanagerinterface.h79
-rw-r--r--src/plugins/cpptools/cppquickopenfilter.cpp280
-rw-r--r--src/plugins/cpptools/cppquickopenfilter.h118
-rw-r--r--src/plugins/cpptools/cpptools.cpp256
-rw-r--r--src/plugins/cpptools/cpptools.h86
-rw-r--r--src/plugins/cpptools/cpptools.pri3
-rw-r--r--src/plugins/cpptools/cpptools.pro40
-rw-r--r--src/plugins/cpptools/cpptools.qrc5
-rw-r--r--src/plugins/cpptools/cpptools_dependencies.pri3
-rw-r--r--src/plugins/cpptools/cpptools_global.h42
-rw-r--r--src/plugins/cpptools/cpptoolsconstants.h49
-rw-r--r--src/plugins/cpptools/cpptoolseditorsupport.cpp97
-rw-r--r--src/plugins/cpptools/cpptoolseditorsupport.h87
-rw-r--r--src/plugins/cpptools/images/f1.svg175
-rw-r--r--src/plugins/cpptools/rpp/pp-cctype.h76
-rw-r--r--src/plugins/cpptools/rpp/pp-client.h69
-rw-r--r--src/plugins/cpptools/rpp/pp-engine.cpp1085
-rw-r--r--src/plugins/cpptools/rpp/pp-engine.h230
-rw-r--r--src/plugins/cpptools/rpp/pp-environment.cpp231
-rw-r--r--src/plugins/cpptools/rpp/pp-environment.h109
-rw-r--r--src/plugins/cpptools/rpp/pp-fwd.h62
-rw-r--r--src/plugins/cpptools/rpp/pp-internal.h102
-rw-r--r--src/plugins/cpptools/rpp/pp-macro-expander.cpp362
-rw-r--r--src/plugins/cpptools/rpp/pp-macro-expander.h103
-rw-r--r--src/plugins/cpptools/rpp/pp-macro.h95
-rw-r--r--src/plugins/cpptools/rpp/pp-scanner.h380
-rw-r--r--src/plugins/cpptools/rpp/pp-symbol.h52
-rw-r--r--src/plugins/cpptools/rpp/pp.h76
-rw-r--r--src/plugins/cpptools/rpp/rpp.pri20
36 files changed, 6762 insertions, 0 deletions
diff --git a/src/plugins/cpptools/CppTools.pluginspec b/src/plugins/cpptools/CppTools.pluginspec
new file mode 100644
index 0000000000..ca4a8a0e52
--- /dev/null
+++ b/src/plugins/cpptools/CppTools.pluginspec
@@ -0,0 +1,12 @@
+<plugin name="CppTools" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Tools for analyzing C/C++ code.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="TextEditor" version="0.9.1"/>
+ <dependency name="ProjectExplorer" version="0.9.1"/>
+ <dependency name="QuickOpen" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp
new file mode 100644
index 0000000000..5950477184
--- /dev/null
+++ b/src/plugins/cpptools/cppcodecompletion.cpp
@@ -0,0 +1,1040 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cppcodecompletion.h"
+#include "cppmodelmanager.h"
+
+#include <Control.h>
+#include <AST.h>
+#include <ASTVisitor.h>
+#include <CoreTypes.h>
+#include <Literals.h>
+#include <Names.h>
+#include <NameVisitor.h>
+#include <Symbols.h>
+#include <SymbolVisitor.h>
+#include <Scope.h>
+#include <TranslationUnit.h>
+#include <cplusplus/ResolveExpression.h>
+#include <cplusplus/LookupContext.h>
+#include <cplusplus/Overview.h>
+#include <cplusplus/ExpressionUnderCursor.h>
+#include <cplusplus/TokenUnderCursor.h>
+
+#include <coreplugin/icore.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <texteditor/itexteditor.h>
+#include <texteditor/itexteditable.h>
+#include <texteditor/basetexteditor.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QMap>
+#include <QtCore/QFile>
+#include <QtGui/QAction>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QLabel>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QApplication>
+
+using namespace CPlusPlus;
+
+namespace CppTools {
+namespace Internal {
+
+class FunctionArgumentWidget : public QLabel {
+public:
+ FunctionArgumentWidget(Core::ICore *core);
+ void showFunctionHint(Function *functionSymbol);
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *e);
+
+private:
+ void update();
+ void close();
+ void updateHintText();
+
+ int m_startpos;
+ int m_currentarg;
+
+ TextEditor::ITextEditor *m_editor;
+
+ QFrame *m_popupFrame;
+ Function *m_item;
+};
+
+class ConvertToCompletionItem: protected NameVisitor
+{
+ // The completion collector.
+ CppCodeCompletion *_collector;
+
+ // The completion item.
+ TextEditor::CompletionItem _item;
+
+ // The current symbol.
+ Symbol *_symbol;
+
+ // The pretty printer.
+ Overview overview;
+
+public:
+ ConvertToCompletionItem(CppCodeCompletion *collector)
+ : _collector(collector),
+ _item(0),
+ _symbol(0)
+ { }
+
+ TextEditor::CompletionItem operator()(Symbol *symbol)
+ {
+ if (! symbol || ! symbol->name() || symbol->name()->isQualifiedNameId())
+ return 0;
+
+ TextEditor::CompletionItem previousItem = switchCompletionItem(0);
+ Symbol *previousSymbol = switchSymbol(symbol);
+ accept(symbol->identity());
+ if (_item)
+ _item.m_data = QVariant::fromValue(symbol);
+ (void) switchSymbol(previousSymbol);
+ return switchCompletionItem(previousItem);
+ }
+
+protected:
+ Symbol *switchSymbol(Symbol *symbol)
+ {
+ Symbol *previousSymbol = _symbol;
+ _symbol = symbol;
+ return previousSymbol;
+ }
+
+ TextEditor::CompletionItem switchCompletionItem(TextEditor::CompletionItem item)
+ {
+ TextEditor::CompletionItem previousItem = _item;
+ _item = item;
+ return previousItem;
+ }
+
+ TextEditor::CompletionItem newCompletionItem(Name *name)
+ {
+ TextEditor::CompletionItem item(_collector);
+ item.m_text = overview.prettyName(name);
+ item.m_icon = _collector->iconForSymbol(_symbol);
+ return item;
+ }
+
+ virtual void visit(NameId *name)
+ { _item = newCompletionItem(name); }
+
+ virtual void visit(TemplateNameId *name)
+ {
+ _item = newCompletionItem(name);
+ _item.m_text = QLatin1String(name->identifier()->chars());
+ }
+
+ virtual void visit(DestructorNameId *name)
+ { _item = newCompletionItem(name); }
+
+ virtual void visit(OperatorNameId *name)
+ { _item = newCompletionItem(name); }
+
+ virtual void visit(ConversionNameId *name)
+ { _item = newCompletionItem(name); }
+
+ virtual void visit(QualifiedNameId *name)
+ { _item = newCompletionItem(name->unqualifiedNameId()); }
+};
+
+
+} // namespace Internal
+} // namespace CppTools
+
+
+
+using namespace CppTools::Internal;
+
+FunctionArgumentWidget::FunctionArgumentWidget(Core::ICore *core)
+ : m_item(0)
+{
+ QObject *editorObject = core->editorManager()->currentEditor();
+ m_editor = qobject_cast<TextEditor::ITextEditor *>(editorObject);
+
+ m_popupFrame = new QFrame(0, Qt::ToolTip|Qt::WindowStaysOnTopHint);
+ m_popupFrame->setFocusPolicy(Qt::NoFocus);
+ m_popupFrame->setAttribute(Qt::WA_DeleteOnClose);
+
+ setFrameStyle(QFrame::Box);
+ setFrameShadow(QFrame::Plain);
+
+ setParent(m_popupFrame);
+ setFocusPolicy(Qt::NoFocus);
+
+ QVBoxLayout *layout = new QVBoxLayout();
+ layout->addWidget(this);
+ layout->setMargin(0);
+ m_popupFrame->setLayout(layout);
+
+ QPalette pal = palette();
+ setAutoFillBackground(true);
+ pal.setColor(QPalette::Background, QColor(255, 255, 220));
+ setPalette(pal);
+
+ setTextFormat(Qt::RichText);
+ setMargin(1);
+}
+
+void FunctionArgumentWidget::showFunctionHint(Function *functionSymbol)
+{
+ m_item = functionSymbol;
+ m_startpos = m_editor->position();
+
+ // update the text
+ m_currentarg = -1;
+ update();
+
+ QPoint pos = m_editor->cursorRect().topLeft();
+ pos.setY(pos.y() - sizeHint().height());
+ m_popupFrame->move(pos);
+ m_popupFrame->show();
+
+ QCoreApplication::instance()->installEventFilter(this);
+}
+
+void FunctionArgumentWidget::update()
+{
+ int curpos = m_editor->position();
+ if (curpos < m_startpos) {
+ close();
+ return;
+ }
+
+ QString str = m_editor->textAt(m_startpos, curpos - m_startpos);
+ int argnr = 0;
+ int parcount = 0;
+ SimpleLexer tokenize;
+ QList<SimpleToken> tokens = tokenize(str);
+ for (int i = 0; i < tokens.count(); ++i) {
+ const SimpleToken &tk = tokens.at(i);
+ if (tk.is(T_LPAREN))
+ ++parcount;
+ else if (tk.is(T_RPAREN))
+ --parcount;
+ else if (! parcount && tk.is(T_COMMA))
+ ++argnr;
+ }
+
+ if (m_currentarg != argnr) {
+ m_currentarg = argnr;
+ updateHintText();
+ }
+
+ if (parcount < 0)
+ close();
+}
+
+bool FunctionArgumentWidget::eventFilter(QObject *obj, QEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::KeyRelease:
+ {
+ if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) {
+ close();
+ return false;
+ }
+ update();
+ break;
+ }
+ case QEvent::WindowDeactivate:
+ case QEvent::Leave:
+ case QEvent::FocusOut:
+ {
+ if (obj != m_editor->widget())
+ break;
+ }
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::Wheel:
+ close();
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void FunctionArgumentWidget::close()
+{
+ m_popupFrame->close();
+}
+
+void FunctionArgumentWidget::updateHintText()
+{
+ Overview overview;
+ overview.setShowReturnTypes(true);
+ overview.setShowArgumentNames(true);
+ overview.setMarkArgument(m_currentarg + 1);
+ QString text = overview(m_item->type(), m_item->name());
+ setText(text);
+}
+
+CppCodeCompletion::CppCodeCompletion(CppModelManager *manager, Core::ICore *core)
+ : ICompletionCollector(manager),
+ m_core(core),
+ m_manager(manager),
+ m_forcedCompletion(false),
+ m_completionOperator(T_EOF_SYMBOL)
+{ }
+
+QIcon CppCodeCompletion::iconForSymbol(Symbol *symbol) const
+{ return m_icons.iconForSymbol(symbol); }
+
+/*
+ Searches beckward for an access operator.
+*/
+static int startOfOperator(TextEditor::ITextEditable *editor,
+ int pos, unsigned *kind,
+ bool wantFunctionCall)
+{
+ const QChar ch = pos > -1 ? editor->characterAt(pos - 1) : QChar();
+ const QChar ch2 = pos > 0 ? editor->characterAt(pos - 2) : QChar();
+ const QChar ch3 = pos > 1 ? editor->characterAt(pos - 3) : QChar();
+
+ int start = pos;
+
+ if (ch2 != QLatin1Char('.') && ch == QLatin1Char('.')) {
+ if (kind)
+ *kind = T_DOT;
+ --start;
+ } else if (wantFunctionCall && ch == QLatin1Char('(')) {
+ if (kind)
+ *kind = T_LPAREN;
+ --start;
+ } else if (ch2 == QLatin1Char(':') && ch == QLatin1Char(':')) {
+ if (kind)
+ *kind = T_COLON_COLON;
+ start -= 2;
+ } else if (ch2 == QLatin1Char('-') && ch == QLatin1Char('>')) {
+ if (kind)
+ *kind = T_ARROW;
+ start -= 2;
+ } else if (ch2 == QLatin1Char('.') && ch == QLatin1Char('*')) {
+ if (kind)
+ *kind = T_DOT_STAR;
+ start -= 2;
+ } else if (ch3 == QLatin1Char('-') && ch2 == QLatin1Char('>') && ch == QLatin1Char('*')) {
+ if (kind)
+ *kind = T_ARROW_STAR;
+ start -= 3;
+ }
+
+ if (start != pos) {
+ TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget());
+ QTextCursor tc(edit->textCursor());
+ tc.setPosition(pos);
+ static CPlusPlus::TokenUnderCursor tokenUnderCursor;
+ const SimpleToken tk = tokenUnderCursor(tc);
+ if (tk.is(T_COMMENT) || tk.isLiteral()) {
+ if (kind)
+ *kind = T_EOF_SYMBOL;
+ return pos;
+ }
+ }
+
+ return start;
+}
+
+bool CppCodeCompletion::triggersCompletion(TextEditor::ITextEditable *editor)
+{
+ if (! m_manager->isCppEditor(editor)) // ### remove me
+ return false;
+
+ const int pos = editor->position();
+ if (startOfOperator(editor, pos, /*token =*/ 0,
+ /*want function call=*/ true) != pos)
+ return true;
+
+ return false;
+}
+
+int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
+{
+ TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget());
+ if (! edit)
+ return -1;
+
+ m_editor = editor;
+ m_startPosition = findStartOfName(editor);
+ m_completionOperator = T_EOF_SYMBOL;
+
+ int endOfExpression = m_startPosition;
+
+ // Skip whitespace preceding this position
+ while (editor->characterAt(endOfExpression - 1).isSpace())
+ --endOfExpression;
+
+ endOfExpression = startOfOperator(editor, endOfExpression,
+ &m_completionOperator,
+ /*want function call =*/ editor->position() == endOfExpression);
+
+ Core::IFile *file = editor->file();
+ QString fileName = file->fileName();
+
+ int line = 0, column = 0;
+ edit->convertPosition(editor->position(), &line, &column);
+ // qDebug() << "line:" << line << "column:" << column;
+
+ ExpressionUnderCursor expressionUnderCursor;
+ QString expression;
+
+ if (m_completionOperator) {
+ QTextCursor tc(edit->document());
+ tc.setPosition(endOfExpression);
+ expression = expressionUnderCursor(tc);
+ if (m_completionOperator == T_LPAREN) {
+ if (expression.endsWith(QLatin1String("SIGNAL")))
+ m_completionOperator = T_SIGNAL;
+ else if (expression.endsWith(QLatin1String("SLOT")))
+ m_completionOperator = T_SLOT;
+ }
+ }
+
+ //if (! expression.isEmpty())
+ //qDebug() << "***** expression:" << expression;
+
+ if (Document::Ptr thisDocument = m_manager->document(fileName)) {
+ Symbol *symbol = thisDocument->findSymbolAt(line, column);
+
+ typeOfExpression.setDocuments(m_manager->documents());
+
+ QList<TypeOfExpression::Result> resolvedTypes = typeOfExpression(expression, thisDocument, symbol);
+ LookupContext context = typeOfExpression.lookupContext();
+
+ if (!typeOfExpression.expressionAST() && (! m_completionOperator ||
+ m_completionOperator == T_COLON_COLON)) {
+ if (!m_completionOperator) {
+ addKeywords();
+ addMacros(context);
+ }
+
+ const QList<Scope *> scopes = context.expand(context.visibleScopes());
+ foreach (Scope *scope, scopes) {
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ addCompletionItem(scope->symbolAt(i));
+ }
+ }
+ return m_startPosition;
+ }
+
+ // qDebug() << "found" << resolvedTypes.count() << "symbols for expression:" << expression;
+
+ if (resolvedTypes.isEmpty() && (m_completionOperator == T_SIGNAL ||
+ m_completionOperator == T_SLOT)) {
+ // Apply signal/slot completion on 'this'
+ expression = QLatin1String("this");
+ resolvedTypes = typeOfExpression(expression, thisDocument, symbol);
+ context = typeOfExpression.lookupContext();
+ }
+
+ if (! resolvedTypes.isEmpty()) {
+ FullySpecifiedType exprTy = resolvedTypes.first().first;
+
+ if (exprTy->isReferenceType())
+ exprTy = exprTy->asReferenceType()->elementType();
+
+ if (m_completionOperator == T_LPAREN && completeFunction(exprTy, resolvedTypes, context)) {
+ return m_startPosition;
+ } if ((m_completionOperator == T_DOT || m_completionOperator == T_ARROW) &&
+ completeMember(exprTy, resolvedTypes, context)) {
+ return m_startPosition;
+ } else if (m_completionOperator == T_COLON_COLON && completeScope(exprTy, resolvedTypes, context)) {
+ return m_startPosition;
+ } else if (m_completionOperator == T_SIGNAL && completeSignal(exprTy, resolvedTypes, context)) {
+ return m_startPosition;
+ } else if (m_completionOperator == T_SLOT && completeSlot(exprTy, resolvedTypes, context)) {
+ return m_startPosition;
+ }
+ }
+ }
+
+ // nothing to do.
+ return -1;
+}
+
+bool CppCodeCompletion::completeFunction(FullySpecifiedType exprTy,
+ const QList<TypeOfExpression::Result> &resolvedTypes,
+ const LookupContext &)
+{
+ ConvertToCompletionItem toCompletionItem(this);
+ Overview o;
+ o.setShowReturnTypes(true);
+ o.setShowArgumentNames(true);
+
+ if (Class *klass = exprTy->asClass()) {
+ for (unsigned i = 0; i < klass->memberCount(); ++i) {
+ Symbol *member = klass->memberAt(i);
+ if (! member->type()->isFunction())
+ continue;
+ else if (! member->identity())
+ continue;
+ else if (! member->identity()->isEqualTo(klass->identity()))
+ continue;
+ if (TextEditor::CompletionItem item = toCompletionItem(member)) {
+ item.m_text = o(member->type(), member->name());
+ m_completions.append(item);
+ }
+ }
+ } else {
+ QSet<QString> signatures;
+ foreach (TypeOfExpression::Result p, resolvedTypes) {
+ FullySpecifiedType ty = p.first;
+ if (Function *fun = ty->asFunction()) {
+ if (TextEditor::CompletionItem item = toCompletionItem(fun)) {
+ QString signature;
+ signature += overview.prettyName(fun->name());
+ signature += overview.prettyType(fun->type());
+ if (signatures.contains(signature))
+ continue;
+ signatures.insert(signature);
+
+ item.m_text = o(ty, fun->name());
+ m_completions.append(item);
+ }
+ }
+ }
+ }
+
+ return ! m_completions.isEmpty();
+}
+
+bool CppCodeCompletion::completeMember(FullySpecifiedType,
+ const QList<TypeOfExpression::Result> &results,
+ const LookupContext &context)
+{
+ Q_ASSERT(! results.isEmpty());
+
+ QList<Symbol *> classObjectCandidates;
+
+ TypeOfExpression::Result p = results.first();
+
+ if (m_completionOperator == T_ARROW) {
+ FullySpecifiedType ty = p.first;
+
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+
+ if (NamedType *namedTy = ty->asNamedType()) {
+ ResolveExpression resolveExpression(context);
+
+ Name *className = namedTy->name();
+ const QList<Symbol *> candidates =
+ context.resolveClass(className, context.visibleScopes(p));
+
+ foreach (Symbol *classObject, candidates) {
+ const QList<TypeOfExpression::Result> overloads =
+ resolveExpression.resolveArrowOperator(p, namedTy,
+ classObject->asClass());
+
+ foreach (TypeOfExpression::Result r, overloads) {
+ FullySpecifiedType ty = r.first;
+ Function *funTy = ty->asFunction();
+ if (! funTy)
+ continue;
+
+ ty = funTy->returnType();
+
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+
+ if (PointerType *ptrTy = ty->asPointerType()) {
+ if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
+ const QList<Symbol *> classes =
+ context.resolveClass(namedTy->name(),
+ context.visibleScopes(p));
+
+ foreach (Symbol *c, classes) {
+ if (! classObjectCandidates.contains(c))
+ classObjectCandidates.append(c);
+ }
+ }
+ }
+ }
+ }
+ } else if (PointerType *ptrTy = ty->asPointerType()) {
+ if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
+ const QList<Symbol *> classes =
+ context.resolveClass(namedTy->name(),
+ context.visibleScopes(p));
+
+ foreach (Symbol *c, classes) {
+ if (! classObjectCandidates.contains(c))
+ classObjectCandidates.append(c);
+ }
+ }
+ }
+ } else if (m_completionOperator == T_DOT) {
+ FullySpecifiedType ty = p.first;
+
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+
+ NamedType *namedTy = 0;
+ if (PointerType *ptrTy = ty->asPointerType()) {
+ // Replace . with ->
+ int length = m_editor->position() - m_startPosition + 1;
+ m_editor->setCurPos(m_startPosition - 1);
+ m_editor->replace(length, QLatin1String("->"));
+ m_startPosition++;
+ namedTy = ptrTy->elementType()->asNamedType();
+ } else {
+ namedTy = ty->asNamedType();
+ if (! namedTy) {
+ Function *fun = ty->asFunction();
+ if (fun && (fun->scope()->isBlockScope() || fun->scope()->isNamespaceScope()))
+ namedTy = fun->returnType()->asNamedType();
+ }
+ }
+
+ if (namedTy) {
+ const QList<Symbol *> classes =
+ context.resolveClass(namedTy->name(),
+ context.visibleScopes(p));
+
+ foreach (Symbol *c, classes) {
+ if (! classObjectCandidates.contains(c))
+ classObjectCandidates.append(c);
+ }
+ }
+ }
+
+ completeClass(classObjectCandidates, context, /*static lookup = */ false);
+ if (! m_completions.isEmpty())
+ return true;
+
+ return false;
+}
+
+bool CppCodeCompletion::completeScope(FullySpecifiedType exprTy,
+ const QList<TypeOfExpression::Result> &resolvedTypes,
+ const LookupContext &context)
+{
+ // Search for a class or a namespace.
+ foreach (TypeOfExpression::Result p, resolvedTypes) {
+ if (p.first->isClass() || p.first->isNamespace()) {
+ exprTy = p.first;
+ break;
+ }
+ }
+
+ if (exprTy->asNamespace()) {
+ QList<Symbol *> candidates;
+ foreach (TypeOfExpression::Result p, resolvedTypes) {
+ if (Namespace *ns = p.first->asNamespace())
+ candidates.append(ns);
+ }
+ completeNamespace(candidates, context);
+ } else if (exprTy->isClass()) {
+ QList<Symbol *> candidates;
+ foreach (TypeOfExpression::Result p, resolvedTypes) {
+ if (Class *k = p.first->asClass())
+ candidates.append(k);
+ }
+ completeClass(candidates, context);
+ }
+
+ return ! m_completions.isEmpty();
+}
+
+void CppCodeCompletion::addKeywords()
+{
+ // keyword completion items.
+ for (int i = T_FIRST_KEYWORD; i < T_FIRST_QT_KEYWORD; ++i) {
+ TextEditor::CompletionItem item(this);
+ item.m_text = QLatin1String(Token::name(i));
+ item.m_icon = m_icons.keywordIcon();
+ m_completions.append(item);
+ }
+}
+
+void CppCodeCompletion::addMacros(const LookupContext &context)
+{
+ // macro completion items.
+ QSet<QByteArray> macroNames;
+ QSet<QString> processed;
+ QList<QString> todo;
+ todo.append(context.thisDocument()->fileName());
+ while (! todo.isEmpty()) {
+ QString fn = todo.last();
+ todo.removeLast();
+ if (processed.contains(fn))
+ continue;
+ processed.insert(fn);
+ if (Document::Ptr doc = context.document(fn)) {
+ macroNames += doc->macroNames();
+ todo += doc->includedFiles();
+ }
+ }
+
+ foreach (const QByteArray macroName, macroNames) {
+ TextEditor::CompletionItem item(this);
+ item.m_text = QString::fromLatin1(macroName.constData(), macroName.length());
+ item.m_icon = m_icons.macroIcon();
+ m_completions.append(item);
+ }
+}
+
+void CppCodeCompletion::addCompletionItem(Symbol *symbol)
+{
+ ConvertToCompletionItem toCompletionItem(this);
+ if (TextEditor::CompletionItem item = toCompletionItem(symbol))
+ m_completions.append(item);
+}
+
+void CppCodeCompletion::completeNamespace(const QList<Symbol *> &candidates,
+ const LookupContext &context)
+{
+ QList<Scope *> todo;
+ QList<Scope *> visibleScopes = context.visibleScopes();
+ foreach (Symbol *candidate, candidates) {
+ if (Namespace *ns = candidate->asNamespace())
+ context.expand(ns->members(), visibleScopes, &todo);
+ }
+
+ foreach (Scope *scope, todo) {
+ addCompletionItem(scope->owner());
+
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ addCompletionItem(scope->symbolAt(i));
+ }
+ }
+}
+
+void CppCodeCompletion::completeClass(const QList<Symbol *> &candidates,
+ const LookupContext &context,
+ bool staticLookup)
+{
+ if (candidates.isEmpty())
+ return;
+
+ Class *klass = candidates.first()->asClass();
+
+ QList<Scope *> todo;
+ context.expand(klass->members(), context.visibleScopes(), &todo);
+
+ foreach (Scope *scope, todo) {
+ addCompletionItem(scope->owner());
+
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ Symbol *symbol = scope->symbolAt(i);
+
+ if (symbol->type().isFriend())
+ continue;
+ else if (! staticLookup && (symbol->isTypedef() ||
+ symbol->isEnum() ||
+ symbol->isClass()))
+ continue;
+
+ addCompletionItem(symbol);
+ }
+ }
+}
+
+bool CppCodeCompletion::completeQtMethod(CPlusPlus::FullySpecifiedType,
+ const QList<TypeOfExpression::Result> &results,
+ const LookupContext &context,
+ bool wantSignals)
+{
+ if (results.isEmpty())
+ return false;
+
+ ConvertToCompletionItem toCompletionItem(this);
+ Overview o;
+ o.setShowReturnTypes(false);
+ o.setShowArgumentNames(false);
+ o.setShowFunctionSignatures(true);
+
+ QSet<QString> signatures;
+ foreach (TypeOfExpression::Result p, results) {
+ FullySpecifiedType ty = p.first;
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+ if (PointerType *ptrTy = ty->asPointerType())
+ ty = ptrTy->elementType();
+ else
+ continue; // not a pointer or a reference to a pointer.
+
+ NamedType *namedTy = ty->asNamedType();
+ if (! namedTy) // not a class name.
+ continue;
+
+ const QList<Scope *> visibleScopes = context.visibleScopes(p);
+
+ const QList<Symbol *> classObjects =
+ context.resolveClass(namedTy->name(), visibleScopes);
+
+ if (classObjects.isEmpty())
+ continue;
+
+ Class *klass = classObjects.first()->asClass();
+
+ QList<Scope *> todo;
+ context.expand(klass->members(), visibleScopes, &todo);
+
+ foreach (Scope *scope, todo) {
+ if (! scope->isClassScope())
+ continue;
+
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ Symbol *member = scope->symbolAt(i);
+ Function *fun = member->type()->asFunction();
+ if (! fun)
+ continue;
+ if (wantSignals && ! fun->isSignal())
+ continue;
+ else if (! wantSignals && ! fun->isSlot())
+ continue;
+ if (TextEditor::CompletionItem item = toCompletionItem(fun)) {
+ unsigned count = fun->argumentCount();
+ while (true) {
+ TextEditor::CompletionItem i = item;
+
+ QString signature;
+ signature += overview.prettyName(fun->name());
+ signature += QLatin1Char('(');
+ for (unsigned i = 0; i < count; ++i) {
+ Symbol *arg = fun->argumentAt(i);
+ if (i != 0)
+ signature += QLatin1Char(',');
+ signature += o.prettyType(arg->type());
+ }
+ signature += QLatin1Char(')');
+
+ const QByteArray normalized =
+ QMetaObject::normalizedSignature(signature.toLatin1());
+
+ signature = QString::fromLatin1(normalized, normalized.size());
+
+ if (! signatures.contains(signature)) {
+ signatures.insert(signature);
+
+ i.m_text = signature; // fix the completion item.
+ m_completions.append(i);
+ }
+
+ if (count && fun->argumentAt(count - 1)->asArgument()->hasInitializer())
+ --count;
+ else
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ! m_completions.isEmpty();
+}
+
+void CppCodeCompletion::completions(QList<TextEditor::CompletionItem> *completions)
+{
+ const int length = m_editor->position() - m_startPosition;
+
+ if (length == 0)
+ *completions = m_completions;
+ else if (length > 0) {
+ const QString key = m_editor->textAt(m_startPosition, length);
+
+ if (m_completionOperator != T_LPAREN) {
+ /*
+ * This code builds a regular expression in order to more intelligently match
+ * camel-case style. This means upper-case characters will be rewritten as follows:
+ *
+ * A => [a-z0-9_]*A (for any but the first capital letter)
+ *
+ * Meaning it allows any sequence of lower-case characters to preceed an
+ * upper-case character. So for example gAC matches getActionController.
+ *
+ * The match is case-sensitive as soon as at least one upper-case character is
+ * present.
+ */
+ QString keyRegExp;
+ keyRegExp += QLatin1Char('^');
+ bool first = true;
+ Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive;
+ foreach (const QChar &c, key) {
+ if (c.isLower()) {
+ keyRegExp.append(c);
+ } else if (c.isUpper()) {
+ sensitivity = Qt::CaseSensitive;
+ if (!first) {
+ keyRegExp.append("[a-z0-9_]*");
+ }
+ keyRegExp.append(c);
+ } else {
+ keyRegExp.append(QRegExp::escape(c));
+ }
+ first = false;
+ }
+ const QRegExp regExp(keyRegExp, sensitivity);
+
+ foreach (TextEditor::CompletionItem item, m_completions) {
+ if (regExp.indexIn(item.m_text) == 0) {
+ item.m_relevance = (key.length() > 0 &&
+ item.m_text.startsWith(key, Qt::CaseInsensitive)) ? 1 : 0;
+ (*completions) << item;
+ }
+ }
+ } else if (m_completionOperator == T_LPAREN ||
+ m_completionOperator == T_SIGNAL ||
+ m_completionOperator == T_SLOT) {
+ foreach (TextEditor::CompletionItem item, m_completions) {
+ if (item.m_text.startsWith(key, Qt::CaseInsensitive)) {
+ (*completions) << item;
+ }
+ }
+ }
+ }
+}
+
+void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
+{
+ Symbol *symbol = 0;
+
+ if (item.m_data.isValid())
+ symbol = item.m_data.value<Symbol *>();
+
+ // qDebug() << "*** complete symbol:" << symbol->fileName() << symbol->line();
+
+ if (m_completionOperator == T_LPAREN) {
+ if (symbol) {
+ Function *function = symbol->type()->asFunction();
+ Q_ASSERT(function != 0);
+
+ m_functionArgumentWidget = new FunctionArgumentWidget(m_core);
+ m_functionArgumentWidget->showFunctionHint(function);
+ }
+ } else if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
+ QString toInsert = item.m_text;
+ toInsert += QLatin1Char(')');
+ // Insert the remainder of the name
+ int length = m_editor->position() - m_startPosition;
+ m_editor->setCurPos(m_startPosition);
+ m_editor->replace(length, toInsert);
+ } else {
+ QString toInsert = item.m_text;
+
+ //qDebug() << "current symbol:" << overview.prettyName(symbol->name())
+ //<< overview.prettyType(symbol->type());
+
+ if (symbol) {
+ if (Function *function = symbol->type()->asFunction()) {
+ // If the member is a function, automatically place the opening parenthesis,
+ // except when it might take template parameters.
+ if (!function->returnType().isValid()
+ && (function->identity() && !function->identity()->isDestructorNameId())) {
+ // Don't insert any magic, since the user might have just wanted to select the class
+
+ } else if (function->templateParameterCount() != 0) {
+ // If there are no arguments, then we need the template specification
+ if (function->argumentCount() == 0) {
+ toInsert.append(QLatin1Char('<'));
+ }
+ } else {
+ toInsert.append(QLatin1Char('('));
+
+ // If the function takes no arguments, automatically place the closing parenthesis
+ if (function->argumentCount() == 0 || (function->argumentCount() == 1 &&
+ function->argumentAt(0)->type()->isVoidType())) {
+ toInsert.append(QLatin1Char(')'));
+
+ // If the function doesn't return anything, automatically place the semicolon,
+ // unless we're doing a scope completion (then it might be function definition).
+ if (function->returnType()->isVoidType() && m_completionOperator != T_COLON_COLON) {
+ toInsert.append(QLatin1Char(';'));
+ }
+ }
+ }
+ }
+ }
+
+ // Insert the remainder of the name
+ int length = m_editor->position() - m_startPosition;
+ m_editor->setCurPos(m_startPosition);
+ m_editor->replace(length, toInsert);
+ }
+}
+
+bool CppCodeCompletion::partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems)
+{
+ if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
+ return false;
+ } else if (completionItems.count() == 1) {
+ complete(completionItems.first());
+ return true;
+ } else if (m_completionOperator != T_LPAREN) {
+ // Compute common prefix
+ QString firstKey = completionItems.first().m_text;
+ QString lastKey = completionItems.last().m_text;
+ const int length = qMin(firstKey.length(), lastKey.length());
+ firstKey.truncate(length);
+ lastKey.truncate(length);
+
+ while (firstKey != lastKey) {
+ firstKey.chop(1);
+ lastKey.chop(1);
+ }
+
+ int typedLength = m_editor->position() - m_startPosition;
+ if (!firstKey.isEmpty() && firstKey.length() > typedLength) {
+ m_editor->setCurPos(m_startPosition);
+ m_editor->replace(typedLength, firstKey);
+ }
+ }
+
+ return false;
+}
+
+void CppCodeCompletion::cleanup()
+{
+ m_completions.clear();
+}
+
+int CppCodeCompletion::findStartOfName(const TextEditor::ITextEditor *editor)
+{
+ int pos = editor->position();
+ QChar chr;
+
+ // Skip to the start of a name
+ do {
+ chr = editor->characterAt(--pos);
+ } while (chr.isLetterOrNumber() || chr == QLatin1Char('_'));
+
+ return pos + 1;
+}
diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h
new file mode 100644
index 0000000000..4977393521
--- /dev/null
+++ b/src/plugins/cpptools/cppcodecompletion.h
@@ -0,0 +1,145 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPCODECOMPLETION_H
+#define CPPCODECOMPLETION_H
+
+// Qt
+#include <QtCore/QObject>
+#include <QtCore/QPointer>
+
+// C++ front-end
+#include <ASTfwd.h>
+#include <FullySpecifiedType.h>
+#include <cplusplus/Icons.h>
+#include <cplusplus/Overview.h>
+#include <cplusplus/TypeOfExpression.h>
+
+// Qt Creator
+#include <texteditor/icompletioncollector.h>
+
+namespace Core {
+class ICore;
+}
+
+namespace TextEditor {
+class ITextEditor;
+}
+
+namespace CppTools {
+namespace Internal {
+
+class CppModelManager;
+class FunctionArgumentWidget;
+
+class CppCodeCompletion : public TextEditor::ICompletionCollector
+{
+ Q_OBJECT
+public:
+ CppCodeCompletion(CppModelManager *manager, Core::ICore *core);
+
+ bool triggersCompletion(TextEditor::ITextEditable *editor);
+ int startCompletion(TextEditor::ITextEditable *editor);
+ void completions(QList<TextEditor::CompletionItem> *completions);
+
+ void complete(const TextEditor::CompletionItem &item);
+ bool partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems);
+ void cleanup();
+
+ QIcon iconForSymbol(CPlusPlus::Symbol *symbol) const;
+
+private:
+ void addKeywords();
+ void addMacros(const CPlusPlus::LookupContext &context);
+ void addCompletionItem(CPlusPlus::Symbol *symbol);
+
+ bool completeFunction(CPlusPlus::FullySpecifiedType exprTy,
+ const QList<CPlusPlus::TypeOfExpression::Result> &,
+ const CPlusPlus::LookupContext &context);
+
+ bool completeMember(CPlusPlus::FullySpecifiedType exprTy,
+ const QList<CPlusPlus::TypeOfExpression::Result> &,
+ const CPlusPlus::LookupContext &context);
+
+ bool completeScope(CPlusPlus::FullySpecifiedType exprTy,
+ const QList<CPlusPlus::TypeOfExpression::Result> &,
+ const CPlusPlus::LookupContext &context);
+
+ void completeNamespace(const QList<CPlusPlus::Symbol *> &candidates,
+ const CPlusPlus::LookupContext &context);
+
+ void completeClass(const QList<CPlusPlus::Symbol *> &candidates,
+ const CPlusPlus::LookupContext &context,
+ bool staticLookup = true);
+
+ bool completeQtMethod(CPlusPlus::FullySpecifiedType exprTy,
+ const QList<CPlusPlus::TypeOfExpression::Result> &,
+ const CPlusPlus::LookupContext &context,
+ bool wantSignals);
+
+ bool completeSignal(CPlusPlus::FullySpecifiedType exprTy,
+ const QList<CPlusPlus::TypeOfExpression::Result> &results,
+ const CPlusPlus::LookupContext &context)
+ { return completeQtMethod(exprTy, results, context, true); }
+
+ bool completeSlot(CPlusPlus::FullySpecifiedType exprTy,
+ const QList<CPlusPlus::TypeOfExpression::Result> &results,
+ const CPlusPlus::LookupContext &context)
+ { return completeQtMethod(exprTy, results, context, false); }
+
+ static int findStartOfName(const TextEditor::ITextEditor *editor);
+
+ QList<TextEditor::CompletionItem> m_completions;
+
+ TextEditor::ITextEditable *m_editor;
+ int m_startPosition; // Position of the cursor from which completion started
+
+ Core::ICore *m_core;
+ CppModelManager *m_manager;
+
+ bool m_forcedCompletion;
+
+ CPlusPlus::Icons m_icons;
+ CPlusPlus::Overview overview;
+ CPlusPlus::TypeOfExpression typeOfExpression;
+
+ unsigned m_completionOperator;
+
+ QPointer<FunctionArgumentWidget> m_functionArgumentWidget;
+};
+
+} // namespace Internal
+} // namespace CppTools
+
+Q_DECLARE_METATYPE(CPlusPlus::Symbol *)
+
+#endif // CPPCODECOMPLETION_H
diff --git a/src/plugins/cpptools/cpphoverhandler.cpp b/src/plugins/cpptools/cpphoverhandler.cpp
new file mode 100644
index 0000000000..dc9bb96661
--- /dev/null
+++ b/src/plugins/cpptools/cpphoverhandler.cpp
@@ -0,0 +1,243 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cpphoverhandler.h"
+#include "cppmodelmanager.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <texteditor/itexteditor.h>
+#include <debugger/debuggerconstants.h>
+
+#include <CoreTypes.h>
+#include <FullySpecifiedType.h>
+#include <Literals.h>
+#include <Names.h>
+#include <Scope.h>
+#include <Symbol.h>
+#include <Symbols.h>
+#include <cplusplus/ExpressionUnderCursor.h>
+#include <cplusplus/Overview.h>
+#include <cplusplus/TypeOfExpression.h>
+
+#include <QtGui/QToolTip>
+#include <QtGui/QPlainTextEdit>
+#include <QtGui/QTextCursor>
+#include <QtGui/QTextBlock>
+#include <QtHelp/QHelpEngineCore>
+#include <QtCore/QtCore>
+
+using namespace CppTools::Internal;
+
+CppHoverHandler::CppHoverHandler(CppModelManager *manager, QObject *parent)
+ : QObject(parent), m_manager(manager)
+{
+ QFileInfo fi(ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()->settings()->fileName());
+ m_helpEngine = new QHelpEngineCore(fi.absolutePath()
+ + QLatin1String("/helpcollection.qhc"), this);
+ //m_helpEngine->setAutoSaveFilter(false);
+ m_helpEngine->setupData();
+ m_helpEngine->setCurrentFilter(tr("Unfiltered"));
+}
+
+void CppHoverHandler::updateContextHelpId(TextEditor::ITextEditor *editor, int pos)
+{
+ updateHelpIdAndTooltip(editor, pos);
+}
+
+void CppHoverHandler::showToolTip(TextEditor::ITextEditor *editor, const QPoint &point, int pos)
+{
+ const int dbgcontext = m_manager->core()->
+ uniqueIDManager()->uniqueIdentifier(Debugger::Constants::C_GDBDEBUGGER);
+
+ if (m_manager->core()->hasContext(dbgcontext))
+ return;
+
+ if (! editor)
+ return;
+
+ updateHelpIdAndTooltip(editor, pos);
+
+ if (m_toolTip.isEmpty())
+ QToolTip::hideText();
+ else {
+ const QPoint pnt = point - QPoint(0,
+#ifdef Q_WS_WIN
+ 24
+#else
+ 16
+#endif
+ );
+
+ QToolTip::showText(pnt, m_toolTip);
+ }
+}
+
+static QString buildHelpId(const CPlusPlus::FullySpecifiedType &type,
+ const CPlusPlus::Symbol *symbol)
+{
+ using namespace CPlusPlus;
+
+ Name *name = 0;
+ Scope *scope = 0;
+
+ if (const Function *f = type->asFunction()) {
+ name = f->name();
+ scope = f->scope();
+ } else if (const Class *c = type->asClass()) {
+ name = c->name();
+ scope = c->scope();
+ } else if (const Enum *e = type->asEnum()) {
+ name = e->name();
+ scope = e->scope();
+ } else if (const NamedType *t = type->asNamedType()) {
+ name = t->name();
+ } else if (const Declaration *d = symbol->asDeclaration()) {
+ if (d->scope() && d->scope()->owner()->isEnum()) {
+ name = d->name();
+ scope = d->scope();
+ }
+ }
+
+ Overview overview;
+ overview.setShowArgumentNames(false);
+ overview.setShowReturnTypes(false);
+
+ QStringList qualifiedNames;
+ qualifiedNames.prepend(overview.prettyName(name));
+
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->owner() && scope->owner()->name() && !scope->isEnumScope()) {
+ Name *name = scope->owner()->name();
+ Identifier *id = 0;
+ if (NameId *nameId = name->asNameId()) {
+ id = nameId->identifier();
+ } else if (TemplateNameId *nameId = name->asTemplateNameId()) {
+ id = nameId->identifier();
+ }
+ if (id)
+ qualifiedNames.prepend(QString::fromLatin1(id->chars(), id->size()));
+ }
+ }
+
+ return qualifiedNames.join(QLatin1String("::"));
+}
+
+void CppHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, int pos)
+{
+ using namespace CPlusPlus;
+
+ m_helpId.clear();
+ m_toolTip.clear();
+
+ QPlainTextEdit *edit = qobject_cast<QPlainTextEdit *>(editor->widget());
+ if (!edit)
+ return;
+
+ QTextCursor tc(edit->document());
+ tc.setPosition(pos);
+
+ const int lineNumber = tc.block().blockNumber() + 1;
+
+ QString fileName = editor->file()->fileName();
+ Document::Ptr doc = m_manager->document(fileName);
+ if (doc) {
+ foreach (Document::DiagnosticMessage m, doc->diagnosticMessages()) {
+ if (m.line() == lineNumber) {
+ m_toolTip = m.text();
+ break;
+ }
+ }
+ }
+
+ if (m_toolTip.isEmpty()) {
+ // Move to the end of a qualified name
+ bool stop = false;
+ while (!stop) {
+ const QChar ch = editor->characterAt(tc.position());
+ if (ch.isLetterOrNumber() || ch == QLatin1Char('_'))
+ tc.setPosition(tc.position() + 1);
+ else if (ch == QLatin1Char(':') && editor->characterAt(tc.position() + 1) == QLatin1Char(':')) {
+ tc.setPosition(tc.position() + 2);
+ } else {
+ stop = true;
+ }
+ }
+
+ // Fetch the expression's code.
+ ExpressionUnderCursor expressionUnderCursor;
+ const QString expression = expressionUnderCursor(tc);
+
+ if (doc) {
+ // Find the last symbol up to the cursor position
+ int line = 0, column = 0;
+ editor->convertPosition(tc.position(), &line, &column);
+ Symbol *lastSymbol = doc->findSymbolAt(line, column);
+
+ TypeOfExpression typeOfExpression;
+ typeOfExpression.setDocuments(m_manager->documents());
+ QList<TypeOfExpression::Result> types = typeOfExpression(expression, doc, lastSymbol);
+
+ if (!types.isEmpty()) {
+ FullySpecifiedType firstType = types.first().first;
+ FullySpecifiedType docType = firstType;
+
+ if (const PointerType *pt = firstType->asPointerType()) {
+ docType = pt->elementType();
+ } else if (const ReferenceType *rt = firstType->asReferenceType()) {
+ docType = rt->elementType();
+ }
+
+
+ m_helpId = buildHelpId(docType, types.first().second);
+ QString displayName = buildHelpId(firstType, types.first().second);
+
+ if (!firstType->isClass() && !firstType->isNamedType()) {
+ Overview overview;
+ overview.setShowArgumentNames(true);
+ overview.setShowReturnTypes(true);
+ m_toolTip = overview.prettyType(firstType, displayName);
+ } else {
+ m_toolTip = m_helpId;
+ }
+ }
+ }
+ }
+
+ if (!m_helpId.isEmpty() && !m_helpEngine->linksForIdentifier(m_helpId).isEmpty()) {
+ m_toolTip = QString(QLatin1String("<table><tr><td valign=middle><nobr>%1</td>"
+ "<td><img src=\":/cpptools/images/f1.svg\"></td></tr></table>")).arg(Qt::escape(m_toolTip));
+ editor->setContextHelpId(m_helpId);
+ } else if (!m_toolTip.isEmpty()) {
+ m_toolTip = QString(QLatin1String("<nobr>%1")).arg(Qt::escape(m_toolTip));
+ }
+}
diff --git a/src/plugins/cpptools/cpphoverhandler.h b/src/plugins/cpptools/cpphoverhandler.h
new file mode 100644
index 0000000000..ca828c35db
--- /dev/null
+++ b/src/plugins/cpptools/cpphoverhandler.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPHOVERHANDLER_H
+#define CPPHOVERHANDLER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QPoint>
+
+QT_BEGIN_NAMESPACE
+class QHelpEngineCore;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+class ITextEditor;
+}
+
+namespace CppTools {
+namespace Internal {
+
+class CppModelManager;
+
+class CppHoverHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ CppHoverHandler(CppModelManager *manager, QObject *parent);
+
+public slots:
+ void showToolTip(TextEditor::ITextEditor *editor, const QPoint &point, int pos);
+ void updateContextHelpId(TextEditor::ITextEditor *editor, int pos);
+
+private:
+ void updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, int pos);
+
+ CppModelManager *m_manager;
+ QHelpEngineCore *m_helpEngine;
+ QString m_helpId;
+ QString m_toolTip;
+};
+
+} // namespace Internal
+} // namespace CppTools
+
+#endif // CPPHOVERHANDLER_H
diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp
new file mode 100644
index 0000000000..6ec5391267
--- /dev/null
+++ b/src/plugins/cpptools/cppmodelmanager.cpp
@@ -0,0 +1,740 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#define _SCL_SECURE_NO_WARNINGS 1
+#include "pp.h"
+
+#include "cppmodelmanager.h"
+#include "cpphoverhandler.h"
+#include "cpptoolsconstants.h"
+#include "cpptoolseditorsupport.h"
+
+#include <qtconcurrent/runextensions.h>
+#include <texteditor/itexteditor.h>
+#include <texteditor/basetexteditor.h>
+
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/session.h>
+
+#include <coreplugin/icore.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/progressmanager/progressmanager.h>
+
+#include <TranslationUnit.h>
+#include <Semantic.h>
+#include <AST.h>
+#include <Scope.h>
+#include <Literals.h>
+#include <Symbols.h>
+#include <Names.h>
+#include <NameVisitor.h>
+#include <TypeVisitor.h>
+#include <Lexer.h>
+#include <Token.h>
+
+#include <QPlainTextEdit>
+#include <QTime>
+#include <QDebug>
+
+using namespace CPlusPlus;
+
+namespace CppTools {
+namespace Internal {
+
+static const char pp_configuration_file[] = "<configuration>";
+
+static const char pp_configuration[] =
+ "# 1 \"<configuration>\"\n"
+ "#define __GNUC_MINOR__ 0\n"
+ "#define __GNUC__ 4\n"
+ "#define __GNUG__ 4\n"
+ "#define __STDC_HOSTED__ 1\n"
+ "#define __VERSION__ \"4.0.1 (fake)\"\n"
+ "#define __cplusplus 1\n"
+
+ "#define __extension__\n"
+ "#define __context__\n"
+ "#define __range__\n"
+ "#define __asm(a...)\n"
+ "#define __asm__(a...)\n"
+ "#define restrict\n"
+ "#define __restrict\n"
+
+ // ### add macros for win32
+ "#define __cdecl\n"
+ "#define QT_WA(x) x\n"
+ "#define API\n"
+ "#define WINAPI\n"
+ "#define CALLBACK\n"
+ "#define STDMETHODCALLTYPE\n"
+ "#define __RPC_FAR\n"
+ "#define APIENTRY\n"
+ "#define __declspec(a)\n"
+ "#define STDMETHOD(method) virtual HRESULT STDMETHODCALLTYPE method\n";
+
+class CppPreprocessor: public rpp::Client
+{
+public:
+ CppPreprocessor(QPointer<CppModelManager> modelManager)
+ : m_modelManager(modelManager),
+ m_documents(modelManager->documents()),
+ m_proc(this, env)
+ { }
+
+ void setWorkingCopy(const QMap<QString, QByteArray> &workingCopy)
+ { m_workingCopy = workingCopy; }
+
+ void setIncludePaths(const QStringList &includePaths)
+ { m_includePaths = includePaths; }
+
+ void setFrameworkPaths(const QStringList &frameworkPaths)
+ { m_frameworkPaths = frameworkPaths; }
+
+ void addIncludePath(const QString &path)
+ { m_includePaths.append(path); }
+
+ void setProjectFiles(const QStringList &files)
+ { m_projectFiles = files; }
+
+ void operator()(QString &fileName)
+ { sourceNeeded(fileName, IncludeGlobal); }
+
+protected:
+ bool includeFile(const QString &absoluteFilePath, QByteArray *result)
+ {
+ if (absoluteFilePath.isEmpty() || m_included.contains(absoluteFilePath)) {
+ return true;
+ }
+
+ if (m_workingCopy.contains(absoluteFilePath)) {
+ m_included.insert(absoluteFilePath);
+ *result = m_workingCopy.value(absoluteFilePath);
+ return true;
+ }
+
+ QFileInfo fileInfo(absoluteFilePath);
+ if (! fileInfo.isFile())
+ return false;
+
+ QFile file(absoluteFilePath);
+ if (file.open(QFile::ReadOnly)) {
+ m_included.insert(absoluteFilePath);
+ QTextStream stream(&file);
+ const QString contents = stream.readAll();
+ *result = contents.toUtf8();
+ file.close();
+ return true;
+ }
+
+ return false;
+ }
+
+ QByteArray tryIncludeFile(QString &fileName, IncludeType type)
+ {
+ QFileInfo fileInfo(fileName);
+ if (fileName == QLatin1String(pp_configuration_file) || fileInfo.isAbsolute()) {
+ QByteArray contents;
+ includeFile(fileName, &contents);
+ return contents;
+ }
+
+ if (type == IncludeLocal && m_currentDoc) {
+ QFileInfo currentFileInfo(m_currentDoc->fileName());
+ QString path = currentFileInfo.absolutePath();
+ path += QLatin1Char('/');
+ path += fileName;
+ path = QDir::cleanPath(path);
+ QByteArray contents;
+ if (includeFile(path, &contents)) {
+ fileName = path;
+ return contents;
+ }
+ }
+
+ foreach (const QString &includePath, m_includePaths) {
+ QString path = includePath;
+ path += QLatin1Char('/');
+ path += fileName;
+ path = QDir::cleanPath(path);
+ QByteArray contents;
+ if (includeFile(path, &contents)) {
+ fileName = path;
+ return contents;
+ }
+ }
+
+ // look in the system include paths
+ foreach (const QString &includePath, m_systemIncludePaths) {
+ QString path = includePath;
+ path += QLatin1Char('/');
+ path += fileName;
+ path = QDir::cleanPath(path);
+ QByteArray contents;
+ if (includeFile(path, &contents)) {
+ fileName = path;
+ return contents;
+ }
+ }
+
+ int index = fileName.indexOf(QLatin1Char('/'));
+ if (index != -1) {
+ QString frameworkName = fileName.left(index);
+ QString name = fileName.mid(index + 1);
+
+ foreach (const QString &frameworkPath, m_frameworkPaths) {
+ QString path = frameworkPath;
+ path += QLatin1Char('/');
+ path += frameworkName;
+ path += QLatin1String(".framework/Headers/");
+ path += name;
+ QByteArray contents;
+ if (includeFile(path, &contents)) {
+ fileName = path;
+ return contents;
+ }
+ }
+ }
+
+ QString path = fileName;
+ if (path.at(0) != QLatin1Char('/'))
+ path.prepend(QLatin1Char('/'));
+
+ foreach (const QString &projectFile, m_projectFiles) {
+ if (projectFile.endsWith(path)) {
+ fileName = projectFile;
+ QByteArray contents;
+ includeFile(fileName, &contents);
+ return contents;
+ }
+ }
+
+ //qDebug() << "**** file" << fileName << "not found!";
+ return QByteArray();
+ }
+
+ virtual void macroAdded(const QByteArray &macroName, const QByteArray &macroText)
+ {
+ if (! m_currentDoc)
+ return;
+
+ m_currentDoc->appendMacro(macroName, macroText);
+ }
+
+ void mergeEnvironment(Document::Ptr doc)
+ {
+ QSet<QString> processed;
+ mergeEnvironment(doc, &processed);
+ }
+
+ void mergeEnvironment(Document::Ptr doc, QSet<QString> *processed)
+ {
+ if (! doc)
+ return;
+
+ const QString fn = doc->fileName();
+
+ if (processed->contains(fn))
+ return;
+
+ processed->insert(fn);
+
+ foreach (QString includedFile, doc->includedFiles())
+ mergeEnvironment(m_documents.value(includedFile), processed);
+
+ const QByteArray macros = doc->definedMacros();
+ QByteArray localFileName = doc->fileName().toUtf8();
+
+ QByteArray dummy;
+ m_proc(localFileName, macros, &dummy);
+ }
+
+ virtual void startSkippingBlocks(unsigned offset)
+ {
+ //qDebug() << "start skipping blocks:" << offset;
+ if (m_currentDoc)
+ m_currentDoc->startSkippingBlocks(offset);
+ }
+
+ virtual void stopSkippingBlocks(unsigned offset)
+ {
+ //qDebug() << "stop skipping blocks:" << offset;
+ if (m_currentDoc)
+ m_currentDoc->stopSkippingBlocks(offset);
+ }
+
+ virtual void sourceNeeded(QString &fileName, IncludeType type)
+ {
+ if (fileName.isEmpty())
+ return;
+
+ QByteArray contents = tryIncludeFile(fileName, type);
+
+ if (m_currentDoc) {
+ m_currentDoc->addIncludeFile(fileName);
+ if (contents.isEmpty() && ! QFileInfo(fileName).isAbsolute()) {
+ QString msg;
+ msg += fileName;
+ msg += QLatin1String(": No such file or directory");
+ Document::DiagnosticMessage d(Document::DiagnosticMessage::Warning,
+ m_currentDoc->fileName(),
+ env.currentLine, /*column = */ 0,
+ msg);
+ m_currentDoc->addDiagnosticMessage(d);
+ //qWarning() << "file not found:" << fileName << m_currentDoc->fileName() << env.current_line;
+ }
+ }
+
+ if (! contents.isEmpty()) {
+ Document::Ptr cachedDoc = m_documents.value(fileName);
+ if (cachedDoc && m_currentDoc) {
+ mergeEnvironment(cachedDoc);
+ } else {
+ Document::Ptr previousDoc = switchDocument(Document::create(fileName));
+
+ const QByteArray previousFile = env.current_file;
+ const unsigned previousLine = env.currentLine;
+
+ env.current_file = QByteArray(m_currentDoc->translationUnit()->fileName(),
+ m_currentDoc->translationUnit()->fileNameLength());
+
+ QByteArray preprocessedCode;
+ m_proc(contents, &preprocessedCode);
+ //qDebug() << preprocessedCode;
+
+ env.current_file = previousFile;
+ env.currentLine = previousLine;
+
+ m_currentDoc->setSource(preprocessedCode);
+ m_currentDoc->parse();
+ m_currentDoc->check();
+ m_currentDoc->releaseTranslationUnit(); // release the AST and the token stream.
+
+ if (m_modelManager)
+ m_modelManager->emitDocumentUpdated(m_currentDoc);
+ (void) switchDocument(previousDoc);
+ }
+ }
+ }
+
+ Document::Ptr switchDocument(Document::Ptr doc)
+ {
+ Document::Ptr previousDoc = m_currentDoc;
+ m_currentDoc = doc;
+ return previousDoc;
+ }
+
+private:
+ QPointer<CppModelManager> m_modelManager;
+ CppModelManager::DocumentTable m_documents;
+ rpp::Environment env;
+ rpp::pp m_proc;
+ QStringList m_includePaths;
+ QStringList m_systemIncludePaths;
+ QMap<QString, QByteArray> m_workingCopy;
+ QStringList m_projectFiles;
+ QStringList m_frameworkPaths;
+ QSet<QString> m_included;
+ Document::Ptr m_currentDoc;
+};
+
+} // namespace Internal
+} // namespace CppTools
+
+
+using namespace CppTools;
+using namespace CppTools::Internal;
+
+/*!
+ \class CppTools::CppModelManager
+ \brief The CppModelManager keeps track of one CppCodeModel instance
+ for each project and all related CppCodeModelPart instances.
+
+ It also takes care of updating the code models when C++ files are
+ modified within Workbench.
+*/
+
+CppModelManager::CppModelManager(QObject *parent) :
+ CppModelManagerInterface(parent),
+ m_core(ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>())
+{
+ m_projectExplorer = ExtensionSystem::PluginManager::instance()
+ ->getObject<ProjectExplorer::ProjectExplorerPlugin>();
+
+ Q_ASSERT(m_projectExplorer);
+
+ ProjectExplorer::SessionManager *session = m_projectExplorer->session();
+ Q_ASSERT(session != 0);
+
+ connect(session, SIGNAL(aboutToRemoveProject(ProjectExplorer::Project *)),
+ this, SLOT(onAboutToRemoveProject(ProjectExplorer::Project *)));
+
+ connect(session, SIGNAL(sessionUnloaded()),
+ this, SLOT(onSessionUnloaded()));
+
+ qRegisterMetaType<CPlusPlus::Document::Ptr>("CPlusPlus::Document::Ptr");
+
+ // thread connections
+ connect(this, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)),
+ this, SLOT(onDocumentUpdated(CPlusPlus::Document::Ptr)));
+
+ m_hoverHandler = new CppHoverHandler(this, this);
+
+ // Listen for editor closed and opened events so that we can keep track of changing files
+ connect(m_core->editorManager(), SIGNAL(editorOpened(Core::IEditor *)),
+ this, SLOT(editorOpened(Core::IEditor *)));
+
+ connect(m_core->editorManager(), SIGNAL(editorAboutToClose(Core::IEditor *)),
+ this, SLOT(editorAboutToClose(Core::IEditor *)));
+}
+
+CppModelManager::~CppModelManager()
+{ }
+
+Document::Ptr CppModelManager::document(const QString &fileName)
+{ return m_documents.value(fileName); }
+
+CppModelManager::DocumentTable CppModelManager::documents()
+{ return m_documents; }
+
+QStringList CppModelManager::projectFiles() const
+{
+ QStringList files;
+ QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects);
+ while (it.hasNext()) {
+ it.next();
+ ProjectInfo pinfo = it.value();
+ files += pinfo.sourceFiles;
+ }
+ return files;
+}
+
+QStringList CppModelManager::includePaths() const
+{
+ QStringList includePaths;
+ QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects);
+ while (it.hasNext()) {
+ it.next();
+ ProjectInfo pinfo = it.value();
+ includePaths += pinfo.includePaths;
+ }
+ return includePaths;
+}
+
+QStringList CppModelManager::frameworkPaths() const
+{
+ QStringList frameworkPaths;
+ QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects);
+ while (it.hasNext()) {
+ it.next();
+ ProjectInfo pinfo = it.value();
+ frameworkPaths += pinfo.frameworkPaths;
+ }
+ return frameworkPaths;
+}
+
+QByteArray CppModelManager::definedMacros() const
+{
+ QByteArray macros;
+ QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects);
+ while (it.hasNext()) {
+ it.next();
+ ProjectInfo pinfo = it.value();
+ macros += pinfo.defines;
+ }
+ return macros;
+}
+
+QMap<QString, QByteArray> CppModelManager::buildWorkingCopyList() const
+{
+ QMap<QString, QByteArray> workingCopy;
+ QMapIterator<TextEditor::ITextEditor *, CppEditorSupport *> it(m_editorSupport);
+ while (it.hasNext()) {
+ it.next();
+ TextEditor::ITextEditor *textEditor = it.key();
+ CppEditorSupport *editorSupport = it.value();
+ QString fileName = textEditor->file()->fileName();
+ workingCopy[fileName] = editorSupport->contents().toUtf8();
+ }
+
+ // add the project configuration file
+ QByteArray conf(pp_configuration);
+ conf += definedMacros();
+ workingCopy[pp_configuration_file] = conf;
+
+ return workingCopy;
+}
+
+void CppModelManager::updateSourceFiles(const QStringList &sourceFiles)
+{ (void) refreshSourceFiles(sourceFiles); }
+
+CppModelManager::ProjectInfo *CppModelManager::projectInfo(ProjectExplorer::Project *project)
+{ return &m_projects[project]; }
+
+QFuture<void> CppModelManager::refreshSourceFiles(const QStringList &sourceFiles)
+{
+ if (qgetenv("QTCREATOR_NO_CODE_INDEXER").isNull()) {
+ const QMap<QString, QByteArray> workingCopy = buildWorkingCopyList();
+
+ QFuture<void> result = QtConcurrent::run(&CppModelManager::parse, this,
+ sourceFiles, workingCopy);
+
+ if (sourceFiles.count() > 1) {
+ m_core->progressManager()->addTask(result, tr("Indexing"),
+ CppTools::Constants::TASK_INDEX,
+ Core::ProgressManagerInterface::CloseOnSuccess);
+ }
+ return result;
+ }
+ return QFuture<void>();
+}
+
+/*!
+ \fn void CppModelManager::editorOpened(Core::IEditor *editor)
+ \brief If a C++ editor is opened, the model manager listens to content changes
+ in order to update the CppCodeModel accordingly. It also updates the
+ CppCodeModel for the first time with this editor.
+
+ \sa void CppModelManager::editorContentsChanged()
+ */
+void CppModelManager::editorOpened(Core::IEditor *editor)
+{
+ if (isCppEditor(editor)) {
+ TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor *>(editor);
+ Q_ASSERT(textEditor != 0);
+
+ CppEditorSupport *editorSupport = new CppEditorSupport(this);
+ editorSupport->setTextEditor(textEditor);
+ m_editorSupport[textEditor] = editorSupport;
+
+ // ### move in CppEditorSupport
+ connect(editor, SIGNAL(tooltipRequested(TextEditor::ITextEditor*, QPoint, int)),
+ m_hoverHandler, SLOT(showToolTip(TextEditor::ITextEditor*, QPoint, int)));
+
+ // ### move in CppEditorSupport
+ connect(editor, SIGNAL(contextHelpIdRequested(TextEditor::ITextEditor*, int)),
+ m_hoverHandler, SLOT(updateContextHelpId(TextEditor::ITextEditor*, int)));
+ }
+}
+
+void CppModelManager::editorAboutToClose(Core::IEditor *editor)
+{
+ if (isCppEditor(editor)) {
+ TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor *>(editor);
+ Q_ASSERT(textEditor != 0);
+
+ CppEditorSupport *editorSupport = m_editorSupport.value(textEditor);
+ m_editorSupport.remove(textEditor);
+ delete editorSupport;
+ }
+}
+
+bool CppModelManager::isCppEditor(Core::IEditor *editor) const
+{
+ Core::UniqueIDManager *uidm = m_core->uniqueIDManager();
+ const int uid = uidm->uniqueIdentifier(ProjectExplorer::Constants::LANG_CXX);
+ return editor->context().contains(uid);
+}
+
+void CppModelManager::emitDocumentUpdated(Document::Ptr doc)
+{ emit documentUpdated(doc); }
+
+void CppModelManager::onDocumentUpdated(Document::Ptr doc)
+{
+ const QString fileName = doc->fileName();
+ m_documents[fileName] = doc;
+ QList<Core::IEditor *> openedEditors = m_core->editorManager()->openedEditors();
+ foreach (Core::IEditor *editor, openedEditors) {
+ if (editor->file()->fileName() == fileName) {
+ TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor *>(editor);
+ if (! textEditor)
+ continue;
+
+ TextEditor::BaseTextEditor *ed = qobject_cast<TextEditor::BaseTextEditor *>(textEditor->widget());
+ if (! ed)
+ continue;
+
+ QList<TextEditor::BaseTextEditor::BlockRange> blockRanges;
+
+ foreach (const Document::Block block, doc->skippedBlocks()) {
+ blockRanges.append(TextEditor::BaseTextEditor::BlockRange(block.begin(), block.end()));
+ }
+ ed->setIfdefedOutBlocks(blockRanges);
+
+ QList<QTextEdit::ExtraSelection> selections;
+
+ // set up the format for the errors
+ QTextCharFormat errorFormat;
+ errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline);
+ errorFormat.setUnderlineColor(Qt::red);
+
+ // set up the format for the warnings.
+ QTextCharFormat warningFormat;
+ warningFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline);
+ warningFormat.setUnderlineColor(Qt::darkYellow);
+
+ QSet<int> lines;
+ foreach (const Document::DiagnosticMessage m, doc->diagnosticMessages()) {
+ if (m.fileName() != fileName)
+ continue;
+ else if (lines.contains(m.line()))
+ continue;
+ else if (lines.size() == MAX_SELECTION_COUNT)
+ break; // we're done.
+
+ lines.insert(m.line());
+
+ QTextEdit::ExtraSelection sel;
+ if (m.isWarning())
+ sel.format = warningFormat;
+ else
+ sel.format = errorFormat;
+
+ QTextCursor c(ed->document()->findBlockByNumber(m.line() - 1));
+ const QString text = c.block().text();
+ for (int i = 0; i < text.size(); ++i) {
+ if (! text.at(i).isSpace()) {
+ c.setPosition(c.position() + i);
+ break;
+ }
+ }
+ c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+ sel.cursor = c;
+ selections.append(sel);
+ }
+ ed->setExtraExtraSelections(selections);
+ break;
+ }
+ }
+}
+
+void CppModelManager::onAboutToRemoveProject(ProjectExplorer::Project *project)
+{
+ m_projects.remove(project);
+ GC();
+}
+
+void CppModelManager::onSessionUnloaded()
+{
+ if (m_core->progressManager())
+ m_core->progressManager()->cancelTasks(CppTools::Constants::TASK_INDEX);
+}
+
+void CppModelManager::parse(QFutureInterface<void> &future,
+ CppModelManager *model,
+ QStringList files,
+ QMap<QString, QByteArray> workingCopy)
+{
+ // Change the priority of the background parser thread to idle.
+ QThread::currentThread()->setPriority(QThread::IdlePriority);
+
+ future.setProgressRange(0, files.size());
+
+ CppPreprocessor preproc(model);
+ preproc.setWorkingCopy(workingCopy);
+ preproc.setProjectFiles(model->projectFiles());
+ preproc.setIncludePaths(model->includePaths());
+ preproc.setFrameworkPaths(model->frameworkPaths());
+
+ QString conf = QLatin1String(pp_configuration_file);
+ (void) preproc(conf);
+
+ const int STEP = 10;
+
+ for (int i = 0; i < files.size(); ++i) {
+ if (future.isPaused())
+ future.waitForResume();
+
+ if (future.isCanceled())
+ break;
+
+ future.setProgressValue(i);
+
+#ifdef CPPTOOLS_DEBUG_PARSING_TIME
+ QTime tm;
+ tm.start();
+#endif
+
+ QString fileName = files.at(i);
+ preproc(fileName);
+
+ if (! (i % STEP)) // Yields execution of the current thread.
+ QThread::yieldCurrentThread();
+
+#ifdef CPPTOOLS_DEBUG_PARSING_TIME
+ qDebug() << fileName << "parsed in:" << tm.elapsed();
+#endif
+ }
+
+ // Restore the previous thread priority.
+ QThread::currentThread()->setPriority(QThread::NormalPriority);
+}
+
+void CppModelManager::GC()
+{
+ DocumentTable documents = m_documents;
+
+ QSet<QString> processed;
+ QStringList todo = m_projectFiles;
+
+ while (! todo.isEmpty()) {
+ QString fn = todo.last();
+ todo.removeLast();
+
+ if (processed.contains(fn))
+ continue;
+
+ processed.insert(fn);
+
+ if (Document::Ptr doc = documents.value(fn)) {
+ todo += doc->includedFiles();
+ }
+ }
+
+ QStringList removedFiles;
+ QMutableMapIterator<QString, Document::Ptr> it(documents);
+ while (it.hasNext()) {
+ it.next();
+ const QString fn = it.key();
+ if (! processed.contains(fn)) {
+ removedFiles.append(fn);
+ it.remove();
+ }
+ }
+
+ emit aboutToRemoveFiles(removedFiles);
+ m_documents = documents;
+}
+
+
diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h
new file mode 100644
index 0000000000..bed882f9cd
--- /dev/null
+++ b/src/plugins/cpptools/cppmodelmanager.h
@@ -0,0 +1,135 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPMODELMANAGER_H
+#define CPPMODELMANAGER_H
+
+#include <cpptools/cppmodelmanagerinterface.h>
+#include <projectexplorer/project.h>
+#include <cplusplus/CppDocument.h>
+
+#include <QMap>
+#include <QFutureInterface>
+
+namespace Core {
+class ICore;
+class IEditor;
+}
+
+namespace TextEditor {
+class ITextEditor;
+}
+
+namespace ProjectExplorer {
+class ProjectExplorerPlugin;
+}
+
+namespace CppTools {
+namespace Internal {
+
+class CppEditorSupport;
+class CppHoverHandler;
+
+class CppModelManager : public CppModelManagerInterface
+{
+ Q_OBJECT
+
+public:
+ CppModelManager(QObject *parent);
+ virtual ~CppModelManager();
+
+ virtual void updateSourceFiles(const QStringList &sourceFiles);
+ virtual ProjectInfo *projectInfo(ProjectExplorer::Project *project);
+ virtual CPlusPlus::Document::Ptr document(const QString &fileName);
+ virtual DocumentTable documents();
+ virtual void GC();
+
+ QFuture<void> refreshSourceFiles(const QStringList &sourceFiles);
+
+ inline Core::ICore *core() const { return m_core; }
+
+ bool isCppEditor(Core::IEditor *editor) const; // ### private
+
+ void emitDocumentUpdated(CPlusPlus::Document::Ptr doc);
+
+Q_SIGNALS:
+ void projectPathChanged(const QString &projectPath);
+
+ void documentUpdated(CPlusPlus::Document::Ptr doc);
+ void aboutToRemoveFiles(const QStringList &files);
+
+public Q_SLOTS:
+ void editorOpened(Core::IEditor *editor);
+ void editorAboutToClose(Core::IEditor *editor);
+
+private Q_SLOTS:
+ // this should be executed in the GUI thread.
+ void onDocumentUpdated(CPlusPlus::Document::Ptr doc);
+ void onAboutToRemoveProject(ProjectExplorer::Project *project);
+ void onSessionUnloaded();
+
+private:
+ QMap<QString, QByteArray> buildWorkingCopyList() const;
+ QStringList projectFiles() const;
+ QStringList includePaths() const;
+ QStringList frameworkPaths() const;
+ QByteArray definedMacros() const;
+
+ static void parse(QFutureInterface<void> &future,
+ CppModelManager *model,
+ QStringList files,
+ QMap<QString, QByteArray> workingCopy);
+
+private:
+ Core::ICore *m_core;
+ ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
+ CppHoverHandler *m_hoverHandler;
+ DocumentTable m_documents;
+
+ // List of available source files
+ QStringList m_projectFiles;
+
+ // editor integration
+ QMap<TextEditor::ITextEditor *, CppEditorSupport *> m_editorSupport;
+
+ // project integration
+ QMap<ProjectExplorer::Project *, ProjectInfo> m_projects;
+
+ enum {
+ MAX_SELECTION_COUNT = 5
+ };
+};
+
+} // namespace Internal
+} // namespace CppTools
+
+#endif // CPPMODELMANAGER_H
diff --git a/src/plugins/cpptools/cppmodelmanagerinterface.h b/src/plugins/cpptools/cppmodelmanagerinterface.h
new file mode 100644
index 0000000000..3b93c346c5
--- /dev/null
+++ b/src/plugins/cpptools/cppmodelmanagerinterface.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPMODELMANAGERINTERFACE_H
+#define CPPMODELMANAGERINTERFACE_H
+
+#include <cpptools/cpptools_global.h>
+#include <cplusplus/CppDocument.h>
+#include <QtCore/QObject>
+#include <QtCore/QMap>
+
+namespace ProjectExplorer {
+ class Project;
+}
+
+namespace CppTools {
+
+class CPPTOOLS_EXPORT CppModelManagerInterface
+ : public QObject
+{
+ Q_OBJECT
+
+public:
+ typedef QMap<QString, CPlusPlus::Document::Ptr> DocumentTable;
+
+ struct ProjectInfo
+ {
+ QString projectPath;
+ QByteArray defines;
+ QStringList sourceFiles;
+ QStringList includePaths;
+ QStringList frameworkPaths;
+ };
+
+public:
+ CppModelManagerInterface(QObject *parent = 0) : QObject(parent) {}
+ virtual ~CppModelManagerInterface() {}
+
+ virtual void GC() = 0;
+ virtual void updateSourceFiles(const QStringList &sourceFiles) = 0;
+
+ virtual CPlusPlus::Document::Ptr document(const QString &fileName) = 0;
+ virtual DocumentTable documents() = 0;
+
+ virtual ProjectInfo *projectInfo(ProjectExplorer::Project *project) = 0;
+};
+
+} // namespace CppTools
+
+#endif // CPPMODELMANAGERINTERFACE_H
diff --git a/src/plugins/cpptools/cppquickopenfilter.cpp b/src/plugins/cpptools/cppquickopenfilter.cpp
new file mode 100644
index 0000000000..98086d3f81
--- /dev/null
+++ b/src/plugins/cpptools/cppquickopenfilter.cpp
@@ -0,0 +1,280 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cppquickopenfilter.h"
+
+#include <Literals.h>
+#include <Symbols.h>
+#include <SymbolVisitor.h>
+#include <Scope.h>
+#include <cplusplus/Overview.h>
+#include <cplusplus/Icons.h>
+
+#include <coreplugin/editormanager/ieditor.h>
+#include <texteditor/itexteditor.h>
+#include <texteditor/basetexteditor.h>
+
+#include <QtCore/QMultiMap>
+
+#include <functional>
+
+using namespace CPlusPlus;
+
+namespace CppTools {
+namespace Internal {
+
+class SearchSymbols: public std::unary_function<Document::Ptr, QList<ModelItemInfo> >,
+ protected SymbolVisitor
+{
+ Overview overview;
+ Icons icons;
+ QList<ModelItemInfo> items;
+
+public:
+ QList<ModelItemInfo> operator()(Document::Ptr doc)
+ { return operator()(doc, QString()); }
+
+ QList<ModelItemInfo> operator()(Document::Ptr doc, const QString &scope)
+ {
+ QString previousScope = switchScope(scope);
+ items.clear();
+ for (unsigned i = 0; i < doc->globalSymbolCount(); ++i) {
+ accept(doc->globalSymbolAt(i));
+ }
+ (void) switchScope(previousScope);
+ return items;
+ }
+
+protected:
+ using SymbolVisitor::visit;
+
+ void accept(Symbol *symbol)
+ { Symbol::visitSymbol(symbol, this); }
+
+ QString switchScope(const QString &scope)
+ {
+ QString previousScope = _scope;
+ _scope = scope;
+ return previousScope;
+ }
+
+ virtual bool visit(Enum *symbol)
+ {
+ QString name = symbolName(symbol);
+ QString previousScope = switchScope(name);
+ QIcon icon = icons.iconForSymbol(symbol);
+ Scope *members = symbol->members();
+ items.append(ModelItemInfo(name, QString(), ModelItemInfo::Enum,
+ QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()),
+ symbol->line(),
+ icon));
+ for (unsigned i = 0; i < members->symbolCount(); ++i) {
+ accept(members->symbolAt(i));
+ }
+ (void) switchScope(previousScope);
+ return false;
+ }
+
+ virtual bool visit(Function *symbol)
+ {
+ QString name = symbolName(symbol);
+ QString type = overview.prettyType(symbol->type());
+ QIcon icon = icons.iconForSymbol(symbol);
+ items.append(ModelItemInfo(name, type, ModelItemInfo::Method,
+ QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()),
+ symbol->line(),
+ icon));
+ return false;
+ }
+
+ virtual bool visit(Namespace *symbol)
+ {
+ QString name = symbolName(symbol);
+ QString previousScope = switchScope(name);
+ Scope *members = symbol->members();
+ for (unsigned i = 0; i < members->symbolCount(); ++i) {
+ accept(members->symbolAt(i));
+ }
+ (void) switchScope(previousScope);
+ return false;
+ }
+#if 0
+ // This visit method would make function declaration be included in QuickOpen
+ virtual bool visit(Declaration *symbol)
+ {
+ if (symbol->type()->isFunction()) {
+ QString name = symbolName(symbol);
+ QString type = overview.prettyType(symbol->type());
+ //QIcon icon = ...;
+ items.append(ModelItemInfo(name, type, ModelItemInfo::Method,
+ QString::fromUtf8(symbol->fileName(), symbol->line()),
+ symbol->line()));
+ }
+ return false;
+ }
+#endif
+ virtual bool visit(Class *symbol)
+ {
+ QString name = symbolName(symbol);
+ QString previousScope = switchScope(name);
+ QIcon icon = icons.iconForSymbol(symbol);
+ items.append(ModelItemInfo(name, QString(), ModelItemInfo::Class,
+ QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()),
+ symbol->line(),
+ icon));
+ Scope *members = symbol->members();
+ for (unsigned i = 0; i < members->symbolCount(); ++i) {
+ accept(members->symbolAt(i));
+ }
+ (void) switchScope(previousScope);
+ return false;
+ }
+
+ QString symbolName(Symbol *symbol) const
+ {
+ QString name = _scope;
+ if (! name.isEmpty())
+ name += QLatin1String("::");
+ QString symbolName = overview.prettyName(symbol->name());
+ if (symbolName.isEmpty()) {
+ QString type;
+ if (symbol->isNamespace()) {
+ type = QLatin1String("namespace");
+ } else if (symbol->isEnum()) {
+ type = QLatin1String("enum");
+ } else if (Class *c = symbol->asClass()) {
+ if (c->isUnion()) {
+ type = QLatin1String("union");
+ } else if (c->isStruct()) {
+ type = QLatin1String("struct");
+ } else {
+ type = QLatin1String("class");
+ }
+ } else {
+ type = QLatin1String("symbol");
+ }
+ symbolName = QLatin1String("<anonymous ");
+ symbolName += type;
+ symbolName += QLatin1String(">");
+ }
+ name += symbolName;
+ return name;
+ }
+
+private:
+ QString _scope;
+};
+
+} // namespace Internal
+} // namespace CppTools
+
+using namespace CppTools::Internal;
+
+CppQuickOpenFilter::CppQuickOpenFilter(CppModelManager *manager, Core::EditorManager *editorManager)
+ : m_manager(manager),
+ m_editorManager(editorManager),
+ m_forceNewSearchList(true)
+{
+ setShortcutString(":");
+ setIncludedByDefault(false);
+
+ connect(manager, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)),
+ this, SLOT(onDocumentUpdated(CPlusPlus::Document::Ptr)));
+
+ connect(manager, SIGNAL(aboutToRemoveFiles(QStringList)),
+ this, SLOT(onAboutToRemoveFiles(QStringList)));
+}
+
+CppQuickOpenFilter::~CppQuickOpenFilter()
+{ }
+
+void CppQuickOpenFilter::onDocumentUpdated(CPlusPlus::Document::Ptr doc)
+{
+ m_searchList[doc->fileName()] = Info(doc);
+}
+
+void CppQuickOpenFilter::onAboutToRemoveFiles(const QStringList &files)
+{
+ foreach (QString file, files) {
+ m_searchList.remove(file);
+ }
+}
+
+void CppQuickOpenFilter::refresh(QFutureInterface<void> &future)
+{
+ Q_UNUSED(future);
+}
+
+QList<QuickOpen::FilterEntry> CppQuickOpenFilter::matchesFor(const QString &origEntry)
+{
+ QString entry = trimWildcards(origEntry);
+ QList<QuickOpen::FilterEntry> entries;
+ QStringMatcher matcher(entry, Qt::CaseInsensitive);
+ const QRegExp regexp("*"+entry+"*", Qt::CaseInsensitive, QRegExp::Wildcard);
+ if (!regexp.isValid())
+ return entries;
+ bool hasWildcard = (entry.contains('*') || entry.contains('?'));
+
+ SearchSymbols search;
+ QMutableMapIterator<QString, Info> it(m_searchList);
+ while (it.hasNext()) {
+ it.next();
+
+ Info info = it.value();
+ if (info.dirty) {
+ info.dirty = false;
+ info.items = search(info.doc);
+ it.setValue(info);
+ }
+
+ QList<ModelItemInfo> items = info.items;
+
+ foreach (ModelItemInfo info, items) {
+ if ((hasWildcard && regexp.exactMatch(info.symbolName))
+ || (!hasWildcard && matcher.indexIn(info.symbolName) != -1)) {
+ QVariant id = qVariantFromValue(info);
+ QuickOpen::FilterEntry filterEntry(this, info.symbolName, id, info.icon);
+ filterEntry.extraInfo = info.symbolType;
+ entries.append(filterEntry);
+ }
+ }
+ }
+
+ return entries;
+}
+
+void CppQuickOpenFilter::accept(QuickOpen::FilterEntry selection) const
+{
+ ModelItemInfo info = qvariant_cast<CppTools::Internal::ModelItemInfo>(selection.internalData);
+
+ TextEditor::BaseTextEditor::openEditorAt(info.fileName, info.line);
+}
diff --git a/src/plugins/cpptools/cppquickopenfilter.h b/src/plugins/cpptools/cppquickopenfilter.h
new file mode 100644
index 0000000000..1375e468f5
--- /dev/null
+++ b/src/plugins/cpptools/cppquickopenfilter.h
@@ -0,0 +1,118 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPQUICKOPENFILTER_H
+#define CPPQUICKOPENFILTER_H
+
+#include "cppmodelmanager.h"
+#include <cplusplus/CppDocument.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <quickopen/iquickopenfilter.h>
+#include <QtGui/QIcon>
+#include <QFile>
+#include <QMetaType>
+
+namespace CppTools {
+namespace Internal {
+
+struct ModelItemInfo
+{
+ enum ItemType { Enum, Class, Method };
+
+ ModelItemInfo()
+ { }
+
+ ModelItemInfo(const QString &symbolName,
+ const QString &symbolType,
+ ItemType type,
+ const QString &fileName,
+ int line,
+ const QIcon &icon)
+ : symbolName(symbolName),
+ symbolType(symbolType),
+ type(type),
+ fileName(fileName),
+ line(line),
+ icon(icon)
+ { }
+
+ QString symbolName;
+ QString symbolType;
+ ItemType type;
+ QString fileName;
+ int line;
+ QIcon icon;
+};
+
+class CppQuickOpenFilter : public QuickOpen::IQuickOpenFilter
+{
+ Q_OBJECT
+public:
+ CppQuickOpenFilter(CppModelManager *manager, Core::EditorManager *editorManager);
+ ~CppQuickOpenFilter();
+
+ QString trName() const { return tr("Classes and Methods"); }
+ QString name() const { return "Classes and Methods"; }
+ Priority priority() const { return Medium; }
+ QList<QuickOpen::FilterEntry> matchesFor(const QString &entry);
+ void accept(QuickOpen::FilterEntry selection) const;
+ void refresh(QFutureInterface<void> &future);
+
+private slots:
+ void onDocumentUpdated(CPlusPlus::Document::Ptr doc);
+ void onAboutToRemoveFiles(const QStringList &files);
+
+private:
+ CppModelManager *m_manager;
+ Core::EditorManager *m_editorManager;
+
+ struct Info {
+ Info(): dirty(true) {}
+ Info(CPlusPlus::Document::Ptr doc): doc(doc), dirty(true) {}
+
+ CPlusPlus::Document::Ptr doc;
+ QList<ModelItemInfo> items;
+ bool dirty;
+ };
+
+ QMap<QString, Info> m_searchList;
+ QList<ModelItemInfo> m_previousResults;
+ bool m_forceNewSearchList;
+ QString m_previousEntry;
+};
+
+} // namespace Internal
+} // namespace CppTools
+
+Q_DECLARE_METATYPE(CppTools::Internal::ModelItemInfo)
+
+#endif // CPPQUICKOPENFILTER_H
diff --git a/src/plugins/cpptools/cpptools.cpp b/src/plugins/cpptools/cpptools.cpp
new file mode 100644
index 0000000000..ceca43afaa
--- /dev/null
+++ b/src/plugins/cpptools/cpptools.cpp
@@ -0,0 +1,256 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "cpptools.h"
+#include "cppcodecompletion.h"
+#include "cpphoverhandler.h"
+#include "cppmodelmanager.h"
+#include "cpptoolsconstants.h"
+#include "cppquickopenfilter.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <cppeditor/cppeditorconstants.h>
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+
+using namespace CppTools::Internal;
+
+enum { debug = 0 };
+
+
+CppToolsPlugin *CppToolsPlugin::m_instance = 0;
+
+CppToolsPlugin::CppToolsPlugin() :
+ m_core(0),
+ m_context(-1),
+ m_modelManager(0)
+{
+ m_instance = this;
+}
+
+CppToolsPlugin::~CppToolsPlugin()
+{
+ m_instance = 0;
+ m_modelManager = 0; // deleted automatically
+}
+
+bool CppToolsPlugin::initialize(const QStringList & /*arguments*/, QString *)
+{
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ Core::ActionManagerInterface *am = m_core->actionManager();
+
+ // Objects
+ m_modelManager = new CppModelManager(this);
+ addAutoReleasedObject(m_modelManager);
+ CppCodeCompletion *cppcodecompletion = new CppCodeCompletion(m_modelManager, m_core);
+ addAutoReleasedObject(cppcodecompletion);
+ CppQuickOpenFilter *quickOpenFilter = new CppQuickOpenFilter(m_modelManager,
+ m_core->editorManager());
+ addAutoReleasedObject(quickOpenFilter);
+
+ // Menus
+ Core::IActionContainer *mtools = am->actionContainer(Core::Constants::M_TOOLS);
+ Core::IActionContainer *mcpptools = am->createMenu(CppTools::Constants::M_TOOLS_CPP);
+ QMenu *menu = mcpptools->menu();
+ menu->setTitle(tr("&C++"));
+ menu->setEnabled(true);
+ mtools->addMenu(mcpptools);
+
+ // Actions
+ m_context = m_core->uniqueIDManager()->uniqueIdentifier(CppEditor::Constants::C_CPPEDITOR);
+ QList<int> context = QList<int>() << m_context;
+
+ QAction *switchAction = new QAction(tr("Switch Header/Source"), this);
+ Core::ICommand *command = am->registerAction(switchAction, Constants::SWITCH_HEADER_SOURCE, context);
+ command->setDefaultKeySequence(QKeySequence(Qt::Key_F4));
+ mcpptools->addAction(command);
+ connect(switchAction, SIGNAL(triggered()), this, SLOT(switchHeaderSource()));
+
+ return true;
+}
+
+void CppToolsPlugin::extensionsInitialized()
+{
+}
+
+void CppToolsPlugin::switchHeaderSource()
+{
+ if (!m_core)
+ return;
+
+ Core::IEditor *editor = m_core->editorManager()->currentEditor();
+ QString otherFile = correspondingHeaderOrSource(editor->file()->fileName());
+ if (!otherFile.isEmpty()) {
+ m_core->editorManager()->openEditor(otherFile);
+ m_core->editorManager()->ensureEditorManagerVisible();
+ }
+}
+
+QFileInfo CppToolsPlugin::findFile(const QDir &dir, const QString &name,
+ const ProjectExplorer::Project *project) const
+{
+ if (debug)
+ qDebug() << Q_FUNC_INFO << dir << name;
+
+ if (project) {
+ QString pattern = QString(1, QLatin1Char('/'));
+ pattern += name;
+ const QStringList projectFiles = project->files(ProjectExplorer::Project::AllFiles);
+ const QStringList::const_iterator pcend = projectFiles.constEnd();
+ for (QStringList::const_iterator it = projectFiles.constBegin(); it != pcend; ++it)
+ if (it->endsWith(pattern))
+ return QFileInfo(*it);
+ return QFileInfo();
+ }
+ return QFileInfo(dir, name);
+}
+
+// Figure out file type
+enum FileType { HeaderFile, C_SourceFile, CPP_SourceFile, UnknownType };
+
+static inline FileType fileType(const Core::MimeDatabase *mimeDatase, const QFileInfo & fi)
+{
+ const Core::MimeType mimeType = mimeDatase->findByFile(fi);
+ if (!mimeType)
+ return UnknownType;
+ const QString typeName = mimeType.type();
+ if (typeName == QLatin1String(CppTools::Constants::C_SOURCE_MIMETYPE))
+ return C_SourceFile;
+ if (typeName == QLatin1String(CppTools::Constants::CPP_SOURCE_MIMETYPE))
+ return CPP_SourceFile;
+ if (typeName == QLatin1String(CppTools::Constants::C_HEADER_MIMETYPE)
+ || typeName == QLatin1String(CppTools::Constants::CPP_HEADER_MIMETYPE))
+ return HeaderFile;
+ return UnknownType;
+}
+
+// Return the suffixes that should be checked when trying to find a
+// source belonging to a header and vice versa
+static QStringList matchingCandidateSuffixes(const Core::MimeDatabase *mimeDatase, FileType type)
+{
+ switch (type) {
+ case UnknownType:
+ break;
+ case HeaderFile: // Note that C/C++ headers are undistinguishable
+ return mimeDatase->findByType(QLatin1String(CppTools::Constants::C_SOURCE_MIMETYPE)).suffixes() +
+ mimeDatase->findByType(QLatin1String(CppTools::Constants::CPP_SOURCE_MIMETYPE)).suffixes();
+ case C_SourceFile:
+ return mimeDatase->findByType(QLatin1String(CppTools::Constants::C_HEADER_MIMETYPE)).suffixes();
+ case CPP_SourceFile:
+ return mimeDatase->findByType(QLatin1String(CppTools::Constants::CPP_HEADER_MIMETYPE)).suffixes();
+ }
+ return QStringList();
+}
+
+QString CppToolsPlugin::correspondingHeaderOrSourceI(const QString &fileName) const
+{
+ const Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+ const Core::MimeDatabase *mimeDatase = core->mimeDatabase();
+ ProjectExplorer::ProjectExplorerPlugin *explorer =
+ ExtensionSystem::PluginManager::instance()->getObject<ProjectExplorer::ProjectExplorerPlugin>();
+ ProjectExplorer::Project *project = (explorer ? explorer->currentProject() : 0);
+
+ const QFileInfo fi(fileName);
+ const FileType type = fileType(mimeDatase, fi);
+
+ if (debug)
+ qDebug() << Q_FUNC_INFO << fileName << type;
+
+ if (type == UnknownType)
+ return QString();
+
+ const QDir absoluteDir = fi.absoluteDir();
+ const QString baseName = fi.baseName();
+ const QStringList suffixes = matchingCandidateSuffixes(mimeDatase, type);
+
+ const QString privateHeaderSuffix = QLatin1String("_p");
+ const QChar dot = QLatin1Char('.');
+ QStringList candidates;
+ // Check base matches 'source.h'-> 'source.cpp' and vice versa
+ const QStringList::const_iterator scend = suffixes.constEnd();
+ for (QStringList::const_iterator it = suffixes.constBegin(); it != scend; ++it) {
+ QString candidate = baseName;
+ candidate += dot;
+ candidate += *it;
+ const QFileInfo candidateFi = findFile(absoluteDir, candidate, project);
+ if (candidateFi.isFile())
+ return candidateFi.absoluteFilePath();
+ }
+ if (type == HeaderFile) {
+ // 'source_p.h': try 'source.cpp'
+ if (baseName.endsWith(privateHeaderSuffix)) {
+ QString sourceBaseName = baseName;
+ sourceBaseName.truncate(sourceBaseName.size() - privateHeaderSuffix.size());
+ for (QStringList::const_iterator it = suffixes.constBegin(); it != scend; ++it) {
+ QString candidate = sourceBaseName;
+ candidate += dot;
+ candidate += *it;
+ const QFileInfo candidateFi = findFile(absoluteDir, candidate, project);
+ if (candidateFi.isFile())
+ return candidateFi.absoluteFilePath();
+ }
+ }
+ } else {
+ // 'source.cpp': try 'source_p.h'
+ const QStringList::const_iterator scend = suffixes.constEnd();
+ for (QStringList::const_iterator it = suffixes.constBegin(); it != scend; ++it) {
+ QString candidate = baseName;
+ candidate += privateHeaderSuffix;
+ candidate += dot;
+ candidate += *it;
+ const QFileInfo candidateFi = findFile(absoluteDir, candidate, project);
+ if (candidateFi.isFile())
+ return candidateFi.absoluteFilePath();
+ }
+ }
+ return QString();
+}
+
+QString CppToolsPlugin::correspondingHeaderOrSource(const QString &fileName) const
+{
+ const QString rc = correspondingHeaderOrSourceI(fileName);
+ if (debug)
+ qDebug() << Q_FUNC_INFO << fileName << rc;
+ return rc;
+}
+
+Q_EXPORT_PLUGIN(CppToolsPlugin)
diff --git a/src/plugins/cpptools/cpptools.h b/src/plugins/cpptools/cpptools.h
new file mode 100644
index 0000000000..3d0f195309
--- /dev/null
+++ b/src/plugins/cpptools/cpptools.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPTOOLS_H
+#define CPPTOOLS_H
+
+#include <extensionsystem/iplugin.h>
+#include <projectexplorer/ProjectExplorerInterfaces>
+
+QT_BEGIN_NAMESPACE
+class QFileInfo;
+class QDir;
+QT_END_NAMESPACE
+
+namespace Core {
+class ICore;
+}
+
+namespace CppTools {
+namespace Internal {
+
+class CppCodeCompletion;
+class CppModelManager;
+
+class CppToolsPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ static CppToolsPlugin *instance() { return m_instance; }
+
+ CppToolsPlugin();
+ ~CppToolsPlugin();
+
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void extensionsInitialized();
+ CppModelManager *cppModelManager() { return m_modelManager; }
+ QString correspondingHeaderOrSource(const QString &fileName) const;
+
+private slots:
+ void switchHeaderSource();
+
+private:
+ QString correspondingHeaderOrSourceI(const QString &fileName) const;
+ QFileInfo findFile(const QDir &dir, const QString &name, const ProjectExplorer::Project *project) const;
+
+ Core::ICore *m_core;
+ int m_context;
+ CppModelManager *m_modelManager;
+
+ static CppToolsPlugin *m_instance;
+};
+
+} // namespace Internal
+} // namespace CppTools
+
+#endif // CPPTOOLS_H
diff --git a/src/plugins/cpptools/cpptools.pri b/src/plugins/cpptools/cpptools.pri
new file mode 100644
index 0000000000..1dffbfc556
--- /dev/null
+++ b/src/plugins/cpptools/cpptools.pri
@@ -0,0 +1,3 @@
+include(cpptools_dependencies.pri)
+
+LIBS *= -l$$qtLibraryTarget(CppTools)
diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro
new file mode 100644
index 0000000000..17b72496a9
--- /dev/null
+++ b/src/plugins/cpptools/cpptools.pro
@@ -0,0 +1,40 @@
+TEMPLATE = lib
+TARGET = CppTools
+include(../../qworkbenchplugin.pri)
+include(../../plugins/quickopen/quickopen.pri)
+include(cpptools_dependencies.pri)
+
+#DEFINES += QT_NO_CAST_FROM_ASCII
+DEFINES += QT_NO_CAST_TO_ASCII
+unix:QMAKE_CXXFLAGS_DEBUG+=-O3
+
+INCLUDEPATH += .
+
+DEFINES += CPPTOOLS_LIBRARY
+
+CONFIG += help
+include(rpp/rpp.pri)|error("Can't find RPP")
+
+HEADERS += \
+ cpptools_global.h \
+ cppquickopenfilter.h
+
+SOURCES += \
+ cppquickopenfilter.cpp \
+ cpptoolseditorsupport.cpp
+
+# Input
+SOURCES += cpptools.cpp \
+ cppmodelmanager.cpp \
+ cppcodecompletion.cpp \
+ cpphoverhandler.cpp
+
+HEADERS += cpptools.h \
+ cppmodelmanager.h \
+ cppcodecompletion.h \
+ cpphoverhandler.h \
+ cppmodelmanagerinterface.h \
+ cpptoolseditorsupport.h \
+ cpptoolsconstants.h
+
+RESOURCES += cpptools.qrc
diff --git a/src/plugins/cpptools/cpptools.qrc b/src/plugins/cpptools/cpptools.qrc
new file mode 100644
index 0000000000..a750578a4b
--- /dev/null
+++ b/src/plugins/cpptools/cpptools.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/cpptools" >
+ <file>images/f1.svg</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/cpptools/cpptools_dependencies.pri b/src/plugins/cpptools/cpptools_dependencies.pri
new file mode 100644
index 0000000000..e12a33bc46
--- /dev/null
+++ b/src/plugins/cpptools/cpptools_dependencies.pri
@@ -0,0 +1,3 @@
+include(../../libs/cplusplus/cplusplus.pri)
+include(../../plugins/projectexplorer/projectexplorer.pri)
+include(../../plugins/texteditor/texteditor.pri)
diff --git a/src/plugins/cpptools/cpptools_global.h b/src/plugins/cpptools/cpptools_global.h
new file mode 100644
index 0000000000..294a54ceb2
--- /dev/null
+++ b/src/plugins/cpptools/cpptools_global.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPTOOLS_GLOBAL_H
+#define CPPTOOLS_GLOBAL_H
+
+#if defined(CPPTOOLS_LIBRARY)
+# define CPPTOOLS_EXPORT Q_DECL_EXPORT
+#else
+# define CPPTOOLS_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // CPPTOOLS_GLOBAL_H
diff --git a/src/plugins/cpptools/cpptoolsconstants.h b/src/plugins/cpptools/cpptoolsconstants.h
new file mode 100644
index 0000000000..8a3e92cf2d
--- /dev/null
+++ b/src/plugins/cpptools/cpptoolsconstants.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPTOOLSCONSTANTS_H
+#define CPPTOOLSCONSTANTS_H
+
+namespace CppTools {
+namespace Constants {
+
+const char * const M_TOOLS_CPP = "CppTools.Tools.Menu";
+const char * const SWITCH_HEADER_SOURCE = "CppTools.SwitchHeaderSource";
+const char * const TASK_INDEX = "CppTools.Task.Index";
+const char * const C_SOURCE_MIMETYPE = "text/x-csrc";
+const char * const C_HEADER_MIMETYPE = "text/x-chdr";
+const char * const CPP_SOURCE_MIMETYPE = "text/x-c++src";
+const char * const CPP_HEADER_MIMETYPE = "text/x-c++hdr";
+}
+}
+
+#endif //CPPTOOLSCONSTANTS_H
diff --git a/src/plugins/cpptools/cpptoolseditorsupport.cpp b/src/plugins/cpptools/cpptoolseditorsupport.cpp
new file mode 100644
index 0000000000..ca36045422
--- /dev/null
+++ b/src/plugins/cpptools/cpptoolseditorsupport.cpp
@@ -0,0 +1,97 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "cpptoolseditorsupport.h"
+#include "cppmodelmanager.h"
+
+#include <texteditor/itexteditor.h>
+#include <QTimer>
+
+using namespace CppTools::Internal;
+
+CppEditorSupport::CppEditorSupport(CppModelManager *modelManager)
+ : QObject(modelManager),
+ _modelManager(modelManager),
+ _updateDocumentInterval(UPDATE_DOCUMENT_DEFAULT_INTERVAL)
+{
+ _updateDocumentTimer = new QTimer(this);
+ _updateDocumentTimer->setSingleShot(true);
+ _updateDocumentTimer->setInterval(_updateDocumentInterval);
+ connect(_updateDocumentTimer, SIGNAL(timeout()), this, SLOT(updateDocumentNow()));
+}
+
+CppEditorSupport::~CppEditorSupport()
+{ }
+
+TextEditor::ITextEditor *CppEditorSupport::textEditor() const
+{ return _textEditor; }
+
+void CppEditorSupport::setTextEditor(TextEditor::ITextEditor *textEditor)
+{
+ _textEditor = textEditor;
+
+ if (! _textEditor)
+ return;
+
+ connect(_textEditor, SIGNAL(contentsChanged()), this, SLOT(updateDocument()));
+ updateDocument();
+}
+
+QString CppEditorSupport::contents() const
+{
+ if (! _textEditor)
+ return QString();
+
+ return _textEditor->contents();
+}
+
+int CppEditorSupport::updateDocumentInterval() const
+{ return _updateDocumentInterval; }
+
+void CppEditorSupport::setUpdateDocumentInterval(int updateDocumentInterval)
+{ _updateDocumentInterval = updateDocumentInterval; }
+
+void CppEditorSupport::updateDocument()
+{ _updateDocumentTimer->start(_updateDocumentInterval); }
+
+void CppEditorSupport::updateDocumentNow()
+{
+ if (_documentParser.isRunning()) {
+ _updateDocumentTimer->start(_updateDocumentInterval);
+ } else {
+ _updateDocumentTimer->stop();
+ QStringList sourceFiles(_textEditor->file()->fileName());
+ _documentParser = _modelManager->refreshSourceFiles(sourceFiles);
+ }
+}
+
diff --git a/src/plugins/cpptools/cpptoolseditorsupport.h b/src/plugins/cpptools/cpptoolseditorsupport.h
new file mode 100644
index 0000000000..51a905e895
--- /dev/null
+++ b/src/plugins/cpptools/cpptoolseditorsupport.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CPPTOOLSEDITORSUPPORT_H
+#define CPPTOOLSEDITORSUPPORT_H
+
+#include <QObject>
+#include <QPointer>
+#include <QFuture>
+
+QT_BEGIN_NAMESPACE
+class QTimer;
+class QByteArray;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+ class ITextEditor;
+} // end of namespace TextEditor
+
+namespace CppTools {
+namespace Internal {
+
+class CppModelManager;
+
+class CppEditorSupport: public QObject
+{
+ Q_OBJECT
+
+public:
+ CppEditorSupport(CppModelManager *modelManager);
+ virtual ~CppEditorSupport();
+
+ TextEditor::ITextEditor *textEditor() const;
+ void setTextEditor(TextEditor::ITextEditor *textEditor);
+
+ int updateDocumentInterval() const;
+ void setUpdateDocumentInterval(int updateDocumentInterval);
+
+ QString contents() const;
+
+private Q_SLOTS:
+ void updateDocument();
+ void updateDocumentNow();
+
+private:
+ enum { UPDATE_DOCUMENT_DEFAULT_INTERVAL = 150 };
+
+ CppModelManager *_modelManager;
+ QPointer<TextEditor::ITextEditor> _textEditor;
+ QTimer *_updateDocumentTimer;
+ int _updateDocumentInterval;
+ QFuture<void> _documentParser;
+};
+
+} // end of namespace Internal
+} // end of namespace CppTools
+
+#endif // CPPTOOLSEDITORSUPPORT_H
diff --git a/src/plugins/cpptools/images/f1.svg b/src/plugins/cpptools/images/f1.svg
new file mode 100644
index 0000000000..468594cb77
--- /dev/null
+++ b/src/plugins/cpptools/images/f1.svg
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="24"
+ height="24"
+ id="svg2411"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docname="f1.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs2413">
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient001"
+ id="linearGradient3201"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(3.6285394,0,0,3.6290105,-1258.7023,-359.38242)"
+ spreadMethod="pad"
+ x1="375.31006"
+ y1="88.869247"
+ x2="466.8873"
+ y2="180.4346" />
+ <linearGradient
+ id="linearGradient001">
+ <stop
+ id="stop608"
+ offset="0.000000"
+ style="stop-color:#cfcfcf;stop-opacity:1;" />
+ <stop
+ id="stop609"
+ offset="1.000000"
+ style="stop-color:#efefef;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient001"
+ id="linearGradient3207"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(3.8401167,0,0,3.8424815,-1348.031,-388.46373)"
+ spreadMethod="pad"
+ x1="470.3931"
+ y1="136.23064"
+ x2="374.90988"
+ y2="136.23064" />
+ <linearGradient
+ id="linearGradient002">
+ <stop
+ id="stop566"
+ offset="0.000000"
+ style="stop-color:#9d9d9f;stop-opacity:1;" />
+ <stop
+ id="stop567"
+ offset="1.000000"
+ style="stop-color:#e5e5e5;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient002"
+ id="linearGradient2419"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(3.6611924,0,0,3.6628816,-1231.7325,-383.72165)"
+ spreadMethod="pad"
+ x1="471.00525"
+ y1="201.05208"
+ x2="348.94803"
+ y2="79.051147" />
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective2419" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="11.2"
+ inkscape:cx="22.801892"
+ inkscape:cy="10.456883"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="963"
+ inkscape:window-height="667"
+ inkscape:window-x="207"
+ inkscape:window-y="207" />
+ <metadata
+ id="metadata2416">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Ebene 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <g
+ transform="matrix(4.3636364e-2,0,0,4.3636364e-2,0,6.1090908)"
+ id="g2404">
+ <rect
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ y="-140"
+ x="2.4832567e-14"
+ width="550"
+ style="font-size:12px;fill:#b0b0b0;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.81658993pt;stroke-opacity:1"
+ ry="81.511414"
+ id="rect621"
+ height="550" />
+ <rect
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="c:\Documents and Settings\aportale\Desktop\rect621.png"
+ y="-128.55069"
+ x="11.458333"
+ width="527.08331"
+ style="font-size:12px;fill:url(#linearGradient2419);fill-rule:evenodd;stroke:none;stroke-width:1.03125;stroke-miterlimit:4;stroke-dasharray:none"
+ ry="78.116447"
+ id="rect2417"
+ height="527.09235" />
+ <rect
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="c:\Documents and Settings\aportale\Desktop\rect621.png"
+ y="-71.25"
+ x="68.950378"
+ width="412.29962"
+ style="font-size:12px;fill:url(#linearGradient3207);fill-rule:evenodd;stroke:none;stroke-width:2.4979167;stroke-miterlimit:4;stroke-dasharray:none"
+ ry="39.785442"
+ rx="34.514793"
+ id="rect3205"
+ height="412.5" />
+ <rect
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="c:\Documents and Settings\aportale\Desktop\rect621.png"
+ y="-59.791668"
+ x="80.208336"
+ width="389.58334"
+ style="font-size:12px;fill:url(#linearGradient3201);fill-rule:evenodd;stroke:none;stroke-width:25.41458321;stroke-miterlimit:4;stroke-dasharray:none"
+ ry="25.400656"
+ rx="22.902761"
+ id="rect3199"
+ height="389.58334" />
+ <path
+ sodipodi:nodetypes="ccccccccccccccccsccc"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="c:\Documents and Settings\aportale\Desktop\rect621.png"
+ id="text3219"
+ d="M 137.5,157.91667 L 137.5,-2.4752517 L 229.16667,-2.5 L 229.16667,20.416667 L 160.41667,20.416667 L 160.41667,66.25 L 206.25,66.25 L 206.25,89.166667 L 160.41667,89.166667 L 160.41667,157.91667 L 137.5,157.91667 z M 320.89291,157.91667 L 297.91667,157.91667 L 297.91667,40.04211 C 284.08134,48.574912 275.21133,59.2993 252.08333,66.25 L 252.08333,47.355939 C 263.04835,44.807707 286.00818,25.67917 293.48823,18.312241 C 300.9682,10.945593 306.26379,4.4293192 309.375,-2.5 L 320.83333,-2.5 L 320.89291,157.91667 z"
+ style="font-size:261.65481567px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" />
+ </g>
+ </g>
+</svg>
diff --git a/src/plugins/cpptools/rpp/pp-cctype.h b/src/plugins/cpptools/rpp/pp-cctype.h
new file mode 100644
index 0000000000..aff4fb2c51
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-cctype.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ 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
+ KDEVELOP TEAM 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 PP_CCTYPE_H
+#define PP_CCTYPE_H
+
+#include <cctype>
+
+namespace rpp {
+
+inline bool pp_isalpha (int __ch)
+{ return std::isalpha ((unsigned char) __ch) != 0; }
+
+inline bool pp_isalnum (int __ch)
+{ return std::isalnum ((unsigned char) __ch) != 0; }
+
+inline bool pp_isdigit (int __ch)
+{ return std::isdigit ((unsigned char) __ch) != 0; }
+
+inline bool pp_isspace (int __ch)
+{ return std::isspace ((unsigned char) __ch) != 0; }
+
+} // namespace rpp
+
+#endif // PP_CCTYPE_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/src/plugins/cpptools/rpp/pp-client.h b/src/plugins/cpptools/rpp/pp-client.h
new file mode 100644
index 0000000000..13d9eda713
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-client.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PP_CLIENT_H
+#define PP_CLIENT_H
+
+#include <QByteArray>
+#include <QString>
+#include <QFile>
+
+namespace rpp {
+
+class Client
+{
+ Client(const Client &other);
+ void operator=(const Client &other);
+
+public:
+ enum IncludeType {
+ IncludeLocal,
+ IncludeGlobal
+ };
+
+public:
+ Client()
+ { }
+
+ virtual ~Client()
+ { }
+
+ virtual void macroAdded(const QByteArray &macroId, const QByteArray &text) = 0;
+ virtual void sourceNeeded(QString &fileName, IncludeType mode) = 0; // ### FIX the signature.
+
+ virtual void startSkippingBlocks(unsigned offset) = 0;
+ virtual void stopSkippingBlocks(unsigned offset) = 0;
+};
+
+} // end of namespace rpp
+
+#endif // PP_CLIENT_H
diff --git a/src/plugins/cpptools/rpp/pp-engine.cpp b/src/plugins/cpptools/rpp/pp-engine.cpp
new file mode 100644
index 0000000000..97e168f0c2
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-engine.cpp
@@ -0,0 +1,1085 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ 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
+ KDEVELOP TEAM 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 "pp.h"
+#include <Lexer.h>
+#include <Token.h>
+#include <QtDebug>
+
+using namespace rpp;
+using namespace CPlusPlus;
+
+namespace {
+
+class RangeLexer
+{
+ const Token *first;
+ const Token *last;
+ Token trivial;
+
+public:
+ inline RangeLexer(const Token *first, const Token *last)
+ : first(first), last(last)
+ {
+ // WARN: `last' must be a valid iterator.
+ trivial.offset = last->offset;
+ }
+
+ inline operator bool() const
+ { return first != last; }
+
+ inline bool isValid() const
+ { return first != last; }
+
+ inline int size() const
+ { return std::distance(first, last); }
+
+ inline const Token *dot() const
+ { return first; }
+
+ inline const Token &operator*() const
+ {
+ if (first != last)
+ return *first;
+
+ return trivial;
+ }
+
+ inline const Token *operator->() const
+ {
+ if (first != last)
+ return first;
+
+ return &trivial;
+ }
+
+ inline RangeLexer &operator++()
+ {
+ ++first;
+ return *this;
+ }
+};
+
+class ExpressionEvaluator
+{
+ ExpressionEvaluator(const ExpressionEvaluator &other);
+ void operator = (const ExpressionEvaluator &other);
+
+public:
+ ExpressionEvaluator(Environment *env)
+ : env(env), _lex(0)
+ { }
+
+ Value operator()(const Token *firstToken, const Token *lastToken,
+ const QByteArray &source)
+ {
+ this->source = source;
+ const Value previousValue = switchValue(Value());
+ RangeLexer tmp(firstToken, lastToken);
+ RangeLexer *previousLex = _lex;
+ _lex = &tmp;
+ process_expression();
+ _lex = previousLex;
+ return switchValue(previousValue);
+ }
+
+protected:
+ Value switchValue(const Value &value)
+ {
+ Value previousValue = _value;
+ _value = value;
+ return previousValue;
+ }
+
+ bool isTokenDefined() const
+ {
+ if ((*_lex)->isNot(T_IDENTIFIER))
+ return false;
+ const QByteArray spell = tokenSpell();
+ if (spell.size() != 7)
+ return false;
+ return spell == "defined";
+ }
+
+ QByteArray tokenSpell() const
+ {
+ const QByteArray text = QByteArray::fromRawData(source.constData() + (*_lex)->offset,
+ (*_lex)->length);
+ return text;
+ }
+
+ bool process_expression()
+ { return process_constant_expression(); }
+
+ bool process_primary()
+ {
+ if ((*_lex)->is(T_INT_LITERAL)) {
+ _value.set_long(tokenSpell().toLong());
+ ++(*_lex);
+ return true;
+ } else if (isTokenDefined()) {
+ ++(*_lex);
+ if ((*_lex)->is(T_IDENTIFIER)) {
+ _value.set_long(env->resolve(tokenSpell()) != 0);
+ ++(*_lex);
+ return true;
+ } else if ((*_lex)->is(T_LPAREN)) {
+ ++(*_lex);
+ if ((*_lex)->is(T_IDENTIFIER)) {
+ _value.set_long(env->resolve(tokenSpell()) != 0);
+ ++(*_lex);
+ if ((*_lex)->is(T_RPAREN)) {
+ ++(*_lex);
+ return true;
+ }
+ }
+ return false;
+ }
+ return true;
+ } else if ((*_lex)->is(T_IDENTIFIER)) {
+ _value.set_long(0);
+ ++(*_lex);
+ return true;
+ } else if ((*_lex)->is(T_MINUS)) {
+ ++(*_lex);
+ process_primary();
+ _value.set_long(- _value.l);
+ return true;
+ } else if ((*_lex)->is(T_PLUS)) {
+ ++(*_lex);
+ process_primary();
+ return true;
+ } else if ((*_lex)->is(T_EXCLAIM)) {
+ ++(*_lex);
+ process_primary();
+ _value.set_long(_value.is_zero());
+ return true;
+ } else if ((*_lex)->is(T_LPAREN)) {
+ ++(*_lex);
+ process_expression();
+ if ((*_lex)->is(T_RPAREN))
+ ++(*_lex);
+ return true;
+ }
+
+ return false;
+ }
+
+ bool process_multiplicative()
+ {
+ process_primary();
+
+ while ((*_lex)->is(T_STAR) || (*_lex)->is(T_SLASH) || (*_lex)->is(T_PERCENT)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_primary();
+
+ if (op.is(T_STAR)) {
+ _value = left * _value;
+ } else if (op.is(T_SLASH)) {
+ if (_value.is_zero())
+ _value.set_long(0);
+ else
+ _value = left / _value;
+ } else if (op.is(T_PERCENT)) {
+ if (_value.is_zero())
+ _value.set_long(0);
+ else
+ _value = left % _value;
+ }
+ }
+
+ return true;
+ }
+
+ bool process_additive()
+ {
+ process_multiplicative();
+
+ while ((*_lex)->is(T_PLUS) || (*_lex)->is(T_MINUS)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_multiplicative();
+
+ if (op.is(T_PLUS))
+ _value = left + _value;
+ else if (op.is(T_MINUS))
+ _value = left - _value;
+ }
+
+ return true;
+ }
+
+ bool process_shift()
+ {
+ process_additive();
+
+ while ((*_lex)->is(T_MINUS_MINUS) || (*_lex)->is(T_GREATER_GREATER)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_additive();
+
+ if (op.is(T_MINUS_MINUS))
+ _value = left << _value;
+ else if (op.is(T_GREATER_GREATER))
+ _value = left >> _value;
+ }
+
+ return true;
+ }
+
+ bool process_relational()
+ {
+ process_shift();
+
+ while ((*_lex)->is(T_LESS) || (*_lex)->is(T_LESS_EQUAL) ||
+ (*_lex)->is(T_GREATER) || (*_lex)->is(T_GREATER_EQUAL)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_shift();
+
+ if (op.is(T_LESS))
+ _value = left < _value;
+ else if (op.is(T_LESS_EQUAL))
+ _value = left <= _value;
+ else if (op.is(T_GREATER))
+ _value = left > _value;
+ else if (op.is(T_GREATER_EQUAL))
+ _value = left >= _value;
+ }
+
+ return true;
+ }
+
+ bool process_equality()
+ {
+ process_relational();
+
+ while ((*_lex)->is(T_EXCLAIM_EQUAL) || (*_lex)->is(T_EQUAL_EQUAL)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_relational();
+
+ if (op.is(T_EXCLAIM_EQUAL))
+ _value = left != _value;
+ else if (op.is(T_EQUAL_EQUAL))
+ _value = left == _value;
+ }
+
+ return true;
+ }
+
+ bool process_and()
+ {
+ process_equality();
+
+ while ((*_lex)->is(T_AMPER)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_equality();
+
+ _value = left & _value;
+ }
+
+ return true;
+ }
+
+ bool process_xor()
+ {
+ process_and();
+
+ while ((*_lex)->is(T_CARET)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_and();
+
+ _value = left ^ _value;
+ }
+
+ return true;
+ }
+
+ bool process_or()
+ {
+ process_xor();
+
+ while ((*_lex)->is(T_CARET)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_xor();
+
+ _value = left | _value;
+ }
+
+ return true;
+ }
+
+ bool process_logical_and()
+ {
+ process_or();
+
+ while ((*_lex)->is(T_AMPER_AMPER)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_or();
+
+ _value = left && _value;
+ }
+
+ return true;
+ }
+
+ bool process_logical_or()
+ {
+ process_logical_and();
+
+ while ((*_lex)->is(T_PIPE_PIPE)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_logical_and();
+
+ _value = left || _value;
+ }
+
+ return true;
+ }
+
+ bool process_constant_expression()
+ {
+ process_logical_or();
+ const Value cond = _value;
+ if ((*_lex)->is(T_QUESTION)) {
+ ++(*_lex);
+ process_constant_expression();
+ Value left = _value, right;
+ if ((*_lex)->is(T_COLON)) {
+ ++(*_lex);
+ process_constant_expression();
+ right = _value;
+ }
+ _value = ! cond.is_zero() ? left : right;
+ }
+
+ return true;
+ }
+
+private:
+ Environment *env;
+ QByteArray source;
+ RangeLexer *_lex;
+ Value _value;
+};
+
+} // end of anonymous namespace
+
+
+pp::pp (Client *client, Environment &env)
+ : client(client),
+ env(env),
+ expand(env)
+{
+ resetIfLevel ();
+}
+
+void pp::pushState(const State &s)
+{
+ _savedStates.append(state());
+ _source = s.source;
+ _tokens = s.tokens;
+ _dot = s.dot;
+}
+
+pp::State pp::state() const
+{
+ State state;
+ state.source = _source;
+ state.tokens = _tokens;
+ state.dot = _dot;
+ return state;
+}
+
+void pp::popState()
+{
+ const State &state = _savedStates.last();
+ _source = state.source;
+ _tokens = state.tokens;
+ _dot = state.dot;
+ _savedStates.removeLast();
+}
+
+void pp::operator () (const QByteArray &filename,
+ const QByteArray &source,
+ QByteArray *result)
+{
+ const QByteArray previousFile = env.current_file;
+ env.current_file = filename;
+
+ operator () (source, result);
+
+ env.current_file = previousFile;
+}
+
+pp::State pp::createStateFromSource(const QByteArray &source) const
+{
+ State state;
+ state.source = source;
+ Lexer lex(state.source.constBegin(), state.source.constEnd());
+ lex.setScanKeywords(false);
+ Token tok;
+ do {
+ lex(&tok);
+ state.tokens.append(tok);
+ } while (tok.isNot(T_EOF_SYMBOL));
+ state.dot = state.tokens.constBegin();
+ return state;
+}
+
+void pp::operator()(const QByteArray &source, QByteArray *result)
+{
+ pushState(createStateFromSource(source));
+
+ const unsigned previousCurrentLine = env.currentLine;
+ env.currentLine = 0;
+
+ while (true) {
+ if (env.currentLine != _dot->lineno) {
+ if (env.currentLine > _dot->lineno) {
+ result->append('\n');
+ result->append('#');
+ result->append(QByteArray::number(_dot->lineno));
+ result->append(' ');
+ result->append('"');
+ result->append(env.current_file);
+ result->append('"');
+ result->append('\n');
+ } else {
+ for (unsigned i = env.currentLine; i < _dot->lineno; ++i)
+ result->append('\n');
+ }
+ env.currentLine = _dot->lineno;
+ }
+
+ if (_dot->is(T_EOF_SYMBOL)) {
+ break;
+ } else if (_dot->is(T_POUND) && (! _dot->joined && _dot->newline)) {
+ TokenIterator start = _dot;
+ do {
+ ++_dot;
+ } while (_dot->isNot(T_EOF_SYMBOL) && (_dot->joined || ! _dot->newline));
+
+ //qDebug() << QByteArray(first + beginPP.offset,
+ //tokens.last().end() - beginPP.offset);
+
+ const bool skippingBlocks = _skipping[iflevel];
+
+ processDirective(start, _dot);
+
+ if (client && skippingBlocks != _skipping[iflevel]) {
+ unsigned offset = start->offset;
+ if (_skipping[iflevel]) {
+ if (_dot->newline)
+ ++offset;
+ client->startSkippingBlocks(offset);
+ } else {
+ if (offset)
+ --offset;
+ client->stopSkippingBlocks(offset);
+ }
+ }
+ } else if (skipping()) {
+ do {
+ ++_dot;
+ } while (_dot->isNot(T_EOF_SYMBOL) && (_dot->joined || ! _dot->newline));
+ } else {
+ if (_dot->joined)
+ result->append("\\\n");
+ else if (_dot->newline) {
+ result->append('\n');
+ result->append('#');
+ result->append(QByteArray::number(_dot->lineno));
+ result->append(' ');
+ result->append('"');
+ result->append(env.current_file);
+ result->append('"');
+ result->append('\n');
+ }
+ else if (_dot->whitespace)
+ result->append(' ');
+
+ if (_dot->isNot(T_IDENTIFIER)) {
+ result->append(tokenSpell(*_dot));
+ ++_dot;
+ } else {
+ const TokenIterator identifierToken = _dot;
+ ++_dot; // skip T_IDENTIFIER
+
+ const QByteArray spell = tokenSpell(*identifierToken);
+ if (env.isBuiltinMacro(spell)) {
+ expand(spell.constBegin(), spell.constEnd(), result);
+ continue;
+ }
+
+ Macro *m = env.resolve(spell);
+ if (! m) {
+ result->append(spell);
+ } else {
+ if (! m->function_like) {
+ if (_dot->isNot(T_LPAREN)) {
+ expand(m->definition.constBegin(),
+ m->definition.constEnd(),
+ result);
+ continue;
+ } else {
+ QByteArray tmp;
+ expand(m->definition.constBegin(),
+ m->definition.constEnd(),
+ &tmp);
+
+ m = 0; // reset the active the macro
+
+ pushState(createStateFromSource(tmp));
+ if (_dot->is(T_IDENTIFIER)) {
+ const QByteArray id = tokenSpell(*_dot);
+ Macro *macro = env.resolve(id);
+ if (macro && macro->function_like)
+ m = macro;
+ }
+ popState();
+
+ if (! m) {
+ result->append(tmp);
+ continue;
+ }
+ }
+ }
+
+ // collect the actual arguments
+ if (_dot->isNot(T_LPAREN)) {
+ // ### warnng expected T_LPAREN
+ result->append(m->name);
+ continue;
+ }
+
+ int count = 0;
+ while (_dot->isNot(T_EOF_SYMBOL)) {
+ if (_dot->is(T_LPAREN))
+ ++count;
+ else if (_dot->is(T_RPAREN)) {
+ if (! --count)
+ break;
+ }
+ ++_dot;
+ }
+ if (_dot->isNot(T_RPAREN)) {
+ // ### warning expected T_RPAREN
+ } else {
+ const char *beginOfText = startOfToken(*identifierToken);
+ const char *endOfText = endOfToken(*_dot);
+ ++_dot; // skip T_RPAREN
+ expand(beginOfText, endOfText, result);
+ }
+ }
+ }
+ }
+ }
+
+ popState();
+ env.currentLine = previousCurrentLine;
+}
+
+const char *pp::startOfToken(const Token &token) const
+{ return _source.constBegin() + token.begin(); }
+
+const char *pp::endOfToken(const Token &token) const
+{ return _source.constBegin() + token.end(); }
+
+QByteArray pp::tokenSpell(const Token &token) const
+{
+ const QByteArray text = QByteArray::fromRawData(_source.constBegin() + token.offset,
+ token.length);
+ return text;
+}
+
+QByteArray pp::tokenText(const Token &token) const
+{
+ const QByteArray text(_source.constBegin() + token.offset,
+ token.length);
+ return text;
+}
+
+void pp::processDirective(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+ ++tk; // skip T_POUND
+
+ if (tk->is(T_IDENTIFIER)) {
+ const QByteArray directive = tokenSpell(*tk);
+ switch (PP_DIRECTIVE_TYPE d = classifyDirective(directive)) {
+ case PP_DEFINE:
+ if (! skipping())
+ processDefine(firstToken, lastToken);
+ break;
+
+ case PP_INCLUDE:
+ case PP_INCLUDE_NEXT:
+ if (! skipping())
+ processInclude(d == PP_INCLUDE_NEXT, firstToken, lastToken);
+ break;
+
+ case PP_UNDEF:
+ if (! skipping())
+ processUndef(firstToken, lastToken);
+ break;
+
+ case PP_ELIF:
+ processElif(firstToken, lastToken);
+ break;
+
+ case PP_ELSE:
+ processElse(firstToken, lastToken);
+ break;
+
+ case PP_ENDIF:
+ processEndif(firstToken, lastToken);
+ break;
+
+ case PP_IF:
+ processIf(firstToken, lastToken);
+ break;
+
+ case PP_IFDEF:
+ case PP_IFNDEF:
+ processIfdef(d == PP_IFNDEF, firstToken, lastToken);
+ break;
+
+ default:
+ break;
+ } // switch
+ }
+}
+
+QVector<Token> pp::tokenize(const QByteArray &text) const
+{
+ QVector<Token> tokens;
+ Lexer lex(text.constBegin(), text.constEnd());
+ lex.setScanKeywords(false);
+ Token tk;
+ do {
+ lex(&tk);
+ tokens.append(tk);
+ } while (tk.isNot(T_EOF_SYMBOL));
+ return tokens;
+}
+
+void pp::processInclude(bool skipCurentPath,
+ TokenIterator firstToken, TokenIterator lastToken,
+ bool acceptMacros)
+{
+ RangeLexer tk(firstToken, lastToken);
+ ++tk; // skip T_POUND
+ ++tk; // skip `include|nclude_next'
+
+ if (acceptMacros && tk->is(T_IDENTIFIER)) {
+#if 0
+ QByteArray name;
+ name.reserve(256);
+ MacroExpander expandInclude(env);
+ expandInclude(startOfToken(tokens.at(2)),
+ startOfToken(tokens.last()),
+ &name);
+ const QByteArray previousSource = switchSource(name);
+ //processInclude(skipCurentPath, tokenize(name), /*accept macros=*/ false);
+ (void) switchSource(previousSource);
+#endif
+ } else if (tk->is(T_LESS)) {
+ TokenIterator start = tk.dot();
+ for (; tk->isNot(T_EOF_SYMBOL); ++tk) {
+ if (tk->is(T_GREATER))
+ break;
+ }
+ const char *beginOfPath = endOfToken(*start);
+ const char *endOfPath = startOfToken(*tk);
+ const QByteArray path = QByteArray::fromRawData(beginOfPath,
+ endOfPath - beginOfPath);
+
+ QString fn = QString::fromUtf8(path.constData(), path.length());
+
+ if (client)
+ client->sourceNeeded(fn, Client::IncludeGlobal);
+ } else if (tk->is(T_ANGLE_STRING_LITERAL) || tk->is(T_STRING_LITERAL)) {
+ const QByteArray spell = tokenSpell(*tk);
+ const char *beginOfPath = spell.constBegin();
+ const char *endOfPath = spell.constEnd();
+ const char quote = *beginOfPath;
+ if (beginOfPath + 1 != endOfPath && ((quote == '"' && endOfPath[-1] == '"') ||
+ (quote == '<' && endOfPath[-1] == '>'))) {
+ const QByteArray path = QByteArray::fromRawData(beginOfPath + 1,
+ spell.length() - 2);
+ QString fn = QString::fromUtf8(path.constData(), path.length());
+
+ if (client)
+ client->sourceNeeded(fn, Client::IncludeLocal);
+ }
+ }
+}
+
+void pp::processDefine(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+
+ if (tk.size() < 3)
+ return; // nothing to do
+
+ ++tk; // skip T_POUND
+ ++tk; // skip T_DEFINE
+
+ if (tk->isNot(T_IDENTIFIER)) {
+ // ### warning expected an `identifier'
+ return;
+ }
+
+ Macro macro;
+ macro.name = tokenText(*tk);
+ ++tk; // skip T_IDENTIFIER
+
+ if (tk->is(T_LPAREN) && ! tk->whitespace) {
+ // a function-like macro definition
+ macro.function_like = true;
+
+ ++tk; // skip T_LPAREN
+ if (tk->is(T_IDENTIFIER)) {
+ macro.formals.append(tokenText(*tk));
+ ++tk; // skip T_IDENTIFIER
+ while (tk->is(T_COMMA)) {
+ ++tk;// skip T_COMMA
+ if (tk->isNot(T_IDENTIFIER))
+ break;
+ macro.formals.append(tokenText(*tk));
+ ++tk; // skip T_IDENTIFIER
+ }
+ }
+
+ if (tk->is(T_DOT_DOT_DOT)) {
+ macro.variadics = true;
+ ++tk; // skip T_DOT_DOT_DOT
+ }
+
+ if (tk->isNot(T_RPAREN)) {
+ // ### warning expected `)'
+ return;
+ }
+
+ ++tk; // skip T_RPAREN
+ }
+
+ QByteArray macroId = macro.name;
+ const bool isQtWord = isQtReservedWord(macroId);
+
+ if (macro.function_like) {
+ macroId += '(';
+ for (int i = 0; i < macro.formals.size(); ++i) {
+ if (i != 0)
+ macroId += ", ";
+
+ const QByteArray formal = macro.formals.at(i);
+ macroId += formal;
+ }
+ macroId += ')';
+ }
+
+ if (isQtWord)
+ macro.definition = macroId;
+ else {
+ const char *startOfDefinition = startOfToken(*tk);
+ const char *endOfDefinition = startOfToken(*lastToken);
+ macro.definition.append(startOfDefinition,
+ endOfDefinition - startOfDefinition);
+ macro.definition.replace("\\\n", " ");
+ }
+
+ env.bind(macro);
+
+ QByteArray macroText;
+ macroText.reserve(64);
+ macroText += "#define ";
+
+ macroText += macroId;
+ macroText += ' ';
+ macroText += macro.definition;
+ macroText += '\n';
+
+ client->macroAdded(macroId, macroText);
+}
+
+void pp::processIf(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+
+ ++tk; // skip T_POUND
+ ++tk; // skipt `if'
+
+ if (testIfLevel()) {
+ const char *first = startOfToken(*tk);
+ const char *last = startOfToken(*lastToken);
+
+ MacroExpander expandCondition (env);
+ QByteArray condition;
+ condition.reserve(256);
+ expandCondition(first, last, &condition);
+
+ QVector<Token> tokens = tokenize(condition);
+
+ const Value result = evalExpression(tokens.constBegin(),
+ tokens.constEnd() - 1,
+ condition);
+
+ _true_test[iflevel] = ! result.is_zero ();
+ _skipping[iflevel] = result.is_zero ();
+ }
+}
+
+void pp::processElse(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+
+ if (iflevel == 0 && !skipping ()) {
+ // std::cerr << "*** WARNING #else without #if" << std::endl;
+ } else if (iflevel > 0 && _skipping[iflevel - 1]) {
+ _skipping[iflevel] = true;
+ } else {
+ _skipping[iflevel] = _true_test[iflevel];
+ }
+}
+
+void pp::processElif(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+ ++tk; // skip T_POUND
+ ++tk; // skipt `elif'
+
+ if (! (iflevel > 0)) {
+ // std::cerr << "*** WARNING: " << __FILE__ << __LINE__ << std::endl;
+ } else if (iflevel == 0 && !skipping()) {
+ // std::cerr << "*** WARNING #else without #if" << std::endl;
+ } else if (!_true_test[iflevel] && !_skipping[iflevel - 1]) {
+ const Value result = evalExpression(tk.dot(), lastToken, _source);
+ _true_test[iflevel] = ! result.is_zero ();
+ _skipping[iflevel] = result.is_zero ();
+ } else {
+ _skipping[iflevel] = true;
+ }
+}
+
+void pp::processEndif(TokenIterator, TokenIterator)
+{
+ if (iflevel == 0 && !skipping()) {
+ // std::cerr << "*** WARNING #endif without #if" << std::endl;
+ } else {
+ _skipping[iflevel] = false;
+ _true_test[iflevel] = false;
+
+ --iflevel;
+ }
+}
+
+void pp::processIfdef(bool checkUndefined,
+ TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+
+ ++tk; // skip T_POUND
+ ++tk; // skip `ifdef'
+ if (testIfLevel()) {
+ if (tk->is(T_IDENTIFIER)) {
+ const QByteArray macroName = tokenSpell(*tk);
+ bool value = env.resolve(macroName) != 0 || env.isBuiltinMacro(macroName);
+
+ if (checkUndefined)
+ value = ! value;
+
+ _true_test[iflevel] = value;
+ _skipping [iflevel] = ! value;
+ }
+ }
+}
+
+void pp::processUndef(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+
+ ++tk; // skip T_POUND
+ ++tk; // skip `undef'
+
+ if (tk->is(T_IDENTIFIER)) {
+ const QByteArray macroName = tokenText(*tk);
+ env.remove(macroName);
+
+ QByteArray macroText;
+ macroText += "#undef ";
+ macroText += macroName;
+ macroText += '\n';
+ client->macroAdded(macroName, macroText);
+ }
+}
+
+void pp::resetIfLevel ()
+{
+ iflevel = 0;
+ _skipping[iflevel] = false;
+ _true_test[iflevel] = false;
+}
+
+pp::PP_DIRECTIVE_TYPE pp::classifyDirective (const QByteArray &__directive) const
+{
+ switch (__directive.size())
+ {
+ case 2:
+ if (__directive[0] == 'i' && __directive[1] == 'f')
+ return PP_IF;
+ break;
+
+ case 4:
+ if (__directive[0] == 'e' && __directive == "elif")
+ return PP_ELIF;
+ else if (__directive[0] == 'e' && __directive == "else")
+ return PP_ELSE;
+ break;
+
+ case 5:
+ if (__directive[0] == 'i' && __directive == "ifdef")
+ return PP_IFDEF;
+ else if (__directive[0] == 'u' && __directive == "undef")
+ return PP_UNDEF;
+ else if (__directive[0] == 'e' && __directive == "endif")
+ return PP_ENDIF;
+ break;
+
+ case 6:
+ if (__directive[0] == 'i' && __directive == "ifndef")
+ return PP_IFNDEF;
+ else if (__directive[0] == 'd' && __directive == "define")
+ return PP_DEFINE;
+ break;
+
+ case 7:
+ if (__directive[0] == 'i' && __directive == "include")
+ return PP_INCLUDE;
+ break;
+
+ case 12:
+ if (__directive[0] == 'i' && __directive == "include_next")
+ return PP_INCLUDE_NEXT;
+ break;
+
+ default:
+ break;
+ }
+
+ return PP_UNKNOWN_DIRECTIVE;
+}
+
+bool pp::testIfLevel()
+{
+ const bool result = !_skipping[iflevel++];
+ _skipping[iflevel] = _skipping[iflevel - 1];
+ _true_test[iflevel] = false;
+ return result;
+}
+
+int pp::skipping() const
+{ return _skipping[iflevel]; }
+
+Value pp::evalExpression(TokenIterator firstToken, TokenIterator lastToken,
+ const QByteArray &source) const
+{
+ ExpressionEvaluator eval(&env);
+ const Value result = eval(firstToken, lastToken, source);
+ return result;
+}
+
+bool pp::isQtReservedWord (const QByteArray &macroId) const
+{
+ const int size = macroId.size();
+ if (size == 9 && macroId.at(0) == 'Q' && macroId == "Q_SIGNALS")
+ return true;
+ else if (size == 7 && macroId.at(0) == 'Q' && macroId == "Q_SLOTS")
+ return true;
+ else if (size == 6 && macroId.at(0) == 'S' && macroId == "SIGNAL")
+ return true;
+ else if (size == 4 && macroId.at(0) == 'S' && macroId == "SLOT")
+ return true;
+ else if (size == 7 && macroId.at(0) == 's' && macroId == "signals")
+ return true;
+ else if (size == 5 && macroId.at(0) == 's' && macroId == "slots")
+ return true;
+ return false;
+}
diff --git a/src/plugins/cpptools/rpp/pp-engine.h b/src/plugins/cpptools/rpp/pp-engine.h
new file mode 100644
index 0000000000..fb3b9a3212
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-engine.h
@@ -0,0 +1,230 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ 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
+ KDEVELOP TEAM 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 PP_ENGINE_H
+#define PP_ENGINE_H
+
+#include "pp-client.h"
+#include <Token.h>
+#include <QVector>
+
+namespace CPlusPlus {
+ class Token;
+}
+
+namespace rpp {
+
+ struct Value
+ {
+ enum Kind {
+ Kind_Long,
+ Kind_ULong,
+ };
+
+ Kind kind;
+
+ union {
+ long l;
+ unsigned long ul;
+ };
+
+
+ Value()
+ : kind(Kind_Long), l(0)
+ { }
+
+ inline bool is_ulong () const
+ { return kind == Kind_ULong; }
+
+ inline void set_ulong (unsigned long v)
+ {
+ ul = v;
+ kind = Kind_ULong;
+ }
+
+ inline void set_long (long v)
+ {
+ l = v;
+ kind = Kind_Long;
+ }
+
+ inline bool is_zero () const
+ { return l == 0; }
+
+#define PP_DEFINE_BIN_OP(name, op) \
+ inline Value operator op(const Value &other) const \
+ { \
+ Value v = *this; \
+ if (v.is_ulong () || other.is_ulong ()) \
+ v.set_ulong (v.ul op other.ul); \
+ else \
+ v.set_long (v.l op other.l); \
+ return v; \
+ }
+
+ PP_DEFINE_BIN_OP(op_add, +)
+ PP_DEFINE_BIN_OP(op_sub, -)
+ PP_DEFINE_BIN_OP(op_mult, *)
+ PP_DEFINE_BIN_OP(op_div, /)
+ PP_DEFINE_BIN_OP(op_mod, %)
+ PP_DEFINE_BIN_OP(op_lhs, <<)
+ PP_DEFINE_BIN_OP(op_rhs, >>)
+ PP_DEFINE_BIN_OP(op_lt, <)
+ PP_DEFINE_BIN_OP(op_gt, >)
+ PP_DEFINE_BIN_OP(op_le, <=)
+ PP_DEFINE_BIN_OP(op_ge, >=)
+ PP_DEFINE_BIN_OP(op_eq, ==)
+ PP_DEFINE_BIN_OP(op_ne, !=)
+ PP_DEFINE_BIN_OP(op_bit_and, &)
+ PP_DEFINE_BIN_OP(op_bit_or, |)
+ PP_DEFINE_BIN_OP(op_bit_xor, ^)
+ PP_DEFINE_BIN_OP(op_and, &&)
+ PP_DEFINE_BIN_OP(op_or, ||)
+
+#undef PP_DEFINE_BIN_OP
+ };
+
+ class pp
+ {
+ Client *client;
+ Environment &env;
+ MacroExpander expand;
+
+ enum { MAX_LEVEL = 512 };
+
+ bool _skipping[MAX_LEVEL]; // ### move in state
+ bool _true_test[MAX_LEVEL]; // ### move in state
+ int iflevel; // ### move in state
+
+ enum PP_DIRECTIVE_TYPE
+ {
+ PP_UNKNOWN_DIRECTIVE,
+ PP_DEFINE,
+ PP_INCLUDE,
+ PP_INCLUDE_NEXT,
+ PP_ELIF,
+ PP_ELSE,
+ PP_ENDIF,
+ PP_IF,
+ PP_IFDEF,
+ PP_IFNDEF,
+ PP_UNDEF
+ };
+
+ typedef const CPlusPlus::Token *TokenIterator;
+
+ struct State {
+ QByteArray source;
+ QVector<CPlusPlus::Token> tokens;
+ TokenIterator dot;
+ };
+
+ QList<State> _savedStates;
+
+ State state() const;
+ void pushState(const State &state);
+ void popState();
+
+ QByteArray _source;
+ QVector<CPlusPlus::Token> _tokens;
+ TokenIterator _dot;
+
+ State createStateFromSource(const QByteArray &source) const;
+
+ public:
+ pp(Client *client, Environment &env);
+
+ void operator()(const QByteArray &filename,
+ const QByteArray &source,
+ QByteArray *result);
+
+ void operator()(const QByteArray &source,
+ QByteArray *result);
+
+ private:
+ void resetIfLevel();
+ bool testIfLevel();
+ int skipping() const;
+
+ PP_DIRECTIVE_TYPE classifyDirective(const QByteArray &directive) const;
+
+ Value evalExpression(TokenIterator firstToken,
+ TokenIterator lastToken,
+ const QByteArray &source) const;
+
+ QVector<CPlusPlus::Token> tokenize(const QByteArray &text) const;
+
+ const char *startOfToken(const CPlusPlus::Token &token) const;
+ const char *endOfToken(const CPlusPlus::Token &token) const;
+
+ QByteArray tokenSpell(const CPlusPlus::Token &token) const;
+ QByteArray tokenText(const CPlusPlus::Token &token) const; // does a deep copy
+
+ void processDirective(TokenIterator dot, TokenIterator lastToken);
+ void processInclude(bool skipCurrentPath,
+ TokenIterator dot, TokenIterator lastToken,
+ bool acceptMacros = true);
+ void processDefine(TokenIterator dot, TokenIterator lastToken);
+ void processIf(TokenIterator dot, TokenIterator lastToken);
+ void processElse(TokenIterator dot, TokenIterator lastToken);
+ void processElif(TokenIterator dot, TokenIterator lastToken);
+ void processEndif(TokenIterator dot, TokenIterator lastToken);
+ void processIfdef(bool checkUndefined,
+ TokenIterator dot, TokenIterator lastToken);
+ void processUndef(TokenIterator dot, TokenIterator lastToken);
+
+ bool isQtReservedWord(const QByteArray &name) const;
+ };
+
+} // namespace rpp
+
+#endif // PP_ENGINE_H
diff --git a/src/plugins/cpptools/rpp/pp-environment.cpp b/src/plugins/cpptools/rpp/pp-environment.cpp
new file mode 100644
index 0000000000..1503787898
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-environment.cpp
@@ -0,0 +1,231 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ 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
+ KDEVELOP TEAM 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 "pp-environment.h"
+#include "pp.h"
+#include <cstring>
+
+using namespace rpp;
+
+Environment::Environment ()
+ : currentLine(0),
+ hide_next(false),
+ _macros(0),
+ _allocated_macros(0),
+ _macro_count(-1),
+ _hash(0),
+ _hash_count(401)
+{
+}
+
+Environment::~Environment ()
+{
+ if (_macros) {
+ qDeleteAll(firstMacro(), lastMacro());
+ free(_macros);
+ }
+
+ if (_hash)
+ free(_hash);
+}
+
+unsigned Environment::macroCount () const
+{ return _macro_count + 1; }
+
+Macro *Environment::macroAt (unsigned index) const
+{ return _macros[index]; }
+
+Macro *Environment::bind(const Macro &__macro)
+{
+ Q_ASSERT(! __macro.name.isEmpty());
+
+ Macro *m = new Macro (__macro);
+ m->hashcode = hash_code(m->name);
+ m->fileName = current_file;
+ m->line = currentLine;
+
+ if (++_macro_count == _allocated_macros) {
+ if (! _allocated_macros)
+ _allocated_macros = 401;
+ else
+ _allocated_macros <<= 1;
+
+ _macros = (Macro **) realloc(_macros, sizeof(Macro *) * _allocated_macros);
+ }
+
+ _macros[_macro_count] = m;
+
+ if (! _hash || _macro_count > (_hash_count >> 1)) {
+ rehash();
+ } else {
+ const unsigned h = m->hashcode % _hash_count;
+ m->next = _hash[h];
+ _hash[h] = m;
+ }
+
+ return m;
+}
+
+void Environment::remove (const QByteArray &name)
+{
+ Macro macro;
+ macro.name = name;
+ macro.hidden = true;
+ bind(macro);
+}
+
+bool Environment::isBuiltinMacro(const QByteArray &s) const
+{
+ if (s.length() != 8)
+ return false;
+
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'D') {
+ if (s[3] == 'A') {
+ if (s[4] == 'T') {
+ if (s[5] == 'E') {
+ if (s[6] == '_') {
+ if (s[7] == '_') {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 'F') {
+ if (s[3] == 'I') {
+ if (s[4] == 'L') {
+ if (s[5] == 'E') {
+ if (s[6] == '_') {
+ if (s[7] == '_') {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 'L') {
+ if (s[3] == 'I') {
+ if (s[4] == 'N') {
+ if (s[5] == 'E') {
+ if (s[6] == '_') {
+ if (s[7] == '_') {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 'T') {
+ if (s[3] == 'I') {
+ if (s[4] == 'M') {
+ if (s[5] == 'E') {
+ if (s[6] == '_') {
+ if (s[7] == '_') {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+Macro *Environment::resolve (const QByteArray &name) const
+{
+ if (! _macros)
+ return 0;
+
+ Macro *it = _hash[hash_code (name) % _hash_count];
+ for (; it; it = it->next) {
+ if (it->name != name)
+ continue;
+ else if (it->hidden)
+ return 0;
+ else break;
+ }
+ return it;
+}
+
+unsigned Environment::hash_code (const QByteArray &s)
+{
+ unsigned hash_value = 0;
+
+ for (int i = 0; i < s.size (); ++i)
+ hash_value = (hash_value << 5) - hash_value + s.at (i);
+
+ return hash_value;
+}
+
+void Environment::rehash()
+{
+ if (_hash) {
+ free(_hash);
+ _hash_count <<= 1;
+ }
+
+ _hash = (Macro **) calloc(_hash_count, sizeof(Macro *));
+
+ for (Macro **it = firstMacro(); it != lastMacro(); ++it) {
+ Macro *m= *it;
+ const unsigned h = m->hashcode % _hash_count;
+ m->next = _hash[h];
+ _hash[h] = m;
+ }
+}
diff --git a/src/plugins/cpptools/rpp/pp-environment.h b/src/plugins/cpptools/rpp/pp-environment.h
new file mode 100644
index 0000000000..cdecf4de61
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-environment.h
@@ -0,0 +1,109 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ 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
+ KDEVELOP TEAM 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 PP_ENVIRONMENT_H
+#define PP_ENVIRONMENT_H
+
+#include <QVector>
+#include <QByteArray>
+
+namespace rpp {
+
+struct Macro;
+
+class Environment
+{
+public:
+ Environment();
+ ~Environment();
+
+ unsigned macroCount() const;
+ Macro *macroAt(unsigned index) const;
+
+ Macro *bind(const Macro &macro);
+ void remove(const QByteArray &name);
+
+ Macro *resolve(const QByteArray &name) const;
+ bool isBuiltinMacro(const QByteArray &name) const;
+
+ const Macro *const *firstMacro() const
+ { return _macros; }
+
+ Macro **firstMacro()
+ { return _macros; }
+
+ const Macro *const *lastMacro() const
+ { return _macros + _macro_count + 1; }
+
+ Macro **lastMacro()
+ { return _macros + _macro_count + 1; }
+
+private:
+ static unsigned hash_code (const QByteArray &s);
+ void rehash();
+
+public:
+ QByteArray current_file;
+ unsigned currentLine;
+ bool hide_next;
+
+private:
+ Macro **_macros;
+ int _allocated_macros;
+ int _macro_count;
+ Macro **_hash;
+ int _hash_count;
+};
+
+} // namespace rpp
+
+#endif // PP_ENVIRONMENT_H
diff --git a/src/plugins/cpptools/rpp/pp-fwd.h b/src/plugins/cpptools/rpp/pp-fwd.h
new file mode 100644
index 0000000000..05b68774cf
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-fwd.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ 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
+ KDEVELOP TEAM 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 PP_FWD_H
+#define PP_FWD_H
+
+namespace rpp {
+
+} // namespace rpp
+
+#endif // PP_FWD_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/src/plugins/cpptools/rpp/pp-internal.h b/src/plugins/cpptools/rpp/pp-internal.h
new file mode 100644
index 0000000000..eed958372c
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-internal.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ 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
+ KDEVELOP TEAM 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 PP_INTERNAL_H
+#define PP_INTERNAL_H
+
+#include <QByteArray>
+
+namespace rpp {
+
+ namespace _PP_internal
+ {
+
+ inline void output_line(const QByteArray &__filename, int __line, QByteArray *__result)
+ {
+ QByteArray __msg;
+
+ __msg += "# ";
+
+ char __line_descr[16];
+ qsnprintf (__line_descr, 16, "%d", __line);
+ __msg += __line_descr;
+
+ __msg += " \"";
+
+ if (__filename.isEmpty ())
+ __msg += "<editor>";
+ else
+ __msg += __filename;
+
+ __msg += "\"\n";
+ __result->append(__msg);
+ }
+
+ inline bool comment_p (const char *__first, const char *__last)
+ {
+ if (__first == __last)
+ return false;
+
+ if (*__first != '/')
+ return false;
+
+ if (++__first == __last)
+ return false;
+
+ return (*__first == '/' || *__first == '*');
+ }
+
+ } // _PP_internal
+
+} // namespace rpp
+
+#endif // PP_INTERNAL_H
diff --git a/src/plugins/cpptools/rpp/pp-macro-expander.cpp b/src/plugins/cpptools/rpp/pp-macro-expander.cpp
new file mode 100644
index 0000000000..658f2acc67
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-macro-expander.cpp
@@ -0,0 +1,362 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "pp.h"
+#include "pp-macro-expander.h"
+#include <QDateTime>
+
+using namespace rpp;
+
+MacroExpander::MacroExpander (Environment &env, pp_frame *frame)
+ : env (env), frame (frame),
+ lines (0), generated_lines (0)
+{ }
+
+const QByteArray *MacroExpander::resolve_formal (const QByteArray &__name)
+{
+ if (! (frame && frame->expanding_macro))
+ return 0;
+
+ const QVector<QByteArray> &formals = frame->expanding_macro->formals;
+ for (int index = 0; index < formals.size(); ++index) {
+ const QByteArray formal = formals.at(index);
+
+ if (formal == __name && index < frame->actuals.size())
+ return &frame->actuals.at(index);
+ }
+
+ return 0;
+}
+
+const char *MacroExpander::operator () (const char *__first, const char *__last,
+ QByteArray *__result)
+{
+ generated_lines = 0;
+ __first = skip_blanks (__first, __last);
+ lines = skip_blanks.lines;
+
+ while (__first != __last)
+ {
+ if (*__first == '\n')
+ {
+ __result->append('\n');
+ __result->append('#');
+ __result->append(QByteArray::number(env.currentLine));
+ __result->append(' ');
+ __result->append('"');
+ __result->append(env.current_file);
+ __result->append('"');
+ __result->append('\n');
+ ++lines;
+
+ __first = skip_blanks (++__first, __last);
+ lines += skip_blanks.lines;
+
+ if (__first != __last && *__first == '#')
+ break;
+ }
+ else if (*__first == '#')
+ {
+ __first = skip_blanks (++__first, __last);
+ lines += skip_blanks.lines;
+
+ const char *end_id = skip_identifier (__first, __last);
+ const QByteArray fast_name(__first, end_id - __first);
+ __first = end_id;
+
+ if (const QByteArray *actual = resolve_formal (fast_name))
+ {
+ __result->append('\"');
+
+ const char *actual_begin = actual->constData ();
+ const char *actual_end = actual_begin + actual->size ();
+
+ for (const char *it = skip_whitespaces (actual_begin, actual_end);
+ it != actual_end; ++it)
+ {
+ if (*it == '"' || *it == '\\')
+ {
+ __result->append('\\');
+ __result->append(*it);
+ }
+ else if (*it == '\n')
+ {
+ __result->append('"');
+ __result->append('\n');
+ __result->append('"');
+ }
+ else
+ __result->append(*it);
+ }
+
+ __result->append('\"');
+ }
+ else
+ __result->append('#'); // ### warning message?
+ }
+ else if (*__first == '\"')
+ {
+ const char *next_pos = skip_string_literal (__first, __last);
+ lines += skip_string_literal.lines;
+ __result->append(__first, next_pos - __first);
+ __first = next_pos;
+ }
+ else if (*__first == '\'')
+ {
+ const char *next_pos = skip_char_literal (__first, __last);
+ lines += skip_char_literal.lines;
+ __result->append(__first, next_pos - __first);
+ __first = next_pos;
+ }
+ else if (_PP_internal::comment_p (__first, __last))
+ {
+ __first = skip_comment_or_divop (__first, __last);
+ int n = skip_comment_or_divop.lines;
+ lines += n;
+
+ while (n-- > 0)
+ __result->append('\n');
+ }
+ else if (pp_isspace (*__first))
+ {
+ for (; __first != __last; ++__first)
+ {
+ if (*__first == '\n' || !pp_isspace (*__first))
+ break;
+ }
+
+ __result->append(' ');
+ }
+ else if (pp_isdigit (*__first))
+ {
+ const char *next_pos = skip_number (__first, __last);
+ lines += skip_number.lines;
+ __result->append(__first, next_pos - __first);
+ __first = next_pos;
+ }
+ else if (pp_isalpha (*__first) || *__first == '_')
+ {
+ const char *name_begin = __first;
+ const char *name_end = skip_identifier (__first, __last);
+ __first = name_end; // advance
+
+ // search for the paste token
+ const char *next = skip_blanks (__first, __last);
+ bool paste = false;
+ if (next != __last && *next == '#')
+ {
+ paste = true;
+ ++next;
+ if (next != __last && *next == '#')
+ __first = skip_blanks(++next, __last);
+ }
+
+ const QByteArray fast_name(name_begin, name_end - name_begin);
+
+ if (const QByteArray *actual = resolve_formal (fast_name))
+ {
+ const char *begin = actual->constData ();
+ const char *end = begin + actual->size ();
+ if (paste) {
+ for (--end; end != begin - 1; --end) {
+ if (! pp_isspace(*end))
+ break;
+ }
+ ++end;
+ }
+ __result->append(begin, end - begin);
+ continue;
+ }
+
+ Macro *macro = env.resolve (fast_name);
+ if (! macro || macro->hidden || env.hide_next)
+ {
+ if (fast_name.size () == 7 && fast_name [0] == 'd' && fast_name == "defined")
+ env.hide_next = true;
+ else
+ env.hide_next = false;
+
+ if (fast_name.size () == 8 && fast_name [0] == '_' && fast_name [1] == '_')
+ {
+ if (fast_name == "__LINE__")
+ {
+ char buf [16];
+ const size_t count = qsnprintf (buf, 16, "%d", env.currentLine + lines);
+ __result->append(buf, count);
+ continue;
+ }
+
+ else if (fast_name == "__FILE__")
+ {
+ __result->append('"');
+ __result->append(env.current_file);
+ __result->append('"');
+ continue;
+ }
+
+ else if (fast_name == "__DATE__")
+ {
+ __result->append('"');
+ __result->append(QDate::currentDate().toString().toUtf8());
+ __result->append('"');
+ continue;
+ }
+
+ else if (fast_name == "__TIME__")
+ {
+ __result->append('"');
+ __result->append(QTime::currentTime().toString().toUtf8());
+ __result->append('"');
+ continue;
+ }
+
+ }
+
+ __result->append(name_begin, name_end - name_begin);
+ continue;
+ }
+
+ if (! macro->function_like)
+ {
+ Macro *m = 0;
+
+ if (! macro->definition.isEmpty())
+ {
+ macro->hidden = true;
+
+ QByteArray __tmp;
+ __tmp.reserve (256);
+
+ MacroExpander expand_macro (env);
+ expand_macro (macro->definition.constBegin (), macro->definition.constEnd (), &__tmp);
+ generated_lines += expand_macro.lines;
+
+ if (! __tmp.isEmpty ())
+ {
+ const char *__tmp_begin = __tmp.constBegin();
+ const char *__tmp_end = __tmp.constEnd();
+ const char *__begin_id = skip_whitespaces (__tmp_begin, __tmp_end);
+ const char *__end_id = skip_identifier (__begin_id, __tmp_end);
+
+ if (__end_id == __tmp_end)
+ {
+ const QByteArray __id (__begin_id, __end_id - __begin_id);
+ m = env.resolve (__id);
+ }
+
+ if (! m)
+ *__result += __tmp;
+ }
+
+ macro->hidden = false;
+ }
+
+ if (! m)
+ continue;
+
+ macro = m;
+ }
+
+ // function like macro
+ const char *arg_it = skip_whitespaces (__first, __last);
+
+ if (arg_it == __last || *arg_it != '(')
+ {
+ __result->append(name_begin, name_end - name_begin);
+ lines += skip_whitespaces.lines;
+ __first = arg_it;
+ continue;
+ }
+
+ QVector<QByteArray> actuals;
+ actuals.reserve (5);
+ ++arg_it; // skip '('
+
+ MacroExpander expand_actual (env, frame);
+
+ const char *arg_end = skip_argument_variadics (actuals, macro, arg_it, __last);
+ if (arg_it != arg_end)
+ {
+ const QByteArray actual (arg_it, arg_end - arg_it);
+ QByteArray expanded;
+ expand_actual (actual.constBegin (), actual.constEnd (), &expanded);
+ actuals.push_back (expanded);
+ arg_it = arg_end;
+ }
+
+ while (arg_it != __last && *arg_end == ',')
+ {
+ ++arg_it; // skip ','
+
+ arg_end = skip_argument_variadics (actuals, macro, arg_it, __last);
+ const QByteArray actual (arg_it, arg_end - arg_it);
+ QByteArray expanded;
+ expand_actual (actual.constBegin (), actual.constEnd (), &expanded);
+ actuals.push_back (expanded);
+ arg_it = arg_end;
+ }
+
+ if (! (arg_it != __last && *arg_it == ')'))
+ return __last;
+
+ ++arg_it; // skip ')'
+ __first = arg_it;
+
+ pp_frame frame (macro, actuals);
+ MacroExpander expand_macro (env, &frame);
+ macro->hidden = true;
+ expand_macro (macro->definition.constBegin (), macro->definition.constEnd (), __result);
+ macro->hidden = false;
+ generated_lines += expand_macro.lines;
+ }
+ else
+ __result->append(*__first++);
+ }
+
+ return __first;
+}
+
+const char *MacroExpander::skip_argument_variadics (QVector<QByteArray> const &__actuals,
+ Macro *__macro,
+ const char *__first, const char *__last)
+{
+ const char *arg_end = skip_argument (__first, __last);
+
+ while (__macro->variadics && __first != arg_end && arg_end != __last && *arg_end == ','
+ && (__actuals.size () + 1) == __macro->formals.size ())
+ {
+ arg_end = skip_argument (++arg_end, __last);
+ }
+
+ return arg_end;
+}
diff --git a/src/plugins/cpptools/rpp/pp-macro-expander.h b/src/plugins/cpptools/rpp/pp-macro-expander.h
new file mode 100644
index 0000000000..bdf21a421b
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-macro-expander.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ 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
+ KDEVELOP TEAM 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 PP_MACRO_EXPANDER_H
+#define PP_MACRO_EXPANDER_H
+
+namespace rpp {
+
+ struct pp_frame
+ {
+ Macro *expanding_macro;
+ const QVector<QByteArray> actuals;
+
+ pp_frame (Macro *expanding_macro, const QVector<QByteArray> &actuals)
+ : expanding_macro (expanding_macro),
+ actuals (actuals)
+ { }
+ };
+
+ class MacroExpander
+ {
+ Environment &env;
+ pp_frame *frame;
+
+ pp_skip_number skip_number;
+ pp_skip_identifier skip_identifier;
+ pp_skip_string_literal skip_string_literal;
+ pp_skip_char_literal skip_char_literal;
+ pp_skip_argument skip_argument;
+ pp_skip_comment_or_divop skip_comment_or_divop;
+ pp_skip_blanks skip_blanks;
+ pp_skip_whitespaces skip_whitespaces;
+
+ const QByteArray *resolve_formal (const QByteArray &name);
+
+ public:
+ MacroExpander (Environment &env, pp_frame *frame = 0);
+
+ const char *operator () (const char *first, const char *last,
+ QByteArray *result);
+
+ const char *skip_argument_variadics (const QVector<QByteArray> &actuals,
+ Macro *macro,
+ const char *first, const char *last);
+
+ public: // attributes
+ int lines;
+ int generated_lines;
+ };
+
+} // namespace rpp
+
+#endif // PP_MACRO_EXPANDER_H
+
diff --git a/src/plugins/cpptools/rpp/pp-macro.h b/src/plugins/cpptools/rpp/pp-macro.h
new file mode 100644
index 0000000000..b220168989
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-macro.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ 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
+ KDEVELOP TEAM 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 PP_MACRO_H
+#define PP_MACRO_H
+
+#include <QByteArray>
+#include <QVector>
+
+namespace rpp {
+
+ struct Macro
+ {
+ QByteArray name;
+ QByteArray definition;
+ QVector<QByteArray> formals;
+ QByteArray fileName;
+ int line;
+ int lines;
+ Macro *next;
+ unsigned hashcode;
+
+ union
+ {
+ unsigned state;
+
+ struct
+ {
+ unsigned hidden: 1;
+ unsigned function_like: 1;
+ unsigned variadics: 1;
+ };
+ };
+
+ inline Macro():
+ line(0),
+ lines(0),
+ next(0),
+ hashcode(0),
+ state(0)
+ { }
+ };
+
+} // namespace rpp
+
+#endif // PP_MACRO_H
diff --git a/src/plugins/cpptools/rpp/pp-scanner.h b/src/plugins/cpptools/rpp/pp-scanner.h
new file mode 100644
index 0000000000..d9036d8855
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-scanner.h
@@ -0,0 +1,380 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ 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
+ KDEVELOP TEAM 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 PP_SCANNER_H
+#define PP_SCANNER_H
+
+namespace rpp {
+
+struct pp_skip_blanks
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ if (*__first == '\\')
+ {
+ const char *__begin = __first;
+ ++__begin;
+
+ if (__begin != __last && *__begin == '\n')
+ ++__first;
+ else
+ break;
+ }
+ else if (*__first == '\n' || !pp_isspace (*__first))
+ break;
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_whitespaces
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ if (! pp_isspace (*__first))
+ break;
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_comment_or_divop
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ enum {
+ MAYBE_BEGIN,
+ BEGIN,
+ MAYBE_END,
+ END,
+ IN_COMMENT,
+ IN_CXX_COMMENT
+ } state (MAYBE_BEGIN);
+
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ switch (state)
+ {
+ default:
+ assert (0);
+ break;
+
+ case MAYBE_BEGIN:
+ if (*__first != '/')
+ return __first;
+
+ state = BEGIN;
+ break;
+
+ case BEGIN:
+ if (*__first == '*')
+ state = IN_COMMENT;
+ else if (*__first == '/')
+ state = IN_CXX_COMMENT;
+ else
+ return __first;
+ break;
+
+ case IN_COMMENT:
+ if (*__first == '*')
+ state = MAYBE_END;
+ break;
+
+ case IN_CXX_COMMENT:
+ if (*__first == '\n')
+ return __first;
+ break;
+
+ case MAYBE_END:
+ if (*__first == '/')
+ state = END;
+ else if (*__first != '*')
+ state = IN_COMMENT;
+ break;
+
+ case END:
+ return __first;
+ }
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_identifier
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ if (! pp_isalnum (*__first) && *__first != '_')
+ break;
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_number
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ if (! pp_isalnum (*__first) && *__first != '.')
+ break;
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_string_literal
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ enum {
+ BEGIN,
+ IN_STRING,
+ QUOTE,
+ END
+ } state (BEGIN);
+
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ switch (state)
+ {
+ default:
+ assert (0);
+ break;
+
+ case BEGIN:
+ if (*__first != '\"')
+ return __first;
+ state = IN_STRING;
+ break;
+
+ case IN_STRING:
+ if (! (*__first != '\n'))
+ return __last;
+
+ if (*__first == '\"')
+ state = END;
+ else if (*__first == '\\')
+ state = QUOTE;
+ break;
+
+ case QUOTE:
+ state = IN_STRING;
+ break;
+
+ case END:
+ return __first;
+ }
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_char_literal
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ enum {
+ BEGIN,
+ IN_STRING,
+ QUOTE,
+ END
+ } state (BEGIN);
+
+ lines = 0;
+
+ for (; state != END && __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ switch (state)
+ {
+ default:
+ assert (0);
+ break;
+
+ case BEGIN:
+ if (*__first != '\'')
+ return __first;
+ state = IN_STRING;
+ break;
+
+ case IN_STRING:
+ if (! (*__first != '\n'))
+ return __last;
+
+ if (*__first == '\'')
+ state = END;
+ else if (*__first == '\\')
+ state = QUOTE;
+ break;
+
+ case QUOTE:
+ state = IN_STRING;
+ break;
+ }
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_argument
+{
+ pp_skip_identifier skip_number;
+ pp_skip_identifier skip_identifier;
+ pp_skip_string_literal skip_string_literal;
+ pp_skip_char_literal skip_char_literal;
+ pp_skip_comment_or_divop skip_comment_or_divop;
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ int depth = 0;
+ lines = 0;
+
+ while (__first != __last)
+ {
+ if (!depth && (*__first == ')' || *__first == ','))
+ break;
+ else if (*__first == '(')
+ ++depth, ++__first;
+ else if (*__first == ')')
+ --depth, ++__first;
+ else if (*__first == '\"')
+ {
+ __first = skip_string_literal (__first, __last);
+ lines += skip_string_literal.lines;
+ }
+ else if (*__first == '\'')
+ {
+ __first = skip_char_literal (__first, __last);
+ lines += skip_char_literal.lines;
+ }
+ else if (*__first == '/')
+ {
+ __first = skip_comment_or_divop (__first, __last);
+ lines += skip_comment_or_divop.lines;
+ }
+ else if (pp_isalpha (*__first) || *__first == '_')
+ {
+ __first = skip_identifier (__first, __last);
+ lines += skip_identifier.lines;
+ }
+ else if (pp_isdigit (*__first))
+ {
+ __first = skip_number (__first, __last);
+ lines += skip_number.lines;
+ }
+ else if (*__first == '\n')
+ {
+ ++__first;
+ ++lines;
+ }
+ else
+ ++__first;
+ }
+
+ return __first;
+ }
+};
+
+} // namespace rpp
+
+#endif // PP_SCANNER_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/src/plugins/cpptools/rpp/pp-symbol.h b/src/plugins/cpptools/rpp/pp-symbol.h
new file mode 100644
index 0000000000..37e2a623e5
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-symbol.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ 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
+ KDEVELOP TEAM 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.
+*/
+
diff --git a/src/plugins/cpptools/rpp/pp.h b/src/plugins/cpptools/rpp/pp.h
new file mode 100644
index 0000000000..52411f7624
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 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.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ 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
+ KDEVELOP TEAM 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 PP_H
+#define PP_H
+
+#if defined(_WIN64) || defined(WIN64) || defined(__WIN64__) \
+ || defined(_WIN32) || defined(WIN32) || defined(__WIN32__)
+# define PP_OS_WIN
+#endif
+
+#include <cassert>
+#include <cstring>
+#include <cctype>
+
+#include "pp-fwd.h"
+#include "pp-cctype.h"
+#include "pp-symbol.h"
+#include "pp-internal.h"
+#include "pp-macro.h"
+#include "pp-environment.h"
+#include "pp-scanner.h"
+#include "pp-macro-expander.h"
+#include "pp-engine.h"
+#include "pp-client.h"
+
+#endif // PP_H
diff --git a/src/plugins/cpptools/rpp/rpp.pri b/src/plugins/cpptools/rpp/rpp.pri
new file mode 100644
index 0000000000..f47976e6fe
--- /dev/null
+++ b/src/plugins/cpptools/rpp/rpp.pri
@@ -0,0 +1,20 @@
+DEPENDPATH += $$PWD
+INCLUDEPATH += $$PWD
+
+HEADERS += $$PWD/pp-cctype.h \
+ $$PWD/pp-engine.h \
+ $$PWD/pp-environment.h \
+ $$PWD/pp-fwd.h \
+ $$PWD/pp-internal.h \
+ $$PWD/pp-macro-expander.h \
+ $$PWD/pp-macro.h \
+ $$PWD/pp-scanner.h \
+ $$PWD/pp-symbol.h \
+ $$PWD/pp.h \
+ $$PWD/pp-client.h
+
+SOURCES += $$PWD/pp-engine.cpp \
+ $$PWD/pp-environment.cpp \
+ $$PWD/pp-macro-expander.cpp
+
+