C++: Clean up dev tools.

* Add -h and -help options describing the tools and their usage.

* Make the tools compile and run on Windows (MinGW, MSVC).

* Rename project dirs, executables and main source files to more
  meaningful names:
  - Use same base name for project dir, *.pro file, main source file
    and (if applicable) script file.
  - Use the prefix "cplusplus-".
  - The names are now:
      - gen-cpp-ast/generate-ast --> cplusplus-update-frontend
      - mkvisitor --> cplusplus-mkvisitor
      - cplusplus-dump/cplusplus0 --> cplusplus-ast2png

* Get rid of 'c++' shell scripts.

* Get rid of duplicates of 'conf.c++'. Rename to 'pp-configuration.inc'.

* Introduce src/tools/cplusplus-tools-utils containing common stuff
  that is used at least in two tools. 'pp-configuration.inc' can also be
  found here.

* cplusplus-update-frontend:
  - Print file paths of written files to stdout.
  - Convenience: Use default values referencing the appropriate dirs and
    files.

* cplusplus-mkvisitor:
  - Take only one argument, namely the path to AST.h.
  - Convenience: Use default path to AST.h.

* cplusplus-ast2png:
  - Make it run without LD_LIBRARY_PATH.
  - As the name suggests, generate image files in png format (needs
    'dot' from graphviz).
  - Convenience: Read from stdin, which useful for small snippets.

Change-Id: I79c4061fce4a1571c0588dfedd50d4a70715d9df
Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
Nikolai Kosjar
2012-10-29 13:54:33 +01:00
parent 1a003ed29b
commit d0f3d7cb89
25 changed files with 564 additions and 185 deletions

12
.gitignore vendored
View File

