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;
}
QPair<DUContext*, QualifiedIdentifier> ContextBuilder::findPrefixContext(const QualifiedIdentifier& id, KDevelop::SimpleCursor pos) {
  if(id.count() < 2)
    return qMakePair((DUContext*)0, QualifiedIdentifier());
  
  QualifiedIdentifier prefixId(id);
  prefixId.pop();

  DUContext* import = 0;

  {
    DUChainReadLocker lock(DUChain::lock());

    QualifiedIdentifier currentScopeId = currentContext()->scopeIdentifier(true);

    QList<Declaration*> decls = currentContext()->findDeclarations(prefixId, pos);

    if(!decls.isEmpty()) {
      DUContext* classContext = decls.first()->logicalInternalContext(0);
      if(classContext && classContext->type() == DUContext::Class) {
        import = classContext;
        //Change the prefix-id so it respects namespace-imports
        
        prefixId = classContext->scopeIdentifier(true);
        if(prefixId.count() >= currentScopeId.count() && prefixId.left(currentScopeId.count()) == currentScopeId)
          prefixId = prefixId.mid(currentScopeId.count());
        else
          kDebug() << "resolved bad prefix context. Should start with" << currentScopeId.toString() << "but is" << prefixId.toString();
      }
    }
  }
  
  return qMakePair(import, prefixId);
}
Example #3
0
void ADLTypeVisitor::endVisit(const FunctionType * /*type*/)
{
    // return type and argument types are handled by FunctionType::accept0

    // here we process the namespace of the function name (or containing class), if any

    /* at the bottom of 3.4.2.2 we find the following:

    In addition, if the argument is the name or address of a set of overloaded functions and/or function tem-
    plates, its associated classes and namespaces are the union of those associated with each of the members of
    the set: the namespace in which the function or function template is defined and the classes and namespaces
    associated with its (non-dependent) parameter types and return type.
    */

    if (m_helper.m_possibleFunctionName.data() && m_helper.m_possibleFunctionName.data()->isFunctionDeclaration())
    {
        Declaration * declaration = m_helper.m_possibleFunctionName.data();

#ifdef DEBUG_ADL
        qCDebug(CPPDUCHAIN) << "    function name = " << declaration->toString() << " ; identifier = " << declaration->qualifiedIdentifier().toString();
#endif

        // start going towards the global scope until we match an interesting name
        // note that calling addDeclarationScopeIdentifier does not work because for some reason
        // for function names DUContext::scopeIdentifier returns the function name instead of the
        // name of the function's scope
        DUContext* context = declaration->context();
        while (context) {
            if (Declaration* decl = context->owner())
            {
              if (context->type() == DUContext::Namespace)
              {
                  m_helper.addAssociatedNamespace(decl->qualifiedIdentifier());
                  break;
              } else if (context->type() == DUContext::Class) {
                  m_helper.addAssociatedClass(decl);
                  break;
              }
            }
            context = context->parentContext();
        }
    }
}
Example #4
0
void AdaptSignatureAction::execute()
{
    ENSURE_CHAIN_NOT_LOCKED
    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);
    lock.unlock();
    changeParameters.m_ignoreOldText = true;
    changes.addChange(changeParameters);
    changes.setReplacementPolicy(DocumentChangeSet::WarnOnFailedChange);
    DocumentChangeSet::ChangeResult result = changes.applyAllChanges();
    if (!result) {
        KMessageBox::error(nullptr, i18n("Failed to apply changes: %1", result.m_failureReason));
    }
    emit executed(this);

    foreach(RenameAction * renAct, m_renameActions) {
        renAct->execute();
    }
}
void CorrectionFileGenerator::addHint(const QString &typeCode, const QStringList &modules, Declaration *forDeclaration,
                                      CorrectionFileGenerator::HintType hintType)
{
    if ( ! forDeclaration || ! forDeclaration->context() ) {
        qCWarning(KDEV_PYTHON_CODEGEN) << "Declaration does not have context!" << (forDeclaration ? forDeclaration->toString() : "");
        return;
    }

    DUContext* context = forDeclaration->context();
    if ( context->type() == DUContext::Function ) {
        auto otherImporters = context->importers();
        if ( otherImporters.isEmpty() ) {
            return;
        }
        context = otherImporters.first();
    }

    // We're in a class if the context of the declaration is a Class or if its
    // parent context is a class. This is because a function body has a context
    // of type Other.
    bool inClass = context->type() == DUContext::Class
            || (context->parentContext() && context->parentContext()->type() == DUContext::Class);

    // If the declaration is part of the function's arguments or it's parent
    // context is one of a function.
    bool inFunction = context->type() == DUContext::Function
            || (context->owner() && context->owner()->abstractType()->whichType() == AbstractType::TypeFunction);

    qCDebug(KDEV_PYTHON_CODEGEN) << "Are we in a class: " << inClass;
    qCDebug(KDEV_PYTHON_CODEGEN) << "Are we in a function: " << inFunction;

    QString enclosingClassIdentifier, enclosingFunctionIdentifier;

    if ( context->owner() ) {
        if ( inClass && inFunction ) {
            Declaration *functionDeclaration = context->owner();

            enclosingClassIdentifier = functionDeclaration->context()->owner()->identifier().identifier().str();
            enclosingFunctionIdentifier = functionDeclaration->identifier().identifier().str();
        }
        else if ( inClass ) {
            enclosingClassIdentifier = context->owner()->identifier().identifier().str();
        }
        else if ( inFunction ) {
            enclosingFunctionIdentifier = context->owner()->identifier().identifier().str();
        }
    }

    qCDebug(KDEV_PYTHON_CODEGEN) << "Enclosing class: " << enclosingClassIdentifier;
    qCDebug(KDEV_PYTHON_CODEGEN) << "Enclosing function: " << enclosingFunctionIdentifier;

    QString declarationIdentifier = forDeclaration->identifier().identifier().str();

    bool foundClassDeclaration = false;
    bool foundFunctionDeclaration = false;

    QString functionIdentifier;

    if ( hintType == FunctionReturnHint ) {
        functionIdentifier = declarationIdentifier;
    }
    else if ( hintType == LocalVariableHint ) {
        functionIdentifier = enclosingFunctionIdentifier;
    }

    int line = findStructureFor(enclosingClassIdentifier, functionIdentifier);

    if ( line == -1 ) {
        line = findStructureFor(enclosingClassIdentifier, QString());
    }
    else if ( inFunction || hintType == FunctionReturnHint ) {
        foundFunctionDeclaration = true;
    }

    if ( line == -1 ) {
        line = findStructureFor(QString(), QString());
    }
    else if ( inClass ) {
        foundClassDeclaration = true;
    }

    qCDebug(KDEV_PYTHON_CODEGEN) << "Found class declaration: " << foundClassDeclaration << enclosingClassIdentifier;
    qCDebug(KDEV_PYTHON_CODEGEN) << "Found function declaration: " << foundFunctionDeclaration << functionIdentifier;
    qCDebug(KDEV_PYTHON_CODEGEN) << "Line: " << line;

    int indentsForNextStatement = m_fileIndents->indentForLine(line);

    if ( foundClassDeclaration ) {
        indentsForNextStatement += DEFAULT_INDENT_LEVEL;
    }

    QStringList newCode;
    if ( inClass ) {
        if ( ! foundClassDeclaration ) {
            QString classDeclaration = createStructurePart(enclosingClassIdentifier, ClassType);
            classDeclaration.prepend(QString(indentsForNextStatement, ' '));

            newCode.append(classDeclaration);
            indentsForNextStatement += DEFAULT_INDENT_LEVEL;
        }
        else {
            line++;
        }
    }

    if ( inFunction || hintType == FunctionReturnHint ) {
        if ( ! foundFunctionDeclaration ) {
            QString functionDeclaration;
            if ( inClass ) {
                functionDeclaration = createStructurePart(functionIdentifier, MemberFunctionType);
            }
            else {
                functionDeclaration = createStructurePart(functionIdentifier, FunctionType);
            }
            functionDeclaration.prepend(QString(indentsForNextStatement, ' '));

            newCode.append(functionDeclaration);
            indentsForNextStatement += DEFAULT_INDENT_LEVEL;
        }
        else {
            line++;
        }
    }

    if ( foundFunctionDeclaration && ! foundClassDeclaration ) {
        indentsForNextStatement += DEFAULT_INDENT_LEVEL;
    }
    QString hintCode;
    if ( hintType == FunctionReturnHint ) {
        hintCode = "returns = " + typeCode;
    }
    else if ( hintType == LocalVariableHint ) {
        hintCode = "l_" + declarationIdentifier + " = " + typeCode;
    }
    qCDebug(KDEV_PYTHON_CODEGEN) << "Hint code: " << hintCode;
    hintCode.prepend(QString(indentsForNextStatement, ' '));
    newCode.append(hintCode);

    for ( int i = 0; i < newCode.length(); i++ ) {
        m_code.insert(line + i, newCode.at(i));
    }

    // We safely insert any import declaration at the top
    foreach ( const QString &moduleName, modules ) {
        bool importExists = false;
        foreach (const QString &line, m_code) {
            if ( ! line.startsWith("import") && ! line.startsWith("from") && ! line.isEmpty() ) {
                break;
            }

            // In both import ... and from ... import ..., the second part is what we want
            if ( line.section(' ', 1, 1, QString::SectionSkipEmpty) == moduleName.trimmed() ) {
                importExists = true;
            }
        }

        if ( ! importExists ) {
            m_code.prepend("import " + moduleName.trimmed());
        }
    }