diff options
author | Roberto Raggi <roberto.raggi@nokia.com> | 2009-11-12 17:35:48 +0100 |
---|---|---|
committer | Roberto Raggi <roberto.raggi@nokia.com> | 2009-11-12 18:03:05 +0100 |
commit | 5dcf449afd7755d0ab88e55638fcbd8bc98deded (patch) | |
tree | 2e9a0abdadc4474d5bbf513183ac8818dd2bbcd1 /src/tools/cplusplus/Main.cpp | |
parent | b2f6803329126c7f8f391e97ffd50f26b98064a0 (diff) | |
download | qt-creator-5dcf449afd7755d0ab88e55638fcbd8bc98deded.tar.gz |
Initial work on the pattern matcher for AST nodes.
Diffstat (limited to 'src/tools/cplusplus/Main.cpp')
-rw-r--r-- | src/tools/cplusplus/Main.cpp | 203 |
1 files changed, 150 insertions, 53 deletions
diff --git a/src/tools/cplusplus/Main.cpp b/src/tools/cplusplus/Main.cpp index 16c9908a13..00fc4eea00 100644 --- a/src/tools/cplusplus/Main.cpp +++ b/src/tools/cplusplus/Main.cpp @@ -55,66 +55,158 @@ static const char copyrightHeader[] = "**************************************************************************/\n" ; -class SearchListNodes: protected ASTVisitor +class VisitCG: protected ASTVisitor { - QList<QByteArray> _listNodes; + QDir _cplusplusDir; + QTextStream *out; public: - SearchListNodes(Control *control) - : ASTVisitor(control) + VisitCG(const QDir &cplusplusDir, Control *control) + : ASTVisitor(control), _cplusplusDir(cplusplusDir), out(0) { } - QList<QByteArray> operator()(AST *ast) + void operator()(AST *ast) { - _listNodes.clear(); + QFileInfo fileInfo(_cplusplusDir, QLatin1String("ASTVisit.cpp")); + + QFile file(fileInfo.absoluteFilePath()); + if (! file.open(QFile::WriteOnly)) + return; + + QTextStream output(&file); + out = &output; + + *out << copyrightHeader << + "\n" + "#include \"AST.h\"\n" + "#include \"ASTVisitor.h\"\n" + "\n" + "using namespace CPlusPlus;\n" << endl; + accept(ast); - return _listNodes; } protected: - virtual bool visit(ClassSpecifierAST *ast) + using ASTVisitor::visit; + + QMap<QByteArray, ClassSpecifierAST *> classMap; + + QByteArray id_cast(NameAST *name) { - const QString className = oo(ast->symbol->name()); - - if (! (className.length() > 3 && className.endsWith(QLatin1String("AST")))) - return true; + if (! name) + return QByteArray(); + + Identifier *id = identifier(name->asSimpleName()->identifier_token); + + return QByteArray::fromRawData(id->chars(), id->size()); + } - for (unsigned i = 0; i < ast->symbol->memberCount(); ++i) { - Symbol *member = ast->symbol->memberAt(i); - Name *memberName = member->name(); + void visitMembers(Class *klass) + { + const QByteArray className = klass->name()->identifier()->chars(); - if (! memberName) + // *out << " // visit " << className.constData() << endl; + for (unsigned i = 0; i < klass->memberCount(); ++i) { + Symbol *member = klass->memberAt(i); + if (! member->name()) continue; - else if (! memberName->identifier()) + + Identifier *id = member->name()->identifier(); + + if (! id) continue; - - if (! qstrcmp("next", memberName->identifier()->chars())) { - _listNodes.append(className.toUtf8()); - break; + + const QByteArray memberName = QByteArray::fromRawData(id->chars(), id->size()); + if (member->type().isUnsigned() && memberName.endsWith("_token")) { + // nothing to do. The member is a token. + + } else if (PointerType *ptrTy = member->type()->asPointerType()) { + + if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) { + QByteArray typeName = namedTy->name()->identifier()->chars(); + + if (typeName.endsWith("AST") && memberName != "next") { + *out << " accept(" << memberName.constData() << ", visitor);" << endl; + } + } + } + } + + for (unsigned i = 0; i < klass->baseClassCount(); ++i) { + const QByteArray baseClassName = klass->baseClassAt(i)->identifier()->chars(); + + if (ClassSpecifierAST *baseClassSpec = classMap.value(baseClassName, 0)) { + visitMembers(baseClassSpec->symbol); } } + } + + bool checkMethod(Symbol *accept0Method) const + { + Declaration *decl = accept0Method->asDeclaration(); + if (! decl) + return false; + + Function *funTy = decl->type()->asFunctionType(); + if (! funTy) + return false; + + else if (funTy->isPureVirtual()) + return false; return true; } -private: - Overview oo; + virtual bool visit(ClassSpecifierAST *ast) + { + Class *klass = ast->symbol; + const QByteArray className = id_cast(ast->name); + + Identifier *visit_id = control()->findOrInsertIdentifier("accept0"); + Symbol *accept0Method = klass->members()->lookat(visit_id); + for (; accept0Method; accept0Method = accept0Method->next()) { + if (accept0Method->identifier() != visit_id) + continue; + + if (checkMethod(accept0Method)) + break; + } + + if (! accept0Method) + return true; + + classMap.insert(className, ast); + + *out + << "void " << className.constData() << "::accept0(ASTVisitor *visitor)" << endl + << "{" << endl + << " if (visitor->visit(this)) {" << endl; + + visitMembers(klass); + + *out + << " }" << endl + << " visitor->endVisit(this);" << endl + << "}" << endl + << endl; + + return true; + } }; -class VisitCG: protected ASTVisitor +class MatchCG: protected ASTVisitor { QDir _cplusplusDir; - QList<QByteArray> _listNodes; QTextStream *out; public: - VisitCG(const QDir &cplusplusDir, Control *control) + MatchCG(const QDir &cplusplusDir, Control *control) : ASTVisitor(control), _cplusplusDir(cplusplusDir), out(0) { } void operator()(AST *ast) { - QFileInfo fileInfo(_cplusplusDir, QLatin1String("ASTVisit.cpp")); + QFileInfo fileInfo(_cplusplusDir, QLatin1String("ASTMatch0.cpp")); QFile file(fileInfo.absoluteFilePath()); if (! file.open(QFile::WriteOnly)) @@ -126,13 +218,10 @@ public: *out << copyrightHeader << "\n" "#include \"AST.h\"\n" - "#include \"ASTVisitor.h\"\n" + "#include \"ASTMatcher.h\"\n" "\n" "using namespace CPlusPlus;\n" << endl; - SearchListNodes listNodes(control()); - _listNodes = listNodes(ast); - accept(ast); } @@ -153,9 +242,14 @@ protected: void visitMembers(Class *klass) { - const QByteArray className = klass->name()->identifier()->chars(); + Overview oo; + const QString className = oo(klass->name()); + + *out << " if (" << className << " *_other = pattern->as" << className.left(className.length() - 3) << "()) {" << endl; + + *out << " if (! matcher->match(this, _other))" << endl + << " return false;" << endl; - // *out << " // visit " << className.constData() << endl; for (unsigned i = 0; i < klass->memberCount(); ++i) { Symbol *member = klass->memberAt(i); if (! member->name()) @@ -168,21 +262,17 @@ protected: const QByteArray memberName = QByteArray::fromRawData(id->chars(), id->size()); if (member->type().isUnsigned() && memberName.endsWith("_token")) { - // nothing to do. The member is a token. + // nothing to do here. } else if (PointerType *ptrTy = member->type()->asPointerType()) { if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) { QByteArray typeName = namedTy->name()->identifier()->chars(); - if (_listNodes.contains(typeName) && memberName != "next") { - *out - << " for (" << typeName.constData() << " *it = " - << memberName.constData() << "; it; it = it->next)" << endl - << " accept(it, visitor);" << endl; + if (typeName.endsWith("AST")) { + *out << " if (! match(" << memberName << ", _other->" << memberName << ", matcher))" << endl + << " return false;" << endl; - } else if (typeName.endsWith("AST") && memberName != "next") { - *out << " accept(" << memberName.constData() << ", visitor);" << endl; } } } @@ -195,6 +285,9 @@ protected: visitMembers(baseClassSpec->symbol); } } + + *out << " return true;" << endl; + *out << " }" << endl; } bool checkMethod(Symbol *accept0Method) const @@ -218,10 +311,10 @@ protected: Class *klass = ast->symbol; const QByteArray className = id_cast(ast->name); - Identifier *visit_id = control()->findOrInsertIdentifier("accept0"); - Symbol *accept0Method = klass->members()->lookat(visit_id); + Identifier *match0_id = control()->findOrInsertIdentifier("match0"); + Symbol *accept0Method = klass->members()->lookat(match0_id); for (; accept0Method; accept0Method = accept0Method->next()) { - if (accept0Method->identifier() != visit_id) + if (accept0Method->identifier() != match0_id) continue; if (checkMethod(accept0Method)) @@ -234,15 +327,13 @@ protected: classMap.insert(className, ast); *out - << "void " << className.constData() << "::accept0(ASTVisitor *visitor)" << endl - << "{" << endl - << " if (visitor->visit(this)) {" << endl; + << "bool " << className.constData() << "::match0(AST *pattern, ASTMatcher *matcher)" << endl + << "{" << endl; visitMembers(klass); *out - << " }" << endl - << " visitor->endVisit(this);" << endl + << " return false;" << endl << "}" << endl << endl; @@ -317,8 +408,8 @@ protected: _nodes.deriveds.append(ast); AccessDeclarationAST *accessDeclaration = 0; - for (DeclarationListAST *it = ast->member_specifiers; it; it = it->next) { - if (AccessDeclarationAST *decl = it->declaration->asAccessDeclaration()) { + for (DeclarationListAST *it = ast->member_specifier_list; it; it = it->next) { + if (AccessDeclarationAST *decl = it->value->asAccessDeclaration()) { if (tokenKind(decl->access_specifier_token) == T_PUBLIC) accessDeclaration = decl; } @@ -457,6 +548,9 @@ QStringList generateAST_H(const Snapshot &snapshot, const QDir &cplusplusDir) VisitCG cg(cplusplusDir, doc->control()); cg(doc->translationUnit()->ast()); + MatchCG cg2(cplusplusDir, doc->control()); + cg2(doc->translationUnit()->ast()); + return astDerivedClasses; } @@ -476,8 +570,11 @@ public: protected: bool visit(SimpleDeclarationAST *ast) { - if (ElaboratedTypeSpecifierAST *e = ast->decl_specifier_seq->asElaboratedTypeSpecifier()) { - if (tokenKind(e->classkey_token) == T_CLASS && !ast->declarators) { + if (! ast->decl_specifier_list) + return false; + + if (ElaboratedTypeSpecifierAST *e = ast->decl_specifier_list->value->asElaboratedTypeSpecifier()) { + if (tokenKind(e->classkey_token) == T_CLASS && !ast->declarator_list) { QString className = oo(e->name->name); if (className.length() > 3 && className.endsWith(QLatin1String("AST"))) { |