@@ -109,8 +109,10 @@ bin/qml2puppet.exe
bin/qtpromaker bin/qtpromaker
bin/qtpromaker.exe bin/qtpromaker.exe
share/doc/qtcreator/*.qch share/doc/qtcreator/*.qch
src/tools/gen-cpp-ast/generate-ast src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor
src/tools/mkvisitor/cplusplus0 src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.exe
src/tools/cplusplus-update-frontend/cplusplus-update-frontend
src/tools/cplusplus-update-frontend/cplusplus-update-frontend.exe
src/tools/qml/qmldump/qmldump src/tools/qml/qmldump/qmldump
src/tools/examplesscanner/examplesscanner src/tools/examplesscanner/examplesscanner
src/tools/valgrindfake/valgrind-fake src/tools/valgrindfake/valgrind-fake
@@ -118,13 +120,15 @@ bin/*.exe
# Tests # Tests
#------ #------
tests/manual/cplusplus-frontend/cplusplus0 tests/manual/cplusplus-frontend/cplusplus-frontend
tests/manual/cplusplus-dump/cplusplus0 tests/manual/cplusplus-frontend/cplusplus-frontend.exe
tests/manual/qml-ast2dot/qml-ast2dot tests/manual/qml-ast2dot/qml-ast2dot
tests/manual/debugger/simple/libsimple_test_plugin.*dylib tests/manual/debugger/simple/libsimple_test_plugin.*dylib
tests/manual/debugger/simple/simple_test_app tests/manual/debugger/simple/simple_test_app
tests/manual/plain-cplusplus/plain-c++ tests/manual/plain-cplusplus/plain-c++
tests/manual/preprocessor/pp tests/manual/preprocessor/pp
tests/tools/cplusplus-ast2png/cplusplus-ast2png
tests/tools/cplusplus-ast2png/cplusplus-ast2png.exe
tests/auto/cplusplus/codegen/tst_codegen tests/auto/cplusplus/codegen/tst_codegen
tests/auto/cplusplus/ast/tst_ast tests/auto/cplusplus/ast/tst_ast
tests/auto/cplusplus/codeformatter/tst_codeformatter tests/auto/cplusplus/codeformatter/tst_codeformatter

View File

@@ -29,7 +29,7 @@
/* /*
All firstToken/lastToken methods below which have a doxygen comment with All firstToken/lastToken methods below which have a doxygen comment with
\generated in it, will be re-generated when the tool "generate-ast" is run. \generated in it, will be re-generated when the tool "cplusplus-update-frontend" is run.
For methods which are hand-coded, or which should not be changed, make sure that For methods which are hand-coded, or which should not be changed, make sure that
the comment is gone. the comment is gone.

View File

@@ -44,6 +44,8 @@
#include <Overview.h> #include <Overview.h>
#include <LookupContext.h> #include <LookupContext.h>
#include "cplusplus-tools-utils.h"
#include <QFile> #include <QFile>
#include <QList> #include <QList>
#include <QCoreApplication> #include <QCoreApplication>
@@ -422,17 +424,49 @@ protected:
} }
}; };
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[]) int main(int argc, char *argv[])
{ {
QCoreApplication app(argc, argv); QCoreApplication app(argc, argv);
QStringList args = app.arguments();
args.removeFirst();
QStringList files = app.arguments(); bool optionVerbose = false;
files.removeFirst();
foreach (const QString &fileName, files) { // Process options & arguments
QFile file(fileName); if (args.contains("-v")) {
if (! file.open(QFile::ReadOnly)) optionVerbose = true;
continue; 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(); const QByteArray source = file.readAll();
file.close(); file.close();
@@ -441,16 +475,14 @@ int main(int argc, char *argv[])
//doc->control()->setDiagnosticClient(0); //doc->control()->setDiagnosticClient(0);
doc->setUtf8Source(source); doc->setUtf8Source(source);
doc->parse(); doc->parse();
doc->translationUnit()->blockErrors(true); doc->translationUnit()->blockErrors(true);
doc->check(); doc->check();
Snapshot snapshot; Snapshot snapshot;
snapshot.insert(doc); snapshot.insert(doc);
LookupContext context(doc, snapshot); LookupContext context(doc, snapshot);
MkVisitor mkVisitor(context); MkVisitor mkVisitor(context);
}
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -0,0 +1,13 @@
QT = core gui
macx:CONFIG -= app_bundle
win32:CONFIG += console
TEMPLATE = app
TARGET = cplusplus-mkvisitor
DESTDIR = ./
include(../../../qtcreator.pri)
include(../../libs/cplusplus/cplusplus-lib.pri)
include(../../../src/tools/cplusplus-tools-utils/cplusplus-tools-utils.pri)
DEFINES += PATH_AST_H=\\\"$$PWD/../../libs/3rdparty/cplusplus/AST.h\\\"
SOURCES += cplusplus-mkvisitor.cpp

View File

@@ -0,0 +1,140 @@
/****************************************************************************
**
** 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 "cplusplus-tools-utils.h"
#include "environment.h"
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QProcess>
namespace CplusplusToolsUtils {
QString portableExecutableName(const QString &executable)
{
#if defined(Q_OS_WIN)
return executable + QLatin1String(".exe");
#else
return executable;
#endif
}
void executeCommand(const QString &command, const QStringList &arguments, const QString &outputFile,
bool verbose)
{
QTextStream out(stderr);
if (command.isEmpty()) {
out << "Error: " << Q_FUNC_INFO << "Got empty command to execute." << endl;
exit(EXIT_FAILURE);
}
const QString fullCommand = command + QLatin1Char(' ') + arguments.join(QLatin1String(" "));
if (verbose)
out << "Executing: " << fullCommand << endl;
QProcess process;
if (!outputFile.isEmpty())
process.setStandardOutputFile(outputFile, QIODevice::Truncate);
process.start(command, arguments);
if (!process.waitForStarted()) {
out << QString("Error: Process \"%1\" did not start within timeout: %2.")
.arg(fullCommand, process.errorString())
<< endl;
exit(EXIT_FAILURE);
}
if (!process.waitForFinished()) {
if (!verbose)
out << process.readAll() << endl;
out << QString("Error: Process \"%1\" did not finish within timeout.").arg(fullCommand)
<< endl;
exit(EXIT_FAILURE);
}
const int exitCode = process.exitCode();
if (exitCode != 0) {
out << process.readAllStandardError() << endl;
out << QString("Error: Process \"%1\" finished with non zero exit value %2")
.arg(fullCommand, exitCode) << endl;
exit(EXIT_FAILURE);
}
}
SystemPreprocessor::SystemPreprocessor(bool verbose)
: m_verbose(verbose)
{
m_knownCompilers[portableExecutableName("gcc")]
= QLatin1String("-DCPLUSPLUS_WITHOUT_QT -U__BLOCKS__ -xc++ -E -include");
m_knownCompilers[portableExecutableName("cl")]
= QLatin1String("/DCPLUSPLUS_WITHOUT_QT /U__BLOCKS__ /TP /E /I . /FI");
QMapIterator<QString, QString> i(m_knownCompilers);
while (i.hasNext()) {
i.next();
const QString executablePath
= Utils::Environment::systemEnvironment().searchInPath(i.key());
if (!executablePath.isEmpty()) {
m_compiler = i.key();
m_compilerArguments = i.value().split(QLatin1String(" "), QString::SkipEmptyParts);
m_compilerArguments
<< QDir::toNativeSeparators(QLatin1String(PATH_PREPROCESSOR_CONFIG));
break;
}
}
}
void SystemPreprocessor::check() const
{
QTextStream out(stderr);
if (!QFile::exists(PATH_PREPROCESSOR_CONFIG)) {
out << QString("Error: File \"%1\" does not exist.").arg(PATH_PREPROCESSOR_CONFIG) << endl;
exit(EXIT_FAILURE);
}
if (m_compiler.isEmpty()) {
const QString triedCompilers
= QStringList(m_knownCompilers.keys()).join(QLatin1String(", "));
out << QString("Error: No compiler found. Tried %1.").arg(triedCompilers) << endl;
exit(EXIT_FAILURE);
}
}
void SystemPreprocessor::preprocessFile(const QString &inputFile, const QString &outputFile) const
{
check();
if (!QFile::exists(inputFile)) {
QTextStream out(stderr);
out << QString("Error: File \"%1\" does not exist.").arg(inputFile) << endl;
exit(EXIT_FAILURE);
}
const QStringList arguments = QStringList(m_compilerArguments)
<< QDir::toNativeSeparators(inputFile);
executeCommand(m_compiler, arguments, outputFile, m_verbose);
}
} // namespace

View File

@@ -0,0 +1,62 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#ifndef CPLUSPLUSTOOLSUTILS_H
#define CPLUSPLUSTOOLSUTILS_H
#include <QString>
#include <QStringList>
#include <QMap>
namespace CplusplusToolsUtils {
QString portableExecutableName(const QString &executable);
void executeCommand(const QString &command, const QStringList &arguments, const QString &outputFile,
bool verbose = false);
// Preprocess a file by calling an external compiler in preprocessor mode (-E, /E).
class SystemPreprocessor
{
public:
SystemPreprocessor(bool verbose = false);
void preprocessFile(const QString &inputFile, const QString &outputFile) const;
private:
void check() const;
QMap<QString, QString> m_knownCompilers;
QString m_compiler; // Compiler that will be called in preprocessor mode
QStringList m_compilerArguments;
bool m_verbose;
};
} // namespace
#endif // CPLUSPLUSTOOLSUTILS_H

View File

@@ -0,0 +1,13 @@
DEPENDPATH += $$PWD
INCLUDEPATH += $$PWD $$PWD/../../libs/utils
DEFINES += PATH_PREPROCESSOR_CONFIG=\\\"$$PWD/pp-configuration.inc\\\"
DEFINES += QTCREATOR_UTILS_STATIC_LIB
HEADERS += \
$$PWD/cplusplus-tools-utils.h \
$$PWD/../../libs/utils/environment.h
SOURCES += \
$$PWD/cplusplus-tools-utils.cpp \
$$PWD/../../libs/utils/environment.cpp

View File

@@ -1,15 +1,17 @@
#define __extension__ #define __extension__
#define __context__ #define __context__
#define __range__ #define __range__
#if !defined(_WIN32) && !defined(_WIN64)
# define __asm(a...) # define __asm(a...)
# define __asm__(a...) # define __asm__(a...)
# define __stdcall
# define __fastcall
#endif
#define restrict #define restrict
#define __restrict #define __restrict
#define __restrict__ #define __restrict__
// #define __weak // #define __weak
#define __builtin_va_arg(a,b) ((b)0) #define __builtin_va_arg(a,b) ((b)0)
#define __stdcall
#define __fastcall
#define __imag__ #define __imag__
#define __real__ #define __real__
#define __complex__ #define __complex__

View File

@@ -91,12 +91,21 @@ static const char generatedHeader[] =
"// W A R N I N G\n" "// W A R N I N G\n"
"// -------------\n" "// -------------\n"
"//\n" "//\n"
"// This file is automatically generated.\n" "// This file is automatically generated by \"cplusplus-update-frontend\".\n"
"// Changes will be lost.\n" "// Changes will be lost.\n"
"//\n" "//\n"
"\n" "\n"
; ;
static void closeAndPrintFilePath(QFile &file)
{
if (file.isOpen()) {
const QString filePath = QFileInfo(file).canonicalFilePath();
std::cout << QDir::toNativeSeparators(filePath).toLatin1().constData() << std::endl;
file.close();
}
}
class ASTNodes class ASTNodes
{ {
public: public:
@@ -226,6 +235,8 @@ public:
"using namespace CPlusPlus;\n" << endl; "using namespace CPlusPlus;\n" << endl;
accept(ast); accept(ast);
closeAndPrintFilePath(file);
} }
protected: protected:
@@ -354,7 +365,6 @@ public:
QTextStream output(&file); QTextStream output(&file);
out = &output; out = &output;
*out << copyrightHeader << generatedHeader << *out << copyrightHeader << generatedHeader <<
"\n" "\n"
"#include \"AST.h\"\n" "#include \"AST.h\"\n"
@@ -363,6 +373,8 @@ public:
"using namespace CPlusPlus;\n" << endl; "using namespace CPlusPlus;\n" << endl;
accept(ast); accept(ast);
closeAndPrintFilePath(file);
} }
protected: protected:
@@ -480,6 +492,8 @@ public:
<< endl; << endl;
accept(ast); accept(ast);
closeAndPrintFilePath(file);
} }
protected: protected:
@@ -627,7 +641,7 @@ public:
accept(ast); accept(ast);
file.close(); closeAndPrintFilePath(file);
} }
protected: protected:
@@ -761,7 +775,7 @@ public:
d.accept(unit->ast()); d.accept(unit->ast());
file.close(); closeAndPrintFilePath(file);
} }
protected: protected:
@@ -1220,6 +1234,7 @@ void generateAST_cpp(const Snapshot &snapshot, const QDir &cplusplusDir)
if (file.open(QFile::WriteOnly)) { if (file.open(QFile::WriteOnly)) {
QTextStream out(&file); QTextStream out(&file);
out << cpp_document.toPlainText(); out << cpp_document.toPlainText();
closeAndPrintFilePath(file);
} }
} }
@@ -1312,6 +1327,8 @@ void generateASTVisitor_H(const Snapshot &, const QDir &cplusplusDir,
"} // namespace CPlusPlus\n" "} // namespace CPlusPlus\n"
"\n" "\n"
"#endif // CPLUSPLUS_ASTVISITOR_H\n"; "#endif // CPLUSPLUS_ASTVISITOR_H\n";
closeAndPrintFilePath(file);
} }
void generateASTMatcher_H(const Snapshot &, const QDir &cplusplusDir, void generateASTMatcher_H(const Snapshot &, const QDir &cplusplusDir,
@@ -1353,6 +1370,8 @@ void generateASTMatcher_H(const Snapshot &, const QDir &cplusplusDir,
"} // namespace CPlusPlus\n" "} // namespace CPlusPlus\n"
"\n" "\n"
"#endif // CPLUSPLUS_ASTMATCHER_H\n"; "#endif // CPLUSPLUS_ASTMATCHER_H\n";
closeAndPrintFilePath(file);
} }
QStringList generateAST_H(const Snapshot &snapshot, const QDir &cplusplusDir, const QString &dumpersFile) QStringList generateAST_H(const Snapshot &snapshot, const QDir &cplusplusDir, const QString &dumpersFile)
@@ -1437,6 +1456,7 @@ QStringList generateAST_H(const Snapshot &snapshot, const QDir &cplusplusDir, co
if (file.open(QFile::WriteOnly)) { if (file.open(QFile::WriteOnly)) {
QTextStream out(&file); QTextStream out(&file);
out << document.toPlainText(); out << document.toPlainText();
closeAndPrintFilePath(file);
} }
Accept0CG cg(cplusplusDir, AST_h_document->translationUnit()); Accept0CG cg(cplusplusDir, AST_h_document->translationUnit());
@@ -1537,6 +1557,7 @@ void generateASTFwd_h(const Snapshot &snapshot, const QDir &cplusplusDir, const
if (file.open(QFile::WriteOnly)) { if (file.open(QFile::WriteOnly)) {
QTextStream out(&file); QTextStream out(&file);
out << document.toPlainText(); out << document.toPlainText();
closeAndPrintFilePath(file);
} }
} }
@@ -1664,36 +1685,67 @@ void generateASTPatternBuilder_h(const QDir &cplusplusDir)
<< "} // end of namespace CPlusPlus" << endl << "} // end of namespace CPlusPlus" << endl
<< endl << endl
<< "#endif // CPLUSPLUS_AST_PATTERN_BUILDER_H" << endl; << "#endif // CPLUSPLUS_AST_PATTERN_BUILDER_H" << endl;
closeAndPrintFilePath(file);
}
void printUsage()
{
const QByteArray executable = QFileInfo(qApp->arguments().first()).fileName().toLatin1();
std::cout << "Usage: " << executable.constData() << "\n"
<< " " << executable.constData() << " <frontend-dir> <dumpers-file>"
<< "\n\n"
<< "Generate appropriate header and source files of the C++ frontend accordingly\n"
<< "to AST.h and print the paths of the written files. Run this tool after\n"
<< "modifying AST.h."
<< "\n\n";
const QString defaultPathCppFrontend = QFileInfo(PATH_CPP_FRONTEND).canonicalFilePath();
const QString defaultPathDumpersFile = QFileInfo(PATH_DUMPERS_FILE).canonicalFilePath();
std::cout << "Default values:" << "\n"
<< " frontend-dir: " << qPrintable(defaultPathCppFrontend) << "\n"
<< " dumpers-file: " << qPrintable(defaultPathDumpersFile) << "\n";
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
MyQApplication app(argc, argv); MyQApplication app(argc, argv);
QStringList args = app.arguments();
args.removeFirst();
QStringList files = app.arguments(); QString pathCppFrontend = PATH_CPP_FRONTEND;
files.removeFirst(); QString pathDumpersFile = PATH_DUMPERS_FILE;
if (files.size() != 1 && files.size() != 2) { const bool helpRequested = args.contains("-h") || args.contains("-help");
std::cerr << "Usage: cplusplus [path to C++ front-end]" << std::endl; if (args.count() == 1 || args.count() >= 3 || helpRequested) {
std::cerr << " or: cplusplus [path to C++ front-end] [dumpers file name]" << std::endl; printUsage();
return EXIT_FAILURE; return helpRequested ? EXIT_SUCCESS : EXIT_FAILURE;
} else if (args.count() == 2) {
pathCppFrontend = args.at(0);
pathDumpersFile = args.at(1);
} }
QDir cplusplusDir(files.first()); QDir cplusplusDir(pathCppFrontend);
if (!QFile::exists(pathCppFrontend)) {
std::cerr << "Error: Directory \"" << qPrintable(cplusplusDir.absolutePath())
<< "\" does not exist." << std::endl;
return EXIT_FAILURE;
}
if (!QFileInfo(cplusplusDir, QLatin1String("AST.h")).exists()) { if (!QFileInfo(cplusplusDir, QLatin1String("AST.h")).exists()) {
std::cerr << "Cannot find AST.h in " << qPrintable(cplusplusDir.absolutePath()) std::cerr << "Error: Cannot find AST.h in \"" << qPrintable(cplusplusDir.absolutePath())
<< std::endl; << "\"." << std::endl;
return EXIT_FAILURE;
}
if (!QFile::exists(pathDumpersFile)) {
std::cerr << "Error: File \"" << qPrintable(pathDumpersFile)
<< "\" does not exist." << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
QString dumpersFile;
if (files.size() == 2)
dumpersFile = files.last();
Snapshot snapshot; Snapshot snapshot;
QStringList astDerivedClasses = generateAST_H(snapshot, cplusplusDir, dumpersFile); QStringList astDerivedClasses = generateAST_H(snapshot, cplusplusDir, pathDumpersFile);
astDerivedClasses.sort(); astDerivedClasses.sort();
generateASTFwd_h(snapshot, cplusplusDir, astDerivedClasses); generateASTFwd_h(snapshot, cplusplusDir, astDerivedClasses);
generateASTPatternBuilder_h(cplusplusDir); generateASTPatternBuilder_h(cplusplusDir);
return EXIT_SUCCESS;
} }

View File

@@ -0,0 +1,15 @@
QT = core gui
macx:CONFIG -= app_bundle
win32:CONFIG += console
TEMPLATE = app
TARGET = cplusplus-update-frontend
DESTDIR = ./
DEFINES += QTCREATOR_UTILS_STATIC_LIB
INCLUDEPATH += . ../../libs
include(../../../qtcreator.pri)
include(../../libs/cplusplus/cplusplus-lib.pri)
DEFINES += PATH_CPP_FRONTEND=\\\"$$PWD/../../libs/3rdparty/cplusplus\\\"
DEFINES += PATH_DUMPERS_FILE=\\\"$$PWD/../../../tests/tools/cplusplus-ast2png/dumpers.inc\\\"
SOURCES += cplusplus-update-frontend.cpp ../../libs/utils/changeset.cpp

View File

@@ -1,10 +0,0 @@
QT = core gui
macx:CONFIG -= app_bundle
TEMPLATE = app
TARGET = generate-ast
INCLUDEPATH += . ../../libs
include(../../libs/cplusplus/cplusplus-lib.pri)
# Input
SOURCES += generate-ast.cpp ../../libs/utils/changeset.cpp

View File

@@ -1,15 +0,0 @@
#define __extension__
#define __context__
#define __range__
#define __asm(a...)
#define __asm__(a...)
#define restrict
#define __restrict
#define __restrict__
// #define __weak
#define __builtin_va_arg(a,b) ((b)0)
#define __stdcall
#define __fastcall
#define __imag__
#define __real__
#define __complex__

View File

@@ -1,5 +0,0 @@
#!/bin/sh
me=$(dirname $0)
${CPP-gcc} -DCPLUSPLUS_WITHOUT_QT -U__BLOCKS__ -xc++ -E -include $me/conf.c++ ../../libs/3rdparty/cplusplus/AST.h > $me/file.i
$me/cplusplus0 $me/file.i
rm -f $me/file.i

View File

@@ -1,20 +0,0 @@
QT = core gui
macx:CONFIG -= app_bundle
TARGET = cplusplus0
INCLUDEPATH += . ../../libs
include(../../libs/cplusplus/cplusplus-lib.pri)
# Input
SOURCES += main.cpp
unix {
debug:OBJECTS_DIR = $${OUT_PWD}/.obj/debug-shared
release:OBJECTS_DIR = $${OUT_PWD}/.obj/release-shared
debug:MOC_DIR = $${OUT_PWD}/.moc/debug-shared
release:MOC_DIR = $${OUT_PWD}/.moc/release-shared
RCC_DIR = $${OUT_PWD}/.rcc/
UI_DIR = $${OUT_PWD}/.uic/
}

View File

@@ -1,5 +0,0 @@
#!/bin/sh
me=$(dirname $0)
${CPP-gcc} -U__BLOCKS__ -xc++ -E -include $me/conf.c++ $* > $me/file.i
$me/cplusplus0 $me/file.i

View File

@@ -40,6 +40,8 @@
#include <CoreTypes.h> #include <CoreTypes.h>
#include <CppDocument.h> #include <CppDocument.h>
#include "cplusplus-tools-utils.h"
#include <QFile> #include <QFile>
#include <QList> #include <QList>
#include <QCoreApplication> #include <QCoreApplication>
@@ -54,18 +56,47 @@
using namespace CPlusPlus; using namespace CPlusPlus;
void printUsage()
{
std::cout << "Usage: " << qPrintable(QFileInfo(qApp->arguments().at(0)).fileName())
<< " [-v] <file1> <file2> ...\n\n"
<< "Run the parser with the given files.\n";
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QCoreApplication app(argc, argv); QCoreApplication app(argc, argv);
QStringList args = app.arguments();
args.removeFirst();
QStringList files = app.arguments(); bool optionVerbose = false;
files.removeFirst();
// Process options & arguments
if (args.contains("-v")) {
optionVerbose = true;
args.removeOne("-v");
}
const bool helpRequested = args.contains("-h") || args.contains("-help");
if (args.isEmpty() || helpRequested) {
printUsage();
return helpRequested ? EXIT_SUCCESS : EXIT_FAILURE;
}
// Process files
const QStringList files = args;
foreach (const QString &fileName, files) { foreach (const QString &fileName, files) {
QFile file(fileName); // Run preprocessor
if (! file.open(QFile::ReadOnly)) const QString fileNamePreprocessed = fileName + QLatin1String(".preprocessed");
continue; CplusplusToolsUtils::SystemPreprocessor preprocessor(optionVerbose);
preprocessor.preprocessFile(fileName, fileNamePreprocessed);
// Run parser
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(); const QByteArray source = file.readAll();
file.close(); file.close();

View File

@@ -1,21 +1,13 @@
QT = core gui QT = core gui
macx:CONFIG -= app_bundle macx:CONFIG -= app_bundle
TARGET = cplusplus0 win32:CONFIG += console
TEMPLATE = app
TARGET = cplusplus-frontend
DESTDIR = ./
include(../../../qtcreator.pri) include(../../../qtcreator.pri)
include($$IDE_SOURCE_TREE/src/libs/cplusplus/cplusplus.pri) include($$IDE_SOURCE_TREE/src/libs/cplusplus/cplusplus-lib.pri)
include($$IDE_SOURCE_TREE/src/libs/languageutils/languageutils.pri) include($$IDE_SOURCE_TREE/tests/auto/qttestrpath.pri)
include($$IDE_SOURCE_TREE/src/libs/utils/utils.pri) include(../../../src/tools/cplusplus-tools-utils/cplusplus-tools-utils.pri)
# Input SOURCES += cplusplus-frontend.cpp
SOURCES += main.cpp
unix {
debug:OBJECTS_DIR = $${OUT_PWD}/.obj/debug-shared
release:OBJECTS_DIR = $${OUT_PWD}/.obj/release-shared
debug:MOC_DIR = $${OUT_PWD}/.moc/debug-shared
release:MOC_DIR = $${OUT_PWD}/.moc/release-shared
RCC_DIR = $${OUT_PWD}/.rcc/
UI_DIR = $${OUT_PWD}/.uic/
}

View File

@@ -42,6 +42,9 @@
#include <SymbolVisitor.h> #include <SymbolVisitor.h>
#include <Overview.h> #include <Overview.h>
#include "cplusplus-tools-utils.h"
#include <QDir>
#include <QFile> #include <QFile>
#include <QList> #include <QList>
#include <QCoreApplication> #include <QCoreApplication>
@@ -58,6 +61,22 @@
# include <cxxabi.h> # include <cxxabi.h>
#endif #endif
// For isatty(), _isatty()
#if defined(Q_OS_WIN)
# include <io.h>
#else
# include <unistd.h>
#endif
bool tty_for_stdin()
{
#if defined(Q_OS_WIN)
return _isatty(_fileno(stdin));
#else
return isatty(fileno(stdin));
#endif
}
using namespace CPlusPlus; using namespace CPlusPlus;
class ASTDump: protected ASTVisitor class ASTDump: protected ASTVisitor
@@ -68,9 +87,6 @@ public:
void operator()(AST *ast) { void operator()(AST *ast) {
QByteArray basename = translationUnit()->fileName(); QByteArray basename = translationUnit()->fileName();
int dotIdx = basename.lastIndexOf('.');
if (dotIdx != -1)
basename.truncate(dotIdx);
basename.append(".ast.dot"); basename.append(".ast.dot");
out.open(basename.constData()); out.open(basename.constData());
@@ -89,11 +105,10 @@ public:
out << "}" << std::endl; out << "}" << std::endl;
out.close(); out.close();
std::cout << basename.constData() << std::endl;
} }
// the following file can be generated by using: // the following file can be generated by using:
// generate-ast <path to cpp stuff> <path to dumpers.inc> // cplusplus-update-frontend <frontend-dir> <dumpers-file>
#include "dumpers.inc" #include "dumpers.inc"
protected: protected:
@@ -195,9 +210,6 @@ public:
void operator()(Symbol *s) { void operator()(Symbol *s) {
QByteArray basename = translationUnit->fileName(); QByteArray basename = translationUnit->fileName();
int dotIdx = basename.lastIndexOf('.');
if (dotIdx != -1)
basename.truncate(dotIdx);
basename.append(".symbols.dot"); basename.append(".symbols.dot");
out.open(basename.constData()); out.open(basename.constData());
@@ -218,7 +230,6 @@ public:
out << "}" << std::endl; out << "}" << std::endl;
out.close(); out.close();
std::cout << basename.constData() << std::endl;
} }
protected: protected:
@@ -351,19 +362,103 @@ private:
Overview o; Overview o;
}; };
void createImageFromDot(const QString &inputFile, const QString &outputFile, bool verbose)
{
const QString command = CplusplusToolsUtils::portableExecutableName(QLatin1String("dot"));
const QStringList arguments = QStringList()
<< QLatin1String("-Tpng") << QLatin1String("-o") << outputFile << inputFile;
CplusplusToolsUtils::executeCommand(command, arguments, QString(), verbose);
}
const char PATH_STDIN_FILE[] = "_stdincontents.cpp";
QString example()
{
return
#if defined(Q_OS_WIN)
QString::fromLatin1("> echo int foo() {} | %1 && %2.ast.png")
#elif defined(Q_OS_MAC)
QString::fromLatin1("$ echo \"int foo() {}\" | ./%1 && open %2.ast.png")
#else
QString::fromLatin1("$ echo \"int foo() {}\" | ./%1 && xdg-open %2.ast.png")
#endif
.arg(QFileInfo(qApp->arguments().at(0)).fileName(), PATH_STDIN_FILE);
}
void printUsage()
{
std::cout << "Usage: " << qPrintable(QFileInfo(qApp->arguments().at(0)).fileName())
<< " [-v] <file1> <file2> ...\n\n";
std::cout << qPrintable(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"
"and are created in the current working directory. To show the AST for simple snippets\n"
"you might want to execute:\n"
"\n"
" %2\n"
"\n"
"Prerequisites:\n"
" 1) Make sure to have 'dot' from graphviz locatable by PATH.\n"
" 2) Make sure to have an up to date dumpers file by using 'cplusplus-update-frontend'.\n"
).arg(PATH_STDIN_FILE, example()));
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QCoreApplication app(argc, argv); QCoreApplication app(argc, argv);
QStringList args = app.arguments();
args.removeFirst();
QStringList files = app.arguments(); bool optionVerbose = false;
files.removeFirst();
// Data from stdin?
if (!tty_for_stdin()) {
QFile file("_stdincontents.cpp");
if (! file.open(QFile::WriteOnly)) {
std::cerr << "Error: Cannot open file for writing\"" << qPrintable(file.fileName())
<< "\"" << std::endl;
exit(EXIT_FAILURE);
}
file.write(QTextStream(stdin).readAll().toLocal8Bit());
file.close();
args.append(file.fileName());
}
// Process options & arguments
if (args.contains("-v")) {
optionVerbose = true;
args.removeOne("-v");
}
const bool helpRequested = args.contains("-h") || args.contains("-help");
if (args.isEmpty() || helpRequested) {
printUsage();
return helpRequested ? EXIT_SUCCESS : EXIT_FAILURE;
}
// Process files
const QStringList files = args;
foreach (const QString &fileName, files) { foreach (const QString &fileName, files) {
QFile file(fileName); if (! QFile::exists(fileName)) {
std::cerr << "Error: File \"" << qPrintable(fileName) << "\" does not exist."
<< std::endl;
exit(EXIT_FAILURE);
}
// Run the preprocessor
const QString fileNamePreprocessed = fileName + QLatin1String(".preprocessed");
CplusplusToolsUtils::SystemPreprocessor preprocessor(optionVerbose);
preprocessor.preprocessFile(fileName, fileNamePreprocessed);
// Convert to dot
QFile file(fileNamePreprocessed);
if (! file.open(QFile::ReadOnly)) { if (! file.open(QFile::ReadOnly)) {
std::cerr << "Cannot open \"" << qPrintable(fileName) std::cerr << "Error: Could not open file \"" << qPrintable(fileNamePreprocessed)
<< "\", skipping it." << std::endl; << "\"" << std::endl;
continue; exit(EXIT_FAILURE);
} }
const QByteArray source = file.readAll(); const QByteArray source = file.readAll();
@@ -373,7 +468,6 @@ int main(int argc, char *argv[])
doc->control()->setDiagnosticClient(0); doc->control()->setDiagnosticClient(0);
doc->setUtf8Source(source); doc->setUtf8Source(source);
doc->parse(); doc->parse();
doc->check(); doc->check();
ASTDump dump(doc->translationUnit()); ASTDump dump(doc->translationUnit());
@@ -381,6 +475,18 @@ int main(int argc, char *argv[])
SymbolDump dump2(doc->translationUnit()); SymbolDump dump2(doc->translationUnit());
dump2(doc->globalNamespace()); dump2(doc->globalNamespace());
// Create images
typedef QPair<QString, QString> Pair;
QList<Pair> inputOutputFiles;
inputOutputFiles.append(qMakePair(QString(fileName + QLatin1String(".ast.dot")),
QString(fileName + QLatin1String(".ast.png"))));
inputOutputFiles.append(qMakePair(QString(fileName + QLatin1String(".symbols.dot")),
QString(fileName + QLatin1String(".symbols.png"))));
foreach (const Pair &pair, inputOutputFiles) {
createImageFromDot(pair.first, pair.second, optionVerbose);
std::cout << qPrintable(QDir::toNativeSeparators(pair.second)) << std::endl;
}
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@@ -0,0 +1,12 @@
QT = core gui
macx:CONFIG -= app_bundle
win32:CONFIG += console
TEMPLATE = app
TARGET = cplusplus-ast2png
DESTDIR = ./
include(../../../qtcreator.pri)
include(../../../src/libs/cplusplus/cplusplus-lib.pri)
include(../../../src/tools/cplusplus-tools-utils/cplusplus-tools-utils.pri)
SOURCES += cplusplus-ast2png.cpp

View File

@@ -1,5 +0,0 @@
#!/bin/sh
me=$(dirname $0)
${CPP-gcc} -U__BLOCKS__ -xc++ -E -include $me/conf.c++ $* > $me/file.i
$me/cplusplus0 $me/file.i

View File

@@ -1,15 +0,0 @@
#define __extension__
#define __context__
#define __range__
#define __asm(a...)
#define __asm__(a...)
#define restrict
#define __restrict
#define __restrict__
// #define __weak
#define __builtin_va_arg(a,b) ((b)0)
#define __stdcall
#define __fastcall
#define __imag__
#define __real__
#define __complex__

View File

@@ -1,20 +0,0 @@
QT = core gui
macx:CONFIG -= app_bundle
TARGET = cplusplus0
include(../../../qtcreator.pri)
include(../../../src/libs/cplusplus/cplusplus.pri)
# Input
SOURCES += main.cpp
unix {
debug:OBJECTS_DIR = $${OUT_PWD}/.obj/debug-shared
release:OBJECTS_DIR = $${OUT_PWD}/.obj/release-shared
debug:MOC_DIR = $${OUT_PWD}/.moc/debug-shared
release:MOC_DIR = $${OUT_PWD}/.moc/release-shared
RCC_DIR = $${OUT_PWD}/.rcc/
UI_DIR = $${OUT_PWD}/.uic/
}

View File

@@ -1,5 +1,5 @@
TEMPLATE=subdirs TEMPLATE=subdirs
SUBDIRS= \ SUBDIRS= \
cplusplus-dump \ cplusplus-ast2png \
qml-ast2dot qml-ast2dot