Example #1
0
T * DeclarationBuilder::reopenDeclaration(const QualifiedIdentifier &id,
                                          const RangeInRevision &range,
                                          DUContext *context,
                                          DeclarationKind kind)
{
    Declaration *res = nullptr;
    DUChainReadLocker rlock;
    QList<Declaration *> decls = context->findDeclarations(id);
    rlock.unlock();

    foreach (Declaration *d, decls) {
        Declaration *fitting = dynamic_cast<T*>(d);
        if (fitting) {
            const bool valid = validReDeclaration(d, id, range, kind);
            if (!valid)
                return nullptr;

            rDebug() << "Reopening the following declaration: " << d->toString();
            openDeclarationInternal(d);
            d->setRange(range);
            setEncountered(d);
            // TODO: register the re-opening
            res = d;
            break;
        } else
            rDebug() << "Do not reopen since it's not in the same top context";
    }
Example #2
0
void DeclarationBuilder::visitBlockVariables(Ast *node)
{
    DUChainReadLocker rlock;
    MethodDeclaration *last = dynamic_cast<MethodDeclaration *>(m_lastMethodCall);
    Node *n = node->tree;
    if (!n) {
        return;
    }

    uint max = 0, i = 0;
    const YieldType *yieldList = nullptr;
    if (last) {
        yieldList = last->yieldTypes();
        max = last->yieldTypesSize();
    }

    AbstractType::Ptr type;
    for (Node *aux = n; aux != nullptr; aux = aux->next, i++) {
        node->tree = aux;
        if (yieldList && i < max) {
            type = yieldList[i].type.abstractType();
        } else {
            type = getBuiltinsType(QStringLiteral("Object"), currentContext());
        }
        rlock.unlock();
        declareVariable(getIdentifier(node), type, node, DUContext::DontSearchInParent);
        rlock.lock();
    }
}
Example #3
0
void DeclarationBuilder::visitForStatement(Ast *node)
{
    Node *aux = node->tree;
    node->tree = node->tree->cond;

    ExpressionVisitor ev(currentContext(), m_editor);
    ev.visitNode(node);
    AbstractType::Ptr type = ev.lastType();

    DUChainReadLocker rlock;
    if (type) {
        ClassType::Ptr ctype = type.cast<ClassType>();
        if (ctype && ctype->contentType()) {
            type = ctype->contentType().abstractType();
        } else {
            type = getBuiltinsType(QStringLiteral("Object"), currentContext());
        }
    } else {
        type = getBuiltinsType(QStringLiteral("Object"), currentContext());
    }

    node->tree = aux->r;
    for (Node *n = node->tree; n != nullptr; n = n->next) {
        node->tree = n;
        QualifiedIdentifier id = getIdentifier(node);
        rlock.unlock();
        declareVariable(id, type, node);
        rlock.lock();
    }
    node->tree = aux;
}
bool DUChainItemData::execute( QString& /*filterText*/ )
{
  DUChainReadLocker lock;;
  Declaration* decl = m_item.m_item.data();
  if(!decl) {
    return false;
  }

  if(m_openDefinition && FunctionDefinition::definition(decl)) {
    decl = FunctionDefinition::definition(decl);
  }

  QUrl url = decl->url().toUrl();
  KTextEditor::Cursor cursor = decl->rangeInCurrentRevision().start();

  DUContext* internal = decl->internalContext();

  if(internal && (internal->type() == DUContext::Other || internal->type() == DUContext::Class)) {
    //Move into the body
    if(internal->range().end.line > internal->range().start.line) {
      cursor = KTextEditor::Cursor(internal->range().start.line+1, 0); //Move into the body
    }
  }

  lock.unlock();
  ICore::self()->documentController()->openDocument( url, cursor );
  return true;
}
Example #5
0
bool ParseJob::isUpdateRequired(const IndexedString& languageString)
{
    if (abortRequested()) {
        return false;
    }

    if (minimumFeatures() & TopDUContext::ForceUpdate) {
        return true;
    }

    DUChainReadLocker lock;
    if (abortRequested()) {
        return false;
    }
    foreach(const ParsingEnvironmentFilePointer &file, DUChain::self()->allEnvironmentFiles(document())) {
        if (file->language() != languageString) {
            continue;
        }
        if (!file->needsUpdate() && file->featuresSatisfied(minimumFeatures())) {
            kDebug() << "Already up to date" << document().str();
            setDuChain(file->topContext());
            lock.unlock();
            highlightDUChain();
            return false;
        }
        break;
    }
    return !abortRequested();
}
void TypeCorrection::executeSpecifyTypeAction()
{
    QAction* action = qobject_cast<QAction*>(sender());
    if ( ! action ) {
        qCWarning(KDEV_PYTHON_CODEGEN) << "slot not invoked by triggering a QAction, should not happen"; // :)
        return;
    }

    DUChainReadLocker lock;
    IndexedDeclaration decl = action->data().value<IndexedDeclaration>();
    if ( ! decl.isValid() ) {
        decl = Helper::declarationUnderCursor();
    }

    if ( ! decl.isValid() ) {
        qCWarning(KDEV_PYTHON_CODEGEN) << "No declaration found!";
        return;
    }

    CorrectionFileGenerator::HintType hintType;
    if ( decl.data()->isFunctionDeclaration() ) {
        hintType = CorrectionFileGenerator::FunctionReturnHint;
    }
    else if ( decl.data()->kind() == Declaration::Instance ) {
        hintType = CorrectionFileGenerator::LocalVariableHint;
    }
    else {
        qCWarning(KDEV_PYTHON_CODEGEN) << "Correction requested for something that's not a local variable or function.";
        return;
    }

    CorrectionAssistant *dialog = new CorrectionAssistant(decl, hintType);
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->setWindowTitle("Specify type for " + decl.data()->identifier().toString());
    connect(dialog, &QDialog::accepted, this, &TypeCorrection::accepted);

    m_ui->setupUi(dialog);
    connect(m_ui->buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
    connect(m_ui->buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject);
    if ( hintType == CorrectionFileGenerator::FunctionReturnHint ) {
        m_ui->kindLabel->setText(i18n("Function return type"));
    }
    else if ( hintType == CorrectionFileGenerator::LocalVariableHint ) {
        m_ui->kindLabel->setText(i18n("Local variable"));
    }

    m_ui->identifierLabel->setText(decl.data()->qualifiedIdentifier().toString());
    m_ui->typeText->setFocus();
    dialog->resize(560, 180);
    lock.unlock();

    dialog->show();
}
Example #7
0
void AdaptSignatureAction::execute()
{
    DUChainReadLocker lock;
    IndexedString url = m_otherSideTopContext->url();
    lock.unlock();
    m_otherSideTopContext = DUChain::self()->waitForUpdate(url, TopDUContext::AllDeclarationsContextsAndUses);
    if (!m_otherSideTopContext) {
        clangDebug() << "failed to update" << url.str();
        return;
    }

    lock.lock();

    Declaration* otherSide = m_otherSideId.getDeclaration(m_otherSideTopContext.data());
    if (!otherSide) {
        clangDebug() << "could not find definition";
        return;
    }
    DUContext* functionContext = DUChainUtils::getFunctionContext(otherSide);
    if (!functionContext) {
        clangDebug() << "no function context";
        return;
    }
    if (!functionContext || functionContext->type() != DUContext::Function) {
        clangDebug() << "no correct function context";
        return;
    }

    DocumentChangeSet changes;
    KTextEditor::Range parameterRange = ClangIntegration::DUChainUtils::functionSignatureRange(otherSide);
    QString newText = CodegenHelper::makeSignatureString(otherSide, m_newSignature, !m_editingDefinition);
    if (!m_editingDefinition) {
        // append a newline after the method signature in case the method definition follows
        newText += QLatin1Char('\n');
    }

    DocumentChange changeParameters(functionContext->url(), parameterRange, QString(), newText);
    changeParameters.m_ignoreOldText = true;
    changes.addChange(changeParameters);
    changes.setReplacementPolicy(DocumentChangeSet::WarnOnFailedChange);
    DocumentChangeSet::ChangeResult result = changes.applyAllChanges();
    if (!result) {
        KMessageBox::error(0, i18n("Failed to apply changes: %1", result.m_failureReason));
    }
    emit executed(this);

    foreach(RenameAction * renAct, m_renameActions) {
        renAct->execute();
    }
}
Example #8
0
void FunctionDeclarationCompletionItem::executed(KTextEditor::View* view, const KTextEditor::Range& word)
{
    qCDebug(KDEV_PYTHON_CODECOMPLETION) << "FunctionDeclarationCompletionItem executed";
    KTextEditor::Document* document = view->document();
    auto resolvedDecl = Helper::resolveAliasDeclaration(declaration().data());
    DUChainReadLocker lock;
    auto functionDecl = Helper::functionForCalled(resolvedDecl).declaration;
    lock.unlock();
    if ( ! functionDecl && (! resolvedDecl || ! resolvedDecl->abstractType()
                           || resolvedDecl->abstractType()->whichType() != AbstractType::TypeStructure) ) {
        qCritical(KDEV_PYTHON_CODECOMPLETION) << "ERROR: could not get declaration data, not executing completion item!";
        return;
    }
    QString suffix = "()";
    KTextEditor::Range checkPrefix(word.start().line(), 0, word.start().line(), word.start().column());
    KTextEditor::Range checkSuffix(word.end().line(), word.end().column(), word.end().line(), document->lineLength(word.end().line()));
    if ( m_doNotCall || document->text(checkSuffix).trimmed().startsWith('(')
         || document->text(checkPrefix).trimmed().endsWith('@')
         || (functionDecl && Helper::findDecoratorByName(functionDecl, QLatin1String("property"))) )
    {
        // don't insert brackets if they're already there,
        // the item is a decorator, or if it's an import item.
        suffix.clear();
    }
    // place cursor behind bracktes by default
    int skip = 2;
    if ( functionDecl ) {
        bool needsArguments = false;
        int argumentCount = functionDecl->type<FunctionType>()->arguments().length();
        if ( functionDecl->context()->type() == KDevelop::DUContext::Class ) {
            // it's a member function, so it has the implicit self
            // TODO static methods
            needsArguments = argumentCount > 1;
        }
        else {
            // it's a free function
            needsArguments = argumentCount > 0;
        }
        if ( needsArguments ) {
            // place cursor in brackets if there's parameters
            skip = 1;
        }
    }
    document->replaceText(word, declaration()->identifier().toString() + suffix);
    view->setCursorPosition( Cursor(word.end().line(), word.end().column() + skip) );
}
Example #9
0
QList< ReferencedTopDUContext > ParseSession::contextForThisPackage(IndexedString package)
{
    QList<ReferencedTopDUContext> contexts;
    QUrl url = package.toUrl();
    QDir path(url.adjusted(QUrl::RemoveFilename).path());
    if(path.exists())
    {
        int priority = BackgroundParser::WorstPriority;
        if(!forExport)
            priority = -1; //import this package as soon as possible
        else if(m_priority<=-1)
            priority = BackgroundParser::WorstPriority-2;//all needed files should be scheduled already
        else
            priority = m_priority;//currently parsejob does not get created in this cases to reduce recursion
	 QStringList files = path.entryList(QStringList("*.go"), QDir::Files | QDir::NoSymLinks);
	 bool shouldReparse=false;
	 for(QString filename : files)
	 {
	    filename = path.filePath(filename);
	    QFile file(filename);
	    if(!file.exists())
		continue;
            if(forExport && filename.endsWith("_test.go"))
                continue;
	
	    IndexedString url(filename);
	    DUChainReadLocker lock; 
	    ReferencedTopDUContext context = DUChain::self()->chainForDocument(url);
	    lock.unlock();
	    if(context)
		contexts.append(context);
	    else
	    {
		if(scheduleForParsing(url, priority, (TopDUContext::Features)(TopDUContext::ForceUpdate | TopDUContext::AllDeclarationsAndContexts)))
                    shouldReparse=true;
	    }
	     
	 }
	 if(shouldReparse)
	     scheduleForParsing(m_document, priority+1, (TopDUContext::Features)(m_features | TopDUContext::ForceUpdate));
    }
    return contexts;
}
Example #10
0
AbstractType::Ptr CodeCompletionContext::getExpressionType(const QString &token)
{
    AbstractType::Ptr res;
    QString expr = m_text.left(m_text.lastIndexOf(token));
    EditorIntegrator e;
    ExpressionVisitor ev(m_duContext.data(), &e);

    DUChainReadLocker lock;
    Parser parser(IndexedString(), expr.toUtf8());
    Ast *ast = parser.parse();
    if (!ast || !ast->tree) {
        return AbstractType::Ptr(nullptr);
    }
    lock.unlock();
    ev.visitCode(ast);
    res = ev.lastType();
    lock.lock();

    return res;
}
Example #11
0
/**
 * Currently priority order works in this way
 * 	-1: Direct imports of opened file
 * 	 0: opened files
 * 	...
 * 	 99... imports of imports of imports....
 * 	 99998: Imports of direct imports(needed to resolve types of some function)
 * 	 99999: Reparse of direct imports, after its imports are finished
 * 	 100000: reparse of opened file, after all recursive imports
 * layers higher than 99998 are NOT parsed right now because its too slow
 */
QList<ReferencedTopDUContext> ParseSession::contextForImport(QString package)
{
    package = package.mid(1, package.length()-2);
    QStringList files;
    //try canonical paths first
    if(m_canonicalImports && m_canonicalImports->contains(package))
    {
        QDir path((*m_canonicalImports)[package]);
        if(path.exists())
        {
            for(const QString& file : path.entryList(QStringList("*.go"), QDir::Files | QDir::NoSymLinks))
                files.append(path.filePath(file));
        }
    }
    if(files.empty())
    {
        for(const QString& pathname : m_includePaths)
        {
            QDir path(pathname);
            if(path.exists() && path.cd(package))
            {
                for(const QString& file : path.entryList(QStringList("*.go"), QDir::Files | QDir::NoSymLinks))
                    files.append(path.filePath(file));
                break;
            }
        }
    }
    QList<ReferencedTopDUContext> contexts;
    bool shouldReparse=false;
    //reduce priority if it is recursive import
    //int priority = forExport ? m_priority + 2 : m_priority - 1;
    int priority = BackgroundParser::WorstPriority;
    if(!forExport)
        priority = -1; //parse direct imports as soon as possible
    else if(m_priority<=-1)
        priority = BackgroundParser::WorstPriority-2;//imports of direct imports to the stack bottom
    else
        priority = m_priority - 2;//currently parsejob does not get created in this cases to reduce recursion
    for(QString filename : files)
    {
        QFile file(filename);
        if(!file.exists())
            continue;
        //test files are not part of binary package, so we can exclude them
        //we parse test files only if we open them in KDevelop
        if(filename.endsWith("_test.go"))
            continue;

        IndexedString url(filename);
        DUChainReadLocker lock;
        ReferencedTopDUContext context = DUChain::self()->chainForDocument(url);
        lock.unlock();
        if(context)
            contexts.append(context);
        else
        {
            if(scheduleForParsing(url, priority, (TopDUContext::Features)(TopDUContext::ForceUpdate | TopDUContext::AllDeclarationsAndContexts)))
                shouldReparse = true;
        }
    }
    if(shouldReparse) 
    //reparse this file after its imports are done
	scheduleForParsing(m_document, priority+1, (TopDUContext::Features)(m_features | TopDUContext::ForceUpdate));

    if(!forExport && m_priority != BackgroundParser::WorstPriority)//always schedule last reparse after all recursive imports are done
        scheduleForParsing(m_document, BackgroundParser::WorstPriority, (TopDUContext::Features)(m_features | TopDUContext::ForceUpdate));
    return contexts;
}
Example #12
0
void TestCppCodegen::testSimplifiedUpdating()
{
  {
    InsertIntoDUChain code1("duchaintest_1.h", "template <typename T> struct test{};"
                                               "template <> struct test<int> {};");
    code1.parse(TopDUContext::SimplifiedVisibleDeclarationsAndContexts | TopDUContext::AST);

    DUChainReadLocker lock;
    //No specializations are handled in simplified parsing
    Cpp::TemplateDeclaration *specClassDecl = dynamic_cast<Cpp::TemplateDeclaration*>(code1->localDeclarations()[1]);
    QVERIFY(!specClassDecl->specializedFrom().data());
  }
  {
    InsertIntoDUChain code1("duchaintest_1.h", "struct A { struct Member2; struct Member1; };");
    InsertIntoDUChain code3("duchaintest_3.h", "#include <duchaintest_1.h>\n struct C : public A { Member1 m1; Member2 m2; };");
    qWarning() << "********************* Parsing step 1";
    code3.parse(TopDUContext::AllDeclarationsContextsUsesAndAST);

    DUChainReadLocker lock;

    QCOMPARE(code3->localDeclarations().size(), 1);
    QCOMPARE(code3->childContexts().size(), 1);
    QCOMPARE(code3->childContexts()[0]->localDeclarations().size(), 2);
    QVERIFY(code3->childContexts()[0]->localDeclarations()[0]->abstractType().cast<StructureType>());
    QVERIFY(code3->childContexts()[0]->localDeclarations()[1]->abstractType().cast<StructureType>());
    QCOMPARE(code3->childContexts()[0]->importedParentContexts().size(), 1);
    QCOMPARE(code1->childContexts().size(), 1);
  }
  {
    InsertIntoDUChain code1("duchaintest_1.h", "struct A { struct Member1; };");
    InsertIntoDUChain code2("duchaintest_2.h", "template<class T> struct B : public T{ struct Member2; };");
    InsertIntoDUChain code3("duchaintest_3.h", "#include <duchaintest_2.h>\n #include <duchaintest_1.h>\n struct C : public B<A> { Member1 m1; Member2 m2; };");
    qWarning() << "********************* Parsing step 1";
    code3.parse(TopDUContext::AllDeclarationsContextsUsesAndAST);

    DUChainReadLocker lock;

    QCOMPARE(code3->localDeclarations().size(), 1);
    QCOMPARE(code3->childContexts().size(), 1);
    QCOMPARE(code3->childContexts()[0]->localDeclarations().size(), 2);
    QVERIFY(code3->childContexts()[0]->localDeclarations()[0]->abstractType().cast<StructureType>());
    QVERIFY(code3->childContexts()[0]->localDeclarations()[1]->abstractType().cast<StructureType>());
    QCOMPARE(code3->childContexts()[0]->importedParentContexts().size(), 1);
    QCOMPARE(code1->childContexts().size(), 1);

    QCOMPARE(code2->localDeclarations().size(), 1);
    ClassDeclaration* BClass = dynamic_cast<ClassDeclaration*>(code2->localDeclarations()[0]);
    QVERIFY(BClass);
    QCOMPARE(BClass->baseClassesSize(), 1u);
    QCOMPARE(BClass->baseClasses()[0].baseClass.abstractType()->toString(), QString("T"));

    QCOMPARE(code3->childContexts()[0]->importedParentContexts().size(), 1);

    DUContext* BAContext = code3->childContexts()[0]->importedParentContexts()[0].context(code3.topContext());
    QVERIFY(BAContext);
    QVERIFY(!BAContext->inSymbolTable());

    //2 contexts are imported: The template-context and the parent-class context
    QCOMPARE(BAContext->importedParentContexts().size(), 2);
    QCOMPARE(BAContext->importedParentContexts()[1].context(code3.topContext()), code1->childContexts()[0]);
    ClassDeclaration* classDecl = dynamic_cast<ClassDeclaration*>(BAContext->owner());
    QVERIFY(classDecl);
    QCOMPARE(classDecl->baseClassesSize(), 1u);
    QCOMPARE(classDecl->baseClasses()[0].baseClass.index(), code1->localDeclarations()[0]->indexedType().index());

    lock.unlock();
    qWarning() << "********************* Parsing step 2";
    code3.parse(TopDUContext::AllDeclarationsContextsUsesAndAST | TopDUContext::ForceUpdateRecursive, true);

    lock.lock();
    QCOMPARE(code3->localDeclarations().size(), 1);
    QCOMPARE(code3->childContexts().size(), 1);
    QCOMPARE(code3->childContexts()[0]->localDeclarations().size(), 2);
    QCOMPARE(code1->childContexts().size(), 1);

    QVERIFY(code3->childContexts()[0]->localDeclarations()[0]->abstractType().cast<StructureType>());
    QVERIFY(code3->childContexts()[0]->localDeclarations()[1]->abstractType().cast<StructureType>());

    //BClass should have been updated, not deleted
    QVERIFY(BClass == dynamic_cast<ClassDeclaration*>(code2->localDeclarations()[0]));
    QCOMPARE(BClass->baseClassesSize(), 1u);
    QCOMPARE(BClass->baseClasses()[0].baseClass.abstractType()->toString(), QString("T"));

    //The template-instantiation context "B<A>" should have been deleted
    DUContext* BAContext2 = code3->childContexts()[0]->importedParentContexts()[0].context(code3.topContext());
//     qDebug() << "BAContexts" << BAContext << BAContext2;
//     QVERIFY(BAContext != BAContext2);
    QCOMPARE(BAContext2->importedParentContexts().size(), 2);
    QCOMPARE(BAContext2->importedParentContexts()[1].context(code3.topContext()), code1->childContexts()[0]);

    classDecl = dynamic_cast<ClassDeclaration*>(BAContext2->owner());
    QVERIFY(classDecl);
    QCOMPARE(classDecl->baseClassesSize(), 1u);
    QCOMPARE(classDecl->baseClasses()[0].baseClass.index(), code1->localDeclarations()[0]->indexedType().index());
  }
  {
    InsertIntoDUChain code1("duchaintest_1.h", "struct A { struct Member1; };");
    InsertIntoDUChain code2("duchaintest_2.h", "template<class T> struct B : public T{ struct Member2; };");
    InsertIntoDUChain code3("duchaintest_3.h", "#include <duchaintest_2.h>\n #include <duchaintest_1.h>\n typedef B<A> Parent; struct C : public Parent { Member1 m1; Member2 m2; };");

    code3.parse(TopDUContext::AllDeclarationsContextsUsesAndAST);

    DUChainReadLocker lock;

    QCOMPARE(code3->localDeclarations().size(), 2);
    QCOMPARE(code3->childContexts().size(), 1);
    QCOMPARE(code3->childContexts()[0]->localDeclarations().size(), 2);
    QVERIFY(code3->childContexts()[0]->localDeclarations()[0]->abstractType().cast<StructureType>());
    QVERIFY(code3->childContexts()[0]->localDeclarations()[1]->abstractType().cast<StructureType>());

    lock.unlock();
    code3.parse(TopDUContext::AllDeclarationsContextsUsesAndAST | TopDUContext::ForceUpdateRecursive, true);

    lock.lock();
    QCOMPARE(code3->localDeclarations().size(), 2);
    QCOMPARE(code3->childContexts().size(), 1);
    QCOMPARE(code3->childContexts()[0]->localDeclarations().size(), 2);
    QVERIFY(code3->childContexts()[0]->localDeclarations()[0]->abstractType().cast<StructureType>());
    QVERIFY(code3->childContexts()[0]->localDeclarations()[1]->abstractType().cast<StructureType>());
  }

  {
    QString text = "class C { class D d; };";

    InsertIntoDUChain code("testsimplified.cpp", text);

    code.parse(TopDUContext::AllDeclarationsContextsUsesAndAST);

    DUChainReadLocker lock;

    dumpAST(code);

    //The forward-declaration of 'D' is forwarded into the top-context
    QCOMPARE(code->localDeclarations().size(), 2);
    Declaration* classDecl = code->localDeclarations()[0];
    QCOMPARE(code->childContexts().size(), 1);
    QCOMPARE(code->childContexts()[0]->localDeclarations().size(), 1);
    QVERIFY(code->childContexts()[0]->localDeclarations()[0]->abstractType().cast<StructureType>());
    QCOMPARE(code->childContexts()[0]->localDeclarations()[0]->abstractType()->toString(), QString("D"));

    lock.unlock();

    code.parse(TopDUContext::AllDeclarationsContextsUsesAndAST | TopDUContext::ForceUpdate, true);
    lock.lock();

    QCOMPARE(code->localDeclarations().size(), 2);

    //Verify that an update has happened, rather than recreating everything
    QCOMPARE(code->localDeclarations()[0], classDecl);

    QCOMPARE(code->childContexts().size(), 1);
    QCOMPARE(code->childContexts()[0]->localDeclarations().size(), 1);
    QVERIFY(code->childContexts()[0]->localDeclarations()[0]->abstractType().cast<StructureType>());
    QCOMPARE(code->childContexts()[0]->localDeclarations()[0]->abstractType()->toString(), QString("D"));
  }

  {
    QString text = "class C {int test(); int mem; }; void test(int a); int i;";

    InsertIntoDUChain code("testsimplified.cpp", text);

    code.parse(TopDUContext::SimplifiedVisibleDeclarationsAndContexts | TopDUContext::AST);

    DUChainReadLocker lock;

    dumpAST(code);

    QCOMPARE(code->localDeclarations().size(), 3);
    QCOMPARE(code->childContexts().size(), 1);
    QCOMPARE(code->childContexts()[0]->localDeclarations().size(), 2);
    QVERIFY(!code->childContexts()[0]->localDeclarations()[0]->abstractType());
    QVERIFY(!code->childContexts()[0]->localDeclarations()[1]->abstractType());
    //In simplified parsing mode, the type should not have been built
    QVERIFY(!code->localDeclarations()[0]->abstractType());
    QVERIFY(code->localDeclarations()[0]->kind() == Declaration::Type);
    QVERIFY(!code->localDeclarations()[1]->abstractType());
    QVERIFY(code->localDeclarations()[1]->kind() == Declaration::Instance);
    QVERIFY(!code->localDeclarations()[2]->abstractType());
    QVERIFY(code->localDeclarations()[2]->kind() == Declaration::Instance);

    {
      uint count;
      const KDevelop::CodeModelItem* items;

      KDevelop::CodeModel::self().items(code->url(), count, items);
      for(uint a = 0; a < count; ++a) {
        if(items[a].id == code->localDeclarations()[0]->qualifiedIdentifier()) {
          QVERIFY(items[a].kind & KDevelop::CodeModelItem::Class);
        }
      }
    }
  }

  {
    InsertIntoDUChain codeA("A.h", "#ifndef A_H\n #define A_H\n class A{}; \n#endif");
    InsertIntoDUChain codeB("B.h", "#include <A.h>\n class B{};");

    codeB.parse(TopDUContext::SimplifiedVisibleDeclarationsAndContexts | TopDUContext::AST | TopDUContext::Recursive);

    DUChainReadLocker lock;

    //This is not only for debug-output, but also verifies that the AST is there as requesed
    dumpAST(codeA);

    QCOMPARE(codeB->importedParentContexts().size(), 1);
    QCOMPARE(codeA->localDeclarations().size(), 1);
    QVERIFY(codeA->parsingEnvironmentFile()->featuresSatisfied((TopDUContext::Features)(TopDUContext::SimplifiedVisibleDeclarationsAndContexts | TopDUContext::AST | TopDUContext::Recursive)));
    QVERIFY(codeB->parsingEnvironmentFile()->featuresSatisfied((TopDUContext::Features)(TopDUContext::SimplifiedVisibleDeclarationsAndContexts | TopDUContext::AST | TopDUContext::Recursive)));

    lock.unlock();

    //Update with more features
    codeB.parse(TopDUContext::AllDeclarationsContextsUsesAndAST | TopDUContext::Recursive, true);

    lock.lock();
    QCOMPARE(codeB->importedParentContexts().size(), 1);
    QCOMPARE(codeA->localDeclarations().size(), 1);
    QVERIFY(codeA->parsingEnvironmentFile()->featuresSatisfied((TopDUContext::Features)(TopDUContext::AllDeclarationsContextsUsesAndAST | TopDUContext::Recursive)));
    QVERIFY(codeB->parsingEnvironmentFile()->featuresSatisfied((TopDUContext::Features)(TopDUContext::AllDeclarationsContextsUsesAndAST | TopDUContext::Recursive)));
  }
  {
    ///Test whether "empty" files work
    InsertIntoDUChain codeA("Q.h", "");
    InsertIntoDUChain codeB("B.h", "#include <Q.h>\n class B{};");

    codeB.parse(TopDUContext::SimplifiedVisibleDeclarationsAndContexts | TopDUContext::AST | TopDUContext::Recursive);

    DUChainReadLocker lock;

    QCOMPARE(codeB->importedParentContexts().size(), 1);
    QVERIFY(codeA->localDeclarations().isEmpty());
    QVERIFY(!codeA->parsingEnvironmentFile()->isProxyContext());
  }
  {
    ///Test the 'ignoring' of header-guards
    InsertIntoDUChain codeA("A.h", "#ifndef A_H\n #define A_H\n class A{};\n #ifdef HONK\n class Honk {};\n #endif\n \n#endif \n");
    InsertIntoDUChain codeB("B.h", "#define A_H\n \n #include <A.h>\n class B{};");

    QVERIFY(!codeA.tryGet());

    codeB.parse(TopDUContext::SimplifiedVisibleDeclarationsAndContexts | TopDUContext::AST | TopDUContext::Recursive);

    DUChainReadLocker lock;

    //This is not only for debug-output, but also verifies that the AST is there as requesed
    dumpAST(codeA);

    QCOMPARE(codeA->localDeclarations().size(), 1);
    QCOMPARE(codeB->importedParentContexts().size(), 1);

    lock.unlock();

    codeB.parse(TopDUContext::SimplifiedVisibleDeclarationsAndContexts | TopDUContext::AST | TopDUContext::ForceUpdateRecursive | TopDUContext::Recursive);

    lock.lock();

    QCOMPARE(codeA->localDeclarations().size(), 1);
    QCOMPARE(codeB->importedParentContexts().size(), 1);
  }
}
Example #13
0
void TestCppCodegen::testUpdateIndices()
{
  /// @todo Extend this test to make sure t hat all kinds of declarations retain their indices when they are updated
  {
    InsertIntoDUChain code1("duchaintest_1.h", "class QW{}; struct A { struct Member2; struct Member1; }; class Oq{};");
    InsertIntoDUChain code3("duchaintest_3.h", "#include <duchaintest_1.h>\n struct C : public A { Member1 m1; Member2 m2; A test(int arg) { int v1; \n{}\n { int v2, *v3; }} int test(); };");
    qWarning() << "********************* Parsing step 1";
    code3.parse(TopDUContext::AllDeclarationsContextsUsesAndAST);

    DUChainReadLocker lock;

    IndexedDeclaration CDecl = code3.getDeclaration("C");
    QVERIFY(CDecl.isValid());
    IndexedDeclaration ADecl = code3.getDeclaration("A");
    QVERIFY(ADecl.isValid());

    IndexedDeclaration C_m1 = code3.getDeclaration("C::m1");
    QVERIFY(C_m1.isValid());
    IndexedDeclaration C_m2 = code3.getDeclaration("C::m2");
    QVERIFY(C_m2.isValid());

    QVERIFY(CDecl.declaration()->internalContext());
    QCOMPARE(CDecl.declaration()->internalContext()->localDeclarations().size(), 4);

    IndexedDeclaration C_test = CDecl.declaration()->internalContext()->localDeclarations()[2];
    QVERIFY(C_test.isValid());
    DUContext* testCtx = C_test.data()->internalContext();
    QVERIFY(testCtx);
    QCOMPARE(testCtx->localDeclarations().size(), 1);

    IndexedDeclaration C_test_v1 = testCtx->localDeclarations()[0];

    QCOMPARE(testCtx->childContexts().size(), 2);
    DUContext* child = testCtx->childContexts()[1];

    QCOMPARE(child->localDeclarations().size(), 2);

    IndexedDeclaration C_test_v2 = child->localDeclarations()[0];
    IndexedDeclaration C_test_v3 = child->localDeclarations()[1];

    QCOMPARE(C_test_v1.declaration()->identifier(), Identifier("v1"));
    QCOMPARE(C_test_v2.declaration()->identifier(), Identifier("v2"));
    QCOMPARE(C_test_v3.declaration()->identifier(), Identifier("v3"));
    QCOMPARE(C_m1.declaration()->identifier(), Identifier("m1"));
    QCOMPARE(C_m2.declaration()->identifier(), Identifier("m2"));
    QCOMPARE(C_test.declaration()->identifier(), Identifier("test"));
    QCOMPARE(CDecl.declaration()->identifier(), Identifier("C"));
    QCOMPARE(ADecl.declaration()->identifier(), Identifier("A"));

    lock.unlock();
    code1.m_insertedCode.setText("struct A { struct Member2; struct Member1; };");
    code3.m_insertedCode.setText("#include <duchaintest_1.h>\n class Q{}; struct C : public A { Member2 m2; int c; A test(int arg) { int w1; int v1;\n\n { int     *v3; }} int test(); };");
    code3.parse(TopDUContext::AllDeclarationsContextsAndUses | TopDUContext::ForceUpdateRecursive, true);

    lock.lock();
    QVERIFY(ADecl.declaration());
    QCOMPARE(ADecl.declaration()->identifier(), Identifier("A"));
    QVERIFY(CDecl.declaration());
    QCOMPARE(CDecl.declaration()->identifier(), Identifier("C"));
    QVERIFY(!C_m1.declaration());
    QVERIFY(C_m2.declaration());
    QCOMPARE(C_m2.declaration()->identifier(), Identifier("m2"));
    QVERIFY(C_test.declaration());
    QCOMPARE(C_test.declaration()->identifier(), Identifier("test"));
    QVERIFY(C_test_v1.declaration());
    QCOMPARE(C_test_v1.declaration()->identifier(), Identifier("v1"));
    QVERIFY(!C_test_v2.declaration());
    QVERIFY(C_test_v3.declaration());
    QCOMPARE(C_test_v3.declaration()->identifier(), Identifier("v3"));
  }
}
Example #14
0
void DeclarationBuilder::visitAssignmentStatement(Ast *node)
{
    QList<AbstractType::Ptr> values;
    QList<DeclarationPointer> declarations;
    QList<bool> alias;
    DUChainReadLocker lock;

    /* First of all, fetch the types and declaration on the right side */
    Ast *aux = new Ast(node->tree->r, node->context);
    for (Node *n = aux->tree; n != nullptr; n = n->next) {
        ExpressionVisitor v(currentContext(), m_editor);
        aux->tree = n;
        lock.unlock();
        // TODO: improve this
        DeclarationBuilderBase::visitNode(aux);
        v.visitNode(aux);
        lock.lock();
        values << v.lastType();
        alias << v.lastAlias();
        declarations << v.lastDeclaration();
    }
    lock.unlock();

    /*
     * Check if we can unpack. If it's possible, do it and get out! We can
     * unpack if the following conditions are satisfied:
     *  - More than 1 expressions on the left side.
     *  - Just one expression on the right side, which has Array as its type.
     */
    int rsize = values.length();
    if (rsize == 1) {
        int rest = nodeListSize(node->tree->l);
        ClassType::Ptr ct = values.first().cast<ClassType>();
        if (rest > 1 && ct && ct->contentType()) {
            lock.lock();
            QualifiedIdentifier qi = ct.data()->declaration(topContext())->qualifiedIdentifier();
            lock.unlock();
            if (qi == QualifiedIdentifier("Array")) {
                for (Node *n = node->tree->l; n != nullptr; n = n->next) {
                    aux->tree = n;
                    QualifiedIdentifier id = getIdentifier(aux);
                    declareVariable(id, ct->contentType().abstractType(), aux);
                }
                delete aux;
                return;
            }
        }
    }

    /*
     * We cannot unpack, so iterate over the left side expressions
     * and assign types.
     */
    int i = 0;
    AbstractType::Ptr type;
    for (Node *n = node->tree->l; n != nullptr; n = n->next, i++) {
        if (n->kind == token_method_call)
            continue;
        aux->tree = n;
        if (has_star(n)) {
            int rest = nodeListSize(n) - 1;
            int pack = rsize - i - rest;
            ClassType::Ptr newType = getBuiltinsType(QStringLiteral("Array"), currentContext()).cast<ClassType>();
            DUChainWriteLocker wlock;
            for (int j = pack; j > 0; j--, i++) {
                newType->addContentType(values.at(i));
            }
            wlock.unlock();
            i--;
            if (!is_just_a_star(n)) {
                QualifiedIdentifier id = getIdentifier(aux);
                declareVariable(id, newType.cast<AbstractType>(), aux);
            }
        } else if (i < rsize) {
            if (alias.at(i)) {
                DUChainWriteLocker wlock;
                RangeInRevision range = getNameRange(aux);
                QualifiedIdentifier id = getIdentifier(aux);
                AliasDeclaration *d = openDeclaration<AliasDeclaration>(id, range);
                d->setAliasedDeclaration(declarations.at(i).data());
                closeDeclaration();
            } else {
                type = values.at(i);
                if (!type) { // HACK: provisional fix, should be removed in the future
                    type = getBuiltinsType(QStringLiteral("Object"), currentContext());
                }
                QualifiedIdentifier id = getIdentifier(aux);
                declareVariable(id, type, aux);
            }
        } else {
            lock.lock();
            type = getBuiltinsType(QStringLiteral("NilClass"), currentContext());
            lock.unlock();
            QualifiedIdentifier id = getIdentifier(aux);
            declareVariable(id, type, aux);
        }
    }
    delete aux;
}