summaryrefslogtreecommitdiff
path: root/src/libs/cplusplus
diff options
context:
space:
mode:
authorChristian Kamm <christian.d.kamm@nokia.com>2011-08-23 12:02:29 +0200
committerChristian Kamm <christian.d.kamm@nokia.com>2011-08-24 12:13:41 +0200
commit27d08306986c72aeab1b1f06e96e7072c53d3622 (patch)
tree95cb41bb69e8242b637ec3807ce493b1e4723518 /src/libs/cplusplus
parentc105ae47c1eb38ee24d919f2fee151c05ec852e0 (diff)
downloadqt-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.cpp259
-rw-r--r--src/libs/cplusplus/CppDocument.h23
-rw-r--r--src/libs/cplusplus/ModelManagerInterface.h2
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 &macro) = 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);