File indexing completed on 2024-04-14 04:31:14

0001 /* This file is part of KDevelop
0002  *
0003  * Copyright (C) 2011-2015 Miquel Sabaté Solà <mikisabate@gmail.com>
0004  *
0005  * This program is free software: you can redistribute it and/or modify
0006  * it under the terms of the GNU General Public License as published by
0007  * the Free Software Foundation, either version 3 of the License, or
0008  * (at your option) any later version.
0009  *
0010  * This program is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013  * GNU General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU General Public License
0016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0017  */
0018 
0019 #include <parser/astvisitor.h>
0020 #include <parserdebug.h>
0021 
0022 /*
0023  * Note that each visitor method has a comment that explains how the AST
0024  * is structured for the specific statement. Only the following attributes
0025  * will be considered: l, r, cond and ensure. If any of these pointers are not
0026  * specified, it means that its value is just nullptr.
0027  */
0028 
0029 using namespace ruby;
0030 
0031 AstVisitor::~AstVisitor()
0032 {
0033 }
0034 
0035 void AstVisitor::visitCode(Ast *node)
0036 {
0037     qCDebug(PARSER) << "Visiting Code...";
0038     Node *aux = node->tree;
0039 
0040     for (Node *n = aux; n; n = n->next) {
0041         visitNode(node);
0042         node->tree = n->next;
0043     }
0044     node->tree = aux;
0045 }
0046 
0047 void AstVisitor::visitName(Ast *node)
0048 {
0049     Q_UNUSED(node)
0050 }
0051 
0052 void AstVisitor::visitNumeric(Ast *node)
0053 {
0054     Q_UNUSED(node)
0055 }
0056 
0057 void AstVisitor::visitRegexp(Ast *node)
0058 {
0059     Q_UNUSED(node)
0060 }
0061 
0062 void AstVisitor::visitString(Ast *node)
0063 {
0064     /*
0065      * l -> list of variables contained inside the string (by using #{var}).
0066      */
0067 
0068     Node *n = node->tree;
0069     node->tree = n->l;
0070     visitStatements(node);
0071     node->tree = n;
0072 }
0073 
0074 void AstVisitor::visitSymbol(Ast *node)
0075 {
0076     Q_UNUSED(node)
0077 }
0078 
0079 void AstVisitor::visitBody(Ast *node)
0080 {
0081     /*
0082      * l -> list of inner statements.
0083      * r -> optional rescue statement.
0084      * cond -> optional else statement.
0085      * ensure -> optional ensure statement.
0086      */
0087 
0088     Node *n = node->tree;
0089     if (!n) {
0090         return;
0091     }
0092 
0093     node->tree = n->l;
0094     visitStatements(node);
0095     node->tree = n->r;
0096     visitNode(node);
0097     node->tree = n->cond;
0098     visitNode(node);
0099     node->tree = n->ensure;
0100     visitNode(node);
0101     node->tree = n;
0102 }
0103 
0104 void AstVisitor::visitBinary(Ast *node)
0105 {
0106     /*
0107      * l -> left operator.
0108      * r -> right operator.
0109      */
0110 
0111     Node *n = node->tree;
0112     node->tree = n->l;
0113     visitNode(node);
0114     node->tree = n->r;
0115     visitNode(node);
0116     node->tree = n;
0117 }
0118 
0119 void AstVisitor::visitBoolean(Ast *node)
0120 {
0121     /* Same as for the visitBinary method  */
0122 
0123     Node *n = node->tree;
0124     node->tree = n->l;
0125     visitNode(node);
0126     node->tree = n->r;
0127     visitNode(node);
0128     node->tree = n;
0129 }
0130 
0131 void AstVisitor::visitRange(Ast *node)
0132 {
0133     /* Same as for the visitBinary method  */
0134 
0135     Node *n = node->tree;
0136     node->tree = n->l;
0137     visitNode(node);
0138     node->tree = n->r;
0139     visitNode(node);
0140     node->tree = n;
0141 }
0142 
0143 void AstVisitor::visitUnary(Ast *node)
0144 {
0145     /*
0146      * l -> the operator.
0147      */
0148 
0149     Node *n = node->tree;
0150     node->tree = n->l;
0151     visitNode(node);
0152     node->tree = n;
0153 }
0154 
0155 void AstVisitor::visitArray(Ast *node)
0156 {
0157     /*
0158      * l -> list of statements (the items of the array).
0159      */
0160 
0161     Node *n = node->tree;
0162     node->tree = n->l;
0163     visitStatements(node);
0164     node->tree = n;
0165 }
0166 
0167 void AstVisitor::visitArrayValue(Ast *node)
0168 {
0169     /*
0170      * l -> the node containing the Array object.
0171      * r -> the index expression.
0172      */
0173 
0174     Node *n = node->tree;
0175     node->tree = n->l;
0176     visitNode(node);
0177     node->tree = n->r;
0178     visitStatements(node);
0179     node->tree = n;
0180 }
0181 
0182 void AstVisitor::visitHash(Ast *node)
0183 {
0184     /*
0185      * l -> list of hash items.
0186      */
0187 
0188     Node *n = node->tree;
0189     node->tree = n->l;
0190     for (; node->tree != nullptr; node->tree = node->tree->next) {
0191         visitBinary(node);
0192     }
0193     node->tree = n;
0194 }
0195 
0196 void AstVisitor::visitReturnStatement(Ast *node)
0197 {
0198     /*
0199      * l -> the return expression.
0200      */
0201 
0202     Node *n = node->tree;
0203     node->tree = n->l;
0204     visitNode(node);
0205     node->tree = n;
0206 }
0207 
0208 void AstVisitor::visitUndefStatement(Ast *node)
0209 {
0210     /*
0211      * r -> list of undef items.
0212      */
0213 
0214     Node *n = node->tree;
0215     node->tree = n->r;
0216     visitStatements(node);
0217     node->tree = n;
0218 }
0219 
0220 void AstVisitor::visitAliasStatement(Ast *node)
0221 {
0222     /* Same as for the visitBinary method. */
0223 
0224     Node *n = node->tree;
0225     node->tree = n->l;
0226     visitNode(node);
0227     node->tree = n->r;
0228     visitNode(node);
0229     node->tree = n;
0230 }
0231 
0232 void AstVisitor::visitYieldStatement(Ast *node)
0233 {
0234     /*
0235      * l -> the yield expression.
0236      */
0237     Node *n = node->tree;
0238     node->tree = n->l;
0239     visitNode(node);
0240     node->tree = n;
0241 }
0242 
0243 void AstVisitor::visitAssignmentStatement(Ast *node)
0244 {
0245     /*
0246      * l -> the left side of the assignment.
0247      * r -> the right side of the assignment.
0248      */
0249 
0250     Node *n = node->tree;
0251     node->tree = n->l;
0252     visitStatements(node);
0253     node->tree = n->r;
0254     visitStatements(node);
0255     node->tree = n;
0256 }
0257 
0258 void AstVisitor::visitIfStatement(Ast *node)
0259 {
0260     /*
0261      * l -> list of inner statements.
0262      * r -> the "tail": optional list of elsif's and an optional else.
0263      * cond -> the condition expression.
0264      */
0265 
0266     Node *n = node->tree;
0267     node->tree = n->cond;
0268     visitNode(node);
0269     node->tree = n->l;
0270     visitStatements(node);
0271     node->tree = n->r;
0272     visitIfTail(node);
0273     node->tree = n;
0274 }
0275 
0276 void AstVisitor::visitCaseStatement(Ast *node)
0277 {
0278     /*
0279      * l -> the case body: list of when statements and an optional else
0280      * statement at the end.
0281      * cond -> the condition expression.
0282      */
0283 
0284     Node *n = node->tree;
0285     node->tree = n->cond;
0286     visitNode(node);
0287     node->tree = n->l;
0288     visitWhenStatements(node);
0289     node->tree = n;
0290 }
0291 
0292 void AstVisitor::visitBeginStatement(Ast *node)
0293 {
0294     /*
0295      * l -> the body of the begin statement. Note that this body is not just
0296      * a list of "regular" statement, check the visitBody method for more info.
0297      */
0298 
0299     Node *n = node->tree;
0300     node->tree = n->l;
0301     visitBody(node);
0302     node->tree = n;
0303 }
0304 
0305 void AstVisitor::visitUpBeginEndStatement(Ast *node)
0306 {
0307     /*
0308      * l -> list of inner statements.
0309      */
0310 
0311     Node *n = node->tree;
0312     node->tree = n->l;
0313     visitStatements(node);
0314     node->tree = n;
0315 }
0316 
0317 void AstVisitor::visitWhileStatement(Ast *node)
0318 {
0319     /*
0320      * l -> list of inner statements.
0321      * cond -> the condition expression.
0322      */
0323 
0324     Node *n = node->tree;
0325     node->tree = n->cond;
0326     visitNode(node);
0327     node->tree = n->l;
0328     visitStatements(node);
0329     node->tree = n;
0330 }
0331 
0332 void AstVisitor::visitForStatement(Ast *node)
0333 {
0334     /*
0335      * l -> list of inner statements.
0336      * r -> list of variables declared before the "in" keyword.
0337      * cond -> the expression after the "in" keyword.
0338      */
0339 
0340     Node *n = node->tree;
0341     node->tree = n->r;
0342     visitStatements(node);
0343     node->tree = n->cond;
0344     visitNode(node);
0345     node->tree = n->l;
0346     visitStatements(node);
0347     node->tree = n;
0348 }
0349 
0350 void AstVisitor::visitMethodStatement(Ast *node)
0351 {
0352     /*
0353      * l -> list of inner statements.
0354      * r -> list of method arguments.
0355      */
0356 
0357     Node *n = node->tree;
0358     if (!n) {
0359         return;
0360     }
0361 
0362     node->tree = n->r;
0363     visitMethodArguments(node);
0364     node->tree = n->l;
0365     visitBody(node);
0366     node->tree = n;
0367 }
0368 
0369 void AstVisitor::visitMethodArguments(Ast *node)
0370 {
0371     /* Just iterate over the "next" pointer. */
0372 
0373     Node *aux = node->tree;
0374     for (Node *n = aux; n != nullptr; n = n->next) {
0375         visitParameter(node);
0376         node->tree = n->next;
0377     }
0378     node->tree = aux;
0379 }
0380 
0381 void AstVisitor::visitParameter(Ast *node)
0382 {
0383     Q_UNUSED(node)
0384 }
0385 
0386 void AstVisitor::visitClassStatement(Ast *node)
0387 {
0388     /*
0389      * l -> the body of the class statement. Note that this body is not just
0390      * a list of "regular" statement, check the visitBody method for more info.
0391      * r -> the name of the class.
0392      * cond -> the superclass node.
0393      */
0394 
0395     Node *n = node->tree;
0396     node->tree = n->cond;
0397     visitNode(node);
0398     node->tree = n->l;
0399     visitBody(node);
0400     node->tree = n->r;
0401     visitClassName(node);
0402     node->tree = n;
0403 }
0404 
0405 void AstVisitor::visitSingletonClass(Ast *node)
0406 {
0407     /*
0408      * l -> the body of the class statement. Note that this body is not just
0409      * a list of "regular" statement, check the visitBody method for more info.
0410      * r -> the expression after the lshift ("<<") operator.
0411      */
0412 
0413     Node *n = node->tree;
0414     node->tree = n->l;
0415     visitBody(node);
0416     node->tree = n->r;
0417     visitNode(node);
0418     node->tree = n;
0419 }
0420 
0421 void AstVisitor::visitModuleStatement(Ast *node)
0422 {
0423     /*
0424      * l -> the body of the class statement. Note that this body is not just
0425      * a list of "regular" statement, check the visitBody method for more info.
0426      * r -> the name of the module.
0427      */
0428 
0429     Node *n = node->tree;
0430     node->tree = n->l;
0431     visitBody(node);
0432     node->tree = n->r;
0433     visitClassName(node);
0434     node->tree = n;
0435 }
0436 
0437 void AstVisitor::visitMethodCall(Ast *node)
0438 {
0439     /*
0440      * l -> the caller (note that it's a list, i.e. A::B::foo).
0441      * r -> the arguments for this method call.
0442      * cond -> an optional Ruby block.
0443      */
0444 
0445     /*
0446      * Note that the l pointer can contain again another method call.
0447      * This happens for example here:
0448      *  Class.new { def foo(a, b); end }.new.foo(1, 2)
0449      * In order to get everything straight, all builders end up
0450      * re-implementing this method. This is why this method has no
0451      * implementation by default.
0452      */
0453     Q_UNUSED(node);
0454 }
0455 
0456 void AstVisitor::visitSuper(Ast *node)
0457 {
0458     /*
0459      * r -> the arguments passed to the super call.
0460      */
0461 
0462     Node *n = node->tree;
0463     node->tree = n->r;
0464     for (Node *aux = n->r; aux != nullptr; aux = aux->next) {
0465         visitNode(node);
0466         node->tree = aux->next;
0467     }
0468     node->tree = n;
0469 }
0470 
0471 void AstVisitor::visitLambda(Ast *node)
0472 {
0473     /*
0474      * cond -> the block of this lambda expression.
0475      */
0476 
0477     Node *n = node->tree;
0478     node->tree = n->cond;
0479     visitBlock(node);
0480     node->tree = n;
0481 }
0482 
0483 void AstVisitor::visitBlock(Ast *node)
0484 {
0485     /*
0486      * l -> list of inner statements.
0487      * r -> list of block variables.
0488      */
0489 
0490     Node *aux = node->tree;
0491     if (!aux) {
0492         return;
0493     }
0494     node->tree = aux->r;
0495     visitBlockVariables(node);
0496     node->tree = aux->l;
0497     visitStatements(node);
0498     node->tree = aux;
0499 }
0500 
0501 void AstVisitor::visitBlockVariables(Ast *node)
0502 {
0503     /*
0504      * Just iterate over the next pointer.
0505      */
0506 
0507     Node *aux = node->tree;
0508     for (Node *n = node->tree; n != nullptr; n = n->next) {
0509         visitNode(node);
0510         node->tree = n->next;
0511     }
0512     node->tree = aux;
0513 }
0514 
0515 void AstVisitor::visitRequire(Ast *node, bool relative)
0516 {
0517     Q_UNUSED(node)
0518     Q_UNUSED(relative)
0519 }
0520 
0521 void AstVisitor::visitMixin(Ast *node, bool include)
0522 {
0523     Q_UNUSED(node);
0524     Q_UNUSED(include);
0525 }
0526 
0527 void AstVisitor::visitDefined(Ast *node)
0528 {
0529     /*
0530      * l -> the expression from the "defined" statement.
0531      */
0532 
0533     Node *n = node->tree;
0534     node->tree = n->l;
0535     visitNode(node);
0536     node->tree = n;
0537 }
0538 
0539 void AstVisitor::visitTrue(Ast *node)
0540 {
0541     Q_UNUSED(node)
0542 }
0543 
0544 void AstVisitor::visitFalse(Ast *node)
0545 {
0546     Q_UNUSED(node)
0547 }
0548 
0549 void AstVisitor::visitNil(Ast *node)
0550 {
0551     Q_UNUSED(node)
0552 }
0553 
0554 void AstVisitor::visitFile(Ast *node)
0555 {
0556     Q_UNUSED(node)
0557 }
0558 
0559 void AstVisitor::visitLine(Ast *node)
0560 {
0561     Q_UNUSED(node)
0562 }
0563 
0564 void AstVisitor::visitEncoding(Ast *node)
0565 {
0566     Q_UNUSED(node)
0567 }
0568 
0569 void AstVisitor::visitSelf(Ast *node)
0570 {
0571     Q_UNUSED(node)
0572 }
0573 
0574 void AstVisitor::visitAccessSpecifier(const access_t policy)
0575 {
0576     Q_UNUSED(policy)
0577 }
0578 
0579 void AstVisitor::visitClassName(Ast *node)
0580 {
0581     Q_UNUSED(node);
0582 }
0583 
0584 void AstVisitor::visitRescue(Ast *node)
0585 {
0586     /*
0587      * l -> rescue arg.
0588      * r -> list of inner statement.
0589      */
0590 
0591     Node *n = node->tree;
0592     node->tree = n->l;
0593     visitNode(node);
0594     node->tree = n->r;
0595     visitStatements(node);
0596     node->tree = n;
0597 }
0598 
0599 void AstVisitor::visitRescueArg(Ast *node)
0600 {
0601     /*
0602      * l -> Left part of the rescue argument, could be a list.
0603      * r -> Right part of the rescue argument, only the DeclarationBuilder
0604      * wants to access this part.
0605      */
0606 
0607     Node *n = node->tree;
0608     node->tree = n->l;
0609     visitStatements(node);
0610     node->tree = n;
0611 }
0612 
0613 void AstVisitor::visitEnsure(Ast *node)
0614 {
0615     /*
0616      * l -> The inner statements.
0617      */
0618 
0619     Node *n = node->tree;
0620     node->tree = n->l;
0621     visitStatements(node);
0622     node->tree = n;
0623 }
0624 
0625 void AstVisitor::visitNode(Ast *node)
0626 {
0627     QByteArray name;
0628     Node *n = node->tree;
0629 
0630     /* This is not a valid node */
0631     if (!n || n->kind == token_invalid) {
0632         return;
0633     }
0634     switch (n->kind) {
0635         case token_return: visitReturnStatement(node); break;
0636         case token_yield: visitYieldStatement(node); break;
0637         case token_alias: visitAliasStatement(node); break;
0638         case token_undef: visitUndefStatement(node); break;
0639         case token_if: case token_unless: case token_ternary:
0640           visitIfStatement(node);
0641           break;
0642         case token_begin: visitBeginStatement(node); break;
0643         case token_up_begin:
0644         case token_up_end: visitUpBeginEndStatement(node); break;
0645         case token_case: visitCaseStatement(node); break;
0646         case token_while: case token_until: visitWhileStatement(node); break;
0647         case token_for: visitForStatement(node); break;
0648         case token_class: visitClassStatement(node); break;
0649         case token_singleton_class: visitSingletonClass(node); break;
0650         case token_module: visitModuleStatement(node); break;
0651         case token_function: visitMethodStatement(node); break;
0652         case token_super: visitSuper(node); break;
0653         case token_method_call: checkMethodCall(node); break;
0654         case token_assign:
0655         case token_op_assign: visitAssignmentStatement(node); break;
0656         case token_object:
0657             name = QByteArray(node->tree->name);
0658             if (name == "public") {
0659                 if (declaredInContext(name)) {
0660                     visitName(node);
0661                 } else {
0662                     visitAccessSpecifier(public_a);
0663                 }
0664             } else if (name == "protected") {
0665                 if (declaredInContext(name)) {
0666                     visitName(node);
0667                 } else {
0668                     visitAccessSpecifier(protected_a);
0669                 }
0670             } else if (name == "private") {
0671                 if (declaredInContext(name)) {
0672                     visitName(node);
0673                 } else {
0674                     visitAccessSpecifier(private_a);
0675                 }
0676             } else {
0677                 visitName(node);
0678             }
0679             break;
0680         case token_hash: visitHash(node); break;
0681         case token_array: visitArray(node); break;
0682         case token_array_value: visitArrayValue(node); break;
0683         case token_defined: visitDefined(node); break;
0684         case token_unary_plus: case token_unary_minus: case token_neg:
0685         case token_not:
0686             visitUnary(node);
0687             break;
0688         case token_plus: case token_minus: case token_mul: case token_div:
0689         case token_mod: case token_lshift: case token_rshift: case token_pow:
0690             visitBinary(node);
0691             break;
0692         case token_dot2: case token_dot3:
0693             visitRange(node);
0694             break;
0695         case token_cmp: case token_eq: case token_eqq: case token_match:
0696         case token_nmatch: case token_greater: case  token_geq:
0697         case token_lesser:  case token_leq:
0698         case token_or: case token_and: case token_kw_and:
0699         case token_kw_not: case token_kw_or:
0700             visitBoolean(node);
0701             break;
0702         case token_numeric: visitNumeric(node); break;
0703         case token_string: case token_heredoc: visitString(node); break;
0704         case token_regexp: visitRegexp(node); break;
0705         case token_nil: visitNil(node); break;
0706         case token_true: visitTrue(node); break;
0707         case token_false: visitFalse(node); break;
0708         case token_line: visitLine(node); break;
0709         case token_file: visitFile(node); break;
0710         case token_encoding: visitEncoding(node); break;
0711         case token_self: visitSelf(node); break;
0712         case token_symbol: case token_key: visitSymbol(node); break;
0713         case token_rescue: visitRescue(node); break;
0714         case token_rescue_arg: visitRescueArg(node); break;
0715         case token_ensure: visitEnsure(node); break;
0716         case token_break: case token__end__: case token_next:
0717         case token_redo: case token_retry:
0718             return;
0719     }
0720 }
0721 
0722 void AstVisitor::visitStatements(Ast *list)
0723 {
0724     Node *aux = list->tree;
0725     for (Node *n = aux; n; n = n->next) {
0726         visitNode(list);
0727         list->tree = n->next;
0728     }
0729     list->tree = aux;
0730 }
0731 
0732 void AstVisitor::visitIfTail(Ast *tail)
0733 {
0734     Node *n = tail->tree;
0735     if (!n) {
0736         return;
0737     }
0738 
0739     /* Check if this is an elsif or an else statement */
0740     if (!n->cond) {
0741         tail->tree = n->l;
0742         visitStatements(tail);
0743     } else {
0744         visitIfStatement(tail);
0745     }
0746     tail->tree = n;
0747 }
0748 
0749 void AstVisitor::visitWhenStatements(Ast *list)
0750 {
0751     Node *n = list->tree;
0752     if (!n) {
0753         return;
0754     }
0755 
0756     /* Check whether this is a when or an else statement */
0757     if (n->kind == token_when) {
0758         list->tree = n->cond;
0759         visitStatements(list);
0760         list->tree = n->l;
0761         visitStatements(list);
0762         list->tree = n->r;
0763         visitWhenStatements(list);
0764     } else {
0765         list->tree = n->l;
0766         visitStatements(list);
0767     }
0768     list->tree = n;
0769 }
0770 
0771 void AstVisitor::checkMethodCall(Ast *mc)
0772 {
0773     /*
0774      * The method call body resides in the left child. Check if this
0775      * is either a require, an include/extend or just a normal method call.
0776      * If the left child is nullptr, this is not a method call but a lambda
0777      * expression.
0778      */
0779     if (mc->tree->l) {
0780         const QByteArray &name = QByteArray(mc->tree->l->name);
0781         if (name == "require") {
0782             (declaredInContext(name)) ? visitMethodCall(mc) : visitRequire(mc);
0783         } else if (name == "include") {
0784             (declaredInContext(name)) ? visitMethodCall(mc) : visitMixin(mc, true);
0785         } else if (name == "extend") {
0786             (declaredInContext(name)) ? visitMethodCall(mc) : visitMixin(mc, false);
0787         } else if (name == "require_relative") {
0788             (declaredInContext(name)) ? visitMethodCall(mc) : visitRequire(mc, true);
0789         } else if (name == "lambda") {
0790             (declaredInContext(name)) ? visitMethodCall(mc) : visitLambda(mc);
0791         } else {
0792             visitMethodCall(mc);
0793         }
0794     } else {
0795         visitLambda(mc);
0796     }
0797 }
0798