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:
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 &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:
void documentUpdated(CPlusPlus::Document::Ptr doc);
void sourceFilesRefreshed(const QStringList &files);
......
......@@ -1060,7 +1060,9 @@ void CppModelManager::onDocumentUpdated(Document::Ptr doc)
}
#else
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)
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<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
......@@ -34,6 +34,7 @@
#define CPPMODELMANAGER_H
#include "cpptools_global.h"
#include "cpptoolsconstants.h"
#include <cplusplus/ModelManagerInterface.h>
#ifndef ICHECK_BUILD
# include <projectexplorer/project.h>
......@@ -128,6 +129,12 @@ public:
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);
Q_SIGNALS:
......@@ -226,6 +233,9 @@ private:
CppFindReferences *m_findReferences;
bool m_indexerEnabled;
mutable QMutex protectExtraDiagnostics;
QHash<QString, QHash<int, QList<CPlusPlus::Document::DiagnosticMessage> > > m_extraDiagnostics;
};
#endif
......
......@@ -45,6 +45,7 @@
#include <cplusplus/CoreTypes.h>
#include <cplusplus/Symbols.h>
#include <cplusplus/SimpleLexer.h>
#include <cplusplus/ModelManagerInterface.h>
#include <utils/qtcassert.h>
#include <QtCore/QDebug>
......@@ -71,6 +72,7 @@ class FindExportsVisitor : protected ASTVisitor
ASTMatcher _matcher;
ASTPatternBuilder _builder;
Overview _overview;
QList<Document::DiagnosticMessage> _messages;
public:
FindExportsVisitor(CPlusPlus::Document::Ptr doc)
......@@ -86,6 +88,11 @@ public:
return _exportedTypes;
}
QList<Document::DiagnosticMessage> 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;
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<LanguageUtils::FakeMetaObject::ConstPtr> FindExportedCppTypes::operator()(const CPlusPlus::Document::Ptr &document)
{
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()
|| !document->translationUnit()->ast())
return noResults;
FindExportsVisitor finder(document);
QList<ExportedQmlType> exports = finder();
CppModelManagerInterface::instance()->setExtraDiagnostics(
document->fileName(), CppModelManagerInterface::ExportedQmlTypesDiagnostic,
finder.messages());
if (exports.isEmpty())
return noResults;
......
......@@ -36,12 +36,17 @@
#include <cplusplus/CppDocument.h>
#include <languageutils/fakemetaobject.h>
#include <QtCore/QCoreApplication>
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<LanguageUtils::FakeMetaObject::ConstPtr> operator()(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
// 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",
......
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