File indexing completed on 2024-05-12 04:39:14

0001 /*
0002     SPDX-FileCopyrightText: 2013 Milian Wolff <mail@milianw.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include <KAboutData>
0008 
0009 #include <language/util/debuglanguageparserhelper.h>
0010 
0011 #include "../duchain/parsesession.h"
0012 #include "../duchain/debugvisitor.h"
0013 #include "../duchain/clangindex.h"
0014 #include "../util/clangtypes.h"
0015 
0016 using namespace KDevelop;
0017 using namespace KDevelopUtils;
0018 
0019 class ClangParser
0020 {
0021 public:
0022     ClangParser(const bool printAst, const bool printTokens)
0023       : m_session({})
0024       , m_printAst(printAst)
0025       , m_printTokens(printTokens)
0026     {
0027     }
0028 
0029     /// parse contents of a file
0030     void parseFile( const QString &fileName )
0031     {
0032         if (!QFile::exists(fileName)) {
0033             qerr << "File to parse does not exist: " << fileName << Qt::endl;
0034             return;
0035         }
0036         m_session.setData(ParseSessionData::Ptr(new ParseSessionData({}, &m_index, environment(fileName))));
0037         runSession();
0038     }
0039 
0040     /// parse code directly
0041     void parseCode( const QString &code )
0042     {
0043         const QString fileName = QStringLiteral("stdin.cpp");
0044         m_session.setData(ParseSessionData::Ptr(new ParseSessionData({UnsavedFile(fileName, {code})},
0045                                                                      &m_index, environment(fileName))));
0046         runSession();
0047     }
0048 
0049     void setIncludePaths(const QStringList& paths)
0050     {
0051         m_includePaths = paths;
0052     }
0053 
0054     void setCustomArgs(const QString& args)
0055     {
0056         m_customArgs = args;
0057     }
0058 private:
0059     /**
0060      * actually run the parse session
0061      */
0062     void runSession()
0063     {
0064         if (!m_session.unit()) {
0065             qerr << "failed to parse code" << Qt::endl;
0066         }
0067         if (m_printTokens) {
0068             CXTranslationUnit TU = m_session.unit();
0069             auto cursor = clang_getTranslationUnitCursor(TU);
0070             CXSourceRange range = clang_getCursorExtent(cursor);
0071             const ClangTokens tokens(TU, range);
0072             for (CXToken token : tokens) {
0073                 CXString spelling = clang_getTokenSpelling(TU, token);
0074                 qout << "token= " << clang_getCString(spelling) << Qt::endl;
0075                 clang_disposeString(spelling);
0076             }
0077         }
0078 
0079         if (!m_session.unit()) {
0080             qerr << "no AST tree could be generated" << Qt::endl;
0081             exit(255);
0082             return;
0083         }
0084 
0085         qout << "AST tree successfully generated" << Qt::endl;
0086         auto file = m_session.mainFile();
0087 
0088         if (m_printAst) {
0089             DebugVisitor visitor(&m_session);
0090             visitor.visit(m_session.unit(), file);
0091         }
0092 
0093         const auto problems = m_session.problemsForFile(file);
0094         if (!problems.isEmpty()) {
0095             qerr << "\nproblems encountered during parsing:" << Qt::endl;
0096             for (const ProblemPointer& problem : problems) {
0097                 qerr << problem->toString() << Qt::endl;
0098             }
0099         } else {
0100             qout << "no problems encountered during parsing" << Qt::endl;
0101         }
0102     }
0103 
0104     ClangParsingEnvironment environment(const QString& fileName) const
0105     {
0106         ClangParsingEnvironment environment;
0107         environment.setTranslationUnitUrl(IndexedString(fileName));
0108         environment.setParserSettings(ClangSettingsManager::self()->parserSettings(fileName));
0109         environment.addIncludes(toPathList(m_includePaths));
0110         environment.addParserArguments(m_customArgs);
0111         return environment;
0112     }
0113     ParseSession m_session;
0114     const bool m_printAst;
0115     const bool m_printTokens;
0116     ClangIndex m_index;
0117     QStringList m_includePaths;
0118     QString m_customArgs;
0119 };
0120 
0121 namespace KDevelopUtils {
0122 template<>
0123 void setupCustomArgs<ClangParser>(QCommandLineParser* args)
0124 {
0125     args->addOption(QCommandLineOption{QStringList{"I", "include"}, i18n("add include path"), QStringLiteral("include")});
0126     args->addOption(QCommandLineOption{QStringList{"custom-arg"}, i18n("custom clang args"), QStringLiteral("arg")});
0127 }
0128 
0129 template<>
0130 void setCustomArgs<ClangParser>(ClangParser* parser, QCommandLineParser* args)
0131 {
0132     parser->setIncludePaths(args->values(QStringLiteral("include")));
0133     parser->setCustomArgs(args->values(QStringLiteral("custom-arg")).join(QLatin1String(" ")));
0134 }
0135 }
0136 
0137 int main(int argc, char* argv[])
0138 {
0139     KAboutData aboutData( QStringLiteral("clang-parser"), i18n( "clang-parser" ),
0140                           QStringLiteral("1"), i18n("KDevelop Clang parser debugging utility"), KAboutLicense::GPL,
0141                           i18n( "2013 Milian Wolff" ), QString(), QStringLiteral("https://www.kdevelop.org/") );
0142 
0143     return KDevelopUtils::initAndRunParser<ClangParser>(aboutData, argc, argv);
0144 }