forked from qt-creator/qt-creator
Increased dumper accuracy by genererating the dumper methods.
This commit is contained in:
@@ -735,6 +735,138 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
class GenerateDumpers: protected ASTVisitor
|
||||
{
|
||||
QTextStream out;
|
||||
|
||||
public:
|
||||
GenerateDumpers(QFile *file, TranslationUnit *unit)
|
||||
: ASTVisitor(unit), out(file)
|
||||
{ }
|
||||
|
||||
static void go(const QString &fileName, TranslationUnit *unit)
|
||||
{
|
||||
QFile file(fileName);
|
||||
if (! file.open(QFile::WriteOnly)) {
|
||||
std::cerr << "Cannot open dumpers file." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
GenerateDumpers d(&file, unit);
|
||||
d.out << copyrightHeader
|
||||
<< generatedHeader
|
||||
<< endl;
|
||||
|
||||
|
||||
d.accept(unit->ast());
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
protected:
|
||||
using ASTVisitor::visit;
|
||||
|
||||
QMap<QByteArray, ClassSpecifierAST *> classMap;
|
||||
|
||||
QByteArray id_cast(NameAST *name)
|
||||
{
|
||||
if (! name)
|
||||
return QByteArray();
|
||||
|
||||
const Identifier *id = identifier(name->asSimpleName()->identifier_token);
|
||||
|
||||
return QByteArray::fromRawData(id->chars(), id->size());
|
||||
}
|
||||
|
||||
void visitMembers(Class *klass)
|
||||
{
|
||||
for (unsigned i = 0; i < klass->memberCount(); ++i) {
|
||||
Symbol *member = klass->memberAt(i);
|
||||
if (! member->name())
|
||||
continue;
|
||||
|
||||
const Identifier *id = member->name()->identifier();
|
||||
|
||||
if (! id)
|
||||
continue;
|
||||
|
||||
const QByteArray memberName = QByteArray::fromRawData(id->chars(), id->size());
|
||||
if (member->type().isUnsigned() && memberName.endsWith("_token")) {
|
||||
out << " if (ast->" << memberName << ")" << endl;
|
||||
out << " terminal(ast->" << memberName << ", ast);" << endl;
|
||||
} else if (PointerType *ptrTy = member->type()->asPointerType()) {
|
||||
if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
|
||||
QByteArray typeName = namedTy->name()->identifier()->chars();
|
||||
|
||||
if (typeName.endsWith("ListAST")) {
|
||||
out << " for (" << typeName << " *iter = ast->" << memberName << "; iter; iter = iter->next)" << endl
|
||||
<< " nonterminal(iter->value);" << endl;
|
||||
} else if (typeName.endsWith("AST")) {
|
||||
out << " nonterminal(ast->" << memberName << ");" << 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 *cloneMethod) const
|
||||
{
|
||||
Declaration *decl = cloneMethod->asDeclaration();
|
||||
if (! decl)
|
||||
return false;
|
||||
|
||||
Function *funTy = decl->type()->asFunctionType();
|
||||
if (! funTy)
|
||||
return false;
|
||||
|
||||
else if (funTy->isPureVirtual())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool visit(ClassSpecifierAST *ast)
|
||||
{
|
||||
Class *klass = ast->symbol;
|
||||
const QByteArray className = id_cast(ast->name);
|
||||
if (! className.endsWith("AST"))
|
||||
return false;
|
||||
|
||||
const Identifier *clone_id = control()->findOrInsertIdentifier("clone");
|
||||
Symbol *cloneMethod = klass->members()->lookat(clone_id);
|
||||
for (; cloneMethod; cloneMethod = cloneMethod->next()) {
|
||||
if (cloneMethod->identifier() != clone_id)
|
||||
continue;
|
||||
|
||||
if (checkMethod(cloneMethod))
|
||||
break;
|
||||
}
|
||||
|
||||
if (! cloneMethod)
|
||||
return true;
|
||||
|
||||
classMap.insert(className, ast);
|
||||
|
||||
out << "virtual bool visit(" << className.constData() << " *ast)" << endl
|
||||
<< "{" << endl;
|
||||
|
||||
visitMembers(klass);
|
||||
|
||||
out << " return false;" << endl
|
||||
<< "}" << endl << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class RemoveCastMethods: protected ASTVisitor
|
||||
{
|
||||
public:
|
||||
@@ -1093,7 +1225,7 @@ void generateAST_cpp(const Snapshot &snapshot, const QDir &cplusplusDir)
|
||||
}
|
||||
}
|
||||
|
||||
QStringList generateAST_H(const Snapshot &snapshot, const QDir &cplusplusDir)
|
||||
QStringList generateAST_H(const Snapshot &snapshot, const QDir &cplusplusDir, const QString &dumpersFile)
|
||||
{
|
||||
QStringList astDerivedClasses;
|
||||
|
||||
@@ -1193,6 +1325,9 @@ QStringList generateAST_H(const Snapshot &snapshot, const QDir &cplusplusDir)
|
||||
|
||||
generateAST_cpp(snapshot, cplusplusDir);
|
||||
|
||||
if (!dumpersFile.isEmpty())
|
||||
GenerateDumpers::go(dumpersFile, AST_h_document->translationUnit());
|
||||
|
||||
return astDerivedClasses;
|
||||
}
|
||||
|
||||
@@ -1393,8 +1528,9 @@ int main(int argc, char *argv[])
|
||||
QStringList files = app.arguments();
|
||||
files.removeFirst();
|
||||
|
||||
if (files.isEmpty()) {
|
||||
if (files.size() != 1 && files.size() != 2) {
|
||||
std::cerr << "Usage: cplusplus [path to C++ front-end]" << std::endl;
|
||||
std::cerr << " or: cplusplus [path to C++ front-end] [dumpers file name]" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@@ -1405,8 +1541,12 @@ int main(int argc, char *argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
QString dumpersFile;
|
||||
if (files.size() == 2)
|
||||
dumpersFile = files.last();
|
||||
|
||||
Snapshot snapshot;
|
||||
QStringList astDerivedClasses = generateAST_H(snapshot, cplusplusDir);
|
||||
QStringList astDerivedClasses = generateAST_H(snapshot, cplusplusDir, dumpersFile);
|
||||
astDerivedClasses.sort();
|
||||
generateASTFwd_h(snapshot, cplusplusDir, astDerivedClasses);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user