File indexing completed on 2024-05-19 15:46:45

0001 /*
0002     SPDX-FileCopyrightText: 2013 Andrea Scarpino <scarpino@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "usebuilder.h"
0008 #include "expressionvisitor.h"
0009 
0010 #include "helper.h"
0011 #include "parsesession.h"
0012 
0013 using namespace KDevelop;
0014 
0015 UseBuilder::UseBuilder(ParseSession* session)
0016 : UseBuilderBase()
0017 {
0018     m_session = session;
0019     m_nodesThatOpenedContexts.push(nullptr);    // One push here, a thousand isEmpty() calls avoided later
0020 }
0021 
0022 bool UseBuilder::preVisit(QmlJS::AST::Node* node)
0023 {
0024     DUContext* ctx = contextFromNode(node);
0025 
0026     if (ctx && currentContext() != ctx) {
0027         openContext(ctx);
0028         m_nodesThatOpenedContexts.push(node);
0029     }
0030 
0031     return true;
0032 }
0033 
0034 void UseBuilder::postVisit(QmlJS::AST::Node* node)
0035 {
0036     if (m_nodesThatOpenedContexts.top() == node) {
0037         closeContext();
0038         m_nodesThatOpenedContexts.pop();
0039     }
0040 }
0041 
0042 bool UseBuilder::visit(QmlJS::AST::FieldMemberExpression* node)
0043 {
0044     useForExpression(node, m_session->locationToRange(node->identifierToken));
0045     return UseBuilderBase::visit(node);
0046 }
0047 
0048 bool UseBuilder::visit(QmlJS::AST::IdentifierExpression* node)
0049 {
0050     useForExpression(node);
0051     return UseBuilderBase::visit(node);
0052 }
0053 
0054 bool UseBuilder::visit(QmlJS::AST::UiQualifiedId* node)
0055 {
0056     useForExpression(node);
0057     return false;
0058 }
0059 
0060 bool UseBuilder::visit(QmlJS::AST::UiImport* node)
0061 {
0062     Q_UNUSED(node);
0063     return false;   // Don't highlight the identifiers that appear in import statements
0064 }
0065 
0066 bool UseBuilder::visit(QmlJS::AST::UiScriptBinding* node)
0067 {
0068     QString propertyName = node->qualifiedId->name.toString();
0069 
0070     if (propertyName == QLatin1String("name") ||
0071         propertyName == QLatin1String("type") ||
0072         propertyName == QLatin1String("exports") ||
0073         propertyName == QLatin1String("prototype")) {
0074         // Ignore plugin.qmltypes-specific property names. They appear a huge
0075         // number of time and are never declared anywhere.
0076         return false;
0077     }
0078 
0079     return true;
0080 }
0081 
0082 bool UseBuilder::visit(QmlJS::AST::UiPublicMember* node)
0083 {
0084     // node->memberType can contain a type name (if node is a property), use it
0085     DeclarationPointer decl = QmlJS::getDeclaration(
0086         QualifiedIdentifier(node->memberTypeName().toString()),
0087         currentContext()
0088     );
0089 
0090     newUse(
0091         m_session->locationToRange(node->typeToken),
0092         decl
0093     );
0094 
0095     return true;
0096 }
0097 
0098 void UseBuilder::useForExpression(QmlJS::AST::Node* node, const KDevelop::RangeInRevision &range)
0099 {
0100     // ExpressionVisitor can find the type and corresponding declaration of many
0101     // kinds of expressions (identifiers, field members, special identifiers like
0102     // this or parent, etc).
0103     ExpressionVisitor visitor(currentContext());
0104 
0105     node->accept(&visitor);
0106 
0107     if (visitor.lastDeclaration()) {
0108         newUse(
0109             range.isValid() ? range : m_session->locationsToRange(
0110                 node->firstSourceLocation(),
0111                 node->lastSourceLocation()
0112             ),
0113             visitor.lastDeclaration()
0114         );
0115     }
0116 }