File: src/com/google/javascript/jscomp/CheckGlobalThis.java
Issue: Prototypes declared with quotes produce a JSC_USED_GLOBAL_THIS warning.
Compiling the following code (in advanced optimizations with VERBOSE
warning levels):

/** @constructor */
function MyClass() {}
MyClass.prototype["MyMethod"] = function(a) {
  this.a = a;
}
window["MyClass"] = MyClass;

Results in the following warning: "dangerous use of the global this
object." This notation is convenient to declare a prototype that is purely
used for export purposes. The warning can be suppressed by using an @this
notation.

Given the following externs:

/**@interface */
function MyParent() {}
/** @param {*} a */
MyParent.prototype.MyMethod = function(a) {}

And the following code:

/**
* @constructor
* @implements {MyParent}
*/
function MyClass() {}
MyClass.prototype["MyMethod"] = function(a) {
  this.a2 = a;
}
window["MyClass"] = MyClass;

The compiler also produces the waring: "property MyMethod on interface
MyParent is not implemented by type MyClass".

Buggy code:
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {

  if (n.getType() == Token.FUNCTION) {
    // Don't traverse functions that are constructors or have the @this
    // or @override annotation.
    JSDocInfo jsDoc = getFunctionJsDocInfo(n);
    if (jsDoc != null &&
        (jsDoc.isConstructor() ||
         jsDoc.hasThisType() ||
         jsDoc.isOverride())) {
      return false;
    }

    // Don't traverse functions unless they would normally
    // be able to have a @this annotation associated with them. e.g.,
    // var a = function() { }; // or
    // function a() {} // or
    // a.x = function() {};
    int pType = parent.getType();
    if (!(pType == Token.BLOCK ||
          pType == Token.SCRIPT ||
          pType == Token.NAME ||
          pType == Token.ASSIGN)) {
      return false;
    }
  }

  if (parent != null && parent.getType() == Token.ASSIGN) {
    Node lhs = parent.getFirstChild();
    Node rhs = lhs.getNext();
    
    if (n == lhs) {
      // Always traverse the left side of the assignment. To handle
      // nested assignments properly (e.g., (a = this).property = c;),
      // assignLhsChild should not be overridden.
      if (assignLhsChild == null) {
        assignLhsChild = lhs;
      }
    } else {
      // Only traverse the right side if it's not an assignment to a prototype
      // property or subproperty.
        if (lhs.getType() == Token.GETPROP &&
            lhs.getLastChild().getString().equals("prototype")) {
          return false;
        }
        if (lhs.getQualifiedName() != null && lhs.getQualifiedName().contains(".prototype.")) {
          return false;
        }
    }
  }

  return true;
}

Fixed code:
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {

  if (n.getType() == Token.FUNCTION) {
    // Don't traverse functions that are constructors or have the @this
    // or @override annotation.
    JSDocInfo jsDoc = getFunctionJsDocInfo(n);
    if (jsDoc != null &&
        (jsDoc.isConstructor() ||
         jsDoc.isInterface() ||
         jsDoc.hasThisType() ||
         jsDoc.isOverride())) {
      return false;
    }

    // Don't traverse functions unless they would normally
    // be able to have a @this annotation associated with them. e.g.,
    // var a = function() { }; // or
    // function a() {} // or
    // a.x = function() {};
    int pType = parent.getType();
    if (!(pType == Token.BLOCK ||
          pType == Token.SCRIPT ||
          pType == Token.NAME ||
          pType == Token.ASSIGN)) {
      return false;
    }
  }

  if (parent != null && parent.getType() == Token.ASSIGN) {
    Node lhs = parent.getFirstChild();
    Node rhs = lhs.getNext();
    
    if (n == lhs) {
      // Always traverse the left side of the assignment. To handle
      // nested assignments properly (e.g., (a = this).property = c;),
      // assignLhsChild should not be overridden.
      if (assignLhsChild == null) {
        assignLhsChild = lhs;
      }
    } else {
      // Only traverse the right side if it's not an assignment to a prototype
      // property or subproperty.
      if (NodeUtil.isGet(lhs)) {
        if (lhs.getType() == Token.GETPROP &&
            lhs.getLastChild().getString().equals("prototype")) {
          return false;
        }
        Node llhs = lhs.getFirstChild();
        if (llhs.getType() == Token.GETPROP &&
            llhs.getLastChild().getString().equals("prototype")) {
          return false;
        }
      }
    }
  }

  return true;
}