…lines 1–351 unchanged (351 lines)
352 private void findAliases(NodeTraversal t) {
353 Scope scope = t.getScope();
354 for (Var v : scope.getVarIterable()) {
355 Node n = v.getNode();
356 Node parent = n.getParent();
357 boolean isVar = parent.isVar();
358 boolean isFunctionDecl = NodeUtil.isFunctionDeclaration(parent);
359 if (isVar && n.getFirstChild() != null && n.getFirstChild().isQualifiedName()) {
360 recordAlias(v);
361 } else if (v.isBleedingFunction()) {
362 // Bleeding functions already get a BAD_PARAMETERS error, so just
363 // do nothing.
364 } else if (parent.getType() == Token.LP) {
365 // Parameters of the scope function also get a BAD_PARAMETERS
366 // error.
367 } else if (isVar || isFunctionDecl) {
368 boolean isHoisted = NodeUtil.isHoistedFunctionDeclaration(parent);
369 Node grandparent = parent.getParent();
370 Node value = v.getInitialValue() != null ?
371 v.getInitialValue() :
372 null;
373 Node varNode = null;
374
375 String name = n.getString();
376 int nameCount = scopedAliasNames.count(name);
377 scopedAliasNames.add(name);
378 String globalName =
379 "$jscomp.scope." + name + (nameCount == 0 ? "" : ("$" + nameCount));
380
381 compiler.ensureLibraryInjected("base");
382
383 // First, we need to free up the function expression (EXPR)
384 // to be used in another expression.
385 if (isFunctionDecl) {
386 // Replace "function NAME() { ... }" with "var NAME;".
387 Node existingName = v.getNameNode();
388
389 // We can't keep the local name on the function expression,
390 // because IE is buggy and will leak the name into the global
391 // scope. This is covered in more detail here:
392 // http://wiki.ecmascript.org/lib/exe/fetch.php?id=resources:resources&cache=cache&media=resources:jscriptdeviationsfromes3.pdf
393 //
394 // This will only cause problems if this is a hoisted, recursive
395 // function, and the programmer is using the hoisting.
396 Node newName = IR.name("").useSourceInfoFrom(existingName);
397 value.replaceChild(existingName, newName);
398
399 varNode = IR.var(existingName).useSourceInfoFrom(existingName);
400 grandparent.replaceChild(parent, varNode);
401 } else {
402 if (value != null) {
403 // If this is a VAR, we can just detach the expression and
404 // the tree will still be valid.
405 value.detachFromParent();
406 }
407 varNode = parent;
408 }
409
410 // Add $jscomp.scope.name = EXPR;
411 // Make sure we copy over all the jsdoc and debug info.
412 if (value != null || v.getJSDocInfo() != null) {
413 Node newDecl = NodeUtil.newQualifiedNameNodeDeclaration(
414 compiler.getCodingConvention(),
415 globalName,
416 value,
417 v.getJSDocInfo())
418 .useSourceInfoIfMissingFromForTree(n);
419 NodeUtil.setDebugInformation(
420 newDecl.getFirstChild().getFirstChild(), n, name);
421
422 if (isHoisted) {
423 grandparent.addChildToFront(newDecl);
424 } else {
425 grandparent.addChildBefore(newDecl, varNode);
426 }
427 }
428
429 // Rewrite "var name = EXPR;" to "var name = $jscomp.scope.name;"
430 v.getNameNode().addChildToFront(
431 NodeUtil.newQualifiedNameNode(
432 compiler.getCodingConvention(), globalName, n, name));
…lines 433–605 unchanged (173 lines)