aboutsummaryrefslogtreecommitdiffstats
path: root/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp')
-rw-r--r--src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp488
1 files changed, 488 insertions, 0 deletions
diff --git a/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp b/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp
new file mode 100644
index 00000000000..ae21f90d94a
--- /dev/null
+++ b/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp
@@ -0,0 +1,488 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include <AST.h>
+#include <ASTVisitor.h>
+#include <ASTPatternBuilder.h>
+#include <ASTMatcher.h>
+#include <Control.h>
+#include <Scope.h>
+#include <Bind.h>
+#include <TranslationUnit.h>
+#include <Literals.h>
+#include <Symbols.h>
+#include <Names.h>
+#include <CoreTypes.h>
+#include <CppDocument.h>
+#include <SymbolVisitor.h>
+#include <Overview.h>
+#include <LookupContext.h>
+
+#include "cplusplus-tools-utils.h"
+
+#include <QFile>
+#include <QList>
+#include <QCoreApplication>
+#include <QStringList>
+#include <QFileInfo>
+#include <QTime>
+#include <QDebug>
+
+#include <cstdio>
+#include <cstdlib>
+#include <iostream>
+
+using namespace CPlusPlus;
+
+class MkVisitor: protected SymbolVisitor
+{
+ const LookupContext &context;
+ Overview oo;
+ QList<ClassOrNamespace *> interfaces;
+ QList<ClassOrNamespace *> nodes;
+
+ bool isMiscNode(ClassOrNamespace *b) const
+ {
+ foreach (ClassOrNamespace *u, b->usings()) {
+ if (oo(u->symbols().first()->name()) == QLatin1String("AST"))
+ return true;
+ }
+
+ return false;
+ }
+
+ QString getAcceptFunctionName(ClassOrNamespace *b, QString *retType) const
+ {
+ Q_ASSERT(b != 0);
+
+ retType->clear();
+
+ if (interfaces.contains(b) || isMiscNode(b)) {
+ QString className = oo(b->symbols().first()->name());
+
+ if (className.endsWith("AST")) {
+ className.chop(3);
+
+ QString funcName = className;
+ if (! funcName.isEmpty())
+ funcName[0] = funcName[0].toLower();
+
+ if (funcName == QLatin1String("operator"))
+ funcName = QLatin1String("cppOperator");
+
+ if (interfaces.contains(b))
+ *retType = className + QLatin1String("Ty");
+
+ return funcName;
+ }
+ }
+
+ if (! b->usings().isEmpty())
+ return getAcceptFunctionName(b->usings().first(), retType);
+
+ Q_ASSERT(!"wtf?");
+ return QString();
+ }
+
+public:
+ MkVisitor(const LookupContext &context): context(context) {
+ accept(context.thisDocument()->globalNamespace());
+
+ // declaration
+
+ std::cout << "#include <CPlusPlus.h>" << std::endl
+ << "#include <memory>" << std::endl
+ << "#include <cassert>" << std::endl
+ << std::endl
+ << "using namespace CPlusPlus;" << std::endl
+ << std::endl;
+
+
+ std::cout << "class Semantic: protected ASTVisitor" << std::endl
+ << "{" << std::endl
+ << "public:" << std::endl
+ << " Semantic(TranslationUnit *unit): ASTVisitor(unit) { translationUnit(unit->ast()->asTranslationUnit()); }" << std::endl
+ << std::endl;
+
+ foreach (ClassOrNamespace *b, interfaces) {
+ Q_ASSERT(! b->symbols().isEmpty());
+
+ Class *klass = 0;
+ foreach (Symbol *s, b->symbols())
+ if ((klass = s->asClass()) != 0)
+ break;
+
+ Q_ASSERT(klass != 0);
+
+ QString className = oo(klass->name());
+ if (className == "AST")
+ continue;
+
+ QString baseClassName = className;
+ baseClassName.chop(3);
+
+ QString retTy = false;
+ QString funcName = getAcceptFunctionName(b, &retTy);
+
+ std::cout
+ << " typedef void *" << qPrintable(baseClassName) << "Ty;" << std::endl
+ << " " << qPrintable(baseClassName) << "Ty " << qPrintable(funcName)
+ << "(" << qPrintable(className) << " *ast);" << std::endl
+ << std::endl;
+ }
+
+ std::cout << "protected:" << std::endl;
+ std::cout << " using ASTVisitor::translationUnit;" << std::endl
+ << std::endl;
+
+ QHash<ClassOrNamespace *, QList<ClassOrNamespace *> > implements;
+ foreach (ClassOrNamespace *b, nodes) {
+ ClassOrNamespace *iface = 0;
+ foreach (ClassOrNamespace *u, b->usings()) {
+ if (interfaces.contains(u)) {
+ iface = u;
+ break;
+ }
+ }
+ Q_ASSERT(iface != 0);
+ implements[iface].append(b);
+ }
+
+ foreach (ClassOrNamespace *iface, interfaces) {
+ foreach (ClassOrNamespace *b, implements.value(iface)) {
+ if (! isMiscNode(b))
+ continue;
+
+ Class *klass = 0;
+ foreach (Symbol *s, b->symbols())
+ if ((klass = s->asClass()) != 0)
+ break;
+
+ Q_ASSERT(klass != 0);
+
+ QString retTy ;
+ QString className = oo(klass->name());
+ std::cout << " void " << qPrintable(getAcceptFunctionName(b, &retTy)) << "(" << qPrintable(className) << " *ast);" << std::endl;
+ }
+ }
+
+ std::cout << std::endl;
+
+ foreach (ClassOrNamespace *iface, interfaces) {
+ std::cout << " // " << qPrintable(oo(iface->symbols().first()->name())) << std::endl;
+ foreach (ClassOrNamespace *b, implements.value(iface)) {
+ Class *klass = 0;
+ foreach (Symbol *s, b->symbols())
+ if ((klass = s->asClass()) != 0)
+ break;
+
+ Q_ASSERT(klass != 0);
+
+ QString className = oo(klass->name());
+ std::cout << " virtual bool visit(" << qPrintable(className) << " *ast);" << std::endl;
+ }
+ std::cout << std::endl;
+ }
+
+ std::cout << "private:" << std::endl;
+ foreach (ClassOrNamespace *b, interfaces) {
+ Q_ASSERT(! b->symbols().isEmpty());
+
+ Class *klass = 0;
+ foreach (Symbol *s, b->symbols())
+ if ((klass = s->asClass()) != 0)
+ break;
+
+ Q_ASSERT(klass != 0);
+
+ QString className = oo(klass->name());
+ if (className == "AST")
+ continue;
+
+ QString baseClassName = className;
+ baseClassName.chop(3);
+
+ QString current = "_current";
+ current += baseClassName;
+
+ std::cout << " " << qPrintable(baseClassName) << "Ty " << qPrintable(current) << ";" << std::endl;
+ }
+
+ std::cout << "};" << std::endl
+ << std::endl;
+
+
+ std::cout << "namespace { bool debug_todo = false; }" << std::endl
+ << std::endl;
+
+
+ // implementation
+
+ foreach (ClassOrNamespace *b, interfaces) {
+ Q_ASSERT(! b->symbols().isEmpty());
+
+ Class *klass = 0;
+ foreach (Symbol *s, b->symbols())
+ if ((klass = s->asClass()) != 0)
+ break;
+
+ Q_ASSERT(klass != 0);
+
+ QString className = oo(klass->name());
+ if (className == "AST")
+ continue;
+
+ QString baseClassName = className;
+ baseClassName.chop(3);
+
+ QString retTy;
+ QString funcName = getAcceptFunctionName(b, &retTy);
+
+ QString current = "_current";
+ current += baseClassName;
+
+ std::cout << "Semantic::" << qPrintable(baseClassName) << "Ty Semantic::"
+ << qPrintable(funcName) << "(" << qPrintable(className) << " *ast)" << std::endl
+ << "{" << std::endl
+ << " " << qPrintable(baseClassName) << "Ty value = " << qPrintable(baseClassName) << "Ty();" << std::endl
+ << " std::swap(" << qPrintable(current) << ", value);" << std::endl
+ << " accept(ast);" << std::endl
+ << " std::swap(" << qPrintable(current) << ", value);" << std::endl
+ << " return value;" << std::endl
+ << "}" << std::endl
+ << std::endl;
+ }
+
+ foreach (ClassOrNamespace *iface, interfaces) {
+ std::cout << "// " << qPrintable(oo(iface->symbols().first()->name())) << std::endl;
+ foreach (ClassOrNamespace *b, implements.value(iface)) {
+ Class *klass = 0;
+ foreach (Symbol *s, b->symbols())
+ if ((klass = s->asClass()) != 0)
+ break;
+
+ Q_ASSERT(klass != 0);
+
+ QString className = oo(klass->name());
+ std::cout << "bool Semantic::visit(" << qPrintable(className) << " *ast)" << std::endl
+ << "{" << std::endl;
+
+ if (isMiscNode(b)) {
+ std::cout << " (void) ast;" << std::endl
+ << " assert(!\"unreachable\");" << std::endl
+ << " return false;" << std::endl
+ << "}" << std::endl
+ << std::endl;
+
+ QString retTy;
+ std::cout << "void Semantic::" << qPrintable(getAcceptFunctionName(b, &retTy)) << "(" << qPrintable(className) << " *ast)" << std::endl
+ << "{" << std::endl
+ << " if (! ast)" << std::endl
+ << " return;" << std::endl
+ << std::endl;
+ }
+
+ std::cout
+ << " if (debug_todo)" << std::endl
+ << " translationUnit()->warning(ast->firstToken(), \"TODO: %s\", __func__);" << std::endl;
+
+ for (unsigned i = 0; i < klass->memberCount(); ++i) {
+ Declaration *decl = klass->memberAt(i)->asDeclaration();
+ if (! decl)
+ continue;
+ if (decl->type()->isFunctionType())
+ continue;
+ const QString declName = oo(decl->name());
+ if (PointerType *ptrTy = decl->type()->asPointerType()) {
+ if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
+ const QString eltTyName = oo(namedTy->name());
+ if (eltTyName.endsWith("ListAST")) {
+ QString name = eltTyName;
+ name.chop(7);
+ name += "AST";
+
+ Control *control = context.thisDocument()->control();
+ const Name *n = control->identifier(name.toLatin1().constData());
+
+ if (ClassOrNamespace *bb = context.lookupType(n, klass)) {
+ QString retTy;
+ QString funcName = getAcceptFunctionName(bb, &retTy);
+ Q_ASSERT(! funcName.isEmpty());
+
+ QString var;
+ if (! retTy.isEmpty())
+ var += retTy + QLatin1String(" value = ");
+ //std::cout << " // ### accept with function " << qPrintable(getAcceptFunctionName(bb, &hasRetValue)) << std::endl;
+ std::cout << " for (" << qPrintable(eltTyName) << " *it = ast->" << qPrintable(declName) << "; it; it = it->next) {" << std::endl
+ << " " << qPrintable(var) << "this->" << qPrintable(funcName) << "(it->value);" << std::endl
+ << " }" << std::endl;
+ continue;
+ }
+
+ std::cout << " // ### process list of " << qPrintable(name) << std::endl;
+ continue;
+ }
+
+ if (ClassOrNamespace *ty = context.lookupType(namedTy->name(), klass)) {
+ QString className = oo(ty->symbols().first()->name());
+ QString baseClassName = className;
+ if (baseClassName.endsWith("AST")) {
+ baseClassName.chop(3);
+
+ QString retTy;
+ QString funcName = getAcceptFunctionName(ty, &retTy);
+ QString var;
+ if (! retTy.isEmpty())
+ var += retTy + QLatin1String(" ") + declName + QLatin1String(" = ");
+ std::cout << " " << qPrintable(var) << "this->" << qPrintable(funcName) << "(ast->" << qPrintable(declName) << ");" << std::endl;
+ continue;
+ }
+ }
+ }
+ }
+
+ std::cout << " // " << qPrintable(oo.prettyType(decl->type(), declName)) << " = ast->" << qPrintable(declName) << ";" << std::endl;
+ }
+
+ if (! isMiscNode(b))
+ std::cout << " return false;" << std::endl;
+
+ std::cout
+ << "}" << std::endl
+ << std::endl;
+ }
+ std::cout << std::endl;
+ }
+
+ }
+
+protected:
+ using SymbolVisitor::visit;
+
+ QList<ClassOrNamespace *> baseClasses(ClassOrNamespace *b) {
+ QList<ClassOrNamespace *> usings = b->usings();
+ foreach (ClassOrNamespace *u, usings)
+ usings += baseClasses(u);
+ return usings;
+ }
+
+ virtual bool visit(Class *klass) {
+ const QString className = oo(klass->name());
+ if (! className.endsWith("AST"))
+ return false;
+
+ ClassOrNamespace *b = context.lookupType(klass);
+ Q_ASSERT(b != 0);
+
+ const Identifier *accept0 = context.thisDocument()->control()->identifier("accept0");
+ if (Symbol *s = klass->find(accept0)) {
+ if (Function *meth = s->type()->asFunctionType()) {
+ if (! meth->isPureVirtual()) {
+ foreach (ClassOrNamespace *u, b->usings()) {
+ if (interfaces.contains(u)) {
+ // qDebug() << oo(klass->name()) << "implements" << oo(u->symbols().first()->name());
+ } else {
+ Q_ASSERT(!"no way");
+ }
+ }
+ nodes.append(b);
+ return false;
+ }
+ }
+ }
+
+ //qDebug() << oo(klass->name()) << "is a base ast node";
+ interfaces.append(b);
+
+ return false;
+ }
+};
+
+void printUsage()
+{
+ std::cout << "Usage: " << qPrintable(QFileInfo(qApp->arguments().at(0)).fileName())
+ << " [-v] [path to AST.h]\n\n"
+ << "Print a visitor class based on AST.h to stdout.\n\n";
+ const QString defaulPath = QFileInfo(PATH_AST_H).canonicalFilePath();
+ std::cout << "Default path: " << qPrintable(defaulPath) << '.' << "\n";
+}
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+ QStringList args = app.arguments();
+ args.removeFirst();
+
+ bool optionVerbose = false;
+
+ // Process options & arguments
+ if (args.contains("-v")) {
+ optionVerbose = true;
+ args.removeOne("-v");
+ }
+ const bool helpRequested = args.contains("-h") || args.contains("-help");
+ if (helpRequested || args.count() >= 2) {
+ printUsage();
+ return helpRequested ? EXIT_SUCCESS : EXIT_FAILURE;
+ }
+
+ // Run the preprocessor
+ QString fileName = PATH_AST_H;
+ if (!args.isEmpty())
+ fileName = args.first();
+
+ const QString fileNamePreprocessed = fileName + QLatin1String(".preprocessed");
+ CplusplusToolsUtils::SystemPreprocessor preprocessor(optionVerbose);
+ preprocessor.preprocessFile(fileName, fileNamePreprocessed);
+
+ QFile file(fileNamePreprocessed);
+ if (! file.open(QFile::ReadOnly)) {
+ std::cerr << "Error: Could not open file \"" << qPrintable(file.fileName()) << "\"."
+ << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ const QByteArray source = file.readAll();
+ file.close();
+
+ Document::Ptr doc = Document::create(fileName);
+ //doc->control()->setDiagnosticClient(0);
+ doc->setUtf8Source(source);
+ doc->parse();
+ doc->translationUnit()->blockErrors(true);
+ doc->check();
+
+ Snapshot snapshot;
+ snapshot.insert(doc);
+
+ LookupContext context(doc, snapshot);
+ MkVisitor mkVisitor(context);
+
+ return EXIT_SUCCESS;
+}