@Override public void endVisit(JsNameRef x, JsContext ctx) { String ident = x.getIdent(); if (!x.isJsniReference()) { // Not a jsni reference. return; } JsniRef jsniRef = JsniRef.parse(ident); if (jsniRef == null) { emitError(ERR_MALFORMED_JSNI_IDENTIFIER, x.getSourceInfo(), null, ident); return; } Binding binding = resolveReference(x.getSourceInfo(), jsniRef, x.getQualifier() != null, ctx.isLvalue()); assert !x.isResolved(); if (!ident.equals(jsniRef.getResolvedReference())) { // Replace by the resolved reference (consisting of the fully qualified classname and the // method description including actual signature) so that dispatch everywhere is consistent // with the one resolved here. ident = jsniRef.getResolvedReference(); JsNameRef newRef = new JsNameRef(x.getSourceInfo(), ident); newRef.setQualifier(x.getQualifier()); ctx.replaceMe(newRef); } if (binding != null) { jsniRefs.put(ident, binding); } }
@Override public void endVisit(JsBinaryOperation x, JsContext ctx) { // Look for the patern a.f = o.@C::m(); if (!x.getOperator().isAssignment()) { return; } if (!(x.getArg1() instanceof JsNameRef) || !(x.getArg2() instanceof JsNameRef)) { return; } JsNameRef lhs = (JsNameRef) x.getArg1(); JsNameRef rhs = (JsNameRef) x.getArg2(); if (!rhs.isJsniReference() || !(jsniRefs.get(rhs.getIdent()) instanceof MethodBinding)) { // Not a reference to a JSNI method. return; } if (rhs.getQualifier() == null) { // Unqualified JSNI reference is OK. return; } if (lhs.getQualifier() == null) { // Assignment to unqualified variable is OK. return; } // Here we have a qualified JSNI method reference assigned to a field. JsniRef jsniRef = JsniRef.parse(rhs.getIdent()); emitWarning( "unsafe", WARN_NOT_CAPTURING_QUALIFIER, x.getSourceInfo(), jsniRef, rhs.getQualifier().toSource()); }