bool ExpressionVisitor::encounterParent(const QString& declaration) { if (declaration != QLatin1String("parent") || !QmlJS::isQmlFile(m_context)) { return false; } // Go up until we find a class context (the enclosing QML component) const DUContext* parent = m_context; Declaration* owner; while (parent && parent->type() != DUContext::Class) { parent = parent->parentContext(); } // Take the parent context of the current QML component, it is its parent // component if (parent) { parent = parent->parentContext(); } // Parent now points to the parent QML component. This is not always what // the user wants when typing "parent", but already works well for // "anchors.centerIn: parent" and things like that. if (parent && (owner = QmlJS::getOwnerOfContext(parent)) && owner->abstractType()) { encounterLvalue(DeclarationPointer(owner)); instantiateCurrentDeclaration(); return true; } return false; }
bool ExpressionVisitor::visit(QmlJS::AST::ThisExpression* node) { Q_UNUSED(node) DUChainReadLocker lock; DUContext* paramsContext; DUContext* internalContext; Declaration* owner; // "this" points to the current function (not semantically valid in JS, // but this allows ExpressionVisitor to see the declarations of the // function's prototype) if (m_context->type() == DUContext::Other && // Code of the function (paramsContext = m_context->parentContext()) && // Parameters of the function (this context has the function as owner) (owner = QmlJS::getOwnerOfContext(paramsContext)) && // The function itself (owner of its parameters) (internalContext = QmlJS::getInternalContext(DeclarationPointer(owner))) && // The prototype context of the function (owner = QmlJS::getOwnerOfContext(internalContext)) && // The function that declared the prototype context (paramsContext may belong to a method of a class) owner->abstractType()) { encounterLvalue(DeclarationPointer(owner)); instantiateCurrentDeclaration(); } else { encounterNothing(); } return false; }
QString DUChainItemData::text() const { DUChainReadLocker lock;; Declaration* decl = m_item.m_item.data(); if(!decl) return i18n("Not available any more: %1", m_item.m_text); if(FunctionDefinition* def = dynamic_cast<FunctionDefinition*>(decl)) { if(def->declaration()) { decl = def->declaration(); } } QString text = decl->qualifiedIdentifier().toString(); if(!decl->abstractType()) { //With simplified representation, still mark functions as such by adding parens if(dynamic_cast<AbstractFunctionDeclaration*>(decl)) { text += QLatin1String("(...)"); } }else if(TypePtr<FunctionType> function = decl->type<FunctionType>()) { text += function->partToString( FunctionType::SignatureArguments ); } return text; }
//Returns only the name, no template-parameters or scope QString cursorItemText() { KDevelop::DUChainReadLocker lock( DUChain::lock() ); Declaration* decl = cursorDeclaration(); if(!decl) return QString(); IDocument* doc = ICore::self()->documentController()->activeDocument(); if(!doc) return QString(); TopDUContext* context = DUChainUtils::standardContextForUrl( doc->url() ); if( !context ) { qCDebug(PLUGIN_QUICKOPEN) << "Got no standard context"; return QString(); } AbstractType::Ptr t = decl->abstractType(); IdentifiedType* idType = dynamic_cast<IdentifiedType*>(t.data()); if( idType && idType->declaration(context) ) decl = idType->declaration(context); if(!decl->qualifiedIdentifier().isEmpty()) return decl->qualifiedIdentifier().last().identifier().str(); return QString(); }
void TestDUChainMultipleFiles::testForeachImportedIdentifier() { // see https://bugs.kde.org/show_bug.cgi?id=269369 TopDUContext::Features features = TopDUContext::VisibleDeclarationsAndContexts; TestProject* project = new TestProject; m_projectController->clearProjects(); m_projectController->addProject(project); // build dependency TestFile f1("<? class SomeIterator implements Countable, Iterator { }", "php", project); f1.parse(features); f1.waitForParsed(); TestFile f2("<?\n" "class A {\n" " public function foo() { $i = $this->bar(); foreach($i as $a => $b) {} } \n" " public function bar() { $a = new SomeIterator(); return $a; }\n" " }\n", "php", project); for(int i = 0; i < 2; ++i) { if (i > 0) { features = static_cast<TopDUContext::Features>(features | TopDUContext::ForceUpdate); } f2.parse(features); f2.waitForParsed(); QTest::qWait(100); DUChainWriteLocker lock(DUChain::lock()); DUContext* ACtx = f2.topContext()->childContexts().first(); QVERIFY(ACtx); Declaration* iDec = ACtx->childContexts().at(1)->localDeclarations().first(); QVERIFY(iDec); Declaration* SomeIteratorDec = f1.topContext()->localDeclarations().first(); QVERIFY(SomeIteratorDec); if (i == 0) { QEXPECT_FAIL("", "needs a full two-pass (i.e. get rid of PreDeclarationBuilder)", Continue); } QVERIFY(iDec->abstractType()->equals(SomeIteratorDec->abstractType().constData())); QVERIFY(f2.topContext()->imports(f1.topContext(), CursorInRevision(0, 0))); } }
void ExpressionVisitor::encounterObjectAtLocation(const QmlJS::AST::SourceLocation& location) { DUChainReadLocker lock; // Find the anonymous declaration corresponding to the function. This is // the owner of the current context (function expressions create new contexts) Declaration* dec = QmlJS::getOwnerOfContext(m_context->topContext()->findContextAt( CursorInRevision(location.startLine-1, location.startColumn) )); if (dec && dec->abstractType()) { encounterLvalue(DeclarationPointer(dec)); } else { encounterNothing(); } }
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); } }
void AliasDeclaration::setAliasedDeclaration(const IndexedDeclaration& decl) { d_func_dynamic()->m_aliasedDeclaration = decl; Declaration* aliased = decl.data(); if(aliased) Declaration::setAbstractType(aliased->abstractType()); }