summaryrefslogtreecommitdiff
path: root/tests/tools/cplusplus-ast2png/cplusplus-ast2png.cpp
diff options
context:
space:
mode:
authorNikolai Kosjar <nikolai.kosjar@digia.com>2013-01-31 16:23:39 +0100
committerNikolai Kosjar <nikolai.kosjar@digia.com>2013-02-01 14:30:12 +0100
commit4da344c0bf5481ebc36fabd53895c8461716f475 (patch)
tree96124c8edbc251de40b5e356d3b4f5c8d5c70c12 /tests/tools/cplusplus-ast2png/cplusplus-ast2png.cpp
parent1a0bed277db3238d46715c2ec8a3be1635355e7c (diff)
downloadqt-creator-4da344c0bf5481ebc36fabd53895c8461716f475.tar.gz
C++: ast2png: Try parsing harder
Try to parse a declarator, if that fails an expression, if that fails, ...at last a TranslationUnit is tried. It is also possible to specify which AST should be parsed. This simplifies the code snippets we can pass to this tool. Change-Id: Idbc1a8a6f1c5cf7e20d899f7a2e4263c7f9d33a6 Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
Diffstat (limited to 'tests/tools/cplusplus-ast2png/cplusplus-ast2png.cpp')
-rw-r--r--tests/tools/cplusplus-ast2png/cplusplus-ast2png.cpp197
1 files changed, 177 insertions, 20 deletions
diff --git a/tests/tools/cplusplus-ast2png/cplusplus-ast2png.cpp b/tests/tools/cplusplus-ast2png/cplusplus-ast2png.cpp
index 308090ed09..900b0169b6 100644
--- a/tests/tools/cplusplus-ast2png/cplusplus-ast2png.cpp
+++ b/tests/tools/cplusplus-ast2png/cplusplus-ast2png.cpp
@@ -363,8 +363,7 @@ private:
Overview o;
};
-
-void createImageFromDot(const QString &inputFile, const QString &outputFile, bool verbose)
+static void createImageFromDot(const QString &inputFile, const QString &outputFile, bool verbose)
{
const QString command = CplusplusToolsUtils::portableExecutableName(QLatin1String("dot"));
const QStringList arguments = QStringList()
@@ -372,9 +371,9 @@ void createImageFromDot(const QString &inputFile, const QString &outputFile, boo
CplusplusToolsUtils::executeCommand(command, arguments, QString(), verbose);
}
-const char PATH_STDIN_FILE[] = "_stdincontents.cpp";
+static const char PATH_STDIN_FILE[] = "_stdincontents.cpp";
-QString example()
+static QString example()
{
return
#if defined(Q_OS_WIN)
@@ -387,16 +386,120 @@ QString example()
.arg(QFileInfo(qApp->arguments().at(0)).fileName(), QLatin1String(PATH_STDIN_FILE));
}
-void printUsage()
+static QString parseModeToString(Document::ParseMode parseMode)
+{
+ switch (parseMode) {
+ case Document::ParseTranlationUnit:
+ return QLatin1String("TranlationUnit");
+ case Document::ParseDeclaration:
+ return QLatin1String("Declaration");
+ case Document::ParseExpression:
+ return QLatin1String("Expression");
+ case Document::ParseDeclarator:
+ return QLatin1String("Declarator");
+ case Document::ParseStatement:
+ return QLatin1String("Statement");
+ default:
+ return QLatin1String("UnknownParseMode");
+ }
+}
+
+/// Counts errors and appends error messages containing the parse mode to an error string
+class ErrorHandler: public DiagnosticClient {
+public:
+ int m_errorCount;
+ QByteArray *m_errorString;
+ Document::ParseMode m_parseMode;
+
+ ErrorHandler(Document::ParseMode parseMode, QByteArray *errorStringOutput)
+ : m_errorCount(0)
+ , m_errorString(errorStringOutput)
+ , m_parseMode(parseMode) {}
+
+ void report(int level,
+ const StringLiteral *fileName,
+ unsigned line, unsigned column,
+ const char *format, va_list ap)
+ {
+ ++m_errorCount;
+
+ if (! m_errorString)
+ return;
+
+ static const char *const pretty[] = { "warning", "error", "fatal" };
+
+ QString str;
+ str.sprintf("%s:%d:%d: When parsing as %s: %s: ", fileName->chars(), line, column,
+ parseModeToString(m_parseMode).toUtf8().constData(), pretty[level]);
+ m_errorString->append(str.toUtf8());
+
+ str.vsprintf(format, ap);
+ m_errorString->append(str.toUtf8());
+ m_errorString->append('\n');
+ }
+};
+
+/// Try to parse with given parseModes. Returns a document pointer if it was possible to
+/// successfully parse with one of the given parseModes (one parse mode after the other
+/// is tried), otherwise a null pointer.
+static Document::Ptr parse(const QString &fileName, const QByteArray &source,
+ QList<Document::ParseMode> parseModes, QByteArray *errors,
+ bool verbose = false)
+{
+ foreach (const Document::ParseMode parseMode, parseModes) {
+ ErrorHandler *errorHandler = new ErrorHandler(parseMode, errors); // Deleted by ~Document.
+ if (verbose)
+ std::cout << "Parsing as " << qPrintable(parseModeToString(parseMode)) << "...";
+
+ Document::Ptr doc = Document::create(fileName);
+ doc->control()->setDiagnosticClient(errorHandler);
+ doc->setUtf8Source(source);
+ const bool parsed = doc->parse(parseMode);
+ if (parsed && errorHandler->m_errorCount == 0) {
+ if (verbose)
+ std::cout << "succeeded." << std::endl;
+ return doc;
+ }
+
+ if (verbose)
+ std::cout << "failed." << std::endl;
+ }
+
+ return Document::Ptr();
+}
+
+/// Convenience function
+static Document::Ptr parse(const QString &fileName, const QByteArray &source,
+ Document::ParseMode parseMode, QByteArray *errors,
+ bool verbose = false)
+{
+ QList<Document::ParseMode> parseModes = QList<Document::ParseMode>() << parseMode;
+ return parse(fileName, source, parseModes, errors, verbose);
+}
+
+static void printUsage()
{
std::cout << "Usage: " << qPrintable(QFileInfo(qApp->arguments().at(0)).fileName())
- << " [-v] <file1> <file2> ...\n\n";
+ << " [-v] [-p ast] <file1> <file2> ...\n\n";
+
+ std::cout
+ << "Visualize AST and symbol hierarchy of given C++ files by generating png image files\n"
+ << "in the same directory as the input files. Print paths to generated image files.\n"
+ << "\n"
+ << "Options:\n"
+ << " -v Run with increased verbosity.\n"
+ << " -p <ast> Parse each file as <ast>. <ast> is one of:\n"
+ << " - 'declarator' or 'dr'\n"
+ << " - 'expression' or 'ex'\n"
+ << " - 'declaration' or 'dn'\n"
+ << " - 'statement' or 'st'\n"
+ << " - 'translationunit' or 'tr'\n"
+ << " If this option is not provided, each file is tried to be parsed as\n"
+ << " declarator, expression, etc. using the stated order.\n"
+ << "\n";
std::cout << QString::fromLatin1(
- "Visualize AST and symbol hierarchy of given C++ files by generating png image files\n"
- "in the same directory as the input files. Print paths to generated image files.\n"
- "\n"
- "Standard input is also read. The resulting files starts with \"%1\"\n"
+ "Standard input is also read. The resulting files start with \"%1\"\n"
"and are created in the current working directory. To show the AST for simple snippets\n"
"you might want to execute:\n"
"\n"
@@ -415,9 +518,12 @@ int main(int argc, char *argv[])
args.removeFirst();
bool optionVerbose = false;
+ int optionParseMode = -1;
- // Data from stdin?
- if (!tty_for_stdin()) {
+ // Test only for stdin if not input files are specified.
+ const bool doTestForStdIn = args.isEmpty()
+ || (args.count() == 1 && args.contains(QLatin1String("-v")));
+ if (doTestForStdIn && !tty_for_stdin()) {
QFile file((QLatin1String(PATH_STDIN_FILE)));
if (! file.open(QFile::WriteOnly)) {
std::cerr << "Error: Cannot open file for writing\"" << qPrintable(file.fileName())
@@ -430,15 +536,46 @@ int main(int argc, char *argv[])
}
// Process options & arguments
+ const bool helpRequested = args.contains(QLatin1String("-h"))
+ || args.contains(QLatin1String("-help"));
+ if (helpRequested) {
+ printUsage();
+ return helpRequested ? EXIT_SUCCESS : EXIT_FAILURE;
+ }
+
if (args.contains(QLatin1String("-v"))) {
optionVerbose = true;
args.removeOne(QLatin1String("-v"));
}
- const bool helpRequested = args.contains(QLatin1String("-h"))
- || args.contains(QLatin1String("-help"));
- if (args.isEmpty() || helpRequested) {
+ if (args.contains(QLatin1String("-p"))) {
+ args.removeOne(QLatin1String("-p"));
+ if (args.isEmpty()) {
+ std::cerr << "Error: Expected ast after option \"-p\"." << std::endl;
+ printUsage();
+ exit(EXIT_FAILURE);
+ }
+ const QString parseAs = args.first();
+ if (parseAs == QLatin1String("declarator") || parseAs == QLatin1String("dr"))
+ optionParseMode = Document::ParseDeclarator;
+ else if (parseAs == QLatin1String("expression") || parseAs == QLatin1String("ex"))
+ optionParseMode = Document::ParseExpression;
+ else if (parseAs == QLatin1String("declaration") || parseAs == QLatin1String("dn"))
+ optionParseMode = Document::ParseDeclaration;
+ else if (parseAs == QLatin1String("statement") || parseAs == QLatin1String("st"))
+ optionParseMode = Document::ParseStatement;
+ else if (parseAs == QLatin1String("translationunit") || parseAs == QLatin1String("tr"))
+ optionParseMode = Document::ParseTranlationUnit;
+ else {
+ std::cerr << "Error: Invalid ast for option \"-p\"." << std::endl;
+ printUsage();
+ exit(EXIT_FAILURE);
+ }
+ args.removeOne(parseAs);
+ }
+
+ if (args.isEmpty()) {
printUsage();
- return helpRequested ? EXIT_SUCCESS : EXIT_FAILURE;
+ return EXIT_SUCCESS;
}
// Process files
@@ -466,12 +603,32 @@ int main(int argc, char *argv[])
const QByteArray source = file.readAll();
file.close();
- Document::Ptr doc = Document::create(fileName);
- doc->control()->setDiagnosticClient(0);
- doc->setUtf8Source(source);
- doc->parse();
+ // Parse Document
+ QByteArray errors;
+ Document::Ptr doc;
+ if (optionParseMode == -1) {
+ QList<Document::ParseMode> parseModes;
+ parseModes
+ << Document::ParseDeclarator
+ << Document::ParseExpression
+ << Document::ParseDeclaration
+ << Document::ParseStatement
+ << Document::ParseTranlationUnit;
+ doc = parse(fileName, source, parseModes, &errors, optionVerbose);
+ } else {
+ doc = parse(fileName, source, static_cast<Document::ParseMode>(optionParseMode),
+ &errors, optionVerbose);
+ }
+
+ if (!doc) {
+ std::cerr << "Error: Could not parse file \"" << qPrintable(fileName) << "\".\n";
+ std::cerr << errors.constData();
+ exit(EXIT_FAILURE);
+ }
+
doc->check();
+ // Run AST dumper
ASTDump dump(doc->translationUnit());
dump(doc->translationUnit()->ast());