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);
}
QualifiedIdentifier InstantiationInformation::applyToIdentifier(const QualifiedIdentifier& id) const {
  QualifiedIdentifier ret;
  if(id.count() > 1) {
    ret = id;
    ret.pop();
    if(previousInstantiationInformation.index())
      ret = previousInstantiationInformation.information().applyToIdentifier(ret);
  }

  Identifier lastId(id.last());

  KDevVarLengthArray<IndexedTypeIdentifier> oldTemplateIdentifiers;
  for(uint a = 0; a < lastId.templateIdentifiersCount(); ++a)
    oldTemplateIdentifiers.append(lastId.templateIdentifier(a)); 
  lastId.clearTemplateIdentifiers();

  for(uint a = 0; a < templateParametersSize(); ++a) {
    if(templateParameters()[a].abstractType()) {
      lastId.appendTemplateIdentifier(IndexedTypeIdentifier(templateParameters()[a].abstractType()->toString(), true));
    }else{
      lastId.appendTemplateIdentifier((uint) oldTemplateIdentifiers.size() > a ? oldTemplateIdentifiers[a] : IndexedTypeIdentifier());
    }
  }

  for(int a = templateParametersSize(); a < oldTemplateIdentifiers.size(); ++a)
    lastId.appendTemplateIdentifier(oldTemplateIdentifiers[a]);

  ret.push(lastId);
  return ret;
}
void ContextBuilder::openPrefixContext(AST* ast, const QualifiedIdentifier& id, const SimpleCursor& pos) {
  if(id.count() < 2)
    return;

  //When creating a prefix-context that is there to embed a class within another class, import the enclosing class into that context.
  //That way items from the base class can be found.

  QPair<DUContext*, QualifiedIdentifier> prefix = findPrefixContext(id, pos);

  openContext(ast, DUContext::Helper, prefix.second);

  DUContext* import = prefix.first;
  
  if(import) {
    DUChainWriteLocker lock(DUChain::lock());
    addImportedParentContextSafely(currentContext(), import);
  }
}
QString DeclarationNavigationContext::html(bool shorten)
{
  clear();
  m_shorten = shorten;
  modifyHtml()  += "<html><body><p>" + fontSizePrefix(shorten);

  addExternalHtml(m_prefix);

  if(!m_declaration.data()) {
    modifyHtml() += i18n("<br /> lost declaration <br />");
    return currentHtml();
  }
  
  if( m_previousContext ) {
    QString link = createLink( m_previousContext->name(), m_previousContext->name(), NavigationAction(m_previousContext) );
    modifyHtml() += navigationHighlight(i18n("Back to %1<br />", link));
  }
  
  QExplicitlySharedDataPointer<IDocumentation> doc;
  
  if( !shorten ) {
    doc = ICore::self()->documentationController()->documentationForDeclaration(m_declaration.data());

    const AbstractFunctionDeclaration* function = dynamic_cast<const AbstractFunctionDeclaration*>(m_declaration.data());
    if( function ) {
      htmlFunction();
    } else if( m_declaration->isTypeAlias() || m_declaration->kind() == Declaration::Instance ) {
	
	
      if( m_declaration->isTypeAlias() )
        modifyHtml() += importantHighlight("type ");

      if(m_declaration->type<EnumeratorType>())
        modifyHtml() += i18n("enumerator ");
      
      if( !m_declaration->isTypeAlias()) 
          modifyHtml() += ' ' + identifierHighlight(declarationName(m_declaration).toHtmlEscaped(), m_declaration) + " ";

      AbstractType::Ptr useType = m_declaration->abstractType();
      if(m_declaration->isTypeAlias()) {
        //Do not show the own name as type of typedefs
        if(useType.cast<TypeAliasType>())
          useType = useType.cast<TypeAliasType>()->type();
      } 
      
      eventuallyMakeTypeLinks( useType );
      
      modifyHtml() += "<br>";

    }else{
      if( m_declaration->kind() == Declaration::Type && m_declaration->abstractType().cast<StructureType>()) {
        htmlClass();
      }
      if ( m_declaration->kind() == Declaration::Namespace ) {
        modifyHtml() += i18n("namespace %1 ", identifierHighlight(m_declaration->qualifiedIdentifier().toString().toHtmlEscaped(), m_declaration));
      }

      if(m_declaration->type<EnumerationType>()) {
        EnumerationType::Ptr enumeration = m_declaration->type<EnumerationType>();
        modifyHtml() += i18n("enumeration %1 ", identifierHighlight(m_declaration->identifier().toString().toHtmlEscaped(), m_declaration));
      }

      if(m_declaration->isForwardDeclaration()) {
        ForwardDeclaration* forwardDec = static_cast<ForwardDeclaration*>(m_declaration.data());
        Declaration* resolved = forwardDec->resolve(m_topContext.data());
        if(resolved) {
          modifyHtml() += i18n("( resolved forward-declaration: ");
          makeLink(resolved->identifier().toString(), KDevelop::DeclarationPointer(resolved), NavigationAction::NavigateDeclaration );
          modifyHtml() += i18n(") ");
        }else{
          modifyHtml() += i18n("(unresolved forward-declaration) ");
          QualifiedIdentifier id = forwardDec->qualifiedIdentifier();
          uint count;
          const IndexedDeclaration* decls;
          PersistentSymbolTable::self().declarations(id, count, decls);
          for(uint a = 0; a < count; ++a) {
            if(decls[a].isValid() && !decls[a].data()->isForwardDeclaration()) {
              modifyHtml() += "<br />";
              makeLink(i18n("possible resolution from"), KDevelop::DeclarationPointer(decls[a].data()), NavigationAction::NavigateDeclaration);
              modifyHtml() += ' ' + decls[a].data()->url().str();
            }
          }
        }
      }
      modifyHtml() += "<br />";
    }
  }else{
    AbstractType::Ptr showType = m_declaration->abstractType();
    if(showType && showType.cast<FunctionType>()) {
      showType = showType.cast<FunctionType>()->returnType();
      if(showType)
        modifyHtml() += labelHighlight(i18n("Returns: "));
    }else  if(showType) {
      modifyHtml() += labelHighlight(i18n("Type: "));
    }
    
    if(showType) {
      eventuallyMakeTypeLinks(showType);
      modifyHtml() += " ";
    }
  }
  
  QualifiedIdentifier identifier = m_declaration->qualifiedIdentifier();
  if( identifier.count() > 1 ) {
    if( m_declaration->context() && m_declaration->context()->owner() )
    {
      Declaration* decl = m_declaration->context()->owner();

      FunctionDefinition* definition = dynamic_cast<FunctionDefinition*>(decl);
      if(definition && definition->declaration())
        decl = definition->declaration();

      if(decl->abstractType().cast<EnumerationType>())
        modifyHtml() += labelHighlight(i18n("Enum: "));
      else
        modifyHtml() += labelHighlight(i18n("Container: "));

      makeLink( declarationName(DeclarationPointer(decl)), DeclarationPointer(decl), NavigationAction::NavigateDeclaration );
      modifyHtml() += " ";
    } else {
      QualifiedIdentifier parent = identifier;
      parent.pop();
      modifyHtml() += labelHighlight(i18n("Scope: %1 ", typeHighlight(parent.toString().toHtmlEscaped())));
    }
  }
  
  if( shorten && !m_declaration->comment().isEmpty() ) {
    QString comment = QString::fromUtf8(m_declaration->comment());
    if( comment.length() > 60 ) {
      comment.truncate(60);
      comment += "...";
    }
    comment.replace('\n', " ");
    comment.replace("<br />", " ");
    comment.replace("<br/>", " ");
    modifyHtml() += commentHighlight(comment.toHtmlEscaped()) + "   ";
  }
  

  QString access = stringFromAccess(m_declaration);
  if( !access.isEmpty() )
    modifyHtml() += labelHighlight(i18n("Access: %1 ", propertyHighlight(access.toHtmlEscaped())));


  ///@todo Enumerations

  QString detailsHtml;
  QStringList details = declarationDetails(m_declaration);
  if( !details.isEmpty() ) {
    bool first = true;
    foreach( const QString &str, details ) {
      if( !first )
        detailsHtml += ", ";
      first = false;
      detailsHtml += propertyHighlight(str);
    }
  }
Beispiel #5
0
void TestIdentifier::testQualifiedIdentifier()
{
  QFETCH(QString, stringId);
  const QStringList list = stringId.split(QStringLiteral("::"), QString::SkipEmptyParts);

  QualifiedIdentifier id(stringId);
  QCOMPARE(id.isEmpty(), stringId.isEmpty());
  QCOMPARE(id, QualifiedIdentifier(stringId));
  QVERIFY(!(id != QualifiedIdentifier(stringId)));
  QCOMPARE(id, QualifiedIdentifier(stringId));
  if (list.size() == 1) {
    QCOMPARE(id, QualifiedIdentifier(Identifier(list.last())));
  } else if (list.isEmpty()) {
    QualifiedIdentifier empty{Identifier()};
    QCOMPARE(id, empty);
    QVERIFY(empty.isEmpty());
    QVERIFY(empty.inRepository());
  }
  QCOMPARE(id.toString(), stringId);
  QCOMPARE(id.toStringList(), list);
  QCOMPARE(id.top(), Identifier(list.isEmpty() ? QString() : list.last()));

  if (stringId.isEmpty()) {
    QVERIFY(id.inRepository());
    QVERIFY(QualifiedIdentifier(id).inRepository());
  }

  QualifiedIdentifier copy = id;
  QCOMPARE(copy, id);
  copy = copy;
  QCOMPARE(copy, id);
  copy = QualifiedIdentifier();
  QVERIFY(copy.isEmpty());
  copy = id;
  QCOMPARE(copy, id);

  IndexedQualifiedIdentifier indexedId(id);
  QVERIFY(indexedId == id);
  QCOMPARE(indexedId, IndexedQualifiedIdentifier(id));
  QCOMPARE(indexedId.isValid(), !stringId.isEmpty());
  QCOMPARE(indexedId.identifier(), id);
  IndexedQualifiedIdentifier indexedCopy = indexedId;
  QCOMPARE(indexedCopy, indexedId);
  indexedCopy = indexedCopy;
  QCOMPARE(indexedCopy, indexedId);
  indexedCopy = IndexedQualifiedIdentifier();
  QVERIFY(!indexedCopy.isValid());
  indexedCopy = indexedId;
  QCOMPARE(indexedCopy, indexedId);

  QualifiedIdentifier moved = std::move(id);
  QVERIFY(id.isEmpty());
  QCOMPARE(moved, copy);

  IndexedQualifiedIdentifier movedIndexed = std::move(indexedId);
  QVERIFY(indexedId.isEmpty());
  QCOMPARE(movedIndexed, indexedCopy);

  copy.clear();
  QVERIFY(copy.isEmpty());

  copy.push(moved);
  QCOMPARE(copy, moved);

  copy.push(Identifier(QStringLiteral("lalala")));
  QCOMPARE(copy.count(), moved.count() + 1);
}
void ContextBuilder::closePrefixContext(const QualifiedIdentifier& id) {
  if(id.count() < 2)
    return;
  closeContext();
}