forked from qt-creator/qt-creator
C++/QmlJS: Warnings if C++ based QML type detection fails.
Change-Id: I1e206e09c4068cc541978ee148f9ed8c4138c249 Reviewed-on: http://codereview.qt.nokia.com/3579 Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
This commit is contained in:
@@ -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:
|
|||||||
|
|
||||||
virtual void findMacroUsages(const CPlusPlus::Macro ¯o) = 0;
|
virtual void findMacroUsages(const CPlusPlus::Macro ¯o) = 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)
|
|||||||
}
|
}
|
||||||
#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)
|
|||||||
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 @@
|
|||||||
#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:
|
|||||||
|
|
||||||
virtual void findMacroUsages(const CPlusPlus::Macro ¯o);
|
virtual void findMacroUsages(const CPlusPlus::Macro ¯o);
|
||||||
|
|
||||||
|
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:
|
|||||||
|
|
||||||
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 @@
|
|||||||
#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
|
|||||||
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:
|
|||||||
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:
|
|||||||
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:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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:
|
|||||||
// 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)
|
|||||||
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 @@
|
|||||||
#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
|
|||||||
// 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",
|
||||||
|
|||||||
Reference in New Issue
Block a user