Commit 94a00259 authored by Christian Kamm's avatar Christian Kamm

C++/QmlJS: Warnings if C++ based QML type detection fails.

Change-Id: I1e206e09c4068cc541978ee148f9ed8c4138c249
Reviewed-on: http://codereview.qt.nokia.com/3579Reviewed-by: default avatarFawzi Mohamed <fawzi.mohamed@nokia.com>
parent 2c7729ee
...@@ -113,6 +113,12 @@ public: ...@@ -113,6 +113,12 @@ public:
Table _elements; Table _elements;
}; };
enum ExtraDiagnosticKind
{
AllExtraDiagnostics = -1,
ExportedQmlTypesDiagnostic
};
public: public:
CppModelManagerInterface(QObject *parent = 0); CppModelManagerInterface(QObject *parent = 0);
virtual ~CppModelManagerInterface(); virtual ~CppModelManagerInterface();
...@@ -140,6 +146,11 @@ public: ...@@ -140,6 +146,11 @@ public:
virtual void findMacroUsages(const CPlusPlus::Macro &macro) = 0; virtual void findMacroUsages(const CPlusPlus::Macro &macro) = 0;
virtual void setExtraDiagnostics(const QString &fileName, int key,
const QList<CPlusPlus::Document::DiagnosticMessage> &diagnostics) = 0;
virtual QList<CPlusPlus::Document::DiagnosticMessage> extraDiagnostics(
const QString &fileName, int key = AllExtraDiagnostics) const = 0;
Q_SIGNALS: Q_SIGNALS:
void documentUpdated(CPlusPlus::Document::Ptr doc); void documentUpdated(CPlusPlus::Document::Ptr doc);
void sourceFilesRefreshed(const QStringList &files); void sourceFilesRefreshed(const QStringList &files);
......
...@@ -1060,7 +1060,9 @@ void CppModelManager::onDocumentUpdated(Document::Ptr doc) ...@@ -1060,7 +1060,9 @@ void CppModelManager::onDocumentUpdated(Document::Ptr doc)
} }
#else #else
QSet<int> lines; QSet<int> lines;
foreach (const Document::DiagnosticMessage &m, doc->diagnosticMessages()) { QList<Document::DiagnosticMessage> messages = doc->diagnosticMessages();
messages += extraDiagnostics(doc->fileName());
foreach (const Document::DiagnosticMessage &m, messages) {
if (m.fileName() != fileName) if (m.fileName() != fileName)
continue; continue;
else if (lines.contains(m.line())) else if (lines.contains(m.line()))
...@@ -1289,5 +1291,34 @@ void CppModelManager::finishedRefreshingSourceFiles(const QStringList &files) ...@@ -1289,5 +1291,34 @@ void CppModelManager::finishedRefreshingSourceFiles(const QStringList &files)
emit sourceFilesRefreshed(files); emit sourceFilesRefreshed(files);
} }
void CppModelManager::setExtraDiagnostics(const QString &fileName, int kind,
const QList<Document::DiagnosticMessage> &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<Document::DiagnosticMessage> CppModelManager::extraDiagnostics(const QString &fileName, int kind) const
{
QMutexLocker locker(&protectExtraDiagnostics);
if (kind == -1) {
QList<Document::DiagnosticMessage> messages;
foreach (const QList<Document::DiagnosticMessage> &list, m_extraDiagnostics.value(fileName))
messages += list;
return messages;
}
return m_extraDiagnostics.value(fileName).value(kind);
}
#endif #endif
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#define CPPMODELMANAGER_H #define CPPMODELMANAGER_H
#include "cpptools_global.h" #include "cpptools_global.h"
#include "cpptoolsconstants.h"
#include <cplusplus/ModelManagerInterface.h> #include <cplusplus/ModelManagerInterface.h>
#ifndef ICHECK_BUILD #ifndef ICHECK_BUILD
# include <projectexplorer/project.h> # include <projectexplorer/project.h>
...@@ -128,6 +129,12 @@ public: ...@@ -128,6 +129,12 @@ public:
virtual void findMacroUsages(const CPlusPlus::Macro &macro); virtual void findMacroUsages(const CPlusPlus::Macro &macro);
virtual void setExtraDiagnostics(const QString &fileName, int key,
const QList<CPlusPlus::Document::DiagnosticMessage> &diagnostics);
virtual QList<CPlusPlus::Document::DiagnosticMessage> extraDiagnostics(
const QString &fileName, int key = AllExtraDiagnostics) const;
void finishedRefreshingSourceFiles(const QStringList &files); void finishedRefreshingSourceFiles(const QStringList &files);
Q_SIGNALS: Q_SIGNALS:
...@@ -226,6 +233,9 @@ private: ...@@ -226,6 +233,9 @@ private:
CppFindReferences *m_findReferences; CppFindReferences *m_findReferences;
bool m_indexerEnabled; bool m_indexerEnabled;
mutable QMutex protectExtraDiagnostics;
QHash<QString, QHash<int, QList<CPlusPlus::Document::DiagnosticMessage> > > m_extraDiagnostics;
}; };
#endif #endif
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include <cplusplus/CoreTypes.h> #include <cplusplus/CoreTypes.h>
#include <cplusplus/Symbols.h> #include <cplusplus/Symbols.h>
#include <cplusplus/SimpleLexer.h> #include <cplusplus/SimpleLexer.h>
#include <cplusplus/ModelManagerInterface.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QtCore/QDebug> #include <QtCore/QDebug>
...@@ -71,6 +72,7 @@ class FindExportsVisitor : protected ASTVisitor ...@@ -71,6 +72,7 @@ class FindExportsVisitor : protected ASTVisitor
ASTMatcher _matcher; ASTMatcher _matcher;
ASTPatternBuilder _builder; ASTPatternBuilder _builder;
Overview _overview; Overview _overview;
QList<Document::DiagnosticMessage> _messages;
public: public:
FindExportsVisitor(CPlusPlus::Document::Ptr doc) FindExportsVisitor(CPlusPlus::Document::Ptr doc)
...@@ -86,6 +88,11 @@ public: ...@@ -86,6 +88,11 @@ public:
return _exportedTypes; return _exportedTypes;
} }
QList<Document::DiagnosticMessage> messages() const
{
return _messages;
}
protected: protected:
virtual bool visit(CompoundStatementAST *ast) virtual bool visit(CompoundStatementAST *ast)
{ {
...@@ -135,10 +142,14 @@ protected: ...@@ -135,10 +142,14 @@ protected:
if (StringLiteralAST *nameAst = ast->expression_list->next->next->next->value->asStringLiteral()) if (StringLiteralAST *nameAst = ast->expression_list->next->next->next->value->asStringLiteral())
nameLit = translationUnit()->stringLiteral(nameAst->literal_token); nameLit = translationUnit()->stringLiteral(nameAst->literal_token);
if (!nameLit) { if (!nameLit) {
// disable this warning for now, we don't want to encourage using string literals if they don't mean to unsigned line, column;
// in the future, we will also accept annotations for the qmlRegisterType arguments in comments translationUnit()->getTokenStartPosition(ast->expression_list->next->next->next->value->firstToken(), &line, &column);
// translationUnit()->warning(ast->expression_list->next->next->next->value->firstToken(), _messages += Document::DiagnosticMessage(
// "The type will only be available in Qt Creator's QML editors when the type name is a string literal"); 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; return false;
} }
...@@ -187,6 +198,19 @@ protected: ...@@ -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 // second and third argument must be integer literals
const NumericLiteral *majorLit = 0; const NumericLiteral *majorLit = 0;
...@@ -199,17 +223,11 @@ protected: ...@@ -199,17 +223,11 @@ protected:
// build the descriptor // build the descriptor
ExportedQmlType exportedType; ExportedQmlType exportedType;
exportedType.typeName = QString::fromUtf8(nameLit->chars(), nameLit->size()); 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( exportedType.version = LanguageUtils::ComponentVersion(
QString::fromUtf8(majorLit->chars(), majorLit->size()).toInt(), QString::fromUtf8(majorLit->chars(), majorLit->size()).toInt(),
QString::fromUtf8(minorLit->chars(), minorLit->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 // we want to do lookup later, so also store the surrounding scope
...@@ -498,12 +516,17 @@ FindExportedCppTypes::FindExportedCppTypes(const CPlusPlus::Snapshot &snapshot) ...@@ -498,12 +516,17 @@ FindExportedCppTypes::FindExportedCppTypes(const CPlusPlus::Snapshot &snapshot)
QList<LanguageUtils::FakeMetaObject::ConstPtr> FindExportedCppTypes::operator()(const CPlusPlus::Document::Ptr &document) QList<LanguageUtils::FakeMetaObject::ConstPtr> FindExportedCppTypes::operator()(const CPlusPlus::Document::Ptr &document)
{ {
QList<LanguageUtils::FakeMetaObject::ConstPtr> noResults; QList<LanguageUtils::FakeMetaObject::ConstPtr> 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() if (document->source().isEmpty()
|| !document->translationUnit()->ast()) || !document->translationUnit()->ast())
return noResults; return noResults;
FindExportsVisitor finder(document); FindExportsVisitor finder(document);
QList<ExportedQmlType> exports = finder(); QList<ExportedQmlType> exports = finder();
CppModelManagerInterface::instance()->setExtraDiagnostics(
document->fileName(), CppModelManagerInterface::ExportedQmlTypesDiagnostic,
finder.messages());
if (exports.isEmpty()) if (exports.isEmpty())
return noResults; return noResults;
......
...@@ -36,12 +36,17 @@ ...@@ -36,12 +36,17 @@
#include <cplusplus/CppDocument.h> #include <cplusplus/CppDocument.h>
#include <languageutils/fakemetaobject.h> #include <languageutils/fakemetaobject.h>
#include <QtCore/QCoreApplication>
namespace QmlJSTools { namespace QmlJSTools {
class FindExportedCppTypes class FindExportedCppTypes
{ {
Q_DECLARE_TR_FUNCTIONS(FindExportedCppTypes)
public: public:
FindExportedCppTypes(const CPlusPlus::Snapshot &snapshot); FindExportedCppTypes(const CPlusPlus::Snapshot &snapshot);
// document must have a valid source and ast for the duration of the call
QList<LanguageUtils::FakeMetaObject::ConstPtr> operator()(const CPlusPlus::Document::Ptr &document); QList<LanguageUtils::FakeMetaObject::ConstPtr> operator()(const CPlusPlus::Document::Ptr &document);
static bool maybeExportsTypes(const CPlusPlus::Document::Ptr &document); static bool maybeExportsTypes(const CPlusPlus::Document::Ptr &document);
......
...@@ -698,10 +698,17 @@ void ModelManager::loadPluginTypes(const QString &libraryPath, const QString &im ...@@ -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 // is called *inside a c++ parsing thread*, to allow hanging on to source and ast
void ModelManager::maybeQueueCppQmlTypeUpdate(const CPlusPlus::Document::Ptr &doc) 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 // keep source and AST alive if we want to scan for register calls
const bool scan = FindExportedCppTypes::maybeExportsTypes(doc); const bool scan = FindExportedCppTypes::maybeExportsTypes(doc);
if (scan) if (!scan)
doc->keepSourceAndAST(); doc->releaseSourceAndAST();
// delegate actual queuing to the gui thread // delegate actual queuing to the gui thread
QMetaObject::invokeMethod(this, "queueCppQmlTypeUpdate", QMetaObject::invokeMethod(this, "queueCppQmlTypeUpdate",
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment