From bdb38acbce1f2e20981b4dbae6438c28fe5d6ec6 Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Thu, 15 Jan 2015 19:38:19 +0100 Subject: [PATCH] ui/logic/data: show parse errors in CodeView This change saves the errors while parsing in the Storage and displays them in the CodeView. The error messages can be read in the tooltip on hovering. The error count is visible in the status bar. --- bin/app/data/src/test/main.cpp | 3 + src/app/qt/element/QtCodeFile.cpp | 36 ++-- src/app/qt/element/QtCodeFile.h | 17 +- src/app/qt/element/QtCodeFileList.cpp | 43 ++++- src/app/qt/element/QtCodeFileList.h | 17 +- src/app/qt/element/QtCodeSnippet.cpp | 159 ++++++++++++++---- src/app/qt/element/QtCodeSnippet.h | 20 ++- src/app/qt/element/QtStatusBar.cpp | 5 + src/app/qt/view/QtCodeView.cpp | 38 +++-- src/app/qt/view/QtCodeView.h | 7 +- src/lib/Application.cpp | 13 +- src/lib/Application.h | 7 +- src/lib/CMakeLists.txt | 2 + src/lib/Project.cpp | 9 +- .../component/controller/CodeController.cpp | 85 +++++++--- src/lib/component/controller/CodeController.h | 6 +- .../component/controller/GraphController.cpp | 27 ++- .../component/controller/GraphController.h | 3 + .../component/controller/SearchController.cpp | 5 + .../component/controller/SearchController.h | 3 + .../controller/StatusBarController.cpp | 12 +- src/lib/component/view/CodeView.h | 3 +- src/lib/data/Storage.cpp | 44 ++++- src/lib/data/Storage.h | 9 + src/lib/data/access/LocationAccess.h | 2 + src/lib/data/access/LocationAccessProxy.cpp | 10 ++ src/lib/data/access/LocationAccessProxy.h | 2 + src/lib/data/parser/ParseLocation.cpp | 13 ++ src/lib/data/parser/ParseLocation.h | 5 + src/lib/data/parser/ParserClient.h | 2 + src/lib/data/parser/cxx/ASTConsumer.cpp | 2 + .../data/parser/cxx/CxxDiagnosticConsumer.cpp | 75 +++++++++ .../data/parser/cxx/CxxDiagnosticConsumer.h | 25 +++ src/lib/data/parser/cxx/CxxParser.cpp | 60 ++++++- src/lib/data/search/SearchNode.cpp | 14 ++ src/lib/data/search/SearchNode.h | 2 + .../messaging/type/MessageFinishedParsing.h | 7 +- src/test/CxxParserTestSuite.h | 19 +++ 38 files changed, 660 insertions(+), 151 deletions(-) create mode 100644 src/lib/data/parser/cxx/CxxDiagnosticConsumer.cpp create mode 100644 src/lib/data/parser/cxx/CxxDiagnosticConsumer.h diff --git a/bin/app/data/src/test/main.cpp b/bin/app/data/src/test/main.cpp index c37743b7..b1f839a9 100644 --- a/bin/app/data/src/test/main.cpp +++ b/bin/app/data/src/test/main.cpp @@ -14,6 +14,9 @@ int main() int a = sum(1, 2); int b = diff(a, 3); int c = a * b; + + int x = y; + return 0; } diff --git a/src/app/qt/element/QtCodeFile.cpp b/src/app/qt/element/QtCodeFile.cpp index 8625b15d..a0b78083 100644 --- a/src/app/qt/element/QtCodeFile.cpp +++ b/src/app/qt/element/QtCodeFile.cpp @@ -3,13 +3,14 @@ #include #include +#include "qt/element/QtCodeFileList.h" #include "qt/element/QtCodeSnippet.h" #include "utility/FileSystem.h" -QtCodeFile::QtCodeFile(const std::string& filePath, QWidget *parent) +QtCodeFile::QtCodeFile(const std::string& filePath, QtCodeFileList* parent) : QWidget(parent) + , m_parent(parent) , m_filePath(filePath) - , m_showMaximizeButton(true) { setObjectName("code_file"); @@ -31,21 +32,35 @@ QtCodeFile::~QtCodeFile() { } +const std::string& QtCodeFile::getFilePath() const +{ + return m_filePath; +} + std::string QtCodeFile::getFileName() const { return FileSystem::fileName(m_filePath); } +const std::vector& QtCodeFile::getActiveTokenIds() const +{ + return m_parent->getActiveTokenIds(); +} + +const std::vector& QtCodeFile::getErrorMessages() const +{ + return m_parent->getErrorMessages(); +} + void QtCodeFile::addCodeSnippet( uint startLineNumber, const std::string& code, - const TokenLocationFile& locationFile, - const std::vector& activeTokenIds + const TokenLocationFile& locationFile ){ std::shared_ptr snippet( - new QtCodeSnippet(startLineNumber, code, locationFile, activeTokenIds, this)); + new QtCodeSnippet(startLineNumber, code, locationFile, this)); - if (m_showMaximizeButton) + if (m_parent->getShowMaximizeButton()) { snippet->addMaximizeButton(); } @@ -65,15 +80,10 @@ void QtCodeFile::addCodeSnippet( } } -void QtCodeFile::setActiveTokenIds(const std::vector& activeTokenIds) +void QtCodeFile::update() { for (std::shared_ptr snippet : m_snippets) { - snippet->setActiveTokenIds(activeTokenIds); + snippet->update(); } } - -void QtCodeFile::setShowMaximizeButton(bool show) -{ - m_showMaximizeButton = show; -} diff --git a/src/app/qt/element/QtCodeFile.h b/src/app/qt/element/QtCodeFile.h index c850c6aa..6efe1e22 100644 --- a/src/app/qt/element/QtCodeFile.h +++ b/src/app/qt/element/QtCodeFile.h @@ -9,31 +9,34 @@ #include "utility/types.h" +class QtCodeFileList; class QtCodeSnippet; class TokenLocationFile; class QtCodeFile : public QWidget { public: - QtCodeFile(const std::string& filePath, QWidget *parent = 0); + QtCodeFile(const std::string& filePath, QtCodeFileList* parent); virtual ~QtCodeFile(); + const std::string& getFilePath() const; std::string getFileName() const; + const std::vector& getActiveTokenIds() const; + const std::vector& getErrorMessages() const; void addCodeSnippet( uint startLineNumber, const std::string& code, - const TokenLocationFile& locationFile, - const std::vector& activeTokenIds + const TokenLocationFile& locationFile ); - void setActiveTokenIds(const std::vector& activeTokenIds); - void setShowMaximizeButton(bool show); + void update(); private: - std::vector > m_snippets; + QtCodeFileList* m_parent; + + std::vector> m_snippets; const std::string m_filePath; - bool m_showMaximizeButton; }; #endif // QT_CODE_FILE_H diff --git a/src/app/qt/element/QtCodeFileList.cpp b/src/app/qt/element/QtCodeFileList.cpp index ed83f4df..30dc853d 100644 --- a/src/app/qt/element/QtCodeFileList.cpp +++ b/src/app/qt/element/QtCodeFileList.cpp @@ -36,8 +36,7 @@ QSize QtCodeFileList::sizeHint() const void QtCodeFileList::addCodeSnippet( uint startLineNumber, const std::string& code, - const TokenLocationFile& locationFile, - const std::vector& activeTokenIds + const TokenLocationFile& locationFile ){ std::string fileName = FileSystem::fileName(locationFile.getFilePath()); QtCodeFile* file = nullptr; @@ -58,11 +57,9 @@ void QtCodeFileList::addCodeSnippet( file = filePtr.get(); m_frame->layout()->addWidget(file); - - file->setShowMaximizeButton(m_showMaximizeButton); } - file->addCodeSnippet(startLineNumber, code, locationFile, activeTokenIds); + file->addCodeSnippet(startLineNumber, code, locationFile); } void QtCodeFileList::clearCodeSnippets() @@ -70,15 +67,43 @@ void QtCodeFileList::clearCodeSnippets() m_files.clear(); } +const std::vector& QtCodeFileList::getActiveTokenIds() const +{ + return m_activeTokenIds; +} + void QtCodeFileList::setActiveTokenIds(const std::vector& activeTokenIds) { - for (std::shared_ptr file: m_files) - { - file->setActiveTokenIds(activeTokenIds); - } + m_activeTokenIds = activeTokenIds; + updateFiles(); +} + +const std::vector& QtCodeFileList::getErrorMessages() const +{ + return m_errorMessages; +} + +void QtCodeFileList::setErrorMessages(const std::vector& errorMessages) +{ + m_errorMessages = errorMessages; + updateFiles(); +} + +bool QtCodeFileList::getShowMaximizeButton() const +{ + return m_showMaximizeButton; } void QtCodeFileList::setShowMaximizeButton(bool show) { m_showMaximizeButton = show; + updateFiles(); +} + +void QtCodeFileList::updateFiles() +{ + for (std::shared_ptr file: m_files) + { + file->update(); + } } diff --git a/src/app/qt/element/QtCodeFileList.h b/src/app/qt/element/QtCodeFileList.h index 278bd5e7..806b8c49 100644 --- a/src/app/qt/element/QtCodeFileList.h +++ b/src/app/qt/element/QtCodeFileList.h @@ -25,19 +25,28 @@ public: void addCodeSnippet( uint startLineNumber, const std::string& code, - const TokenLocationFile& locationFile, - const std::vector& activeTokenIds + const TokenLocationFile& locationFile ); void clearCodeSnippets(); + const std::vector& getActiveTokenIds() const; void setActiveTokenIds(const std::vector& activeTokenIds); + + const std::vector& getErrorMessages() const; + void setErrorMessages(const std::vector& errorMessages); + + bool getShowMaximizeButton() const; void setShowMaximizeButton(bool show); private: - std::shared_ptr m_frame; - std::vector > m_files; + void updateFiles(); + std::shared_ptr m_frame; + std::vector> m_files; + + std::vector m_activeTokenIds; + std::vector m_errorMessages; bool m_showMaximizeButton; }; diff --git a/src/app/qt/element/QtCodeSnippet.cpp b/src/app/qt/element/QtCodeSnippet.cpp index 43f6a05e..d9e39149 100644 --- a/src/app/qt/element/QtCodeSnippet.cpp +++ b/src/app/qt/element/QtCodeSnippet.cpp @@ -4,10 +4,12 @@ #include #include #include +#include #include "ApplicationSettings.h" #include "data/location/TokenLocation.h" #include "data/location/TokenLocationFile.h" +#include "qt/element/QtCodeFile.h" #include "qt/utility/QtHighlighter.h" #include "utility/messaging/type/MessageActivateTokenLocation.h" #include "utility/messaging/type/MessageShowFile.h" @@ -38,14 +40,13 @@ QtCodeSnippet::QtCodeSnippet( uint startLineNumber, const std::string& code, const TokenLocationFile& locationFile, - const std::vector& activeTokenIds, - QWidget *parent + QtCodeFile* parent ) : QPlainTextEdit(parent) + , m_parent(parent) , m_maximizeButton(nullptr) , m_startLineNumber(startLineNumber) - , m_filePath(locationFile.getFilePath()) - , m_activeTokenIds(activeTokenIds) + , m_hoveredAnnotation(nullptr) , m_digits(0) { setObjectName("code_snippet"); @@ -73,8 +74,9 @@ QtCodeSnippet::QtCodeSnippet( connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int))); connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int))); - connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(clickedTokenLocation())); connect(this, SIGNAL(selectionChanged()), this, SLOT(clearSelection())); + + this->setMouseTracking(true); } QtCodeSnippet::~QtCodeSnippet() @@ -154,9 +156,8 @@ void QtCodeSnippet::updateLineNumberAreaWidthForDigits(int digits) updateLineNumberAreaWidth(0); } -void QtCodeSnippet::setActiveTokenIds(const std::vector& activeTokenIds) +void QtCodeSnippet::update() { - m_activeTokenIds = activeTokenIds; annotateText(); } @@ -192,14 +193,52 @@ void QtCodeSnippet::leaveEvent(QEvent* event) } } +void QtCodeSnippet::mouseReleaseEvent(QMouseEvent* event) +{ + if (event->button() == Qt::LeftButton) + { + QTextCursor cursor = this->cursorForPosition(event->pos()); + const Annotation* annotation = findAnnotationForPosition(cursor.position()); + + if (annotation) + { + MessageActivateTokenLocation(annotation->locationId).dispatch(); + } + } +} + void QtCodeSnippet::mouseDoubleClickEvent(QMouseEvent* event) { - if (m_maximizeButton) + if (event->button() == Qt::LeftButton && m_maximizeButton) { clickedMaximizeButton(); } } +void QtCodeSnippet::mouseMoveEvent(QMouseEvent* event) +{ + QTextCursor cursor = this->cursorForPosition(event->pos()); + const Annotation* annotation = findAnnotationForPosition(cursor.position()); + + if (annotation != nullptr ? annotation != m_hoveredAnnotation && !annotation->isScope : m_hoveredAnnotation != nullptr) + { + m_hoveredAnnotation = annotation; + + const std::vector& errorMessages = m_parent->getErrorMessages(); + + if (annotation && errorMessages.size() > annotation->tokenId) + { + QToolTip::showText(event->globalPos(), QString::fromStdString(m_parent->getErrorMessages()[annotation->tokenId])); + } + else + { + QToolTip::hideText(); + } + + annotateText(); + } +} + void QtCodeSnippet::updateLineNumberAreaWidth(int /* newBlockCount */) { setViewportMargins(lineNumberAreaWidth(), 0, 0, 0); @@ -222,34 +261,9 @@ void QtCodeSnippet::updateLineNumberArea(const QRect &rect, int dy) } } -void QtCodeSnippet::clickedTokenLocation() -{ - int clickPosition = textCursor().position(); - int diff = endTextEditPosition() + 1; - Id locationId = 0; - - for (Annotation annotation : m_annotations) - { - if (clickPosition >= annotation.start && clickPosition <= annotation.end) - { - int d = annotation.end - annotation.start; - if (d < diff) - { - diff = d; - locationId = annotation.locationId; - } - } - } - - if (locationId) - { - MessageActivateTokenLocation(locationId).dispatch(); - } -} - void QtCodeSnippet::clickedMaximizeButton() { - MessageShowFile(m_filePath, m_startLineNumber, m_startLineNumber + document()->blockCount() - 1).dispatch(); + MessageShowFile(m_parent->getFilePath(), m_startLineNumber, m_startLineNumber + blockCount() - 1).dispatch(); } void QtCodeSnippet::clearSelection() @@ -259,12 +273,33 @@ void QtCodeSnippet::clearSelection() setTextCursor(cursor); } +const QtCodeSnippet::Annotation* QtCodeSnippet::findAnnotationForPosition(int pos) const +{ + const Annotation* annotationPtr = nullptr; + int diff = endTextEditPosition() + 1; + + for (const Annotation& annotation : m_annotations) + { + if (pos >= annotation.start && pos <= annotation.end) + { + int d = annotation.end - annotation.start; + if (d < diff) + { + diff = d; + annotationPtr = &annotation; + } + } + } + + return annotationPtr; +} + void QtCodeSnippet::createAnnotations(const TokenLocationFile& locationFile) { locationFile.forEachTokenLocation( [&](TokenLocation* location) { - if (location->isEndTokenLocation() && location->getStartTokenLocation()) + if (!locationBelongsToSnippet(location)) { return; } @@ -301,14 +336,27 @@ void QtCodeSnippet::createAnnotations(const TokenLocationFile& locationFile) void QtCodeSnippet::annotateText() { Colori color; - const std::vector& ids = m_activeTokenIds; + const std::vector& ids = m_parent->getActiveTokenIds(); + const std::vector& errorMessages = m_parent->getErrorMessages(); QList extraSelections; for (const Annotation& annotation: m_annotations) { bool isActive = std::find(ids.begin(), ids.end(), annotation.tokenId) != ids.end(); - if (isActive) + if (&annotation == m_hoveredAnnotation && errorMessages.size()) + { + color = Colori(255, 0, 0, 128); + } + else if (&annotation == m_hoveredAnnotation) + { + color = ApplicationSettings::getInstance()->getCodeActiveLinkColor(); + } + else if (errorMessages.size()) + { + color = Colori(255, 0, 0, 255); + } + else if (isActive) { color = ApplicationSettings::getInstance()->getCodeActiveLinkColor(); } @@ -335,6 +383,43 @@ void QtCodeSnippet::annotateText() setExtraSelections(extraSelections); } +bool QtCodeSnippet::locationBelongsToSnippet(TokenLocation* location) const +{ + uint lineNumber = location->getLineNumber(); + + if (location->isEndTokenLocation()) + { + if (location->getStartTokenLocation() || + lineNumber < m_startLineNumber || lineNumber >= m_startLineNumber + blockCount()) + { + return false; + } + else + { + return true; + } + } + + if (lineNumber >= m_startLineNumber + blockCount()) + { + return false; + } + + if (lineNumber >= m_startLineNumber) + { + return true; + } + + TokenLocation* endLocation = location->getEndTokenLocation(); + + if (endLocation && endLocation->getLineNumber() < m_startLineNumber) + { + return false; + } + + return true; +} + int QtCodeSnippet::toTextEditPosition(int lineNumber, int columnNumber) const { lineNumber -= m_startLineNumber - 1; diff --git a/src/app/qt/element/QtCodeSnippet.h b/src/app/qt/element/QtCodeSnippet.h index d70f6ff3..56d708e4 100644 --- a/src/app/qt/element/QtCodeSnippet.h +++ b/src/app/qt/element/QtCodeSnippet.h @@ -11,8 +11,10 @@ class QPaintEvent; class QPushButton; class QResizeEvent; class QSize; +class QtCodeFile; class QtHighlighter; class QWidget; +class TokenLocation; class TokenLocationFile; class QtCodeSnippet: public QPlainTextEdit @@ -39,8 +41,7 @@ public: uint startLineNumber, const std::string& code, const TokenLocationFile& locationFile, - const std::vector& activeTokenIds, - QWidget *parent = 0 + QtCodeFile* parent ); virtual ~QtCodeSnippet(); @@ -53,19 +54,20 @@ public: int lineNumberAreaWidth() const; void updateLineNumberAreaWidthForDigits(int digits); - void setActiveTokenIds(const std::vector& activeTokenIds); + void update(); protected: virtual void resizeEvent(QResizeEvent *event); virtual void showEvent(QShowEvent* event); virtual void enterEvent(QEvent* event); virtual void leaveEvent(QEvent* event); + virtual void mouseReleaseEvent(QMouseEvent* event); virtual void mouseDoubleClickEvent(QMouseEvent* event); + virtual void mouseMoveEvent(QMouseEvent* event); private slots: void updateLineNumberAreaWidth(int newBlockCount); void updateLineNumberArea(const QRect &, int); - void clickedTokenLocation(); void clickedMaximizeButton(); void clearSelection(); @@ -79,24 +81,28 @@ private: bool isScope; }; + const Annotation* findAnnotationForPosition(int pos) const; void createAnnotations(const TokenLocationFile& locationFile); void annotateText(); + bool locationBelongsToSnippet(TokenLocation* location) const; + int toTextEditPosition(int lineNumber, int columnNumber) const; int startTextEditPosition() const; int endTextEditPosition() const; + QtCodeFile* m_parent; + QWidget* m_lineNumberArea; QtHighlighter* m_highlighter; QPushButton* m_maximizeButton; - bool m_showMaximizeButton; const uint m_startLineNumber; - const std::string m_filePath; - std::vector m_activeTokenIds; std::vector m_annotations; + const Annotation* m_hoveredAnnotation; + int m_digits; }; diff --git a/src/app/qt/element/QtStatusBar.cpp b/src/app/qt/element/QtStatusBar.cpp index fecab162..086a3b07 100644 --- a/src/app/qt/element/QtStatusBar.cpp +++ b/src/app/qt/element/QtStatusBar.cpp @@ -17,5 +17,10 @@ void QtStatusBar::setText(const std::string& text, bool isError) { m_text.setStyleSheet("QLabel { color: red }"); } + else + { + m_text.setStyleSheet(""); + } + m_text.setText(text.c_str()); } diff --git a/src/app/qt/view/QtCodeView.cpp b/src/app/qt/view/QtCodeView.cpp index fb647c3c..22837cc2 100644 --- a/src/app/qt/view/QtCodeView.cpp +++ b/src/app/qt/view/QtCodeView.cpp @@ -10,7 +10,6 @@ QtCodeView::QtCodeView(ViewLayout* viewLayout) : CodeView(viewLayout) , m_refreshViewFunctor(std::bind(&QtCodeView::doRefreshView, this)) - , m_clearCodeSnippetsFunctor(std::bind(&QtCodeView::doClearCodeSnippets, this)) , m_showCodeSnippetsFunctor(std::bind(&QtCodeView::doShowCodeSnippets, this, std::placeholders::_1)) , m_showCodeFileFunctor(std::bind(&QtCodeView::doShowCodeFile, this, std::placeholders::_1)) { @@ -35,16 +34,16 @@ void QtCodeView::refreshView() m_refreshViewFunctor(); } -void QtCodeView::clearCodeSnippets() -{ - m_clearCodeSnippetsFunctor(); -} - void QtCodeView::setActiveTokenIds(const std::vector& activeTokenIds) { m_activeTokenIds = activeTokenIds; } +void QtCodeView::setErrorMessages(const std::vector& errorMessages) +{ + m_errorMessages = errorMessages; +} + void QtCodeView::showCodeSnippets(const std::vector& snippets) { m_showCodeSnippetsFunctor(snippets); @@ -66,24 +65,31 @@ void QtCodeView::doRefreshView() } } -void QtCodeView::doClearCodeSnippets() -{ - m_widget->clearCodeSnippets(); -} - void QtCodeView::doShowCodeSnippets(const std::vector& snippets) { - doClearCodeSnippets(); + m_widget->clearCodeSnippets(); clearClosedWindows(); for (std::shared_ptr window: m_windows) { - window->setActiveTokenIds(m_activeTokenIds); + if (m_errorMessages.size()) + { + window->close(); + } + else + { + window->setActiveTokenIds(m_activeTokenIds); + window->setErrorMessages(m_errorMessages); + } } + m_widget->setActiveTokenIds(m_activeTokenIds); + m_widget->setErrorMessages(m_errorMessages); + m_widget->setShowMaximizeButton(m_errorMessages.size() == 0); + for (const CodeSnippetParams& params : snippets) { - m_widget->addCodeSnippet(params.startLineNumber, params.code, params.locationFile, m_activeTokenIds); + m_widget->addCodeSnippet(params.startLineNumber, params.code, params.locationFile); } } @@ -93,7 +99,9 @@ void QtCodeView::doShowCodeFile(const CodeSnippetParams& params) m_windows.push_back(ptr); ptr->setShowMaximizeButton(false); - ptr->addCodeSnippet(1, params.code, params.locationFile, m_activeTokenIds); + ptr->setActiveTokenIds(m_activeTokenIds); + ptr->setErrorMessages(m_errorMessages); + ptr->addCodeSnippet(1, params.code, params.locationFile); ptr->setWindowTitle(FileSystem::fileName(params.locationFile.getFilePath()).c_str()); ptr->show(); diff --git a/src/app/qt/view/QtCodeView.h b/src/app/qt/view/QtCodeView.h index 61593717..5f9ce3dd 100644 --- a/src/app/qt/view/QtCodeView.h +++ b/src/app/qt/view/QtCodeView.h @@ -24,14 +24,14 @@ public: virtual void refreshView(); // CodeView implementation - virtual void clearCodeSnippets(); virtual void setActiveTokenIds(const std::vector& activeTokenIds); + virtual void setErrorMessages(const std::vector& errorMessages); + virtual void showCodeSnippets(const std::vector& snippets); virtual void showCodeFile(const CodeSnippetParams& params); private: void doRefreshView(); - void doClearCodeSnippets(); void doShowCodeSnippets(const std::vector& snippets); void doShowCodeFile(const CodeSnippetParams& params); @@ -41,13 +41,14 @@ private: void clearClosedWindows(); QtThreadedFunctor<> m_refreshViewFunctor; - QtThreadedFunctor<> m_clearCodeSnippetsFunctor; QtThreadedFunctor&> m_showCodeSnippetsFunctor; QtThreadedFunctor m_showCodeFileFunctor; std::shared_ptr m_widget; std::vector> m_windows; + std::vector m_activeTokenIds; + std::vector m_errorMessages; }; # endif // QT_CODE_VIEW_H diff --git a/src/lib/Application.cpp b/src/lib/Application.cpp index fd311c65..49aaec60 100644 --- a/src/lib/Application.cpp +++ b/src/lib/Application.cpp @@ -47,8 +47,6 @@ void Application::loadProject(const std::string& projectSettingsFilePath) m_project->loadProjectSettings(projectSettingsFilePath); m_project->parseCode(); - - activateInitialNode(); } void Application::loadSource(const std::string& sourceDirectoryPath) @@ -58,16 +56,12 @@ void Application::loadSource(const std::string& sourceDirectoryPath) m_project->clearProjectSettings(); m_project->setSourceDirectoryPath(sourceDirectoryPath); m_project->parseCode(); - - activateInitialNode(); } void Application::reloadProject() { m_project->clearStorage(); m_project->parseCode(); - - activateInitialNode(); } void Application::saveProject(const std::string& projectSettingsFilePath) @@ -78,8 +72,13 @@ void Application::saveProject(const std::string& projectSettingsFilePath) } } -void Application::activateInitialNode() const +void Application::handleMessage(MessageFinishedParsing* message) { + if (message->errorCount > 0) + { + return; + } + Id mainId = m_graphAccessProxy->getIdForNodeWithName("main"); if (!mainId) diff --git a/src/lib/Application.h b/src/lib/Application.h index 6b66e2d0..96647dbd 100644 --- a/src/lib/Application.h +++ b/src/lib/Application.h @@ -6,6 +6,7 @@ #include "component/ComponentManager.h" #include "Project.h" #include "utility/messaging/MessageListener.h" +#include "utility/messaging/type/MessageFinishedParsing.h" #include "utility/messaging/type/MessageLoadProject.h" #include "utility/messaging/type/MessageLoadSource.h" #include "utility/messaging/type/MessageRefresh.h" @@ -17,7 +18,8 @@ class GraphAccessProxy; class LocationAccessProxy; class Application - : public MessageListener + : public MessageListener + , public MessageListener , public MessageListener , public MessageListener , public MessageListener @@ -35,8 +37,7 @@ public: private: Application(); - void activateInitialNode() const; - + virtual void handleMessage(MessageFinishedParsing* message); virtual void handleMessage(MessageLoadProject* message); virtual void handleMessage(MessageLoadSource* message); virtual void handleMessage(MessageRefresh* message); diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index b78d5871..d42308d2 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -13,6 +13,8 @@ add_files( data/parser/cxx/ASTConsumer.h data/parser/cxx/ASTVisitor.cpp data/parser/cxx/ASTVisitor.h + data/parser/cxx/CxxDiagnosticConsumer.cpp + data/parser/cxx/CxxDiagnosticConsumer.h data/parser/cxx/CxxParser.cpp data/parser/cxx/CxxParser.h data/parser/cxx/utilityCxx.cpp diff --git a/src/lib/Project.cpp b/src/lib/Project.cpp index 78114ce1..4b914e77 100644 --- a/src/lib/Project.cpp +++ b/src/lib/Project.cpp @@ -102,12 +102,13 @@ void Project::parseCode() ); time = clock() - time; - m_storage->logGraph(); - m_storage->logLocations(); + // m_storage->logGraph(); + // m_storage->logLocations(); - LOG_INFO_STREAM(<< "parse time: " << (double)(time) / CLOCKS_PER_SEC); + double parseTime = (double)(time) / CLOCKS_PER_SEC; + LOG_INFO_STREAM(<< "parse time: " << parseTime); - MessageFinishedParsing().dispatch(); + MessageFinishedParsing(parseTime, m_storage->getErrorCount()).dispatch(); } } diff --git a/src/lib/component/controller/CodeController.cpp b/src/lib/component/controller/CodeController.cpp index 3a1a702a..82b01446 100644 --- a/src/lib/component/controller/CodeController.cpp +++ b/src/lib/component/controller/CodeController.cpp @@ -38,8 +38,34 @@ void CodeController::handleMessage(MessageActivateTokens* message) activeTokenIds = m_graphAccess->getActiveTokenIdsForId(activeTokenIds[0], &declarationId); } - getView()->setActiveTokenIds(activeTokenIds); - getView()->showCodeSnippets(getSnippetsForActiveTokenIds(activeTokenIds, declarationId)); + CodeView* view = getView(); + view->setActiveTokenIds(activeTokenIds); + view->setErrorMessages(std::vector()); + view->showCodeSnippets(getSnippetsForActiveTokenIds(activeTokenIds, declarationId)); +} + +void CodeController::handleMessage(MessageFinishedParsing* message) +{ + if (message->errorCount > 0) + { + std::vector errorMessages; + TokenLocationCollection errorCollection = m_locationAccess->getErrorTokenLocations(&errorMessages); + + std::vector snippets; + + errorCollection.forEachTokenLocationFile( + [&](TokenLocationFile* file) -> void + { + std::vector fileSnippets = getSnippetsForFile(file); + snippets.insert(snippets.end(), fileSnippets.begin(), fileSnippets.end()); + } + ); + + CodeView* view = getView(); + view->setActiveTokenIds(std::vector()); + view->setErrorMessages(errorMessages); + view->showCodeSnippets(snippets); + } } void CodeController::handleMessage(MessageRefresh* message) @@ -78,28 +104,12 @@ std::vector CodeController::getSnippetsForActiveTok collection.forEachTokenLocationFile( [&](TokenLocationFile* file) -> void { - const std::string filePath = file->getFilePath(); - std::shared_ptr textAccess = TextAccess::createFromFile(filePath); + std::vector fileSnippets = getSnippetsForFile(file); - std::vector> ranges = getSnippetRangesForFile(file, s_lineRadius); - std::vector fileSnippets; - - for (const std::pair& range: ranges) + for (CodeView::CodeSnippetParams& params : fileSnippets) { - unsigned int firstLineNumber = std::max(1, range.first - s_lineRadius); - unsigned int lastLineNumber = std::min(textAccess->getLineCount(), range.second + s_lineRadius); - - CodeView::CodeSnippetParams params; - for (const std::string& line: textAccess->getLines(firstLineNumber, lastLineNumber)) - { - params.code += line; - } - - params.startLineNumber = firstLineNumber; - params.locationFile = - m_locationAccess->getTokenLocationsForLinesInFile(filePath, firstLineNumber, lastLineNumber); - - fileSnippets.push_back(params); + params.locationFile = m_locationAccess->getTokenLocationsForLinesInFile( + file->getFilePath(), params.startLineNumber, params.endLineNumber); } if (declarationId != 0) @@ -133,9 +143,32 @@ std::vector CodeController::getSnippetsForActiveTok return snippets; } -std::vector> CodeController::getSnippetRangesForFile( - TokenLocationFile* file, const uint lineRadius -) const +std::vector CodeController::getSnippetsForFile(const TokenLocationFile* file) const +{ + std::shared_ptr textAccess = TextAccess::createFromFile(file->getFilePath()); + + std::vector> ranges = getSnippetRangesForFile(file); + std::vector snippets; + + for (const std::pair& range: ranges) + { + CodeView::CodeSnippetParams params; + params.locationFile = *file; + params.startLineNumber = std::max(1, range.first - s_lineRadius); + params.endLineNumber = std::min(textAccess->getLineCount(), range.second + s_lineRadius); + + for (const std::string& line: textAccess->getLines(params.startLineNumber, params.endLineNumber)) + { + params.code += line; + } + + snippets.push_back(params); + } + + return snippets; +} + +std::vector> CodeController::getSnippetRangesForFile(const TokenLocationFile* file) const { std::vector> ranges; uint start = 0; @@ -152,7 +185,7 @@ std::vector> CodeController::getSnippetRangesForFile( { start = lineNumber; } - else if (end && lineNumber > end + 2 * lineRadius + 1) + else if (end && lineNumber > end + 2 * s_lineRadius + 1) { ranges.push_back(std::make_pair(uint(start), uint(end))); start = lineNumber; diff --git a/src/lib/component/controller/CodeController.h b/src/lib/component/controller/CodeController.h index fa1fc7b6..a4692db4 100644 --- a/src/lib/component/controller/CodeController.h +++ b/src/lib/component/controller/CodeController.h @@ -8,6 +8,7 @@ #include "utility/messaging/MessageListener.h" #include "utility/messaging/type/MessageActivateTokenLocation.h" #include "utility/messaging/type/MessageActivateTokens.h" +#include "utility/messaging/type/MessageFinishedParsing.h" #include "utility/messaging/type/MessageRefresh.h" #include "utility/messaging/type/MessageShowFile.h" #include "utility/types.h" @@ -20,6 +21,7 @@ class CodeController : public Controller , public MessageListener , public MessageListener + , public MessageListener , public MessageListener , public MessageListener { @@ -32,6 +34,7 @@ private: virtual void handleMessage(MessageActivateTokenLocation* message); virtual void handleMessage(MessageActivateTokens* message); + virtual void handleMessage(MessageFinishedParsing* message); virtual void handleMessage(MessageRefresh* message); virtual void handleMessage(MessageShowFile* message); @@ -39,7 +42,8 @@ private: std::vector getSnippetsForActiveTokenIds( const std::vector& ids, Id declarationId) const; - std::vector> getSnippetRangesForFile(TokenLocationFile* file, const uint lineRadius) const; + std::vector getSnippetsForFile(const TokenLocationFile* file) const; + std::vector> getSnippetRangesForFile(const TokenLocationFile* file) const; GraphAccess* m_graphAccess; LocationAccess* m_locationAccess; diff --git a/src/lib/component/controller/GraphController.cpp b/src/lib/component/controller/GraphController.cpp index 36ac6fa0..d9b0719e 100644 --- a/src/lib/component/controller/GraphController.cpp +++ b/src/lib/component/controller/GraphController.cpp @@ -56,6 +56,11 @@ void GraphController::handleMessage(MessageActivateTokens* message) createDummyGraphForTokenIds(m_activeTokenIds); } +void GraphController::handleMessage(MessageFinishedParsing* message) +{ + getView()->clear(); +} + void GraphController::handleMessage(MessageGraphNodeExpand* message) { DummyNode* node = findDummyNodeAccessRecursive(m_dummyNodes, message->tokenId, message->access); @@ -153,10 +158,26 @@ DummyNode GraphController::createDummyNodeTopDown(Node* node) Edge* edge = child->getMemberEdge(); TokenComponentAccess* access = edge->getComponent(); + TokenComponentAccess::AccessType accessType = TokenComponentAccess::ACCESS_NONE; + if (access) { - TokenComponentAccess::AccessType accessType = access->getAccess(); + accessType = access->getAccess(); + } + else + { + if (node->isType(Node::NODE_CLASS | Node::NODE_STRUCT)) + { + accessType = TokenComponentAccess::ACCESS_PUBLIC; + } + else + { + parent = &result; + } + } + if (accessType != TokenComponentAccess::ACCESS_NONE) + { for (DummyNode& dummy : result.subNodes) { if (dummy.accessType == accessType) @@ -178,10 +199,6 @@ DummyNode GraphController::createDummyNodeTopDown(Node* node) } } } - else - { - parent = &result; - } parent->subNodes.push_back(createDummyNodeTopDown(child)); } diff --git a/src/lib/component/controller/GraphController.h b/src/lib/component/controller/GraphController.h index 0bb05c73..1b29c03d 100644 --- a/src/lib/component/controller/GraphController.h +++ b/src/lib/component/controller/GraphController.h @@ -5,6 +5,7 @@ #include "utility/messaging/MessageListener.h" #include "utility/messaging/type/MessageActivateTokens.h" +#include "utility/messaging/type/MessageFinishedParsing.h" #include "utility/messaging/type/MessageGraphNodeExpand.h" #include "utility/messaging/type/MessageGraphNodeMove.h" @@ -21,6 +22,7 @@ class Node; class GraphController : public Controller , public MessageListener + , public MessageListener , public MessageListener , public MessageListener { @@ -47,6 +49,7 @@ public: private: virtual void handleMessage(MessageActivateTokens* message); + virtual void handleMessage(MessageFinishedParsing* message); virtual void handleMessage(MessageGraphNodeExpand* message); virtual void handleMessage(MessageGraphNodeMove* message); diff --git a/src/lib/component/controller/SearchController.cpp b/src/lib/component/controller/SearchController.cpp index b65d62a0..2b803570 100644 --- a/src/lib/component/controller/SearchController.cpp +++ b/src/lib/component/controller/SearchController.cpp @@ -32,6 +32,11 @@ void SearchController::handleMessage(MessageFind* message) getView()->setFocus(); } +void SearchController::handleMessage(MessageFinishedParsing* message) +{ + getView()->setText(""); +} + void SearchController::handleMessage(MessageRefresh* message) { getView()->refreshView(); diff --git a/src/lib/component/controller/SearchController.h b/src/lib/component/controller/SearchController.h index 5479c14d..131ea26b 100644 --- a/src/lib/component/controller/SearchController.h +++ b/src/lib/component/controller/SearchController.h @@ -7,6 +7,7 @@ #include "utility/messaging/MessageListener.h" #include "utility/messaging/type/MessageActivateTokens.h" #include "utility/messaging/type/MessageFind.h" +#include "utility/messaging/type/MessageFinishedParsing.h" #include "utility/messaging/type/MessageRefresh.h" #include "utility/messaging/type/MessageSearch.h" #include "utility/messaging/type/MessageSearchAutocomplete.h" @@ -18,6 +19,7 @@ class SearchController : public Controller , public MessageListener , public MessageListener + , public MessageListener , public MessageListener , public MessageListener , public MessageListener @@ -29,6 +31,7 @@ public: private: virtual void handleMessage(MessageActivateTokens* message); virtual void handleMessage(MessageFind* message); + virtual void handleMessage(MessageFinishedParsing* message); virtual void handleMessage(MessageRefresh* message); virtual void handleMessage(MessageSearch* message); virtual void handleMessage(MessageSearchAutocomplete* message); diff --git a/src/lib/component/controller/StatusBarController.cpp b/src/lib/component/controller/StatusBarController.cpp index bb2c34f3..8b63bc37 100644 --- a/src/lib/component/controller/StatusBarController.cpp +++ b/src/lib/component/controller/StatusBarController.cpp @@ -2,6 +2,9 @@ #include "component/view/StatusBarView.h" +#include +#include + StatusBarController::StatusBarController() : MessageListener(true) , MessageListener(true) @@ -23,7 +26,14 @@ StatusBarView* StatusBarController::getView() void StatusBarController::handleMessage(MessageFinishedParsing* message) { - setStatus("Parsing Finished"); + std::stringstream ss; + ss << "Parsing Finished: "; + ss << std::setprecision(2) << message->parseTime << " seconds, "; + ss << message->errorCount << " error(s)"; + + bool hasErrors = message->errorCount > 0; + + setStatus(ss.str(), hasErrors); } void StatusBarController::handleMessage(MessageStatus* message) diff --git a/src/lib/component/view/CodeView.h b/src/lib/component/view/CodeView.h index 6f71b406..073ce661 100644 --- a/src/lib/component/view/CodeView.h +++ b/src/lib/component/view/CodeView.h @@ -34,8 +34,9 @@ public: virtual std::string getName() const; - virtual void clearCodeSnippets() = 0; virtual void setActiveTokenIds(const std::vector& activeTokenIds) = 0; + virtual void setErrorMessages(const std::vector& errorMessages) = 0; + virtual void showCodeSnippets(const std::vector& snippets) = 0; virtual void showCodeFile(const CodeSnippetParams& params) = 0; diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index 2c8e0fe7..bb2e422b 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -48,6 +48,30 @@ void Storage::logLocations() const LOG_INFO_STREAM(<< '\n' << m_locationCollection); } +size_t Storage::getErrorCount() const +{ + return m_errorMessages.size(); +} + +void Storage::onError(const ParseLocation& location, const std::string& message) +{ + log("ERROR", message, location); + + if (!location.isValid()) + { + return; + } + + Id errorId = m_errorMessages.size(); + + TokenLocation* loc = m_errorLocationCollection.addTokenLocation( + errorId, location.filePath, + location.startLineNumber, location.startColumnNumber, + location.endLineNumber, location.endColumnNumber + ); + + m_errorMessages.push_back(message); +} Id Storage::onTypedefParsed( const ParseLocation& location, const std::vector& nameHierarchy, const ParseTypeUsage& underlyingType, @@ -576,7 +600,6 @@ std::vector Storage::getActiveTokenIdsForId(Id tokenId, Id* declarationId) c ret.push_back(token->getId()); - Node* node; if (token->isNode()) { Node* node = dynamic_cast(token); @@ -744,6 +767,13 @@ TokenLocationFile Storage::getTokenLocationsForLinesInFile( return ret; } +TokenLocationCollection Storage::getErrorTokenLocations(std::vector* errorMessages) const +{ + errorMessages->insert(errorMessages->begin(), m_errorMessages.begin(), m_errorMessages.end()); + + return m_errorLocationCollection; +} + const Graph& Storage::getGraph() const { return m_graph; @@ -941,8 +971,16 @@ bool Storage::getSubQuerySearchResults( { if (word.size()) { - SearchResults res = node->runFuzzySearch(word); - results->insert(res.begin(), res.end()); + if (searchNodes.size() > 1) + { + SearchResults res = node->runFuzzySearchOnSelf(word); + results->insert(res.begin(), res.end()); + } + else + { + SearchResults res = node->runFuzzySearch(word); + results->insert(res.begin(), res.end()); + } } else if (searchNodes.size() == 1) { diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index 296ef8f8..6e309f1a 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -27,7 +27,11 @@ public: void logGraph() const; void logLocations() const; + size_t getErrorCount() const; + // ParserClient implementation + virtual void onError(const ParseLocation& location, const std::string& message); + virtual Id onTypedefParsed( const ParseLocation& location, const std::vector& nameHierarchy, const ParseTypeUsage& underlyingType, AccessType access); @@ -108,6 +112,8 @@ public: const std::string& filePath, uint firstLineNumber, uint lastLineNumber ) const; + virtual TokenLocationCollection getErrorTokenLocations(std::vector* errorMessages) const; + protected: const Graph& getGraph() const; const TokenLocationCollection& getTokenLocationCollection() const; @@ -137,6 +143,9 @@ private: SearchIndex m_tokenIndex; SearchIndex m_filterIndex; + + TokenLocationCollection m_errorLocationCollection; + std::vector m_errorMessages; }; #endif // STORAGE_H diff --git a/src/lib/data/access/LocationAccess.h b/src/lib/data/access/LocationAccess.h index 8a73ff9b..a0f7ea08 100644 --- a/src/lib/data/access/LocationAccess.h +++ b/src/lib/data/access/LocationAccess.h @@ -18,6 +18,8 @@ public: virtual TokenLocationFile getTokenLocationsForLinesInFile( const std::string& filePath, uint firstLineNumber, uint lastLineNumber ) const = 0; + + virtual TokenLocationCollection getErrorTokenLocations(std::vector* errorMessages) const = 0; }; diff --git a/src/lib/data/access/LocationAccessProxy.cpp b/src/lib/data/access/LocationAccessProxy.cpp index 78dc5368..c067abad 100644 --- a/src/lib/data/access/LocationAccessProxy.cpp +++ b/src/lib/data/access/LocationAccessProxy.cpp @@ -60,3 +60,13 @@ TokenLocationFile LocationAccessProxy::getTokenLocationsForLinesInFile( return TokenLocationFile(""); } + +TokenLocationCollection LocationAccessProxy::getErrorTokenLocations(std::vector* errorMessages) const +{ + if (hasSubject()) + { + return m_subject->getErrorTokenLocations(errorMessages); + } + + return TokenLocationCollection(); +} diff --git a/src/lib/data/access/LocationAccessProxy.h b/src/lib/data/access/LocationAccessProxy.h index 53ada5ab..8b6b6445 100644 --- a/src/lib/data/access/LocationAccessProxy.h +++ b/src/lib/data/access/LocationAccessProxy.h @@ -19,6 +19,8 @@ public: const std::string& filePath, uint firstLineNumber, uint lastLineNumber ) const; + virtual TokenLocationCollection getErrorTokenLocations(std::vector* errorMessages) const; + private: LocationAccess* m_subject; }; diff --git a/src/lib/data/parser/ParseLocation.cpp b/src/lib/data/parser/ParseLocation.cpp index 16957979..cd1034d3 100644 --- a/src/lib/data/parser/ParseLocation.cpp +++ b/src/lib/data/parser/ParseLocation.cpp @@ -9,6 +9,19 @@ ParseLocation::ParseLocation() { } +ParseLocation::ParseLocation( + const std::string& filePath, + uint lineNumber, + uint columnNumber +) + : filePath(filePath) + , startLineNumber(lineNumber) + , startColumnNumber(columnNumber) + , endLineNumber(lineNumber) + , endColumnNumber(columnNumber) +{ +} + ParseLocation::ParseLocation( const std::string& filePath, uint startLineNumber, uint startColumnNumber, diff --git a/src/lib/data/parser/ParseLocation.h b/src/lib/data/parser/ParseLocation.h index 77951e84..a97e6234 100644 --- a/src/lib/data/parser/ParseLocation.h +++ b/src/lib/data/parser/ParseLocation.h @@ -8,6 +8,11 @@ struct ParseLocation { ParseLocation(); + ParseLocation( + const std::string& filePath, + uint lineNumber, + uint columnNumber + ); ParseLocation( const std::string& filePath, uint startLineNumber, uint startColumnNumber, diff --git a/src/lib/data/parser/ParserClient.h b/src/lib/data/parser/ParserClient.h index 4d0c51b7..51a8a492 100644 --- a/src/lib/data/parser/ParserClient.h +++ b/src/lib/data/parser/ParserClient.h @@ -49,6 +49,8 @@ public: ParserClient(); virtual ~ParserClient(); + virtual void onError(const ParseLocation& location, const std::string& message) = 0; + virtual Id onTypedefParsed( const ParseLocation& location, const std::vector& nameHierarchy, const ParseTypeUsage& underlyingType, AccessType access) = 0; diff --git a/src/lib/data/parser/cxx/ASTConsumer.cpp b/src/lib/data/parser/cxx/ASTConsumer.cpp index 74591c8c..381a2a1d 100644 --- a/src/lib/data/parser/cxx/ASTConsumer.cpp +++ b/src/lib/data/parser/cxx/ASTConsumer.cpp @@ -1,5 +1,7 @@ #include "data/parser/cxx/ASTConsumer.h" +#include "data/parser/ParserClient.h" + ASTConsumer::ASTConsumer(clang::ASTContext* context, ParserClient* client) : m_visitor(context, client) { diff --git a/src/lib/data/parser/cxx/CxxDiagnosticConsumer.cpp b/src/lib/data/parser/cxx/CxxDiagnosticConsumer.cpp new file mode 100644 index 00000000..5cefa272 --- /dev/null +++ b/src/lib/data/parser/cxx/CxxDiagnosticConsumer.cpp @@ -0,0 +1,75 @@ +#include "data/parser/cxx/CxxDiagnosticConsumer.h" + +#include "clang/Basic/SourceManager.h" + +#include "data/parser/ParseLocation.h" +#include "data/parser/ParserClient.h" + +CxxDiagnosticConsumer::CxxDiagnosticConsumer( + clang::raw_ostream &os, + clang::DiagnosticOptions *diags, + ParserClient* client, + bool useLogging +) + : clang::TextDiagnosticPrinter(os, diags) + , m_client(client) + , m_isParsingFile(false) + , m_useLogging(useLogging) +{ +} + +void CxxDiagnosticConsumer::BeginSourceFile(const clang::LangOptions& langOptions, const clang::Preprocessor* preProcessor) +{ + if (m_useLogging) + { + clang::TextDiagnosticPrinter::BeginSourceFile(langOptions, preProcessor); + } + + m_isParsingFile = true; +} + +void CxxDiagnosticConsumer::EndSourceFile() +{ + if (m_useLogging) + { + clang::TextDiagnosticPrinter::EndSourceFile(); + } + + m_isParsingFile = false; +} + +void CxxDiagnosticConsumer::HandleDiagnostic(clang::DiagnosticsEngine::Level level, const clang::Diagnostic& info) +{ + if (m_useLogging) + { + clang::TextDiagnosticPrinter::HandleDiagnostic(level, info); + } + + if (!m_isParsingFile) + { + return; + } + + if (level == clang::DiagnosticsEngine::Error || level == clang::DiagnosticsEngine::Fatal) + { + llvm::SmallString<100> messageStr; + info.FormatDiagnostic(messageStr); + std::string message = messageStr.str(); + + std::string filePath; + uint line = 0; + uint column = 0; + + if (info.getLocation().isValid() && info.hasSourceManager()) + { + const clang::SourceManager& sourceManager = info.getSourceManager(); + clang::PresumedLoc presumedLocation = sourceManager.getPresumedLoc(info.getLocation()); + + filePath = presumedLocation.getFilename(); + line = presumedLocation.getLine(); + column = presumedLocation.getColumn(); + } + + m_client->onError(ParseLocation(filePath, line, column), message); + } +} diff --git a/src/lib/data/parser/cxx/CxxDiagnosticConsumer.h b/src/lib/data/parser/cxx/CxxDiagnosticConsumer.h new file mode 100644 index 00000000..ac437c6e --- /dev/null +++ b/src/lib/data/parser/cxx/CxxDiagnosticConsumer.h @@ -0,0 +1,25 @@ +#ifndef CXX_DIAGNOSTIC_CONSUMER +#define CXX_DIAGNOSTIC_CONSUMER + +#include "clang/Frontend/TextDiagnosticPrinter.h" + +class ParserClient; + +class CxxDiagnosticConsumer + : public clang::TextDiagnosticPrinter +{ +public: + CxxDiagnosticConsumer(clang::raw_ostream &os, clang::DiagnosticOptions *diags, ParserClient* client, bool useLogging = true); + + void BeginSourceFile(const clang::LangOptions& langOptions, const clang::Preprocessor* preProcessor); + void EndSourceFile(); + + void HandleDiagnostic(clang::DiagnosticsEngine::Level level, const clang::Diagnostic& info); + +private: + ParserClient* m_client; + bool m_isParsingFile; + bool m_useLogging; +}; + +#endif // CXX_DIAGNOSTIC_CONSUMER diff --git a/src/lib/data/parser/cxx/CxxParser.cpp b/src/lib/data/parser/cxx/CxxParser.cpp index 4726a0e7..49bc76a4 100644 --- a/src/lib/data/parser/cxx/CxxParser.cpp +++ b/src/lib/data/parser/cxx/CxxParser.cpp @@ -1,9 +1,54 @@ #include "data/parser/cxx/CxxParser.h" -#include "data/parser/cxx/ASTActionFactory.h" #include "utility/logging/logging.h" #include "utility/text/TextAccess.h" +#include "data/parser/cxx/ASTActionFactory.h" +#include "data/parser/cxx/CxxDiagnosticConsumer.h" + +namespace { + +static std::vector getSyntaxOnlyToolArgs(const std::vector &ExtraArgs, llvm::StringRef FileName) +{ + std::vector Args; + Args.push_back("clang-tool"); + Args.push_back("-fsyntax-only"); + Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end()); + Args.push_back(FileName.str()); + return Args; +} + +// custom implementation of clang::runToolOnCodeWithArgs which also sets our custon DiagnosticConsumer +static bool runToolOnCodeWithArgs( + clang::DiagnosticConsumer* DiagConsumer, + clang::FrontendAction *ToolAction, + const llvm::Twine &Code, + const std::vector &Args, + const llvm::Twine &FileName = "input.cc", + const clang::tooling::FileContentMappings &VirtualMappedFiles = clang::tooling::FileContentMappings() +){ + llvm::SmallString<16> FileNameStorage; + llvm::StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage); + llvm::IntrusiveRefCntPtr Files(new clang::FileManager(clang::FileSystemOptions())); + clang::tooling::ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), ToolAction, Files.get()); + + llvm::SmallString<1024> CodeStorage; + Invocation.mapVirtualFile(FileNameRef, + Code.toNullTerminatedStringRef(CodeStorage)); + + for (auto &FilenameWithContent : VirtualMappedFiles) + { + Invocation.mapVirtualFile(FilenameWithContent.first, + FilenameWithContent.second); + } + + Invocation.setDiagnosticConsumer(DiagConsumer); + + return Invocation.run(); +} + +} + CxxParser::CxxParser(ParserClient* client) : Parser(client) { @@ -68,15 +113,22 @@ void CxxParser::parseFiles( clang::tooling::ClangTool tool(*compilationDatabase, filePaths); - ASTActionFactory actionFactory(m_client); + llvm::IntrusiveRefCntPtr options = new clang::DiagnosticOptions(); + CxxDiagnosticConsumer reporter(llvm::errs(), &*options, m_client); + tool.setDiagnosticConsumer(&reporter); + ASTActionFactory actionFactory(m_client); tool.run(&actionFactory); } void CxxParser::parseFile(std::shared_ptr textAccess) { - ASTActionFactory actionFactory(m_client); std::vector args; args.push_back("-fno-delayed-template-parsing"); - clang::tooling::runToolOnCodeWithArgs(actionFactory.create(), textAccess->getText(), args); + + llvm::IntrusiveRefCntPtr options = new clang::DiagnosticOptions(); + CxxDiagnosticConsumer reporter(llvm::errs(), &*options, m_client, false); + + ASTActionFactory actionFactory(m_client); + runToolOnCodeWithArgs(&reporter, actionFactory.create(), textAccess->getText(), args); } diff --git a/src/lib/data/search/SearchNode.cpp b/src/lib/data/search/SearchNode.cpp index d254cc46..882b6997 100644 --- a/src/lib/data/search/SearchNode.cpp +++ b/src/lib/data/search/SearchNode.cpp @@ -107,6 +107,20 @@ SearchResults SearchNode::runFuzzySearch(const std::string& query) const return result; } +SearchResults SearchNode::runFuzzySearchOnSelf(const std::string& query) const +{ + SearchResults result; + FuzzyMap m = fuzzyMatchRecursive(query, 0, 0, 0); + for (const std::pair& p : m) + { + addResultsRecursive(result, p.first, p.second); + } + + // TODO: Currently all matches are added to the ordered set and get compared by their fullName for alphabetical + // order. This could be improved by limiting the number of items to e.g. 100. + return result; +} + void SearchNode::addResultsRecursive(SearchResults& result, size_t weight, const SearchNode* node) const { result.insert(SearchResult(weight, node, this)); diff --git a/src/lib/data/search/SearchNode.h b/src/lib/data/search/SearchNode.h index d3c7ab9b..f93f6493 100644 --- a/src/lib/data/search/SearchNode.h +++ b/src/lib/data/search/SearchNode.h @@ -37,6 +37,8 @@ public: const std::set>& getChildren() const; SearchResults runFuzzySearch(const std::string& query) const; + SearchResults runFuzzySearchOnSelf(const std::string& query) const; + void addResultsRecursive(SearchResults& result, size_t weight, const SearchNode* node) const; private: diff --git a/src/lib/utility/messaging/type/MessageFinishedParsing.h b/src/lib/utility/messaging/type/MessageFinishedParsing.h index c41978ee..0eca55c3 100644 --- a/src/lib/utility/messaging/type/MessageFinishedParsing.h +++ b/src/lib/utility/messaging/type/MessageFinishedParsing.h @@ -6,7 +6,9 @@ class MessageFinishedParsing: public Message { public: - MessageFinishedParsing() + MessageFinishedParsing(float parseTime, size_t errorCount) + : parseTime(parseTime) + , errorCount(errorCount) { } @@ -14,6 +16,9 @@ public: { return "MessageFinishedParsing"; } + + float parseTime; + size_t errorCount; }; #endif // MESSAGE_FINISHED_PARSING_H diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 88d5ac1a..984f9d8c 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -1397,6 +1397,8 @@ public: filePaths.push_back("data/CxxParserTestSuite/code.cpp"); parser.parseFiles(filePaths, std::vector(), std::vector()); + TS_ASSERT_EQUALS(client.errors.size(), 0); + TS_ASSERT_EQUALS(client.typedefs.size(), 1); TS_ASSERT_EQUALS(client.classes.size(), 4); TS_ASSERT_EQUALS(client.enums.size(), 1); @@ -1414,10 +1416,25 @@ public: TS_ASSERT_EQUALS(client.typeUses.size(), 8); } + void test_cxx_parser_catches_error() + { + std::shared_ptr client = parseCode( + "int a = b;\n" + ); + + TS_ASSERT_EQUALS(client->errors.size(), 1); + TS_ASSERT_EQUALS(client->errors[0], "use of undeclared identifier \'b\' <1:9 1:9>"); + } + private: class TestParserClient: public ParserClient { public: + virtual void onError(const ParseLocation& location, const std::string& message) + { + errors.push_back(addLocationSuffix(message, location)); + } + virtual Id onTypedefParsed( const ParseLocation& location, const std::vector& nameHierarchy, const ParseTypeUsage& underlyingType, AccessType access @@ -1610,6 +1627,8 @@ private: return 0; } + std::vector errors; + std::vector typedefs; std::vector classes; std::vector enums;