Commit 61ec6a08 authored by Denis Steckelmacher's avatar Denis Steckelmacher

Don't put the declarations of a module in a namespace, but store them directly in the top context

A stack of booleans allows endVisit(UiObjectDefinition) to know if a declaration
has to be closed. Module {} declarations are now skipped (but their content is explored),
and all the import logic is greatly simplified (no need for namespace aliases).

This is mostly a cleanup commit: namespaces didn't add anything useful and
were very complex to handle.
parent d764f013
......@@ -79,13 +79,17 @@ QList<CompletionTreeItemPointer> CodeCompletionContext::completionItems(bool& ab
bool inQmlObjectScope = (m_duContext->type() == DUContext::Class && containsOnlySpaces(m_text));
if (inQmlObjectScope) {
DUChainReadLocker lock;
// The cursor is in a QML object and there is nothing before it. Display
// a list of properties and signals that can be used in a script binding.
// Note that the properties/signals of parent QML objects are not displayed here
items << completionsInContext(m_duContext,
CompletionOnlyLocal | CompletionHideWrappers,
CompletionItem::Colon);
items << globalCompletions(CompletionHideWrappers);
items << completionsInContext(DUContextPointer(m_duContext->topContext()),
CompletionHideWrappers,
CompletionItem::NoDecoration);
} else {
items << completionsInContext(m_duContext,
0,
......@@ -132,37 +136,6 @@ QList<CompletionTreeItemPointer> CodeCompletionContext::completionsInContext(con
return items;
}
QList<CompletionTreeItemPointer> CodeCompletionContext::globalCompletions(CompletionInContextFlags flags)
{
QList<CompletionTreeItemPointer> items;
// Iterate over all the imported namespaces and add their definitions
DUChainReadLocker lock;
QList<Declaration*> imports = m_duContext->findDeclarations(globalImportIdentifier());
QList<Declaration*> realImports;
foreach (Declaration* import, imports) {
if (import->kind() != Declaration::NamespaceAlias) {
continue;
}
NamespaceAliasDeclaration* decl = static_cast<NamespaceAliasDeclaration *>(import);
realImports << m_duContext->findDeclarations(decl->importIdentifier());
}
lock.unlock();
foreach (Declaration* import, realImports) {
items << completionsInContext(
DUContextPointer(import->internalContext()),
flags,
CompletionItem::NoDecoration
);
}
return items;
}
QList<CompletionTreeItemPointer> CodeCompletionContext::fieldCompletions(const QString& expression,
CompletionItem::Decoration decoration)
{
......
......@@ -48,7 +48,6 @@ private:
QList<KDevelop::CompletionTreeItemPointer> completionsInContext(const KDevelop::DUContextPointer& context,
CompletionInContextFlags flags,
CompletionItem::Decoration decoration);
QList<KDevelop::CompletionTreeItemPointer> globalCompletions(CompletionInContextFlags flags = 0);
QList<KDevelop::CompletionTreeItemPointer> fieldCompletions(const QString &expression,
CompletionItem::Decoration decoration);
......
......@@ -109,6 +109,13 @@ void DeclarationBuilder::startVisiting(QmlJS::AST::Node* node)
}
}
// Remove all the imported parent contexts: imports may have been edited
// and there musn't be any leftover parent context
{
DUChainWriteLocker lock;
currentContext()->topContext()->clearImportedParentContexts();
}
DeclarationBuilderBase::startVisiting(node);
}
......@@ -502,24 +509,6 @@ void DeclarationBuilder::endVisit(QmlJS::AST::ObjectLiteral* node)
/*
* plugin.qmltypes files
*/
QualifiedIdentifier DeclarationBuilder::declareModule(const RangeInRevision& range)
{
// Declare a namespace whose name is the base name of the current file
QualifiedIdentifier name(m_session->urlBaseName());
StructureType::Ptr type(new StructureType);
{
DUChainWriteLocker lock;
Declaration* decl = openDefinition<Declaration>(name, range);
decl->setKind(Declaration::Namespace);
type->setDeclaration(decl);
}
openType(type);
return name;
}
void DeclarationBuilder::declareComponent(QmlJS::AST::UiObjectInitializer* node,
const RangeInRevision &range,
const QualifiedIdentifier &name)
......@@ -651,10 +640,6 @@ void DeclarationBuilder::declareComponentSubclass(QmlJS::AST::UiObjectInitialize
declareEnum(range, name);
contextType = DUContext::Enum;
name = QualifiedIdentifier(); // Enum contexts should have no name so that their members have the correct scope
} else if (baseclass == QLatin1String("Module")) {
// QML Module, that declares a namespace
name = declareModule(range);
contextType = DUContext::Namespace;
} else {
// Define an anonymous subclass of the baseclass. This subclass will
// be instantiated when "id:" is encountered
......@@ -705,10 +690,7 @@ void DeclarationBuilder::declareComponentSubclass(QmlJS::AST::UiObjectInitialize
decl->setInternalContext(ctx);
}
if (contextType == DUContext::Namespace) {
// If we opened a namespace, ensure that its internal context is of namespace type
ctx->setLocalScopeIdentifier(decl->qualifiedIdentifier());
} else if (contextType == DUContext::Enum) {
if (contextType == DUContext::Enum) {
ctx->setPropagateDeclarations(true);
}
}
......@@ -820,48 +802,23 @@ bool DeclarationBuilder::visit(QmlJS::AST::UiImport* node)
ReferencedTopDUContext importedContext = m_session->contextOfModule(uri + "qml");
if (importedContext) {
{
DUChainWriteLocker lock;
currentContext()->addImportedParentContext(
importedContext,
m_session->locationToRange(node->importToken).start
);
}
// Create a namespace import statement
StructureType::Ptr type(new StructureType);
QualifiedIdentifier importedNamespaceName(uri.left(uri.length() - 1)); // QtQuick.Controls. -> QtQuick.Controls
{
DUChainWriteLocker lock;
NamespaceAliasDeclaration* decl = openDefinition<NamespaceAliasDeclaration>(
QualifiedIdentifier(globalImportIdentifier()),
m_session->locationToRange(node->importIdToken)
);
decl->setImportIdentifier(importedNamespaceName);
}
openType(type);
DUChainWriteLocker lock;
currentContext()->addImportedParentContext(
importedContext,
m_session->locationToRange(node->importToken).start
);
}
return DeclarationBuilderBase::visit(node);
}
void DeclarationBuilder::endVisit(QmlJS::AST::UiImport* node)
{
if (currentDeclaration<NamespaceAliasDeclaration>()) {
closeAndAssignType();
}
return DeclarationBuilderBase::endVisit(node);
}
bool DeclarationBuilder::visit(QmlJS::AST::UiObjectDefinition* node)
{
setComment(node);
// Do not crash if the user has typed an empty object definition
if (!node->initializer || !node->initializer->members) {
m_skipEndVisit.push(true);
return DeclarationBuilderBase::visit(node);
}
......@@ -869,8 +826,17 @@ bool DeclarationBuilder::visit(QmlJS::AST::UiObjectDefinition* node)
RangeInRevision range(m_session->locationToRange(node->qualifiedTypeNameId->identifierToken));
QString baseclass = node->qualifiedTypeNameId->name.toString();
if (baseclass == QLatin1String("Module")) {
// Don't build any declaration or context for Modules, but explore them.
// This way, their declarations are in the global scope, ready to be
// imported by other files.
m_skipEndVisit.push(true);
return true; // Don't declare anything for the module, but explore it
}
declareComponentSubclass(node->initializer, range, baseclass);
m_skipEndVisit.push(false);
return DeclarationBuilderBase::visit(node);
}
......@@ -879,7 +845,7 @@ void DeclarationBuilder::endVisit(QmlJS::AST::UiObjectDefinition* node)
DeclarationBuilderBase::endVisit(node);
// Do not crash if the user has typed an empty object definition
if (node->initializer && node->initializer->members) {
if (!m_skipEndVisit.pop()) {
closeContext();
closeAndAssignType();
}
......
......@@ -81,7 +81,6 @@ protected:
virtual void endVisit(QmlJS::AST::ObjectLiteral* node);
// plugin.qmltypes
KDevelop::QualifiedIdentifier declareModule(const KDevelop::RangeInRevision &range);
void declareComponent(QmlJS::AST::UiObjectInitializer* node,
const KDevelop::RangeInRevision &range,
const KDevelop::QualifiedIdentifier &name);
......@@ -107,7 +106,6 @@ protected:
// UI
virtual bool visit(QmlJS::AST::UiImport* node);
virtual void endVisit(QmlJS::AST::UiImport* node);
virtual bool visit(QmlJS::AST::UiObjectDefinition* node);
virtual void endVisit(QmlJS::AST::UiObjectDefinition* node);
......@@ -133,6 +131,7 @@ private:
private:
bool m_prebuilding;
QStack<bool> m_skipEndVisit;
};
#endif // DECLARATIONBUILDER_H
/**
* "toString" : "plugins plugins",
* "kind" : "Namespace"
*/
Module {
/**
* "toString" : "interface QAbstractItemModel",
......@@ -19,12 +15,12 @@ Module {
]
/**
* "toString" : "plugins::QModelIndex rootItem"
* "toString" : "QModelIndex rootItem"
*/
Property { name: "rootItem"; type: "QModelIndex" }
/**
* "type" : { "toString" : "plugins::QAbstractItemModel::LayoutChangeHint" },
* "type" : { "toString" : "QAbstractItemModel::LayoutChangeHint" },
* "kind" : "Type",
* "internalContext" : { "type" : "Enum" }
*/
......@@ -40,20 +36,20 @@ Module {
}
}
/**
* "toString" : "void dataChanged (plugins::QModelIndex, plugins::QModelIndex, int)",
* "toString" : "void dataChanged (QModelIndex, QModelIndex, int)",
* "useCount" : 2
*/
Signal {
name: "dataChanged"
/**
* "toString" : "plugins::QModelIndex topLeft",
* "toString" : "QModelIndex topLeft",
* "useCount" : 1
*/
Parameter /* */ { name: "topLeft"; type: "QModelIndex" }
/**
* "toString" : "plugins::QModelIndex bottomRight"
* "toString" : "QModelIndex bottomRight"
*/
Parameter /* */ { name: "bottomRight"; type: "QModelIndex" }
......@@ -64,7 +60,7 @@ Module {
}
/**
* "toString" : "bool isItemValid (plugins::QModelIndex)"
* "toString" : "bool isItemValid (QModelIndex)"
*/
Method {
name: "isItemValid"
......
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