Ejemplo n.º 1
0
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()));
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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);
}
Ejemplo n.º 4
0
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());
}
Ejemplo n.º 8
0
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();
    }
}
Ejemplo n.º 9
0
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();
    }
}
Ejemplo n.º 12
0
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);
}
Ejemplo n.º 13
0
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);
}
Ejemplo n.º 15
0
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();
}
Ejemplo n.º 16
0
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();
    }
}