diff options
author | Christian Kamm <christian.d.kamm@nokia.com> | 2011-08-23 12:02:29 +0200 |
---|---|---|
committer | Christian Kamm <christian.d.kamm@nokia.com> | 2011-08-24 12:13:41 +0200 |
commit | 27d08306986c72aeab1b1f06e96e7072c53d3622 (patch) | |
tree | 95cb41bb69e8242b637ec3807ce493b1e4723518 /src/libs/cplusplus | |
parent | c105ae47c1eb38ee24d919f2fee151c05ec852e0 (diff) | |
download | qt-creator-27d08306986c72aeab1b1f06e96e7072c53d3622.tar.gz |
QmlJS: Move the exported-C++-type detection out of C++ code.
It now lives in qmljstools/qmljsfindexportedcpptypes, all in one place.
Also ensures that the source code is available when a file is being
scanned for QML exports. This will enable checking comments for
annotations about the URI a plugin is usually imported as.
Change-Id: I1da36d0678e0a8d34b171dbe0f6b5690d89eb18b
Reviewed-on: http://codereview.qt.nokia.com/3392
Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
Diffstat (limited to 'src/libs/cplusplus')
-rw-r--r-- | src/libs/cplusplus/CppDocument.cpp | 259 | ||||
-rw-r--r-- | src/libs/cplusplus/CppDocument.h | 23 | ||||
-rw-r--r-- | src/libs/cplusplus/ModelManagerInterface.h | 2 |
3 files changed, 19 insertions, 265 deletions
diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp index a72648b8ba..169ec2b694 100644 --- a/src/libs/cplusplus/CppDocument.cpp +++ b/src/libs/cplusplus/CppDocument.cpp @@ -256,7 +256,8 @@ Document::Document(const QString &fileName) : _fileName(QDir::cleanPath(fileName)), _globalNamespace(0), _revision(0), - _editorRevision(0) + _editorRevision(0), + _fastCheck(false) { _control = new Control(); @@ -574,8 +575,10 @@ void Document::check(CheckMode mode) _globalNamespace = _control->newNamespace(0); Bind semantic(_translationUnit); - if (mode == FastCheck) + if (mode == FastCheck) { + _fastCheck = true; semantic.setSkipFunctionBodies(true); + } if (! _translationUnit->ast()) return; // nothing to do. @@ -589,253 +592,19 @@ void Document::check(CheckMode mode) } } -class FindExposedQmlTypes : protected ASTVisitor +void Document::keepSourceAndAST() { - Document *_doc; - QList<Document::ExportedQmlType> _exportedTypes; - CompoundStatementAST *_compound; - ASTMatcher _matcher; - ASTPatternBuilder _builder; - Overview _overview; - -public: - FindExposedQmlTypes(Document *doc) - : ASTVisitor(doc->translationUnit()) - , _doc(doc) - , _compound(0) - {} - - QList<Document::ExportedQmlType> operator()() - { - _exportedTypes.clear(); - accept(translationUnit()->ast()); - return _exportedTypes; - } - -protected: - virtual bool visit(CompoundStatementAST *ast) - { - CompoundStatementAST *old = _compound; - _compound = ast; - accept(ast->statement_list); - _compound = old; - return false; - } - - virtual bool visit(CallAST *ast) - { - IdExpressionAST *idExp = ast->base_expression->asIdExpression(); - if (!idExp || !idExp->name) - return false; - TemplateIdAST *templateId = idExp->name->asTemplateId(); - if (!templateId || !templateId->identifier_token) - return false; - - // check the name - const Identifier *templateIdentifier = translationUnit()->identifier(templateId->identifier_token); - if (!templateIdentifier) - return false; - const QString callName = QString::fromUtf8(templateIdentifier->chars()); - if (callName != QLatin1String("qmlRegisterType")) - return false; - - // must have a single typeid template argument - if (!templateId->template_argument_list || !templateId->template_argument_list->value - || templateId->template_argument_list->next) - return false; - TypeIdAST *typeId = templateId->template_argument_list->value->asTypeId(); - if (!typeId) - return false; - - // must have four arguments - if (!ast->expression_list - || !ast->expression_list->value || !ast->expression_list->next - || !ast->expression_list->next->value || !ast->expression_list->next->next - || !ast->expression_list->next->next->value || !ast->expression_list->next->next->next - || !ast->expression_list->next->next->next->value - || ast->expression_list->next->next->next->next) - return false; - - // last argument must be a string literal - const StringLiteral *nameLit = 0; - 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"); - return false; - } - - // if the first argument is a string literal, things are easy - QString packageName; - if (StringLiteralAST *packageAst = ast->expression_list->value->asStringLiteral()) { - const StringLiteral *packageLit = translationUnit()->stringLiteral(packageAst->literal_token); - packageName = QString::fromUtf8(packageLit->chars(), packageLit->size()); - } - // as a special case, allow an identifier package argument if there's a - // Q_ASSERT(QLatin1String(uri) == QLatin1String("actual uri")); - // in the enclosing compound statement - IdExpressionAST *uriName = ast->expression_list->value->asIdExpression(); - if (packageName.isEmpty() && uriName && _compound) { - for (StatementListAST *it = _compound->statement_list; it; it = it->next) { - StatementAST *stmt = it->value; - - packageName = nameOfUriAssert(stmt, uriName); - if (!packageName.isEmpty()) - break; - } - } - - // second and third argument must be integer literals - const NumericLiteral *majorLit = 0; - const NumericLiteral *minorLit = 0; - if (NumericLiteralAST *majorAst = ast->expression_list->next->value->asNumericLiteral()) - majorLit = translationUnit()->numericLiteral(majorAst->literal_token); - if (NumericLiteralAST *minorAst = ast->expression_list->next->next->value->asNumericLiteral()) - minorLit = translationUnit()->numericLiteral(minorAst->literal_token); - - // build the descriptor - Document::ExportedQmlType exportedType; - exportedType.typeName = QString::fromUtf8(nameLit->chars(), nameLit->size()); - if (!packageName.isEmpty() && majorLit && minorLit && majorLit->isInt() && minorLit->isInt()) { - exportedType.packageName = packageName; - exportedType.majorVersion = QString::fromUtf8(majorLit->chars(), majorLit->size()).toInt(); - exportedType.minorVersion = 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 = QLatin1String("<default>"); - } - - // we want to do lookup later, so also store the surrounding scope - unsigned line, column; - translationUnit()->getTokenStartPosition(ast->firstToken(), &line, &column); - exportedType.scope = _doc->scopeAt(line, column); - - // and the expression - const Token begin = translationUnit()->tokenAt(typeId->firstToken()); - const Token last = translationUnit()->tokenAt(typeId->lastToken() - 1); - exportedType.typeExpression = _doc->source().mid(begin.begin(), last.end() - begin.begin()); - - _exportedTypes += exportedType; - - return false; - } - -private: - QString stringOf(AST *ast) - { - const Token begin = translationUnit()->tokenAt(ast->firstToken()); - const Token last = translationUnit()->tokenAt(ast->lastToken() - 1); - return _doc->source().mid(begin.begin(), last.end() - begin.begin()); - } - - ExpressionAST *skipStringCall(ExpressionAST *exp) - { - if (!exp) - return 0; - - IdExpressionAST *callName = _builder.IdExpression(); - CallAST *call = _builder.Call(callName); - if (!exp->match(call, &_matcher)) - return exp; - - const QString name = stringOf(callName); - if (name != QLatin1String("QLatin1String") - && name != QLatin1String("QString")) - return exp; - - if (!call->expression_list || call->expression_list->next) - return exp; - - return call->expression_list->value; - } - - QString nameOfUriAssert(StatementAST *stmt, IdExpressionAST *uriName) - { - QString null; - - IdExpressionAST *outerCallName = _builder.IdExpression(); - BinaryExpressionAST *binary = _builder.BinaryExpression(); - // assert(... == ...); - ExpressionStatementAST *pattern = _builder.ExpressionStatement( - _builder.Call(outerCallName, _builder.ExpressionList( - binary))); - - if (!stmt->match(pattern, &_matcher)) { - outerCallName = _builder.IdExpression(); - binary = _builder.BinaryExpression(); - // the expansion of Q_ASSERT(...), - // ((!(... == ...)) ? qt_assert(...) : ...); - pattern = _builder.ExpressionStatement( - _builder.NestedExpression( - _builder.ConditionalExpression( - _builder.NestedExpression( - _builder.UnaryExpression( - _builder.NestedExpression( - binary))), - _builder.Call(outerCallName)))); - - if (!stmt->match(pattern, &_matcher)) - return null; - } - - const QString outerCall = stringOf(outerCallName); - if (outerCall != QLatin1String("qt_assert") - && outerCall != QLatin1String("assert") - && outerCall != QLatin1String("Q_ASSERT")) - return null; - - if (translationUnit()->tokenAt(binary->binary_op_token).kind() != T_EQUAL_EQUAL) - return null; - - ExpressionAST *lhsExp = skipStringCall(binary->left_expression); - ExpressionAST *rhsExp = skipStringCall(binary->right_expression); - if (!lhsExp || !rhsExp) - return null; - - StringLiteralAST *uriString = lhsExp->asStringLiteral(); - IdExpressionAST *uriArgName = lhsExp->asIdExpression(); - if (!uriString) - uriString = rhsExp->asStringLiteral(); - if (!uriArgName) - uriArgName = rhsExp->asIdExpression(); - if (!uriString || !uriArgName) - return null; - - if (stringOf(uriArgName) != stringOf(uriName)) - return null; - - const StringLiteral *packageLit = translationUnit()->stringLiteral(uriString->literal_token); - return QString::fromUtf8(packageLit->chars(), packageLit->size()); - } -}; - -void Document::findExposedQmlTypes() -{ - if (! _translationUnit->ast()) - return; - - QByteArray qmlRegisterTypeToken("qmlRegisterType"); - if (_translationUnit->control()->findIdentifier( - qmlRegisterTypeToken.constData(), qmlRegisterTypeToken.size())) { - FindExposedQmlTypes finder(this); - _exportedQmlTypes = finder(); - } -} - -void Document::releaseSource() -{ - _source.clear(); + _keepSourceAndASTCount.ref(); } -void Document::releaseTranslationUnit() +void Document::releaseSourceAndAST() { - _translationUnit->release(); + if (!_keepSourceAndASTCount.deref()) { + _source.clear(); + _translationUnit->release(); + if (_fastCheck) + _control->squeeze(); + } } Snapshot::Snapshot() diff --git a/src/libs/cplusplus/CppDocument.h b/src/libs/cplusplus/CppDocument.h index 48d72cad3c..024fec93fb 100644 --- a/src/libs/cplusplus/CppDocument.h +++ b/src/libs/cplusplus/CppDocument.h @@ -40,6 +40,7 @@ #include <QtCore/QDateTime> #include <QtCore/QHash> #include <QtCore/QFileInfo> +#include <QtCore/QAtomicInt> namespace CPlusPlus { @@ -125,11 +126,6 @@ public: void check(CheckMode mode = FullCheck); - void findExposedQmlTypes(); - - void releaseSource(); - void releaseTranslationUnit(); - static Ptr create(const QString &fileName); class DiagnosticMessage @@ -320,18 +316,8 @@ public: const MacroUse *findMacroUseAt(unsigned offset) const; const UndefinedMacroUse *findUndefinedMacroUseAt(unsigned offset) const; - class ExportedQmlType { - public: - QString packageName; - QString typeName; - int majorVersion; - int minorVersion; - Scope *scope; - QString typeExpression; - }; - - QList<ExportedQmlType> exportedQmlTypes() const - { return _exportedQmlTypes; } + void keepSourceAndAST(); + void releaseSourceAndAST(); private: QString _fileName; @@ -344,11 +330,12 @@ private: QList<Block> _skippedBlocks; QList<MacroUse> _macroUses; QList<UndefinedMacroUse> _undefinedMacroUses; - QList<ExportedQmlType> _exportedQmlTypes; QByteArray _source; QDateTime _lastModified; + QAtomicInt _keepSourceAndASTCount; unsigned _revision; unsigned _editorRevision; + bool _fastCheck; friend class Snapshot; }; diff --git a/src/libs/cplusplus/ModelManagerInterface.h b/src/libs/cplusplus/ModelManagerInterface.h index 0a9cf6eaee..75d084053a 100644 --- a/src/libs/cplusplus/ModelManagerInterface.h +++ b/src/libs/cplusplus/ModelManagerInterface.h @@ -140,8 +140,6 @@ public: virtual void findMacroUsages(const CPlusPlus::Macro ¯o) = 0; - virtual QList<LanguageUtils::FakeMetaObject::ConstPtr> exportedQmlObjects(const CPlusPlus::Document::Ptr &doc) const = 0; - Q_SIGNALS: void documentUpdated(CPlusPlus::Document::Ptr doc); void sourceFilesRefreshed(const QStringList &files); |