void DeclarationBuilder::visitAliasStatement(Ast *node) { Ast *right = new Ast(node->tree->r, node->context); QualifiedIdentifier id = QualifiedIdentifier(QString(right->tree->name)); const RangeInRevision &range = editorFindRange(right, right); DeclarationPointer decl = getDeclaration(id, range, DUContextPointer(currentContext())); if (is_global_var(node->tree->l) && is_global_var(right->tree)) { DUChainWriteLocker wlock; // If the global variable on the right is not declared, declare it as nil if (!decl) { AbstractType::Ptr type = topContext()->findDeclarations(QualifiedIdentifier("NilClass")).first()->abstractType(); VariableDeclaration *vDecl = openDefinition<VariableDeclaration>(id, range); vDecl->setVariableKind(right->tree); vDecl->setKind(Declaration::Instance); vDecl->setType(type); eventuallyAssignInternalContext(); DeclarationBuilderBase::closeDeclaration(); decl = vDecl; } node->tree = node->tree->l; QualifiedIdentifier aid = getIdentifier(node); AbstractType::Ptr type = decl->abstractType(); declareVariable(aid, type, node); } else if (decl && decl->isFunctionDeclaration()) { DUChainWriteLocker wlock; MethodDeclaration *md = dynamic_cast<MethodDeclaration *>(decl.data()); node->tree = node->tree->l; const RangeInRevision & arange = editorFindRange(node, node); QualifiedIdentifier aid = getIdentifier(node); aliasMethodDeclaration(aid, arange, md); } else appendProblem(node->tree, i18n("undefined method `%1'", id.toString())); }
void DeclarationBuilder::visitMethodCall(Ast *node) { Node *aux = node->tree; /* * Handle chained method calls. Take a look at the implementation of * AstVisitor::visitMethodCall() for more details. */ node->tree = aux->l; if (node->tree->kind == token_method_call) visitMethodCall(node); node->tree = aux; ExpressionVisitor v(currentContext(), m_editor); v.visitNode(node); DeclarationPointer lastMethod = v.lastDeclaration(); /* Let's take a look at the method arguments */ visitMethodCallArgs(node, lastMethod); /* And last but not least, go for the block */ node->tree = aux->cond; m_lastMethodCall = lastMethod.data(); visitBlock(node); m_lastMethodCall = nullptr; node->tree = aux; }
void UseBuilder::visitTraitAliasStatement(TraitAliasStatementAst *node) { if (node->conflictIdentifierSequence) { const KDevPG::ListNode< NamespacedIdentifierAst* >* it = node->conflictIdentifierSequence->front(); forever { buildNamespaceUses(it->element, ClassDeclarationType); if ( it->hasNext() ) { it = it->next; } else { break; } } } DUChainWriteLocker lock; DeclarationPointer dec = findDeclarationImport(ClassDeclarationType, identifierForNamespace(node->importIdentifier->identifier, m_editor)); if (dec) { QualifiedIdentifier original = identifierPairForNode(node->importIdentifier->methodIdentifier).second; QList <Declaration*> list = dec.data()->internalContext()->findLocalDeclarations(original.last(), dec.data()->internalContext()->range().start); if (!list.isEmpty()) { UseBuilderBase::newUse(node->importIdentifier->methodIdentifier, DeclarationPointer(list.first())); } } lock.unlock(); visitTraitAliasIdentifier(node->importIdentifier); }
void UseBuilder::newCheckedUse(AstNode* node, const DeclarationPointer& declaration, bool reportNotFound) { if ( declaration && declaration->comment().contains("@deprecated") ) { reportError(i18n("Usage of %1 is deprecated.", declaration->toString()), node, IProblem::Hint); } else if ( !declaration && reportNotFound ) { reportError(i18n("Declaration not found: %1", m_editor->parseSession()->symbol(node)), node, IProblem::Hint); } UseBuilderBase::newUse(node, declaration); }
NavigationContextPointer AbstractNavigationContext::registerChild(DeclarationPointer declaration) { //We create a navigation-widget here, and steal its context.. evil ;) QWidget* navigationWidget = declaration->context()->createNavigationWidget(declaration.data()); NavigationContextPointer ret; AbstractNavigationWidget* abstractNavigationWidget = dynamic_cast<AbstractNavigationWidget*>(navigationWidget); if(abstractNavigationWidget) ret = abstractNavigationWidget->context(); delete navigationWidget; ret->setPreviousContext(this); m_children << ret; return ret; }
void DynamicLanguageExpressionVisitor::encounterLvalue(DeclarationPointer lvalueDeclaration) { m_lastDeclaration = lvalueDeclaration; if ( lvalueDeclaration ) { m_lastType = lvalueDeclaration->abstractType(); } }
AbstractDeclarationNavigationContext::AbstractDeclarationNavigationContext( DeclarationPointer decl, KDevelop::TopDUContextPointer topContext, AbstractNavigationContext* previousContext) : AbstractNavigationContext((topContext ? topContext : TopDUContextPointer(decl ? decl->topContext() : 0)), previousContext), m_declaration(decl), m_fullBackwardSearch(false) { //Jump from definition to declaration if possible FunctionDefinition* definition = dynamic_cast<FunctionDefinition*>(m_declaration.data()); if(definition && definition->declaration()) m_declaration = DeclarationPointer(definition->declaration()); }
void DeclarationBuilder::visitSingletonClass(Ast *node) { ExpressionVisitor ev(currentContext(), m_editor); Node *aux = node->tree; node->tree = node->tree->r; ev.visitNode(node); if (ev.lastType()) { DeclarationPointer d = ev.lastDeclaration(); if (d) { m_instance = false; if (!d->internalContext()) { StructureType::Ptr sType; UnsureType::Ptr ut = ev.lastType().cast<UnsureType>(); if (ut && ut->typesSize() > 0) { sType = ut->types()[0].type<StructureType>(); } else { sType = StructureType::Ptr::dynamicCast(ev.lastType()); } if (sType) { DUChainWriteLocker lock; d = sType->declaration(topContext()); m_instance = true; } else { d = DeclarationPointer(); } } if (d) { m_classDeclarations.push(d); m_injected = true; injectContext(d->internalContext()); } } } node->tree = aux; m_accessPolicy.push(Declaration::Public); AstVisitor::visitSingletonClass(node); m_accessPolicy.pop(); if (m_injected) { closeInjectedContext(); m_injected = false; m_classDeclarations.pop(); } }
void ExpressionVisitor::instantiateCurrentDeclaration() { StructureType::Ptr type = StructureType::Ptr(new StructureType); DeclarationPointer decl = lastDeclaration(); { DUChainReadLocker lock; auto funcType = QmlJS::FunctionType::Ptr::dynamicCast(decl->abstractType()); if (funcType) { decl = funcType->declaration(topContext()); } type->setDeclaration(decl.data()); } encounter(AbstractType::Ptr::staticCast(type), decl); }
QString AbstractNavigationContext::declarationKind(DeclarationPointer decl) { const AbstractFunctionDeclaration* function = dynamic_cast<const AbstractFunctionDeclaration*>(decl.data()); QString kind; if( decl->isTypeAlias() ) kind = i18n("Typedef"); else if( decl->kind() == Declaration::Type ) { if( decl->type<StructureType>() ) kind = i18n("Class"); } else if( decl->kind() == Declaration::Instance ) { kind = i18n("Variable"); } else if ( decl->kind() == Declaration::Namespace ) { kind = i18n("Namespace"); } if( NamespaceAliasDeclaration* alias = dynamic_cast<NamespaceAliasDeclaration*>(decl.data()) ) { if( alias->identifier().isEmpty() ) kind = i18n("Namespace import"); else kind = i18n("Namespace alias"); } if(function) kind = i18n("Function"); if( decl->isForwardDeclaration() ) kind = i18n("Forward Declaration"); return kind; }
DeclarationNavigationContext::DeclarationNavigationContext(DeclarationPointer decl, KDevelop::TopDUContextPointer topContext, AbstractNavigationContext* previousContext) : AbstractDeclarationNavigationContext(decl, topContext, previousContext) { kDebug() << "Generating declaration widget"; importedModuleDeclaration* import_decl = dynamic_cast<importedModuleDeclaration*>(decl.data()); if ( import_decl ) { kDebug() << " >> Module declaration found! Building documentation"; kDebug() << " >> Identifier: " << import_decl->m_moduleIdentifier; m_fullyQualifiedModuleIdentifier = import_decl->m_moduleIdentifier; } else { kDebug() << "Could not find declaration for this module!" << decl->identifier().identifier().str(); } }
DeclarationPointer getDeclarationOrSignal(const QualifiedIdentifier& id, const DUContext* context, bool searchInParent) { QString identifier = id.last().toString(); if (identifier.startsWith(QLatin1String("on")) && identifier.size() > 2) { // The use may have typed the name of a QML slot (onFoo), try to get // the declaration of its corresponding signal (foo) identifier = identifier.at(2).toLower() + identifier.mid(3); DeclarationPointer decl = getDeclaration(QualifiedIdentifier(identifier), context, searchInParent); if (decl) { ClassFunctionDeclaration* classFuncDecl = dynamic_cast<ClassFunctionDeclaration *>(decl.data()); if (classFuncDecl && classFuncDecl->isSignal()) { // Removing "on" has given the identifier of a QML signal, return // it instead of the name of its slot return decl; } } } // No signal found, fall back to normal behavior return getDeclaration(id, context, searchInParent); }
void TestDUChain::testReparse() { TestFile file("int main() { int i = 42; return i; }", "cpp"); file.parse(TopDUContext::AllDeclarationsContextsAndUses); DeclarationPointer mainDecl; DeclarationPointer iDecl; for (int i = 0; i < 3; ++i) { QVERIFY(file.waitForParsed(500)); DUChainReadLocker lock; QVERIFY(file.topContext()); QCOMPARE(file.topContext()->childContexts().size(), 1); QCOMPARE(file.topContext()->localDeclarations().size(), 1); DUContext *exprContext = file.topContext()->childContexts().first()->childContexts().first(); QCOMPARE(exprContext->localDeclarations().size(), 1); if (i) { QVERIFY(mainDecl); QCOMPARE(mainDecl.data(), file.topContext()->localDeclarations().first()); QVERIFY(iDecl); QCOMPARE(iDecl.data(), exprContext->localDeclarations().first()); } mainDecl = file.topContext()->localDeclarations().first(); iDecl = exprContext->localDeclarations().first(); QVERIFY(mainDecl->uses().isEmpty()); QCOMPARE(iDecl->uses().size(), 1); QCOMPARE(iDecl->uses().begin()->size(), 1); if (i == 1) { file.setFileContents("int main()\n{\nfloat i = 13; return i - 5;\n}\n"); } file.parse(TopDUContext::Features(TopDUContext::AllDeclarationsContextsAndUses | TopDUContext::ForceUpdateRecursive)); } }
void AbstractNavigationContext::makeLink( const QString& name, DeclarationPointer declaration, NavigationAction::Type actionType ) { NavigationAction action( declaration, actionType ); QString targetId = QString::number((quint64)declaration.data() * actionType); makeLink(name, targetId, action); }
void DeclarationBuilder::visitClassStatement(Ast *node) { ModuleDeclaration *baseClass = nullptr; RangeInRevision range = getNameRange(node); const QByteArray comment = getComment(node); QualifiedIdentifier id = getIdentifier(node); DUContext *ctx = getContainedNameContext(node); /* First of all, open the declaration. */ ModuleDeclaration *decl = reopenDeclaration<ModuleDeclaration>(id, range, ctx, DeclarationKind::Class); if (!decl) { node->foundProblems = true; return; } // Initialize the declaration. DUChainWriteLocker lock; if (!comment.isEmpty()) { decl->setComment(comment); } decl->setIsModule(false); decl->clearBaseClass(); decl->clearModuleMixins(); decl->setKind(KDevelop::Declaration::Type); m_accessPolicy.push(Declaration::Public); m_classDeclarations.push(DeclarationPointer(decl)); /* * Now let's check for the base class. Ruby does not support multiple * inheritance, and the access is always public. */ Node *aux = node->tree; node->tree = node->tree->cond; if (node->tree) { ExpressionVisitor ev(ctx, m_editor); lock.unlock(); ev.visitNode(node); DeclarationPointer baseDecl = ev.lastDeclaration(); lock.lock(); if (baseDecl) { baseClass = dynamic_cast<ModuleDeclaration *>(baseDecl.data()); if (!baseClass || baseClass->isModule()) { appendProblem( node->tree, i18n("TypeError: wrong argument type (expected Class)") ); } else if (baseClass->internalContext()) { decl->setBaseClass(baseClass->indexedType()); } } } node->tree = aux; /* Setup types and go for the class body */ ClassType::Ptr type(new ClassType()); type->setDeclaration(decl); decl->setType(type); openType(type); openContextForClassDefinition(decl, node); if (baseClass && baseClass->internalContext()) { currentContext()->addImportedParentContext(baseClass->internalContext()); } decl->setInternalContext(currentContext()); lock.unlock(); DeclarationBuilderBase::visitClassStatement(node); lock.lock(); closeContext(); closeType(); closeDeclaration(); m_classDeclarations.pop(); m_accessPolicy.pop(); }
void DeclarationBuilder::visitMethodStatement(Ast *node) { RangeInRevision range = getNameRange(node); QualifiedIdentifier id = getIdentifier(node); const QByteArray comment = getComment(node); bool injectedContext = false; bool instance = true; Node *aux = node->tree; /* * Check if this is a singleton method. If it is so, we have to determine * what's the context to be injected in order to get everything straight. */ // TODO: this will change with the introduction of the eigen class. node->tree = aux->cond; if (valid_children(node->tree)) { node->tree = node->tree->l; ExpressionVisitor ev(currentContext(), m_editor); ev.visitNode(node); if (ev.lastType()) { DeclarationPointer d = ev.lastDeclaration(); if (d) { if (!d->internalContext()) { DUChainWriteLocker lock; StructureType::Ptr sType = StructureType::Ptr::dynamicCast(ev.lastType()); d = (sType) ? sType->declaration(topContext()) : nullptr; instance = true; } else instance = false; if (d) { injectedContext = true; injectContext(d->internalContext()); node->tree = aux->cond->r; id = getIdentifier(node); range = editorFindRange(node, node); } } } } node->tree = aux; // Re-open the declaration. bool isClassMethod = (m_injected) ? !m_instance : !instance; MethodDeclaration *decl = reopenDeclaration(id, range, isClassMethod); DUChainWriteLocker lock; if (!comment.isEmpty()) { decl->setComment(comment); } decl->clearYieldTypes(); decl->setClassMethod(isClassMethod); FunctionType::Ptr type = FunctionType::Ptr(new FunctionType()); if (currentContext()->type() == DUContext::Class) { decl->setAccessPolicy(currentAccessPolicy()); } openType(type); decl->setInSymbolTable(false); decl->setType(type); decl->clearDefaultParameters(); lock.unlock(); DeclarationBuilderBase::visitMethodStatement(node); lock.lock(); closeDeclaration(); closeType(); /* * In Ruby, a method returns the last expression if no return expression * has been fired. Thus, the type of the last expression has to be mixed * into the return type of this method. */ node->tree = aux->l; if (node->tree && node->tree->l) { node->tree = get_last_expr(node->tree->l); if (node->tree->kind != token_return) { lock.unlock(); ExpressionVisitor ev(node->context, m_editor); ev.visitNode(node); if (ev.lastType()) { type->setReturnType(mergeTypes(ev.lastType(), type->returnType())); } lock.lock(); } } node->tree = aux; if (!type->returnType()) { type->setReturnType(getBuiltinsType(QStringLiteral("NilClass"), currentContext())); } decl->setType(type); decl->setInSymbolTable(true); if (injectedContext) { closeInjectedContext(); } }