示例#1
0
void QuickOpenPlugin::quickOpenDeclaration()
{
  if(jumpToSpecialObject())
    return;

  KDevelop::DUChainReadLocker lock( DUChain::lock() );
  Declaration* decl = cursorDeclaration();

  if(!decl) {
    qCDebug(PLUGIN_QUICKOPEN) << "Found no declaration for cursor, cannot jump";
    return;
  }
  decl->activateSpecialization();

  IndexedString u = decl->url();
  KTextEditor::Cursor c = decl->rangeInCurrentRevision().start();

  if(u.isEmpty()) {
    qCDebug(PLUGIN_QUICKOPEN) << "Got empty url for declaration" << decl->toString();
    return;
  }

  lock.unlock();
  core()->documentController()->openDocument(u.toUrl(), c);
}
示例#2
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();
    }
}
示例#3
0
IndexedString ClangIndex::translationUnitForUrl(const IndexedString& url)
{
    { // try explicit pin data first
        QMutexLocker lock(&m_mappingMutex);
        auto tu = m_tuForUrl.find(url);
        if (tu != m_tuForUrl.end()) {
            if (!QFile::exists(tu.value().str())) {
                // TU doesn't exist, unpin
                m_tuForUrl.erase(tu);
                return url;
            }
            return tu.value();
        }
    }
    // if no explicit pin data is available, follow back the duchain import chain
    {
        DUChainReadLocker lock;
        TopDUContext* top = DUChain::self()->chainForDocument(url);
        if (top) {
            TopDUContext* tuTop = top;
            QSet<TopDUContext*> visited;
            while(true) {
                visited.insert(tuTop);
                TopDUContext* next = nullptr;
                auto importers = tuTop->indexedImporters();
                foreach(IndexedDUContext ctx, importers) {
                    if (ctx.data()) {
                        next = ctx.data()->topContext();
                        break;
                    }
                }
                if (!next || visited.contains(next)) {
                    break;
                }
                tuTop = next;
            }
            if (tuTop != top) {
                return tuTop->url();
            }
        }
    }

    // otherwise, fallback to a simple buddy search for headers
    if (ClangHelpers::isHeader(url.str())) {
        foreach(const QUrl& buddy, DocumentFinderHelpers::getPotentialBuddies(url.toUrl(), false)) {
            const QString buddyPath = buddy.toLocalFile();
            if (QFile::exists(buddyPath)) {
                return IndexedString(buddyPath);
            }
        }
    }
示例#4
0
void UseBuilder::visitUnaryExpression( UnaryExpressionAst* node )
{
    IndexedString includeFile = getIncludeFileForNode(node, m_editor);
    if ( !includeFile.isEmpty() ) {
        QualifiedIdentifier identifier(includeFile.str());

        DUChainWriteLocker lock(DUChain::lock());
        foreach ( Declaration* dec, currentContext()->topContext()->findDeclarations(identifier) ) {
            if ( dec->kind() == Declaration::Import ) {
                newUse(node->includeExpression, DeclarationPointer(dec));
                return;
            }
        }
    }
示例#5
0
    FileCodeRepresentation(const IndexedString& document) : m_document(document) {
        QString localFile(document.toUrl().toLocalFile());

        QFile file( localFile );
        if ( file.open(QIODevice::ReadOnly) ) {
            data = QString::fromLocal8Bit(file.readAll());
            lineData = data.split('\n');
        }
        m_exists = file.exists();
    }
示例#6
0
 void computeHash() const {
     Q_ASSERT(dynamic);
     //this must stay thread-safe(may be called by multiple threads at a time)
     //The thread-safety is given because all threads will have the same result, and it will only be written once at the end.
     uint hash = m_identifier.hash();
     FOREACH_FUNCTION_STATIC(const IndexedTypeIdentifier& templateIdentifier, templateIdentifiers)
     hash = hash * 13 + templateIdentifier.hash();
     hash += m_unique;
     m_hash = hash;
 }
示例#7
0
CodeRepresentation::Ptr createCodeRepresentation(const IndexedString& path) {
    if(artificialCodeRepresentationExists(path))
        return CodeRepresentation::Ptr(new StringCodeRepresentation(representationForPath(path)));

    IDocument* document = ICore::self()->documentController()->documentForUrl(path.toUrl());
    if(document && document->textDocument())
        return CodeRepresentation::Ptr(new EditorCodeRepresentation(document->textDocument()));
    else
        return CodeRepresentation::Ptr(new FileCodeRepresentation(path));
}
示例#8
0
//Return the representation for the given URL if it exists, or an empty pointer otherwise
static QExplicitlySharedDataPointer<ArtificialStringData> representationForPath(const IndexedString& path)
{
    if(artificialStrings.contains(path))
        return artificialStrings[path];
    else
    {
        IndexedString constructedPath(CodeRepresentation::artificialPath(path.str()));
        if(artificialStrings.contains(constructedPath))
            return artificialStrings[constructedPath];
        else
            return QExplicitlySharedDataPointer<ArtificialStringData>();
    }
}
//Return the representation for the given URL if it exists, or an empty pointer otherwise
KSharedPtr<ArtificialStringData> representationForUrl(const IndexedString& url)
{
    if(artificialStrings.contains(url))
        return artificialStrings[url];
    else
    {
        IndexedString constructedUrl(CodeRepresentation::artificialUrl(url.str()));
        if(artificialStrings.contains(constructedUrl))
            return artificialStrings[constructedUrl];
        else
            return KSharedPtr<ArtificialStringData>();
    }
}
示例#10
0
IndexedString ClangIndex::translationUnitForUrl(const IndexedString& url)
{
    { // try explicit pin data first
        QMutexLocker lock(&m_mappingMutex);
        auto tu = m_tuForUrl.find(url);
        if (tu != m_tuForUrl.end()) {
            if (!QFile::exists(tu.value().str())) {
                // TU doesn't exist, unpin
                m_tuForUrl.erase(tu);
                return url;
            }
            return tu.value();
        }
    }
    // otherwise, fallback to a simple buddy search for headers
    if (ClangHelpers::isHeader(url.str())) {
        foreach(const QUrl& buddy, DocumentFinderHelpers::getPotentialBuddies(url.toUrl(), false)) {
            const QString buddyPath = buddy.toLocalFile();
            if (QFile::exists(buddyPath)) {
                return IndexedString(buddyPath);
            }
        }
    }
示例#11
0
void ApplyChangesWidget::addDocuments(const IndexedString & original)
{
    int idx=d->m_files.indexOf(original);
    if(idx<0) {
        QWidget * w = new QWidget;
        d->m_documentTabs->addTab(w, original.str());
        d->m_documentTabs->setCurrentWidget(w);

        d->m_files.insert(d->m_index, original);
        d->createEditPart(original);
    } else {
        d->m_index=idx;
    }
}
示例#12
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;
}
InsertArtificialCodeRepresentation::InsertArtificialCodeRepresentation(const IndexedString& file,
                                                                       const QString& text)
: m_file(file)
{
    if(m_file.toUrl().isRelative())
    {
        m_file = IndexedString(CodeRepresentation::artificialUrl(file.str()));
        
        int idx = 0;
        while(artificialStrings.contains(m_file))
        {
            ++idx;
            m_file = IndexedString(CodeRepresentation::artificialUrl(QString("%1_%2").arg(idx).arg(file.str())));
        }
    }
    
    Q_ASSERT(!artificialStrings.contains(m_file));

    artificialStrings.insert(m_file, KSharedPtr<ArtificialStringData>(new ArtificialStringData(text)));
}
示例#14
0
void ApplyChangesWidgetPrivate::createEditPart(const IndexedString & file)
{
    QWidget * widget = m_documentTabs->currentWidget();
    Q_ASSERT(widget);

    QVBoxLayout *m=new QVBoxLayout(widget);
    QSplitter *v=new QSplitter(widget);
    m->addWidget(v);

    QUrl url = file.toUrl();

    QMimeType mimetype = QMimeDatabase().mimeTypeForUrl(url);

    KParts::ReadWritePart* part=KMimeTypeTrader::self()->createPartInstanceFromQuery<KParts::ReadWritePart>(mimetype.name(), widget, widget);
    KTextEditor::Document* document=qobject_cast<KTextEditor::Document*>(part);
    Q_ASSERT(document);

    Q_ASSERT(document->action("file_save"));
    document->action("file_save")->setEnabled(false);

    m_editParts.insert(m_index, part);

    //Open the best code representation, even if it is artificial
    CodeRepresentation::Ptr repr = createCodeRepresentation(file);
    if(!repr->fileExists())
    {
        const QString templateName = QDir::tempPath() + QLatin1Char('/') + url.fileName().split('.').last();
        QTemporaryFile * temp(new QTemporaryFile(templateName));
        temp->open();
        temp->write(repr->text().toUtf8());
        temp->close();

        url = QUrl::fromLocalFile(temp->fileName());

        m_temps << temp;
    }
    m_editParts[m_index]->openUrl(url);

    v->addWidget(m_editParts[m_index]->widget());
    v->setSizes(QList<int>() << 400 << 100);
}
示例#15
0
InsertArtificialCodeRepresentation::InsertArtificialCodeRepresentation(const IndexedString& file,
                                                                       const QString& text)
: m_file(file)
{
    // make it simpler to use this by converting relative strings into artificial paths
    if(QUrl(m_file.str()).isRelative())
    {
        m_file = IndexedString(CodeRepresentation::artificialPath(file.str()));

        int idx = 0;
        while(artificialStrings.contains(m_file))
        {
            ++idx;
            m_file = IndexedString(CodeRepresentation::artificialPath(QStringLiteral("%1_%2").arg(idx).arg(file.str())));
        }
    }

    Q_ASSERT(!artificialStrings.contains(m_file));

    artificialStrings.insert(m_file, QExplicitlySharedDataPointer<ArtificialStringData>(new ArtificialStringData(text)));
}
bool KompareWidgets::compare(const IndexedString & original, const QString & modified, QWidget * widget, int index)
{
    //If there is no current part created, Create it
    if( !d->partExists(index) &&
        !d->createWidget(index, widget))
        return false;
    
    //Prepare the part
    KParts::Part * part = d->m_parts[index];
    KompareInterface * ipart = qobject_cast<KompareInterface * >(part);
    Q_ASSERT(part);
    
    part->widget()->setVisible(true);
    part->widget()->resize(part->widget()->parentWidget()->size());
    part->widget()->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
    
    //Compare
    ipart->compareFileString(original.toUrl(), modified);
    
    //Set to used
    d->m_usedWidgets[index] = true;
    return true;
}
示例#17
0
ReferencedTopDUContext ClangHelpers::buildDUChain(CXFile file, const Imports& imports, const ParseSession& session,
                                                  TopDUContext::Features features, IncludeFileContexts& includedFiles,
                                                  ClangIndex* index, const std::function<bool()>& abortFunction)
{
    if (includedFiles.contains(file)) {
        return {};
    }

    if (abortFunction && abortFunction()) {
        return {};
    }

    // prevent recursion
    includedFiles.insert(file, {});

    // ensure DUChain for imports are build properly
    foreach(const auto& import, imports.values(file)) {
        buildDUChain(import.file, imports, session, features, includedFiles, index, abortFunction);
    }

    const IndexedString path(QDir(ClangString(clang_getFileName(file)).toString()).canonicalPath());
    if (path.isEmpty()) {
        // may happen when the file gets removed before the job is run
        return {};
    }

    const auto& environment = session.environment();

    bool update = false;
    UrlParseLock urlLock(path);
    ReferencedTopDUContext context;
    {
        DUChainWriteLocker lock;
        context = DUChain::self()->chainForDocument(path, &environment);
        if (!context) {
            context = ::createTopContext(path, environment);
        } else {
            update = true;
        }

        includedFiles.insert(file, context);
        if (update) {
            auto envFile = ClangParsingEnvironmentFile::Ptr(dynamic_cast<ClangParsingEnvironmentFile*>(context->parsingEnvironmentFile().data()));
            Q_ASSERT(envFile);
            if (!envFile)
                return context;

            /* NOTE: When we are here, then either the translation unit or one of its headers was changed.
             *       Thus we must always update the translation unit to propagate the change(s).
             *       See also: https://bugs.kde.org/show_bug.cgi?id=356327
             *       This assumes that headers are independent, we may need to improve that in the future
             *       and also update header files more often when other files included therein got updated.
             */
            if (path != environment.translationUnitUrl() && !envFile->needsUpdate(&environment) && envFile->featuresSatisfied(features)) {
                return context;
            } else {
                //TODO: don't attempt to update if this environment is worse quality than the outdated one
                if (index && envFile->environmentQuality() < environment.quality()) {
                    index->pinTranslationUnitForUrl(environment.translationUnitUrl(), path);
                }
                envFile->setEnvironment(environment);
                envFile->setModificationRevision(ModificationRevision::revisionForFile(context->url()));
            }

            context->clearImportedParentContexts();
        }
        context->setFeatures(features);

        foreach(const auto& import, imports.values(file)) {
            auto ctx = includedFiles.value(import.file);
            if (!ctx) {
                // happens for cyclic imports
                continue;
            }
            context->addImportedParentContext(ctx, import.location);
        }
        context->updateImportsCache();
    }

    const auto problems = session.problemsForFile(file);
    {
        DUChainWriteLocker lock;
        context->setProblems(problems);
    }

    Builder::visit(session.unit(), file, includedFiles, update);

    DUChain::self()->emitUpdateReady(path, context);

    return context;
}
示例#18
0
bool UsesCollector::shouldRespectFile(IndexedString document) {
  return (bool)ICore::self()->projectController()->findProjectForUrl(document.toUrl()) || (bool)ICore::self()->documentController()->documentForUrl(document.toUrl());
}
示例#19
0
ReferencedTopDUContext ClangHelpers::buildDUChain(CXFile file, const Imports& imports, const ParseSession& session,
        TopDUContext::Features features, IncludeFileContexts& includedFiles,
        ClangIndex* index)
{
    if (includedFiles.contains(file)) {
        return {};
    }

    // prevent recursion
    includedFiles.insert(file, {});

    // ensure DUChain for imports are build properly
    foreach(const auto& import, imports.values(file)) {
        buildDUChain(import.file, imports, session, features, includedFiles, index);
    }

    const IndexedString path(QDir(ClangString(clang_getFileName(file)).toString()).canonicalPath());
    if (path.isEmpty()) {
        // may happen when the file gets removed before the job is run
        return {};
    }

    const auto& environment = session.environment();

    bool update = false;
    UrlParseLock urlLock(path);
    ReferencedTopDUContext context;
    {
        DUChainWriteLocker lock;
        context = DUChain::self()->chainForDocument(path, &environment);
        if (!context) {
            context = ::createTopContext(path, environment);
        } else {
            update = true;
        }

        includedFiles.insert(file, context);
        if (update) {
            auto envFile = ClangParsingEnvironmentFile::Ptr(dynamic_cast<ClangParsingEnvironmentFile*>(context->parsingEnvironmentFile().data()));
            Q_ASSERT(envFile);
            if (!envFile->needsUpdate(&environment) && envFile->featuresSatisfied(features)) {
                return context;
            } else {
                //TODO: don't attempt to update if this environment is worse quality than the outdated one
                if (index && envFile->environmentQuality() < environment.quality()) {
                    index->pinTranslationUnitForUrl(environment.translationUnitUrl(), path);
                }
                envFile->setEnvironment(environment);
                envFile->setModificationRevision(ModificationRevision::revisionForFile(context->url()));
            }

            context->clearImportedParentContexts();
        }
        context->setFeatures(features);

        foreach(const auto& import, imports.values(file)) {
            Q_ASSERT(includedFiles.contains(import.file));
            auto ctx = includedFiles.value(import.file);
            if (!ctx) {
                // happens for cyclic imports
                continue;
            }
            context->addImportedParentContext(ctx, import.location);
        }
        context->updateImportsCache();
    }

    const auto problems = session.problemsForFile(file);
    {
        DUChainWriteLocker lock;
        context->setProblems(problems);
    }

    Builder::visit(session.unit(), file, includedFiles, update);

    return context;
}
示例#20
0
///TODO: share code with TypeBuilder
void TypeASTVisitor::visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *node)
{
  if(m_stopSearch)
    return;

  Cpp::FindDeclaration find( m_context, m_source, m_flags, m_context->range().end );
  find.openQualifiedIdentifier(false);

  // Don't forget the modifiers!
  uint modifiers = AbstractType::NoModifiers;
  if (node->cv) {
    const ListNode<uint> *it = node->cv->toFront();
    const ListNode<uint> *end = it;
    do {
      int kind = m_session->token_stream->kind(it->element);
      switch (kind) {
        case Token_const:
          modifiers |= AbstractType::ConstModifier;
          break;
        case Token_volatile:
          modifiers |= AbstractType::VolatileModifier;
          break;
        default:
          //qCDebug(CPPDUCHAIN) << "Unknown modifier token" << kind;
          break;
      }
      it = it->next;
    } while (it != end);
  }

  if (node->integrals)
    {
      uint type = IntegralType::TypeNone;

      const ListNode<uint> *it2 = node->integrals->toFront();
      const ListNode<uint> *end = it2;
      do {
        int kind = m_session->token_stream->kind(it2->element);
        switch (kind) {
          case Token_char:
            type = IntegralType::TypeChar;
            break;
          case Token_char16_t:
            type = IntegralType::TypeChar16_t;
            break;
          case Token_char32_t:
            type = IntegralType::TypeChar32_t;
            break;
          case Token_wchar_t:
            type = IntegralType::TypeWchar_t;
            break;
          case Token_bool:
            type = IntegralType::TypeBoolean;
            break;
          case Token_short:
            modifiers |= AbstractType::ShortModifier;
            break;
          case Token_int:
            type = IntegralType::TypeInt;
            break;
          case Token_long:
            if (modifiers & AbstractType::LongModifier)
              modifiers |= AbstractType::LongLongModifier;
            else
              modifiers |= AbstractType::LongModifier;
            break;
          case Token_signed:
            modifiers |= AbstractType::SignedModifier;
            break;
          case Token_unsigned:
            modifiers |= AbstractType::UnsignedModifier;
            break;
          case Token_float:
            type = IntegralType::TypeFloat;
            break;
          case Token_double:
            type = IntegralType::TypeDouble;
            break;
          case Token_void:
            type = IntegralType::TypeVoid;
            break;
        }

        it2 = it2->next;
      } while (it2 != end);

      if(type == IntegralType::TypeNone)
        type = IntegralType::TypeInt; //Happens, example: "unsigned short"

      KDevelop::IntegralType::Ptr integral ( new KDevelop::IntegralType(type) );
      integral->setModifiers(modifiers);

      m_type = integral.cast<AbstractType>();

      m_typeId = QualifiedIdentifier(integral->toString());
    }
  else if (node->isTypeof || node->isDecltype)
    {
      if (node->expression)
      {
         bool isDecltypeInParen = false;
        if (node->isDecltype && node->expression->kind == AST::Kind_PrimaryExpression) {
          int startPosition = m_session->token_stream->position(node->expression->start_token);
          static IndexedString paren("(");
          isDecltypeInParen = m_session->contentsVector()[startPosition] == paren.index();
        }

        ExpressionParser parser(false, false, isDecltypeInParen);
        node->expression->ducontext = const_cast<DUContext*>(m_context);
        ExpressionEvaluationResult result = parser.evaluateType(node->expression, m_session);
        m_type = result.type.abstractType();
        m_typeId = QualifiedIdentifier(result.toString());

        {
          LOCKDUCHAIN;
          // Transform specific constants like '5' into their type 'int'
          m_type = TypeUtils::removeConstants(m_type, m_source);
        }
        // make reference for decltype in additional parens - but only if it's not already a reference
        // see spec 7.1.6/4
        if (isDecltypeInParen && m_type && !TypeUtils::isReferenceType(m_type))
        {
          // type might already be a ref type
          ReferenceType::Ptr refType = ReferenceType::Ptr(new ReferenceType);
          refType->setBaseType(m_type);
          m_type = refType.cast<AbstractType>();
          ///TODO: anything todo with m_typeId ?
        }

        if(m_visitor)
          m_visitor->parse(node->expression); // Give the visitor a chance to build uses
      }
    }

  {
    LOCKDUCHAIN;
    find.closeQualifiedIdentifier();
    m_declarations = find.lastDeclarations();
    if(!m_declarations.isEmpty() && m_declarations[0])
      m_type = m_declarations[0]->abstractType();
  }

  visit(node->name);
}