diff --git a/src/libs/cplusplus/ModelManagerInterface.h b/src/libs/cplusplus/ModelManagerInterface.h index 75d084053a76407d81ffcac3ff29dbd893eaeab7..cf5f719e0e9e737f5f4e6b9a49c8c900b2cb8959 100644 --- a/src/libs/cplusplus/ModelManagerInterface.h +++ b/src/libs/cplusplus/ModelManagerInterface.h @@ -113,6 +113,12 @@ public: Table _elements; }; + enum ExtraDiagnosticKind + { + AllExtraDiagnostics = -1, + ExportedQmlTypesDiagnostic + }; + public: CppModelManagerInterface(QObject *parent = 0); virtual ~CppModelManagerInterface(); @@ -140,6 +146,11 @@ public: virtual void findMacroUsages(const CPlusPlus::Macro ¯o) = 0; + virtual void setExtraDiagnostics(const QString &fileName, int key, + const QList &diagnostics) = 0; + virtual QList extraDiagnostics( + const QString &fileName, int key = AllExtraDiagnostics) const = 0; + Q_SIGNALS: void documentUpdated(CPlusPlus::Document::Ptr doc); void sourceFilesRefreshed(const QStringList &files); diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index 79c96c1478892a88bef8618dbf21d964fb347ccf..9a3fca3935cf446b3295ff2ae4efdd07b1ec6e39 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -1060,7 +1060,9 @@ void CppModelManager::onDocumentUpdated(Document::Ptr doc) } #else QSet lines; - foreach (const Document::DiagnosticMessage &m, doc->diagnosticMessages()) { + QList messages = doc->diagnosticMessages(); + messages += extraDiagnostics(doc->fileName()); + foreach (const Document::DiagnosticMessage &m, messages) { if (m.fileName() != fileName) continue; else if (lines.contains(m.line())) @@ -1289,5 +1291,34 @@ void CppModelManager::finishedRefreshingSourceFiles(const QStringList &files) emit sourceFilesRefreshed(files); } + +void CppModelManager::setExtraDiagnostics(const QString &fileName, int kind, + const QList &diagnostics) +{ + { + QMutexLocker locker(&protectExtraDiagnostics); + m_extraDiagnostics[fileName].insert(kind, diagnostics); + } + Document::Ptr doc; + { + QMutexLocker locker(&protectSnapshot); + doc = m_snapshot.document(fileName); + } + if (doc) + emit documentUpdated(doc); +} + +QList CppModelManager::extraDiagnostics(const QString &fileName, int kind) const +{ + QMutexLocker locker(&protectExtraDiagnostics); + if (kind == -1) { + QList messages; + foreach (const QList &list, m_extraDiagnostics.value(fileName)) + messages += list; + return messages; + } + return m_extraDiagnostics.value(fileName).value(kind); +} + #endif diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index 13a1b851955aeebed3e0f78daf4a3bd8b8cf1902..4bc06f60f088d3990ba36ce0282e0f8c5be879c6 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -34,6 +34,7 @@ #define CPPMODELMANAGER_H #include "cpptools_global.h" +#include "cpptoolsconstants.h" #include #ifndef ICHECK_BUILD # include @@ -128,6 +129,12 @@ public: virtual void findMacroUsages(const CPlusPlus::Macro ¯o); + virtual void setExtraDiagnostics(const QString &fileName, int key, + const QList &diagnostics); + virtual QList extraDiagnostics( + const QString &fileName, int key = AllExtraDiagnostics) const; + + void finishedRefreshingSourceFiles(const QStringList &files); Q_SIGNALS: @@ -226,6 +233,9 @@ private: CppFindReferences *m_findReferences; bool m_indexerEnabled; + + mutable QMutex protectExtraDiagnostics; + QHash > > m_extraDiagnostics; }; #endif diff --git a/src/plugins/qmljstools/qmljsfindexportedcpptypes.cpp b/src/plugins/qmljstools/qmljsfindexportedcpptypes.cpp index 919aacfda319e69f1035c2d6d9d79789376677e2..357c366667adfd474a26e31cc3d259d039b5e4f6 100644 --- a/src/plugins/qmljstools/qmljsfindexportedcpptypes.cpp +++ b/src/plugins/qmljstools/qmljsfindexportedcpptypes.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -71,6 +72,7 @@ class FindExportsVisitor : protected ASTVisitor ASTMatcher _matcher; ASTPatternBuilder _builder; Overview _overview; + QList _messages; public: FindExportsVisitor(CPlusPlus::Document::Ptr doc) @@ -86,6 +88,11 @@ public: return _exportedTypes; } + QList messages() const + { + return _messages; + } + protected: virtual bool visit(CompoundStatementAST *ast) { @@ -135,10 +142,14 @@ protected: if (StringLiteralAST *nameAst = ast->expression_list->next->next->next->value->asStringLiteral()) nameLit = translationUnit()->stringLiteral(nameAst->literal_token); if (!nameLit) { - // disable this warning for now, we don't want to encourage using string literals if they don't mean to - // in the future, we will also accept annotations for the qmlRegisterType arguments in comments -// translationUnit()->warning(ast->expression_list->next->next->next->value->firstToken(), -// "The type will only be available in Qt Creator's QML editors when the type name is a string literal"); + unsigned line, column; + translationUnit()->getTokenStartPosition(ast->expression_list->next->next->next->value->firstToken(), &line, &column); + _messages += Document::DiagnosticMessage( + Document::DiagnosticMessage::Warning, + _doc->fileName(), + line, column, + FindExportedCppTypes::tr( + "The type will only be available in Qt Creator's QML editors when the type name is a string literal")); return false; } @@ -187,6 +198,19 @@ protected: } } } + if (packageName.isEmpty()) { + packageName = QmlJS::CppQmlTypes::defaultPackage; + unsigned line, column; + translationUnit()->getTokenStartPosition(ast->firstToken(), &line, &column); + _messages += Document::DiagnosticMessage( + Document::DiagnosticMessage::Warning, + _doc->fileName(), + line, column, + FindExportedCppTypes::tr( + "The module uri cannot be determined by static analysis. The type will be available\n" + "globally in the QML editor. You can add a \"// @uri My.Module.Uri\" annotation to let\n" + "Qt Creator know about a likely uri.")); + } // second and third argument must be integer literals const NumericLiteral *majorLit = 0; @@ -199,17 +223,11 @@ protected: // build the descriptor ExportedQmlType exportedType; exportedType.typeName = QString::fromUtf8(nameLit->chars(), nameLit->size()); - if (!packageName.isEmpty() && majorLit && minorLit && majorLit->isInt() && minorLit->isInt()) { - exportedType.packageName = packageName; + exportedType.packageName = packageName; + if (majorLit && minorLit && majorLit->isInt() && minorLit->isInt()) { exportedType.version = LanguageUtils::ComponentVersion( QString::fromUtf8(majorLit->chars(), majorLit->size()).toInt(), QString::fromUtf8(minorLit->chars(), minorLit->size()).toInt()); - } else { - // disable this warning, see above for details -// translationUnit()->warning(ast->base_expression->firstToken(), -// "The module will not be available in Qt Creator's QML editors because the uri and version numbers\n" -// "cannot be determined by static analysis. The type will still be available globally."); - exportedType.packageName = QmlJS::CppQmlTypes::defaultPackage; } // we want to do lookup later, so also store the surrounding scope @@ -498,12 +516,17 @@ FindExportedCppTypes::FindExportedCppTypes(const CPlusPlus::Snapshot &snapshot) QList FindExportedCppTypes::operator()(const CPlusPlus::Document::Ptr &document) { QList noResults; + // this check only guards against some input errors, if document's source and AST has not + // been guarded properly the source and AST may still become empty/null while this function is running if (document->source().isEmpty() || !document->translationUnit()->ast()) return noResults; FindExportsVisitor finder(document); QList exports = finder(); + CppModelManagerInterface::instance()->setExtraDiagnostics( + document->fileName(), CppModelManagerInterface::ExportedQmlTypesDiagnostic, + finder.messages()); if (exports.isEmpty()) return noResults; diff --git a/src/plugins/qmljstools/qmljsfindexportedcpptypes.h b/src/plugins/qmljstools/qmljsfindexportedcpptypes.h index 304894e94397a679074821ca97171101070bc6de..2814441ceed627cc19d347ebc4608a7247968c4b 100644 --- a/src/plugins/qmljstools/qmljsfindexportedcpptypes.h +++ b/src/plugins/qmljstools/qmljsfindexportedcpptypes.h @@ -36,12 +36,17 @@ #include #include +#include + namespace QmlJSTools { class FindExportedCppTypes { + Q_DECLARE_TR_FUNCTIONS(FindExportedCppTypes) public: FindExportedCppTypes(const CPlusPlus::Snapshot &snapshot); + + // document must have a valid source and ast for the duration of the call QList operator()(const CPlusPlus::Document::Ptr &document); static bool maybeExportsTypes(const CPlusPlus::Document::Ptr &document); diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp index 47292d489be21423fad502a0bbb408114e6d72b4..f0118fa9d768568ca2c322671c4080836474fcd0 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.cpp +++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp @@ -698,10 +698,17 @@ void ModelManager::loadPluginTypes(const QString &libraryPath, const QString &im // is called *inside a c++ parsing thread*, to allow hanging on to source and ast void ModelManager::maybeQueueCppQmlTypeUpdate(const CPlusPlus::Document::Ptr &doc) { + // avoid scanning documents without source code available + doc->keepSourceAndAST(); + if (doc->source().isEmpty()) { + doc->releaseSourceAndAST(); + return; + } + // keep source and AST alive if we want to scan for register calls const bool scan = FindExportedCppTypes::maybeExportsTypes(doc); - if (scan) - doc->keepSourceAndAST(); + if (!scan) + doc->releaseSourceAndAST(); // delegate actual queuing to the gui thread QMetaObject::invokeMethod(this, "queueCppQmlTypeUpdate",