LCOV - code coverage report
Current view: top level - js/src/frontend - NameFunctions.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 258 369 69.9 %
Date: 2017-07-14 16:53:18 Functions: 11 13 84.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "frontend/NameFunctions.h"
       8             : 
       9             : #include "mozilla/Sprintf.h"
      10             : 
      11             : #include "jsfun.h"
      12             : #include "jsprf.h"
      13             : 
      14             : #include "frontend/BytecodeCompiler.h"
      15             : #include "frontend/ParseNode.h"
      16             : #include "frontend/SharedContext.h"
      17             : #include "vm/StringBuffer.h"
      18             : 
      19             : using namespace js;
      20             : using namespace js::frontend;
      21             : 
      22             : namespace {
      23             : 
      24             : class NameResolver
      25             : {
      26             :     static const size_t MaxParents = 100;
      27             : 
      28             :     JSContext* cx;
      29             :     size_t nparents;                /* number of parents in the parents array */
      30             :     ParseNode* parents[MaxParents]; /* history of ParseNodes we've been looking at */
      31             :     StringBuffer* buf;              /* when resolving, buffer to append to */
      32             : 
      33             :     /* Test whether a ParseNode represents a function invocation */
      34        7622 :     bool call(ParseNode* pn) {
      35        7622 :         return pn && pn->isKind(PNK_CALL);
      36             :     }
      37             : 
      38             :     /*
      39             :      * Append a reference to a property named |name| to |buf|. If |name| is
      40             :      * a proper identifier name, then we append '.name'; otherwise, we
      41             :      * append '["name"]'.
      42             :      *
      43             :      * Note that we need the IsIdentifier check for atoms from both
      44             :      * PNK_NAME nodes and PNK_STRING nodes: given code like a["b c"], the
      45             :      * front end will produce a PNK_DOT with a PNK_NAME child whose name
      46             :      * contains spaces.
      47             :      */
      48         180 :     bool appendPropertyReference(JSAtom* name) {
      49         180 :         if (IsIdentifier(name))
      50         180 :             return buf->append('.') && buf->append(name);
      51             : 
      52             :         /* Quote the string as needed. */
      53           0 :         JSString* source = QuoteString(cx, name, '"');
      54           0 :         return source && buf->append('[') && buf->append(source) && buf->append(']');
      55             :     }
      56             : 
      57             :     /* Append a number to buf. */
      58           0 :     bool appendNumber(double n) {
      59             :         char number[30];
      60           0 :         int digits = SprintfLiteral(number, "%g", n);
      61           0 :         return buf->append(number, digits);
      62             :     }
      63             : 
      64             :     /* Append "[<n>]" to buf, referencing a property named by a numeric literal. */
      65           0 :     bool appendNumericPropertyReference(double n) {
      66           0 :         return buf->append("[") && appendNumber(n) && buf->append(']');
      67             :     }
      68             : 
      69             :     /*
      70             :      * Walk over the given ParseNode, attempting to convert it to a stringified
      71             :      * name that respresents where the function is being assigned to.
      72             :      *
      73             :      * |*foundName| is set to true if a name is found for the expression.
      74             :      */
      75         467 :     bool nameExpression(ParseNode* n, bool* foundName) {
      76         467 :         switch (n->getKind()) {
      77             :           case PNK_DOT:
      78         170 :             if (!nameExpression(n->expr(), foundName))
      79           0 :                 return false;
      80         170 :             if (!*foundName)
      81           0 :                 return true;
      82         170 :             return appendPropertyReference(n->pn_atom);
      83             : 
      84             :           case PNK_NAME:
      85         233 :             *foundName = true;
      86         233 :             return buf->append(n->pn_atom);
      87             : 
      88             :           case PNK_THIS:
      89          58 :             *foundName = true;
      90          58 :             return buf->append("this");
      91             : 
      92             :           case PNK_ELEM:
      93           5 :             if (!nameExpression(n->pn_left, foundName))
      94           0 :                 return false;
      95           5 :             if (!*foundName)
      96           0 :                 return true;
      97           5 :             if (!buf->append('[') || !nameExpression(n->pn_right, foundName))
      98           0 :                 return false;
      99           5 :             if (!*foundName)
     100           0 :                 return true;
     101           5 :             return buf->append(']');
     102             : 
     103             :           case PNK_NUMBER:
     104           0 :             *foundName = true;
     105           0 :             return appendNumber(n->pn_dval);
     106             : 
     107             :           default:
     108             :             /* We're confused as to what to call this function. */
     109           1 :             *foundName = false;
     110           1 :             return true;
     111             :         }
     112             :     }
     113             : 
     114             :     /*
     115             :      * When naming an anonymous function, the process works loosely by walking
     116             :      * up the AST and then translating that to a string. The stringification
     117             :      * happens from some far-up assignment and then going back down the parse
     118             :      * tree to the function definition point.
     119             :      *
     120             :      * This function will walk up the parse tree, gathering relevant nodes used
     121             :      * for naming, and return the assignment node if there is one. The provided
     122             :      * array and size will be filled in, and the returned node could be nullptr
     123             :      * if no assignment is found. The first element of the array will be the
     124             :      * innermost node relevant to naming, and the last element will be the
     125             :      * outermost node.
     126             :      */
     127         912 :     ParseNode* gatherNameable(ParseNode** nameable, size_t* size) {
     128         912 :         *size = 0;
     129             : 
     130        4295 :         for (int pos = nparents - 1; pos >= 0; pos--) {
     131        4083 :             ParseNode* cur = parents[pos];
     132        4083 :             if (cur->isAssignment())
     133         182 :                 return cur;
     134             : 
     135        3901 :             switch (cur->getKind()) {
     136         105 :               case PNK_NAME:     return cur;  /* found the initialized declaration */
     137           0 :               case PNK_THIS:     return cur;  /* Setting a property of 'this'. */
     138         413 :               case PNK_FUNCTION: return nullptr; /* won't find an assignment or declaration */
     139             : 
     140             :               case PNK_RETURN:
     141             :                 /*
     142             :                  * Normally the relevant parent of a node is its direct parent, but
     143             :                  * sometimes with code like:
     144             :                  *
     145             :                  *    var foo = (function() { return function() {}; })();
     146             :                  *
     147             :                  * the outer function is just a helper to create a scope for the
     148             :                  * returned function. Hence the name of the returned function should
     149             :                  * actually be 'foo'.  This loop sees if the current node is a
     150             :                  * PNK_RETURN, and if there is a direct function call we skip to
     151             :                  * that.
     152             :                  */
     153        1030 :                 for (int tmp = pos - 1; tmp > 0; tmp--) {
     154         905 :                     if (isDirectCall(tmp, cur)) {
     155           0 :                         pos = tmp;
     156           0 :                         break;
     157         905 :                     } else if (call(cur)) {
     158             :                         /* Don't skip too high in the tree */
     159           9 :                         break;
     160             :                     }
     161         896 :                     cur = parents[tmp];
     162             :                 }
     163         134 :                 break;
     164             : 
     165             :               case PNK_COLON:
     166             :               case PNK_SHORTHAND:
     167             :                 /*
     168             :                  * Record the PNK_COLON/SHORTHAND but skip the PNK_OBJECT so we're not
     169             :                  * flagged as a contributor.
     170             :                  */
     171          10 :                 pos--;
     172             :                 MOZ_FALLTHROUGH;
     173             : 
     174             :               default:
     175             :                 /* Save any other nodes we encounter on the way up. */
     176        3249 :                 MOZ_ASSERT(*size < MaxParents);
     177        3249 :                 nameable[(*size)++] = cur;
     178        3249 :                 break;
     179             :             }
     180             :         }
     181             : 
     182         212 :         return nullptr;
     183             :     }
     184             : 
     185             :     /*
     186             :      * Resolve the name of a function. If the function already has a name
     187             :      * listed, then it is skipped. Otherwise an intelligent name is guessed to
     188             :      * assign to the function's displayAtom field.
     189             :      */
     190        7234 :     bool resolveFun(ParseNode* pn, HandleAtom prefix, MutableHandleAtom retAtom) {
     191        7234 :         MOZ_ASSERT(pn != nullptr);
     192        7234 :         MOZ_ASSERT(pn->isKind(PNK_FUNCTION));
     193        7234 :         MOZ_ASSERT(pn->isArity(PN_CODE));
     194       14468 :         RootedFunction fun(cx, pn->pn_funbox->function());
     195             : 
     196       14468 :         StringBuffer buf(cx);
     197        7234 :         this->buf = &buf;
     198             : 
     199        7234 :         retAtom.set(nullptr);
     200             : 
     201             :         /* If the function already has a name, use that */
     202        7234 :         if (fun->displayAtom() != nullptr) {
     203        6322 :             if (prefix == nullptr) {
     204        5921 :                 retAtom.set(fun->displayAtom());
     205        5921 :                 return true;
     206             :             }
     207        1203 :             if (!buf.append(prefix) ||
     208         802 :                 !buf.append('/') ||
     209         401 :                 !buf.append(fun->displayAtom()))
     210           0 :                 return false;
     211         401 :             retAtom.set(buf.finishAtom());
     212         401 :             return !!retAtom;
     213             :         }
     214             : 
     215             :         /* If a prefix is specified, then it is a form of namespace */
     216         912 :         if (prefix != nullptr && (!buf.append(prefix) || !buf.append('/')))
     217           0 :             return false;
     218             : 
     219             :         /* Gather all nodes relevant to naming */
     220             :         ParseNode* toName[MaxParents];
     221             :         size_t size;
     222         912 :         ParseNode* assignment = gatherNameable(toName, &size);
     223             : 
     224             :         /* If the function is assigned to something, then that is very relevant */
     225         912 :         if (assignment) {
     226         287 :             if (assignment->isAssignment())
     227         182 :                 assignment = assignment->pn_left;
     228         287 :             bool foundName = false;
     229         287 :             if (!nameExpression(assignment, &foundName))
     230           1 :                 return false;
     231         287 :             if (!foundName)
     232           1 :                 return true;
     233             :         }
     234             : 
     235             :         /*
     236             :          * Other than the actual assignment, other relevant nodes to naming are
     237             :          * those in object initializers and then particular nodes marking a
     238             :          * contribution.
     239             :          */
     240        4159 :         for (int pos = size - 1; pos >= 0; pos--) {
     241        3248 :             ParseNode* node = toName[pos];
     242             : 
     243        3248 :             if (node->isKind(PNK_COLON) || node->isKind(PNK_SHORTHAND)) {
     244          10 :                 ParseNode* left = node->pn_left;
     245          10 :                 if (left->isKind(PNK_OBJECT_PROPERTY_NAME) || left->isKind(PNK_STRING)) {
     246          10 :                     if (!appendPropertyReference(left->pn_atom))
     247           0 :                         return false;
     248           0 :                 } else if (left->isKind(PNK_NUMBER)) {
     249           0 :                     if (!appendNumericPropertyReference(left->pn_dval))
     250           0 :                         return false;
     251             :                 } else {
     252           0 :                     MOZ_ASSERT(left->isKind(PNK_COMPUTED_NAME));
     253             :                 }
     254             :             } else {
     255             :                 /*
     256             :                  * Don't have consecutive '<' characters, and also don't start
     257             :                  * with a '<' character.
     258             :                  */
     259        3238 :                 if (!buf.empty() && buf.getChar(buf.length() - 1) != '<' && !buf.append('<'))
     260           0 :                     return false;
     261             :             }
     262             :         }
     263             : 
     264             :         /*
     265             :          * functions which are "genuinely anonymous" but are contained in some
     266             :          * other namespace are rather considered as "contributing" to the outer
     267             :          * function, so give them a contribution symbol here.
     268             :          */
     269         911 :         if (!buf.empty() && buf.getChar(buf.length() - 1) == '/' && !buf.append('<'))
     270           0 :             return false;
     271             : 
     272         911 :         if (buf.empty())
     273         228 :             return true;
     274             : 
     275         683 :         retAtom.set(buf.finishAtom());
     276         683 :         if (!retAtom)
     277           0 :             return false;
     278         683 :         fun->setGuessedAtom(retAtom);
     279         683 :         return true;
     280             :     }
     281             : 
     282             :     /*
     283             :      * Tests whether parents[pos] is a function call whose callee is cur.
     284             :      * This is the case for functions which do things like simply create a scope
     285             :      * for new variables and then return an anonymous function using this scope.
     286             :      */
     287        8139 :     bool isDirectCall(int pos, ParseNode* cur) {
     288        8139 :         return pos >= 0 && call(parents[pos]) && parents[pos]->pn_head == cur;
     289             :     }
     290             : 
     291         252 :     bool resolveTemplateLiteral(ParseNode* node, HandleAtom prefix) {
     292         252 :         MOZ_ASSERT(node->isKind(PNK_TEMPLATE_STRING_LIST));
     293         252 :         ParseNode* element = node->pn_head;
     294         602 :         while (true) {
     295         854 :             MOZ_ASSERT(element->isKind(PNK_TEMPLATE_STRING));
     296             : 
     297         854 :             element = element->pn_next;
     298         854 :             if (!element)
     299         252 :                 return true;
     300             : 
     301         602 :             if (!resolve(element, prefix))
     302           0 :                 return false;
     303             : 
     304         602 :             element = element->pn_next;
     305             :         }
     306             :     }
     307             : 
     308           1 :     bool resolveTaggedTemplate(ParseNode* node, HandleAtom prefix) {
     309           1 :         MOZ_ASSERT(node->isKind(PNK_TAGGED_TEMPLATE));
     310             : 
     311           1 :         ParseNode* element = node->pn_head;
     312             : 
     313             :         // The list head is a leading expression, e.g. |tag| in |tag`foo`|,
     314             :         // that might contain functions.
     315           1 :         if (!resolve(element, prefix))
     316           0 :             return false;
     317             : 
     318             :         // Next is the callsite object node.  This node only contains
     319             :         // internal strings or undefined and an array -- no user-controlled
     320             :         // expressions.
     321           1 :         element = element->pn_next;
     322             : #ifdef DEBUG
     323             :         {
     324           1 :             MOZ_ASSERT(element->isKind(PNK_CALLSITEOBJ));
     325           1 :             ParseNode* array = element->pn_head;
     326           1 :             MOZ_ASSERT(array->isKind(PNK_ARRAY));
     327           4 :             for (ParseNode* kid = array->pn_head; kid; kid = kid->pn_next)
     328           3 :                 MOZ_ASSERT(kid->isKind(PNK_TEMPLATE_STRING));
     329           4 :             for (ParseNode* next = array->pn_next; next; next = next->pn_next)
     330           3 :                 MOZ_ASSERT(next->isKind(PNK_TEMPLATE_STRING) || next->isKind(PNK_RAW_UNDEFINED));
     331             :         }
     332             : #endif
     333             : 
     334             :         // Next come any interpolated expressions in the tagged template.
     335           1 :         ParseNode* interpolated = element->pn_next;
     336           5 :         for (; interpolated; interpolated = interpolated->pn_next) {
     337           2 :             if (!resolve(interpolated, prefix))
     338           0 :                 return false;
     339             :         }
     340             : 
     341           1 :         return true;
     342             :     }
     343             : 
     344             :   public:
     345        1691 :     explicit NameResolver(JSContext* cx) : cx(cx), nparents(0), buf(nullptr) {}
     346             : 
     347             :     /*
     348             :      * Resolve all names for anonymous functions recursively within the
     349             :      * ParseNode instance given. The prefix is for each subsequent name, and
     350             :      * should initially be nullptr.
     351             :      */
     352      389149 :     bool resolve(ParseNode* cur, HandleAtom prefixArg = nullptr) {
     353      778298 :         RootedAtom prefix(cx, prefixArg);
     354      389149 :         if (cur == nullptr)
     355       83907 :             return true;
     356             : 
     357      305242 :         MOZ_ASSERT((cur->isKind(PNK_FUNCTION) || cur->isKind(PNK_MODULE)) == cur->isArity(PN_CODE));
     358      305242 :         if (cur->isKind(PNK_FUNCTION)) {
     359       14468 :             RootedAtom prefix2(cx);
     360        7234 :             if (!resolveFun(cur, prefix, &prefix2))
     361           0 :                 return false;
     362             : 
     363             :             /*
     364             :              * If a function looks like (function(){})() where the parent node
     365             :              * of the definition of the function is a call, then it shouldn't
     366             :              * contribute anything to the namespace, so don't bother updating
     367             :              * the prefix to whatever was returned.
     368             :              */
     369        7234 :             if (!isDirectCall(nparents - 1, cur))
     370        7188 :                 prefix = prefix2;
     371             :         }
     372      305242 :         if (nparents >= MaxParents)
     373           0 :             return true;
     374      305242 :         parents[nparents++] = cur;
     375             : 
     376      305242 :         switch (cur->getKind()) {
     377             :           // Nodes with no children that might require name resolution need no
     378             :           // further work.
     379             :           case PNK_NOP:
     380             :           case PNK_STRING:
     381             :           case PNK_TEMPLATE_STRING:
     382             :           case PNK_REGEXP:
     383             :           case PNK_TRUE:
     384             :           case PNK_FALSE:
     385             :           case PNK_NULL:
     386             :           case PNK_RAW_UNDEFINED:
     387             :           case PNK_ELISION:
     388             :           case PNK_GENERATOR:
     389             :           case PNK_NUMBER:
     390             :           case PNK_BREAK:
     391             :           case PNK_CONTINUE:
     392             :           case PNK_DEBUGGER:
     393             :           case PNK_EXPORT_BATCH_SPEC:
     394             :           case PNK_OBJECT_PROPERTY_NAME:
     395             :           case PNK_POSHOLDER:
     396       37369 :             MOZ_ASSERT(cur->isArity(PN_NULLARY));
     397       37369 :             break;
     398             : 
     399             :           case PNK_TYPEOFNAME:
     400             :           case PNK_SUPERBASE:
     401         450 :             MOZ_ASSERT(cur->isArity(PN_UNARY));
     402         450 :             MOZ_ASSERT(cur->pn_kid->isKind(PNK_NAME));
     403         450 :             MOZ_ASSERT(!cur->pn_kid->expr());
     404         450 :             break;
     405             : 
     406             :           case PNK_NEWTARGET:
     407          12 :             MOZ_ASSERT(cur->isArity(PN_BINARY));
     408          12 :             MOZ_ASSERT(cur->pn_left->isKind(PNK_POSHOLDER));
     409          12 :             MOZ_ASSERT(cur->pn_right->isKind(PNK_POSHOLDER));
     410          12 :             break;
     411             : 
     412             :           // Nodes with a single non-null child requiring name resolution.
     413             :           case PNK_TYPEOFEXPR:
     414             :           case PNK_VOID:
     415             :           case PNK_NOT:
     416             :           case PNK_BITNOT:
     417             :           case PNK_THROW:
     418             :           case PNK_DELETENAME:
     419             :           case PNK_DELETEPROP:
     420             :           case PNK_DELETEELEM:
     421             :           case PNK_DELETEEXPR:
     422             :           case PNK_NEG:
     423             :           case PNK_POS:
     424             :           case PNK_PREINCREMENT:
     425             :           case PNK_POSTINCREMENT:
     426             :           case PNK_PREDECREMENT:
     427             :           case PNK_POSTDECREMENT:
     428             :           case PNK_COMPUTED_NAME:
     429             :           case PNK_ARRAYPUSH:
     430             :           case PNK_SPREAD:
     431             :           case PNK_MUTATEPROTO:
     432             :           case PNK_EXPORT:
     433        4355 :             MOZ_ASSERT(cur->isArity(PN_UNARY));
     434        4355 :             if (!resolve(cur->pn_kid, prefix))
     435           0 :                 return false;
     436        4355 :             break;
     437             : 
     438             :           // Nodes with a single nullable child.
     439             :           case PNK_SEMI:
     440             :           case PNK_THIS:
     441       22044 :             MOZ_ASSERT(cur->isArity(PN_UNARY));
     442       22044 :             if (ParseNode* expr = cur->pn_kid) {
     443       21295 :                 if (!resolve(expr, prefix))
     444           0 :                     return false;
     445             :             }
     446       22044 :             break;
     447             : 
     448             :           // Binary nodes with two non-null children.
     449             :           case PNK_ASSIGN:
     450             :           case PNK_ADDASSIGN:
     451             :           case PNK_SUBASSIGN:
     452             :           case PNK_BITORASSIGN:
     453             :           case PNK_BITXORASSIGN:
     454             :           case PNK_BITANDASSIGN:
     455             :           case PNK_LSHASSIGN:
     456             :           case PNK_RSHASSIGN:
     457             :           case PNK_URSHASSIGN:
     458             :           case PNK_MULASSIGN:
     459             :           case PNK_DIVASSIGN:
     460             :           case PNK_MODASSIGN:
     461             :           case PNK_POWASSIGN:
     462             :           case PNK_COLON:
     463             :           case PNK_SHORTHAND:
     464             :           case PNK_DOWHILE:
     465             :           case PNK_WHILE:
     466             :           case PNK_SWITCH:
     467             :           case PNK_FOR:
     468             :           case PNK_COMPREHENSIONFOR:
     469             :           case PNK_CLASSMETHOD:
     470             :           case PNK_SETTHIS:
     471       16462 :             MOZ_ASSERT(cur->isArity(PN_BINARY));
     472       16462 :             if (!resolve(cur->pn_left, prefix))
     473           0 :                 return false;
     474       16462 :             if (!resolve(cur->pn_right, prefix))
     475           0 :                 return false;
     476       16462 :             break;
     477             : 
     478             :           case PNK_ELEM:
     479        2822 :             MOZ_ASSERT(cur->isArity(PN_BINARY));
     480        2822 :             if (!cur->as<PropertyByValue>().isSuper() && !resolve(cur->pn_left, prefix))
     481           0 :                 return false;
     482        2822 :             if (!resolve(cur->pn_right, prefix))
     483           0 :                 return false;
     484        2822 :             break;
     485             : 
     486             :           case PNK_WITH:
     487           0 :             MOZ_ASSERT(cur->isArity(PN_BINARY));
     488           0 :             if (!resolve(cur->pn_left, prefix))
     489           0 :                 return false;
     490           0 :             if (!resolve(cur->pn_right, prefix))
     491           0 :                 return false;
     492           0 :             break;
     493             : 
     494             :           case PNK_CASE:
     495        1114 :             MOZ_ASSERT(cur->isArity(PN_BINARY));
     496        1114 :             if (ParseNode* caseExpr = cur->pn_left) {
     497        1059 :                 if (!resolve(caseExpr, prefix))
     498           0 :                     return false;
     499             :             }
     500        1114 :             if (!resolve(cur->pn_right, prefix))
     501           0 :                 return false;
     502        1114 :             break;
     503             : 
     504             :           case PNK_INITIALYIELD:
     505         127 :             MOZ_ASSERT(cur->pn_kid->isKind(PNK_ASSIGN) &&
     506             :                        cur->pn_kid->pn_left->isKind(PNK_NAME) &&
     507             :                        cur->pn_kid->pn_right->isKind(PNK_GENERATOR));
     508         127 :             break;
     509             : 
     510             :           case PNK_YIELD_STAR:
     511           3 :             MOZ_ASSERT(cur->isArity(PN_UNARY));
     512           3 :             if (!resolve(cur->pn_kid, prefix))
     513           0 :                 return false;
     514           3 :             break;
     515             : 
     516             :           case PNK_YIELD:
     517             :           case PNK_AWAIT:
     518         250 :             MOZ_ASSERT(cur->isArity(PN_UNARY));
     519         250 :             if (cur->pn_kid) {
     520         250 :                 if (!resolve(cur->pn_kid, prefix))
     521           0 :                     return false;
     522             :             }
     523         250 :             break;
     524             : 
     525             :           case PNK_RETURN:
     526        6175 :             MOZ_ASSERT(cur->isArity(PN_UNARY));
     527        6175 :             if (ParseNode* returnValue = cur->pn_kid) {
     528        5677 :                 if (!resolve(returnValue, prefix))
     529           0 :                     return false;
     530             :             }
     531        6175 :             break;
     532             : 
     533             :           case PNK_IMPORT:
     534             :           case PNK_EXPORT_FROM:
     535             :           case PNK_EXPORT_DEFAULT:
     536           0 :             MOZ_ASSERT(cur->isArity(PN_BINARY));
     537             :             // The left halves of these nodes don't contain any unconstrained
     538             :             // expressions, but it's very hard to assert this to safely rely on
     539             :             // it.  So recur anyway.
     540           0 :             if (!resolve(cur->pn_left, prefix))
     541           0 :                 return false;
     542           0 :             MOZ_ASSERT_IF(!cur->isKind(PNK_EXPORT_DEFAULT),
     543             :                           cur->pn_right->isKind(PNK_STRING));
     544           0 :             break;
     545             : 
     546             :           // Ternary nodes with three expression children.
     547             :           case PNK_CONDITIONAL:
     548         657 :             MOZ_ASSERT(cur->isArity(PN_TERNARY));
     549         657 :             if (!resolve(cur->pn_kid1, prefix))
     550           0 :                 return false;
     551         657 :             if (!resolve(cur->pn_kid2, prefix))
     552           0 :                 return false;
     553         657 :             if (!resolve(cur->pn_kid3, prefix))
     554           0 :                 return false;
     555         657 :             break;
     556             : 
     557             :           // The first part of a for-in/of is the declaration in the loop (or
     558             :           // null if no declaration).  The latter two parts are the location
     559             :           // assigned each loop and the value being looped over; obviously,
     560             :           // either might contain functions to name.  Declarations may (through
     561             :           // computed property names, and possibly through [deprecated!]
     562             :           // initializers) also contain functions to name.
     563             :           case PNK_FORIN:
     564             :           case PNK_FOROF:
     565         372 :             MOZ_ASSERT(cur->isArity(PN_TERNARY));
     566         372 :             if (ParseNode* decl = cur->pn_kid1) {
     567         372 :                 if (!resolve(decl, prefix))
     568           0 :                     return false;
     569             :             }
     570         372 :             if (!resolve(cur->pn_kid2, prefix))
     571           0 :                 return false;
     572         372 :             if (!resolve(cur->pn_kid3, prefix))
     573           0 :                 return false;
     574         372 :             break;
     575             : 
     576             :           // Every part of a for(;;) head may contain a function needing name
     577             :           // resolution.
     578             :           case PNK_FORHEAD:
     579         441 :             MOZ_ASSERT(cur->isArity(PN_TERNARY));
     580         441 :             if (ParseNode* init = cur->pn_kid1) {
     581         394 :                 if (!resolve(init, prefix))
     582           0 :                     return false;
     583             :             }
     584         441 :             if (ParseNode* cond = cur->pn_kid2) {
     585         432 :                 if (!resolve(cond, prefix))
     586           0 :                     return false;
     587             :             }
     588         441 :             if (ParseNode* step = cur->pn_kid3) {
     589         432 :                 if (!resolve(step, prefix))
     590           0 :                     return false;
     591             :             }
     592         441 :             break;
     593             : 
     594             :           // The first child of a class is a pair of names referring to it,
     595             :           // inside and outside the class.  The second is the class's heritage,
     596             :           // if any.  The third is the class body.
     597             :           case PNK_CLASS:
     598          32 :             MOZ_ASSERT(cur->isArity(PN_TERNARY));
     599          32 :             MOZ_ASSERT_IF(cur->pn_kid1, cur->pn_kid1->isKind(PNK_CLASSNAMES));
     600          32 :             MOZ_ASSERT_IF(cur->pn_kid1, cur->pn_kid1->isArity(PN_BINARY));
     601          32 :             MOZ_ASSERT_IF(cur->pn_kid1 && cur->pn_kid1->pn_left,
     602             :                           cur->pn_kid1->pn_left->isKind(PNK_NAME));
     603          32 :             MOZ_ASSERT_IF(cur->pn_kid1 && cur->pn_kid1->pn_left,
     604             :                           !cur->pn_kid1->pn_left->expr());
     605          32 :             MOZ_ASSERT_IF(cur->pn_kid1, cur->pn_kid1->pn_right->isKind(PNK_NAME));
     606          32 :             MOZ_ASSERT_IF(cur->pn_kid1, !cur->pn_kid1->pn_right->expr());
     607          32 :             if (cur->pn_kid2) {
     608          16 :                 if (!resolve(cur->pn_kid2, prefix))
     609           0 :                     return false;
     610             :             }
     611          32 :             if (!resolve(cur->pn_kid3, prefix))
     612           0 :                 return false;
     613          32 :             break;
     614             : 
     615             :           // The condition and consequent are non-optional, but the alternative
     616             :           // might be omitted.
     617             :           case PNK_IF:
     618        7045 :             MOZ_ASSERT(cur->isArity(PN_TERNARY));
     619        7045 :             if (!resolve(cur->pn_kid1, prefix))
     620           0 :                 return false;
     621        7045 :             if (!resolve(cur->pn_kid2, prefix))
     622           0 :                 return false;
     623        7045 :             if (cur->pn_kid3) {
     624         925 :                 if (!resolve(cur->pn_kid3, prefix))
     625           0 :                     return false;
     626             :             }
     627        7045 :             break;
     628             : 
     629             :           // The statements in the try-block are mandatory.  The catch-blocks
     630             :           // and finally block are optional (but at least one or the other must
     631             :           // be present).
     632             :           case PNK_TRY:
     633         490 :             MOZ_ASSERT(cur->isArity(PN_TERNARY));
     634         490 :             if (!resolve(cur->pn_kid1, prefix))
     635           0 :                 return false;
     636         490 :             MOZ_ASSERT(cur->pn_kid2 || cur->pn_kid3);
     637         490 :             if (ParseNode* catchList = cur->pn_kid2) {
     638         468 :                 MOZ_ASSERT(catchList->isKind(PNK_CATCHLIST));
     639         468 :                 if (!resolve(catchList, prefix))
     640           0 :                     return false;
     641             :             }
     642         490 :             if (ParseNode* finallyBlock = cur->pn_kid3) {
     643          41 :                 if (!resolve(finallyBlock, prefix))
     644           0 :                     return false;
     645             :             }
     646         490 :             break;
     647             : 
     648             :           // The first child, the catch-pattern, may contain functions via
     649             :           // computed property names.  The optional catch-conditions may
     650             :           // contain any expression.  The catch statements, of course, may
     651             :           // contain arbitrary expressions.
     652             :           case PNK_CATCH:
     653         468 :             MOZ_ASSERT(cur->isArity(PN_TERNARY));
     654         468 :             if (!resolve(cur->pn_kid1, prefix))
     655           0 :                 return false;
     656         468 :             if (cur->pn_kid2) {
     657           0 :                 if (!resolve(cur->pn_kid2, prefix))
     658           0 :                     return false;
     659             :             }
     660         468 :             if (!resolve(cur->pn_kid3, prefix))
     661           0 :                 return false;
     662         468 :             break;
     663             : 
     664             :           // Nodes with arbitrary-expression children.
     665             :           case PNK_OR:
     666             :           case PNK_AND:
     667             :           case PNK_BITOR:
     668             :           case PNK_BITXOR:
     669             :           case PNK_BITAND:
     670             :           case PNK_STRICTEQ:
     671             :           case PNK_EQ:
     672             :           case PNK_STRICTNE:
     673             :           case PNK_NE:
     674             :           case PNK_LT:
     675             :           case PNK_LE:
     676             :           case PNK_GT:
     677             :           case PNK_GE:
     678             :           case PNK_INSTANCEOF:
     679             :           case PNK_IN:
     680             :           case PNK_LSH:
     681             :           case PNK_RSH:
     682             :           case PNK_URSH:
     683             :           case PNK_ADD:
     684             :           case PNK_SUB:
     685             :           case PNK_STAR:
     686             :           case PNK_DIV:
     687             :           case PNK_MOD:
     688             :           case PNK_POW:
     689             :           case PNK_COMMA:
     690             :           case PNK_NEW:
     691             :           case PNK_CALL:
     692             :           case PNK_SUPERCALL:
     693             :           case PNK_GENEXP:
     694             :           case PNK_ARRAY:
     695             :           case PNK_STATEMENTLIST:
     696             :           case PNK_PARAMSBODY:
     697             :           // Initializers for individual variables, and computed property names
     698             :           // within destructuring patterns, may contain unnamed functions.
     699             :           case PNK_VAR:
     700             :           case PNK_CONST:
     701             :           case PNK_LET:
     702       62115 :             MOZ_ASSERT(cur->isArity(PN_LIST));
     703      206411 :             for (ParseNode* element = cur->pn_head; element; element = element->pn_next) {
     704      144296 :                 if (!resolve(element, prefix))
     705           0 :                     return false;
     706             :             }
     707       62115 :             break;
     708             : 
     709             :           // Array comprehension nodes are lists with a single child:
     710             :           // PNK_COMPREHENSIONFOR for comprehensions, PNK_LEXICALSCOPE for
     711             :           // legacy comprehensions.  Probably this should be a non-list
     712             :           // eventually.
     713             :           case PNK_ARRAYCOMP:
     714           0 :             MOZ_ASSERT(cur->isArity(PN_LIST));
     715           0 :             MOZ_ASSERT(cur->pn_count == 1);
     716           0 :             MOZ_ASSERT(cur->pn_head->isKind(PNK_LEXICALSCOPE) ||
     717             :                        cur->pn_head->isKind(PNK_COMPREHENSIONFOR));
     718           0 :             if (!resolve(cur->pn_head, prefix))
     719           0 :                 return false;
     720           0 :             break;
     721             : 
     722             :           case PNK_OBJECT:
     723             :           case PNK_CLASSMETHODLIST:
     724        2576 :             MOZ_ASSERT(cur->isArity(PN_LIST));
     725       11872 :             for (ParseNode* element = cur->pn_head; element; element = element->pn_next) {
     726        9296 :                 if (!resolve(element, prefix))
     727           0 :                     return false;
     728             :             }
     729        2576 :             break;
     730             : 
     731             :           // A template string list's contents alternate raw template string
     732             :           // contents with expressions interpolated into the overall literal.
     733             :           case PNK_TEMPLATE_STRING_LIST:
     734         252 :             MOZ_ASSERT(cur->isArity(PN_LIST));
     735         252 :             if (!resolveTemplateLiteral(cur, prefix))
     736           0 :                 return false;
     737         252 :             break;
     738             : 
     739             :           case PNK_TAGGED_TEMPLATE:
     740           1 :             MOZ_ASSERT(cur->isArity(PN_LIST));
     741           1 :             if (!resolveTaggedTemplate(cur, prefix))
     742           0 :                 return false;
     743           1 :             break;
     744             : 
     745             :           // Import/export spec lists contain import/export specs containing
     746             :           // only pairs of names. Alternatively, an export spec lists may
     747             :           // contain a single export batch specifier.
     748             :           case PNK_EXPORT_SPEC_LIST:
     749             :           case PNK_IMPORT_SPEC_LIST: {
     750           0 :             MOZ_ASSERT(cur->isArity(PN_LIST));
     751             : #ifdef DEBUG
     752           0 :             bool isImport = cur->isKind(PNK_IMPORT_SPEC_LIST);
     753           0 :             ParseNode* item = cur->pn_head;
     754           0 :             if (!isImport && item && item->isKind(PNK_EXPORT_BATCH_SPEC)) {
     755           0 :                 MOZ_ASSERT(item->isArity(PN_NULLARY));
     756           0 :                 break;
     757             :             }
     758           0 :             for (; item; item = item->pn_next) {
     759           0 :                 MOZ_ASSERT(item->isKind(isImport ? PNK_IMPORT_SPEC : PNK_EXPORT_SPEC));
     760           0 :                 MOZ_ASSERT(item->isArity(PN_BINARY));
     761           0 :                 MOZ_ASSERT(item->pn_left->isKind(PNK_NAME));
     762           0 :                 MOZ_ASSERT(!item->pn_left->expr());
     763           0 :                 MOZ_ASSERT(item->pn_right->isKind(PNK_NAME));
     764           0 :                 MOZ_ASSERT(!item->pn_right->expr());
     765             :             }
     766             : #endif
     767           0 :             break;
     768             :           }
     769             : 
     770             :           case PNK_CATCHLIST: {
     771         468 :             MOZ_ASSERT(cur->isArity(PN_LIST));
     772         936 :             for (ParseNode* catchNode = cur->pn_head; catchNode; catchNode = catchNode->pn_next) {
     773         468 :                 MOZ_ASSERT(catchNode->isKind(PNK_LEXICALSCOPE));
     774         468 :                 MOZ_ASSERT(catchNode->scopeBody()->isKind(PNK_CATCH));
     775         468 :                 MOZ_ASSERT(catchNode->scopeBody()->isArity(PN_TERNARY));
     776         468 :                 if (!resolve(catchNode->scopeBody(), prefix))
     777           0 :                     return false;
     778             :             }
     779         468 :             break;
     780             :           }
     781             : 
     782             :           case PNK_DOT:
     783       28612 :             MOZ_ASSERT(cur->isArity(PN_NAME));
     784             : 
     785             :             // Super prop nodes do not have a meaningful LHS
     786       28612 :             if (cur->as<PropertyAccess>().isSuper())
     787          13 :                 break;
     788       28599 :             if (!resolve(cur->expr(), prefix))
     789           0 :                 return false;
     790       28599 :             break;
     791             : 
     792             :           case PNK_LABEL:
     793           0 :             MOZ_ASSERT(cur->isArity(PN_NAME));
     794           0 :             if (!resolve(cur->expr(), prefix))
     795           0 :                 return false;
     796           0 :             break;
     797             : 
     798             :           case PNK_NAME:
     799       90826 :             MOZ_ASSERT(cur->isArity(PN_NAME));
     800       90826 :             if (!resolve(cur->expr(), prefix))
     801           0 :                 return false;
     802       90826 :             break;
     803             : 
     804             :           case PNK_LEXICALSCOPE:
     805       12470 :             MOZ_ASSERT(cur->isArity(PN_SCOPE));
     806       12470 :             if (!resolve(cur->scopeBody(), prefix))
     807           0 :                 return false;
     808       12470 :             break;
     809             : 
     810             :           case PNK_FUNCTION:
     811             :           case PNK_MODULE:
     812        7234 :             MOZ_ASSERT(cur->isArity(PN_CODE));
     813        7234 :             if (!resolve(cur->pn_body, prefix))
     814           0 :                 return false;
     815        7234 :             break;
     816             : 
     817             :           // Kinds that should be handled by parent node resolution.
     818             : 
     819             :           case PNK_IMPORT_SPEC: // by PNK_IMPORT_SPEC_LIST
     820             :           case PNK_EXPORT_SPEC: // by PNK_EXPORT_SPEC_LIST
     821             :           case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE
     822             :           case PNK_CLASSNAMES:  // by PNK_CLASS
     823           0 :             MOZ_CRASH("should have been handled by a parent node");
     824             : 
     825             :           case PNK_LIMIT: // invalid sentinel value
     826           0 :             MOZ_CRASH("invalid node kind");
     827             :         }
     828             : 
     829      305242 :         nparents--;
     830      305242 :         return true;
     831             :     }
     832             : };
     833             : 
     834             : } /* anonymous namespace */
     835             : 
     836             : bool
     837        1691 : frontend::NameFunctions(JSContext* cx, ParseNode* pn)
     838             : {
     839        3382 :     AutoTraceLog traceLog(TraceLoggerForCurrentThread(cx), TraceLogger_BytecodeNameFunctions);
     840        1691 :     NameResolver nr(cx);
     841        3382 :     return nr.resolve(pn);
     842             : }

Generated by: LCOV version 1.13