diff options
author | Roberto Raggi <qtc-committer@nokia.com> | 2009-01-02 16:10:28 +0100 |
---|---|---|
committer | Roberto Raggi <qtc-committer@nokia.com> | 2009-01-02 16:10:28 +0100 |
commit | a886a63077520f3cb2cf8e338a0bee7f8dea5b6e (patch) | |
tree | 9cc9acff1437628b138ca040fab011c63ce46f7d /tests/manual/cplusplus/main.cpp | |
parent | bdf1800d83eef2c3940ed93466d3387fe2e172ee (diff) | |
download | qt-creator-a886a63077520f3cb2cf8e338a0bee7f8dea5b6e.tar.gz |
Playing with the AST rewriter.
Diffstat (limited to 'tests/manual/cplusplus/main.cpp')
-rw-r--r-- | tests/manual/cplusplus/main.cpp | 156 |
1 files changed, 144 insertions, 12 deletions
diff --git a/tests/manual/cplusplus/main.cpp b/tests/manual/cplusplus/main.cpp index 641c25366c..e5a68d4058 100644 --- a/tests/manual/cplusplus/main.cpp +++ b/tests/manual/cplusplus/main.cpp @@ -32,40 +32,172 @@ ***************************************************************************/ #include <AST.h> +#include <ASTVisitor.h> #include <Control.h> #include <Scope.h> #include <Semantic.h> #include <TranslationUnit.h> #include <QtCore/QFile> +#include <QtCore/QList> +#include <QtDebug> #include <cstdio> #include <cstdlib> -int main(int, char *[]) +class Rewrite { - Control control; - StringLiteral *fileId = control.findOrInsertFileName("<stdin>"); + QMultiMap<unsigned, QByteArray> _insertBefore; + QMultiMap<unsigned, QByteArray> _insertAfter; + QSet<unsigned> _removed; + +public: + void remove(unsigned index) + { remove(index, index + 1); } + + void remove(unsigned first, unsigned last) + { + Q_ASSERT(first < last); + + for (; first != last; ++first) + _removed.insert(first); + } + + void insertTextBefore(unsigned index, const QByteArray &text) + { _insertBefore.insert(index, text); } + + void insertTextAfter(unsigned index, const QByteArray &text) + { _insertAfter.insert(index, text); } + + void rewrite(const TranslationUnit *unit, + const QByteArray &contents, + QByteArray *out) const + { + const char *source = contents.constData(); + unsigned previousTokenEndPosition = 0; + for (unsigned i = 0; i < unit->tokenCount(); ++i) { + const Token &tk = unit->tokenAt(i); + + if (previousTokenEndPosition != tk.begin()) { + Q_ASSERT(previousTokenEndPosition < tk.begin()); + out->append(source + previousTokenEndPosition, + tk.begin() - previousTokenEndPosition); + } + QMultiMap<unsigned, QByteArray>::const_iterator it; + + it = _insertBefore.constFind(i); + for (; it != _insertBefore.constEnd() && it.key() == i; ++it) { + out->append(it.value()); + } + + if (! _removed.contains(i)) + out->append(source + tk.begin(), tk.length); + + it = _insertAfter.constFind(i); + for (; it != _insertAfter.constEnd() && it.key() == i; ++it) { + out->append(it.value()); + } + + previousTokenEndPosition = tk.end(); + } + } +}; + +class SimpleRefactor: protected ASTVisitor, Rewrite { +public: + SimpleRefactor(Control *control) + : ASTVisitor(control) + { } + + void operator()(const TranslationUnit *unit, + const QByteArray &source, + QByteArray *out) + { + accept(unit->ast()); + rewrite(unit, source, out); + } + +protected: + virtual bool visit(AccessDeclarationAST *ast) + { + if (tokenKind(ast->access_specifier_token) == T_PRIVATE) { + // change visibility from `private' to `public'. + remove(ast->access_specifier_token); + insertTextAfter(ast->access_specifier_token, "public /* #REF# private->public */"); + } + return true; + } + + virtual bool visit(FunctionDefinitionAST *ast) + { + bool isInline = false; + for (SpecifierAST *spec = ast->decl_specifier_seq; spec; spec = spec->next) { + if (SimpleSpecifierAST *simpleSpec = spec->asSimpleSpecifier()) { + if (tokenKind(simpleSpec->specifier_token) == T_INLINE) { + isInline = true; + break; + } + } + } + + // force the `inline' specifier. + if (! isInline) + insertTextBefore(ast->firstToken(), "inline /* #REF# made inline */ "); + + return true; + } + + virtual bool visit(ClassSpecifierAST *ast) + { + // export/import the class using the macro MY_EXPORT. + if (ast->name) + insertTextBefore(ast->name->firstToken(), "MY_EXPORT "); + + // add QObject to the base clause. + if (ast->colon_token) + insertTextAfter(ast->colon_token, " public QObject,"); + else if (ast->lbrace_token) + insertTextBefore(ast->lbrace_token, ": public QObject "); + + // mark the class as Q_OBJECT. + if (ast->lbrace_token) + insertTextAfter(ast->lbrace_token, " Q_OBJECT\n"); + + return true; + } +}; + +int main(int, char *[]) +{ QFile in; if (! in.open(stdin, QFile::ReadOnly)) return EXIT_FAILURE; const QByteArray source = in.readAll(); + Control control; + StringLiteral *fileId = control.findOrInsertFileName("<stdin>"); TranslationUnit unit(&control, fileId); unit.setSource(source.constData(), source.size()); unit.parse(); - if (unit.ast()) { - TranslationUnitAST *ast = unit.ast()->asTranslationUnit(); - Q_ASSERT(ast != 0); - - Scope globalScope; - Semantic sem(&control); - for (DeclarationAST *decl = ast->declarations; decl; decl = decl->next) { - sem.check(decl, &globalScope); - } + if (! unit.ast()) + return EXIT_FAILURE; + + TranslationUnitAST *ast = unit.ast()->asTranslationUnit(); + Q_ASSERT(ast != 0); + + Scope globalScope; + Semantic sem(&control); + for (DeclarationAST *decl = ast->declarations; decl; decl = decl->next) { + sem.check(decl, &globalScope); } + // test the rewriter + QByteArray out; + SimpleRefactor refactor(&control); + refactor(&unit, source, &out); + printf("%s\n", out.constData()); + return EXIT_SUCCESS; } |