From 0d791d7f730481a4e224073c2018e71be67d733e Mon Sep 17 00:00:00 2001 From: Colin Alworth Date: Wed, 8 Jan 2025 09:24:04 -0600 Subject: [PATCH] Exceptions thrown when building GWT's AST should include context Several visit and endVisit methods were missing their try/catch wrapping to translate any exception that occurs, with context of the given JDT ast node where the error took place. Follow-up #10065 --- .../gwt/dev/jjs/impl/GwtAstBuilder.java | 1104 +++++++++-------- 1 file changed, 574 insertions(+), 530 deletions(-) diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java index 6cf609c4f1..1c5db34bcf 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java @@ -293,33 +293,37 @@ private JsniReferenceCollector(JsniMethodBody nativeMethodBody) { @Override public void endVisit(JsNameRef x, JsContext ctx) { - if (!x.isJsniReference()) { - return; - } - String ident = x.getIdent(); - Binding binding = jsniRefs.get(ident); - SourceInfo info = x.getSourceInfo(); - assert binding != null; - if (binding instanceof TypeBinding) { - JType type = typeMap.get((TypeBinding) binding); - processClassLiteral(x, info, type, ctx); - } else if (binding instanceof FieldBinding) { - FieldBinding fieldBinding = (FieldBinding) binding; - if (isOptimizableCompileTimeConstant(fieldBinding)) { - // Replace any compile-time constants with the constant value of the field. - assert !ctx.isLvalue(); - JExpression constant = getConstant(info, fieldBinding.constant()); - JsExpression result = JjsUtils.translateLiteral((JLiteral) constant); - assert (result != null); - ctx.replaceMe(result); + try { + if (!x.isJsniReference()) { + return; + } + String ident = x.getIdent(); + Binding binding = jsniRefs.get(ident); + SourceInfo info = x.getSourceInfo(); + assert binding != null; + if (binding instanceof TypeBinding) { + JType type = typeMap.get((TypeBinding) binding); + processClassLiteral(x, info, type, ctx); + } else if (binding instanceof FieldBinding) { + FieldBinding fieldBinding = (FieldBinding) binding; + if (isOptimizableCompileTimeConstant(fieldBinding)) { + // Replace any compile-time constants with the constant value of the field. + assert !ctx.isLvalue(); + JExpression constant = getConstant(info, fieldBinding.constant()); + JsExpression result = JjsUtils.translateLiteral((JLiteral) constant); + assert (result != null); + ctx.replaceMe(result); + } else { + // Normal: create a jsniRef. + JField field = typeMap.get(fieldBinding); + processField(x, info, field, ctx); + } } else { - // Normal: create a jsniRef. - JField field = typeMap.get(fieldBinding); - processField(x, info, field, ctx); + JMethod method = typeMap.get((MethodBinding) binding); + processMethod(x, info, method); } - } else { - JMethod method = typeMap.get((MethodBinding) binding); - processMethod(x, info, method); + } catch (Throwable e) { + throw translateException(x, e); } } @@ -946,113 +950,117 @@ public void endVisit(FloatLiteral x, BlockScope scope) { @Override public void endVisit(ForeachStatement x, BlockScope scope) { - SourceInfo info = makeSourceInfo(x); - - JBlock body = popBlock(info, x.action); - JExpression collection = pop(x.collection); - JDeclarationStatement elementDecl = pop(x.elementVariable); - assert (elementDecl.initializer == null); + try { + SourceInfo info = makeSourceInfo(x); - JLocal elementVar = (JLocal) curMethod.locals.get(x.elementVariable.binding); - String elementVarName = elementVar.getName(); + JBlock body = popBlock(info, x.action); + JExpression collection = pop(x.collection); + JDeclarationStatement elementDecl = pop(x.elementVariable); + assert (elementDecl.initializer == null); + + JLocal elementVar = (JLocal) curMethod.locals.get(x.elementVariable.binding); + String elementVarName = elementVar.getName(); + + JForStatement result; + if (x.collectionVariable != null) { + /** + *
+           * for (final T[] i$array = collection,
+           *          int i$index = 0,
+           *          final int i$max = i$array.length;
+           *      i$index < i$max; ++i$index) {
+           *   T elementVar = i$array[i$index];
+           *   // user action
+           * }
+           * 
+ */ + JLocal arrayVar = JProgram.createLocal(info, elementVarName + "$array", + typeMap.get(x.collection.resolvedType), true, curMethod.body); + JLocal indexVar = + JProgram.createLocal(info, elementVarName + "$index", JPrimitiveType.INT, false, + curMethod.body); + JLocal maxVar = + JProgram.createLocal(info, elementVarName + "$max", JPrimitiveType.INT, true, + curMethod.body); + + List initializers = Lists.newArrayListWithCapacity(3); + // T[] i$array = arr + initializers.add(makeDeclaration(info, arrayVar, collection)); + // int i$index = 0 + initializers.add(makeDeclaration(info, indexVar, JIntLiteral.get(0))); + // int i$max = i$array.length + initializers.add(makeDeclaration(info, maxVar, + new JArrayLength(info, arrayVar.makeRef(info)))); + + // i$index < i$max + JExpression condition = + new JBinaryOperation(info, JPrimitiveType.BOOLEAN, JBinaryOperator.LT, + indexVar.makeRef(info), maxVar.makeRef(info)); + + // ++i$index + JExpression increments = new JPrefixOperation(info, JUnaryOperator.INC, + indexVar.makeRef(info)); + + // T elementVar = i$array[i$index]; + elementDecl.initializer = + new JArrayRef(info, arrayVar.makeRef(info), indexVar.makeRef(info)); + body.addStmt(0, elementDecl); + + result = new JForStatement(info, initializers, condition, increments, body); + } else { + /** + *
+           * for (Iterator<T> i$iterator = collection.iterator(); i$iterator.hasNext();) {
+           *   T elementVar = i$iterator.next();
+           *   // user action
+           * }
+           * 
+ */ + CompilationUnitScope cudScope = scope.compilationUnitScope(); + ReferenceBinding javaUtilIterator = scope.getJavaUtilIterator(); + ReferenceBinding javaLangIterable = scope.getJavaLangIterable(); + MethodBinding iterator = javaLangIterable.getExactMethod(ITERATOR_, NO_TYPES, cudScope); + MethodBinding hasNext = javaUtilIterator.getExactMethod(HAS_NEXT_, NO_TYPES, cudScope); + MethodBinding next = javaUtilIterator.getExactMethod(NEXT_, NO_TYPES, cudScope); + JLocal iteratorVar = + JProgram.createLocal(info, (elementVarName + "$iterator"), typeMap + .get(javaUtilIterator), false, curMethod.body); + + List initializers = Lists.newArrayListWithCapacity(1); + // Iterator i$iterator = collection.iterator() + initializers.add(makeDeclaration(info, iteratorVar, new JMethodCall(info, collection, + typeMap.get(iterator)))); + + // i$iterator.hasNext() + JExpression condition = + new JMethodCall(info, iteratorVar.makeRef(info), typeMap.get(hasNext)); + + // T elementVar = (T) i$iterator.next(); + elementDecl.initializer = + new JMethodCall(info, iteratorVar.makeRef(info), typeMap.get(next)); + + // Perform any implicit reference type casts (due to generics). + // Note this occurs before potential unboxing. + if (elementVar.getType() != javaLangObject) { + TypeBinding collectionElementType = getCollectionElementTypeBinding(x); + JType toType = typeMap.get(collectionElementType); + assert (toType instanceof JReferenceType); + elementDecl.initializer = maybeCast(toType, elementDecl.initializer); + } - JForStatement result; - if (x.collectionVariable != null) { - /** - *
-       * for (final T[] i$array = collection,
-       *          int i$index = 0,
-       *          final int i$max = i$array.length;
-       *      i$index < i$max; ++i$index) {
-       *   T elementVar = i$array[i$index];
-       *   // user action
-       * }
-       * 
- */ - JLocal arrayVar = JProgram.createLocal(info, elementVarName + "$array", - typeMap.get(x.collection.resolvedType), true, curMethod.body); - JLocal indexVar = - JProgram.createLocal(info, elementVarName + "$index", JPrimitiveType.INT, false, - curMethod.body); - JLocal maxVar = - JProgram.createLocal(info, elementVarName + "$max", JPrimitiveType.INT, true, - curMethod.body); - - List initializers = Lists.newArrayListWithCapacity(3); - // T[] i$array = arr - initializers.add(makeDeclaration(info, arrayVar, collection)); - // int i$index = 0 - initializers.add(makeDeclaration(info, indexVar, JIntLiteral.get(0))); - // int i$max = i$array.length - initializers.add(makeDeclaration(info, maxVar, - new JArrayLength(info, arrayVar.makeRef(info)))); - - // i$index < i$max - JExpression condition = - new JBinaryOperation(info, JPrimitiveType.BOOLEAN, JBinaryOperator.LT, - indexVar.makeRef(info), maxVar.makeRef(info)); - - // ++i$index - JExpression increments = new JPrefixOperation(info, JUnaryOperator.INC, - indexVar.makeRef(info)); - - // T elementVar = i$array[i$index]; - elementDecl.initializer = - new JArrayRef(info, arrayVar.makeRef(info), indexVar.makeRef(info)); - body.addStmt(0, elementDecl); + body.addStmt(0, elementDecl); - result = new JForStatement(info, initializers, condition, increments, body); - } else { - /** - *
-         * for (Iterator<T> i$iterator = collection.iterator(); i$iterator.hasNext();) {
-         *   T elementVar = i$iterator.next();
-         *   // user action
-         * }
-         * 
- */ - CompilationUnitScope cudScope = scope.compilationUnitScope(); - ReferenceBinding javaUtilIterator = scope.getJavaUtilIterator(); - ReferenceBinding javaLangIterable = scope.getJavaLangIterable(); - MethodBinding iterator = javaLangIterable.getExactMethod(ITERATOR_, NO_TYPES, cudScope); - MethodBinding hasNext = javaUtilIterator.getExactMethod(HAS_NEXT_, NO_TYPES, cudScope); - MethodBinding next = javaUtilIterator.getExactMethod(NEXT_, NO_TYPES, cudScope); - JLocal iteratorVar = - JProgram.createLocal(info, (elementVarName + "$iterator"), typeMap - .get(javaUtilIterator), false, curMethod.body); - - List initializers = Lists.newArrayListWithCapacity(1); - // Iterator i$iterator = collection.iterator() - initializers.add(makeDeclaration(info, iteratorVar, new JMethodCall(info, collection, - typeMap.get(iterator)))); - - // i$iterator.hasNext() - JExpression condition = - new JMethodCall(info, iteratorVar.makeRef(info), typeMap.get(hasNext)); - - // T elementVar = (T) i$iterator.next(); - elementDecl.initializer = - new JMethodCall(info, iteratorVar.makeRef(info), typeMap.get(next)); - - // Perform any implicit reference type casts (due to generics). - // Note this occurs before potential unboxing. - if (elementVar.getType() != javaLangObject) { - TypeBinding collectionElementType = getCollectionElementTypeBinding(x); - JType toType = typeMap.get(collectionElementType); - assert (toType instanceof JReferenceType); - elementDecl.initializer = maybeCast(toType, elementDecl.initializer); + result = new JForStatement(info, initializers, condition, + null, body); } - body.addStmt(0, elementDecl); - - result = new JForStatement(info, initializers, condition, - null, body); + // May need to box or unbox the element assignment. + elementDecl.initializer = + maybeBoxOrUnbox(elementDecl.initializer, x.elementVariableImplicitWidening); + push(result); + } catch (Throwable e) { + throw translateException(x, e); } - - // May need to box or unbox the element assignment. - elementDecl.initializer = - maybeBoxOrUnbox(elementDecl.initializer, x.elementVariableImplicitWidening); - push(result); } @Override @@ -1211,54 +1219,62 @@ public void endVisit(LabeledStatement x, BlockScope scope) { @Override public boolean visit(ReferenceExpression x, BlockScope blockScope) { - // T[][][]::new => lambda$n(int x) { return new T[int x][][]; } - if (x.isArrayConstructorReference()) { - // ensure array[]::new synthetic method (created by JDT) has an associated JMethod - JMethod synthMethod = typeMap.get(x.binding); - if (synthMethod.getBody() == null) { - JMethodBody body = new JMethodBody(synthMethod.getSourceInfo()); - List dims = new ArrayList(); - JArrayType arrayType = (JArrayType) synthMethod.getType(); - JParameter dimParam = synthMethod.getParams().get(0); - JExpression dimArgExpr = dimParam.makeRef(dimParam.getSourceInfo()); - dims.add(dimArgExpr); - JNewArray newArray = JNewArray.createArrayWithDimensionExpressions( - synthMethod.getSourceInfo(), arrayType, dims); - body.getBlock().addStmt(newArray.makeReturnStatement()); - synthMethod.setBody(body); + try { + // T[][][]::new => lambda$n(int x) { return new T[int x][][]; } + if (x.isArrayConstructorReference()) { + // ensure array[]::new synthetic method (created by JDT) has an associated JMethod + JMethod synthMethod = typeMap.get(x.binding); + if (synthMethod.getBody() == null) { + JMethodBody body = new JMethodBody(synthMethod.getSourceInfo()); + List dims = new ArrayList(); + JArrayType arrayType = (JArrayType) synthMethod.getType(); + JParameter dimParam = synthMethod.getParams().get(0); + JExpression dimArgExpr = dimParam.makeRef(dimParam.getSourceInfo()); + dims.add(dimArgExpr); + JNewArray newArray = JNewArray.createArrayWithDimensionExpressions( + synthMethod.getSourceInfo(), arrayType, dims); + body.getBlock().addStmt(newArray.makeReturnStatement()); + synthMethod.setBody(body); + } } - } - if (hasQualifier(x)) { - x.lhs.traverse(this, blockScope); + if (hasQualifier(x)) { + x.lhs.traverse(this, blockScope); + } + return false; + } catch (Throwable e) { + throw translateException(x, e); } - return false; } @Override public boolean visit(LambdaExpression x, BlockScope blockScope) { - // Fetch the variables 'captured' by this lambda - SyntheticArgumentBinding[] synthArgs = x.outerLocalVariables; - // Get the parameter names, captured locals + lambda arguments - String paramNames[] = computeCombinedParamNames(x, synthArgs); - SourceInfo info = makeSourceInfo(x); - // JDT synthesizes a method lambda$n(capture1, capture2, ..., lambda_arg1, lambda_arg2, ...) - // Here we create a JMethod from this - JMethod lambdaMethod = createMethodFromBinding(info, x.binding, paramNames); - // Because the lambda implementations is synthesized as a static method in the - // enclosing class, it needs to be adjusted if that class happens to be a JsType. - lambdaMethod.setJsMemberInfo(HasJsInfo.JsMemberType.NONE, null, null, false); - if (curClass.type.isJsNative()) { - lambdaMethod.setJsOverlay(); - } - JMethodBody methodBody = new JMethodBody(info); - lambdaMethod.setBody(methodBody); - // We need to push this method on the stack as it introduces a scope, and - // expressions in the body need to lookup variable refs like parameters from it - pushMethodInfo(new MethodInfo(lambdaMethod, methodBody, x.scope)); - pushLambdaExpressionLocalsIntoMethodScope(x, synthArgs, lambdaMethod); - // now the body of the lambda is processed - return true; + try { + // Fetch the variables 'captured' by this lambda + SyntheticArgumentBinding[] synthArgs = x.outerLocalVariables; + // Get the parameter names, captured locals + lambda arguments + String paramNames[] = computeCombinedParamNames(x, synthArgs); + SourceInfo info = makeSourceInfo(x); + // JDT synthesizes a method lambda$n(capture1, capture2, ..., lambda_arg1, lambda_arg2, ...) + // Here we create a JMethod from this + JMethod lambdaMethod = createMethodFromBinding(info, x.binding, paramNames); + // Because the lambda implementations is synthesized as a static method in the + // enclosing class, it needs to be adjusted if that class happens to be a JsType. + lambdaMethod.setJsMemberInfo(HasJsInfo.JsMemberType.NONE, null, null, false); + if (curClass.type.isJsNative()) { + lambdaMethod.setJsOverlay(); + } + JMethodBody methodBody = new JMethodBody(info); + lambdaMethod.setBody(methodBody); + // We need to push this method on the stack as it introduces a scope, and + // expressions in the body need to lookup variable refs like parameters from it + pushMethodInfo(new MethodInfo(lambdaMethod, methodBody, x.scope)); + pushLambdaExpressionLocalsIntoMethodScope(x, synthArgs, lambdaMethod); + // now the body of the lambda is processed + return true; + } catch (Throwable e) { + throw translateException(x, e); + } } private void pushLambdaExpressionLocalsIntoMethodScope(LambdaExpression x, @@ -1310,80 +1326,84 @@ private String nameForSyntheticArgument(SyntheticArgumentBinding synthArg) { @Override public void endVisit(LambdaExpression x, BlockScope blockScope) { - /** - * Our output of a (args) -> expression_using_locals(locals) looks like this. - * - * class Enclosing { - * - * T lambda$0(locals, args) {...lambda expr } - * - * class lambda$0$type implements I { - * ctor([outer], locals) { ... } - * R (args) { return [outer].lambda$0(locals, args); } - * } - * } - * - * And replaces the lambda with new lambda$0$Type([outer this], captured locals...). - */ + try { + /** + * Our output of a (args) -> expression_using_locals(locals) looks like this. + * + * class Enclosing { + * + * T lambda$0(locals, args) {...lambda expr } + * + * class lambda$0$type implements I { + * ctor([outer], locals) { ... } + * R (args) { return [outer].lambda$0(locals, args); } + * } + * } + * + * And replaces the lambda with new lambda$0$Type([outer this], captured locals...). + */ - // The target accepting this lambda is looking for which type? (e.g. ClickHandler, Runnable) - TypeBinding binding = x.expectedType(); - // Find the single abstract method of this interface - MethodBinding samBinding = binding.getSingleAbstractMethod(blockScope, false); - assert (samBinding != null && samBinding.isValidBinding()); - - // Lookup the JMethod version - JMethod interfaceMethod = typeMap.get(samBinding); - // And its JInterface container we must implement - // There may be more than more JInterface containers to be implemented - // if the lambda expression is cast to a IntersectionCastType. - JInterfaceType[] lambdaInterfaces = getInterfacesToImplement(binding); - SourceInfo info = makeSourceInfo(x); + // The target accepting this lambda is looking for which type? (e.g. ClickHandler, Runnable) + TypeBinding binding = x.expectedType(); + // Find the single abstract method of this interface + MethodBinding samBinding = binding.getSingleAbstractMethod(blockScope, false); + assert (samBinding != null && samBinding.isValidBinding()); + + // Lookup the JMethod version + JMethod interfaceMethod = typeMap.get(samBinding); + // And its JInterface container we must implement + // There may be more than more JInterface containers to be implemented + // if the lambda expression is cast to a IntersectionCastType. + JInterfaceType[] lambdaInterfaces = getInterfacesToImplement(binding); + SourceInfo info = makeSourceInfo(x); - // Create an inner class to implement the interface and SAM method. - // class lambda$0$Type implements T {} + // Create an inner class to implement the interface and SAM method. + // class lambda$0$Type implements T {} - String innerLambdaImplementationClassShortName = String.valueOf(x.binding.selector); - JClassType innerLambdaClass = createInnerClass(curClass.getClassOrInterface(), - innerLambdaImplementationClassShortName, info, lambdaInterfaces); - JConstructor ctor = new JConstructor(info, innerLambdaClass, AccessModifier.PRIVATE); + String innerLambdaImplementationClassShortName = String.valueOf(x.binding.selector); + JClassType innerLambdaClass = createInnerClass(curClass.getClassOrInterface(), + innerLambdaImplementationClassShortName, info, lambdaInterfaces); + JConstructor ctor = new JConstructor(info, innerLambdaClass, AccessModifier.PRIVATE); - // locals captured by the lambda and saved as fields on the anonymous inner class - List locals = new ArrayList(); - SyntheticArgumentBinding[] synthArgs = x.outerLocalVariables; + // locals captured by the lambda and saved as fields on the anonymous inner class + List locals = new ArrayList(); + SyntheticArgumentBinding[] synthArgs = x.outerLocalVariables; - // create the constructor for the anonymous inner and return the field used to store the - // enclosing 'this' which is needed by the SAM method implementation later - JField outerField = - createLambdaConstructor(x, info, innerLambdaClass, ctor, locals, synthArgs); + // create the constructor for the anonymous inner and return the field used to store the + // enclosing 'this' which is needed by the SAM method implementation later + JField outerField = + createLambdaConstructor(x, info, innerLambdaClass, ctor, locals, synthArgs); - // the method containing the lambda expression that the anonymous inner class delegates to, - // it corresponds directly to the lambda expression itself, produced by JDT as a helper method - JMethod lambdaMethod = createLambdaMethod(x); + // the method containing the lambda expression that the anonymous inner class delegates to, + // it corresponds directly to the lambda expression itself, produced by JDT as a helper method + JMethod lambdaMethod = createLambdaMethod(x); - // Now that we've added an implementation method for the lambda, we must create the inner - // class method that implements the target interface type that delegates to the target lambda - // method - JMethod samMethod = new JMethod(info, interfaceMethod.getName(), innerLambdaClass, - interfaceMethod.getType(), false, false, true, interfaceMethod.getAccess()); - samMethod.setSynthetic(); + // Now that we've added an implementation method for the lambda, we must create the inner + // class method that implements the target interface type that delegates to the target lambda + // method + JMethod samMethod = new JMethod(info, interfaceMethod.getName(), innerLambdaClass, + interfaceMethod.getType(), false, false, true, interfaceMethod.getAccess()); + samMethod.setSynthetic(); - // implements the SAM, e.g. Callback.onCallback(), Runnable.run(), etc - createLambdaSamMethod(x, interfaceMethod, info, innerLambdaClass, locals, outerField, - lambdaMethod, - samMethod); + // implements the SAM, e.g. Callback.onCallback(), Runnable.run(), etc + createLambdaSamMethod(x, interfaceMethod, info, innerLambdaClass, locals, outerField, + lambdaMethod, + samMethod); - ctor.freezeParamTypes(); - samMethod.freezeParamTypes(); + ctor.freezeParamTypes(); + samMethod.freezeParamTypes(); - // Create necessary bridges. - createFunctionalExpressionBridges(innerLambdaClass, x, samMethod); + // Create necessary bridges. + createFunctionalExpressionBridges(innerLambdaClass, x, samMethod); - // replace (x,y,z) -> expr with 'new Lambda(args)' - replaceLambdaWithInnerClassAllocation(x, info, innerLambdaClass, ctor, synthArgs); - popMethodInfo(); - // Add the newly generated type - newTypes.add(innerLambdaClass); + // replace (x,y,z) -> expr with 'new Lambda(args)' + replaceLambdaWithInnerClassAllocation(x, info, innerLambdaClass, ctor, synthArgs); + popMethodInfo(); + // Add the newly generated type + newTypes.add(innerLambdaClass); + } catch (Throwable e) { + throw translateException(x, e); + } } private JInterfaceType[] getInterfacesToImplement(TypeBinding binding) { @@ -1867,263 +1887,267 @@ public void endVisit(QualifiedThisReference x, BlockScope scope) { @Override public void endVisit(ReferenceExpression x, BlockScope blockScope) { - /** - * Converts an expression like foo(qualifier::someMethod) into - * - * class Enclosing { - * - * [static] T someMethod(locals, args) {...lambda expr } - * - * class lambda$someMethodType implements I { - * ctor([qualifier]) { ... } - * R (args) { return [outer]someMethod(args); } - * } - * } - * - * and replaces qualifier::someMethod with new lambda$someMethodType([outer this]) - * - * [x] denotes optional, depending on context of whether outer this scope is needed. - */ + try { + /** + * Converts an expression like foo(qualifier::someMethod) into + * + * class Enclosing { + * + * [static] T someMethod(locals, args) {...lambda expr } + * + * class lambda$someMethodType implements I { + * ctor([qualifier]) { ... } + * R (args) { return [outer]someMethod(args); } + * } + * } + * + * and replaces qualifier::someMethod with new lambda$someMethodType([outer this]) + * + * [x] denotes optional, depending on context of whether outer this scope is needed. + */ - // Resolve the reference expression to make sure the declaring class of the method is resolved - // to the right type. - x.resolve(blockScope); - // Calculate what type this reference is going to bind to, and what single abstract method - TypeBinding binding = x.expectedType(); - MethodBinding samBinding = binding.getSingleAbstractMethod(blockScope, false); - MethodBinding declarationSamBinding = - binding.getSingleAbstractMethod(blockScope, false).original(); - // Get the interface method is binds to - JMethod interfaceMethod = typeMap.get(declarationSamBinding); - - JInterfaceType[] funcType = getInterfacesToImplement(binding); - SourceInfo info = makeSourceInfo(x); + // Resolve the reference expression to make sure the declaring class of the method is resolved + // to the right type. + x.resolve(blockScope); + // Calculate what type this reference is going to bind to, and what single abstract method + TypeBinding binding = x.expectedType(); + MethodBinding samBinding = binding.getSingleAbstractMethod(blockScope, false); + MethodBinding declarationSamBinding = + binding.getSingleAbstractMethod(blockScope, false).original(); + // Get the interface method is binds to + JMethod interfaceMethod = typeMap.get(declarationSamBinding); + + JInterfaceType[] funcType = getInterfacesToImplement(binding); + SourceInfo info = makeSourceInfo(x); - // Get the method that the Type::method is actually referring to - MethodBinding referredMethodBinding = x.binding; - if (referredMethodBinding instanceof SyntheticMethodBinding) { - SyntheticMethodBinding synthRefMethodBinding = - (SyntheticMethodBinding) referredMethodBinding; - if (synthRefMethodBinding.targetMethod != null) { - // generated in cases were a private method in an outer class needed to be called - // e.g. outer.access$0 calls some outer.private_method - referredMethodBinding = synthRefMethodBinding.targetMethod; - // privateCtor::new generates overloaded references with fake args that delegate - // to the real ctor (JDT WTF!). Will we ever need to go deeper? - if (synthRefMethodBinding.fakePaddedParameters != 0 - && synthRefMethodBinding.targetMethod instanceof SyntheticMethodBinding) { - referredMethodBinding = ((SyntheticMethodBinding) referredMethodBinding).targetMethod; + // Get the method that the Type::method is actually referring to + MethodBinding referredMethodBinding = x.binding; + if (referredMethodBinding instanceof SyntheticMethodBinding) { + SyntheticMethodBinding synthRefMethodBinding = + (SyntheticMethodBinding) referredMethodBinding; + if (synthRefMethodBinding.targetMethod != null) { + // generated in cases were a private method in an outer class needed to be called + // e.g. outer.access$0 calls some outer.private_method + referredMethodBinding = synthRefMethodBinding.targetMethod; + // privateCtor::new generates overloaded references with fake args that delegate + // to the real ctor (JDT WTF!). Will we ever need to go deeper? + if (synthRefMethodBinding.fakePaddedParameters != 0 + && synthRefMethodBinding.targetMethod instanceof SyntheticMethodBinding) { + referredMethodBinding = ((SyntheticMethodBinding) referredMethodBinding).targetMethod; + } } } - } - JMethod referredMethod = typeMap.get(referredMethodBinding); - boolean hasQualifier = hasQualifier(x); - - // Constructors, overloading and generics means that the safest approach is to consider - // each different member reference as a different lambda implementation. - String lambdaImplementationClassShortName = - String.valueOf(nextReferenceExpressionId++) + "methodref$" - + (x.binding.isConstructor() ? "ctor" : String.valueOf(x.binding.selector)); - List enclosingThisRefs = Lists.newArrayList(); - - // Create an inner class to hold the implementation of the interface - JClassType innerLambdaClass = createInnerClass( - curClass.getClassOrInterface(), lambdaImplementationClassShortName, info, funcType); - newTypes.add(innerLambdaClass); - - JConstructor ctor = new JConstructor(info, innerLambdaClass, AccessModifier.PRIVATE); - - JMethodBody ctorBody = new JMethodBody(info); - JThisRef thisRef = new JThisRef(info, innerLambdaClass); - JExpression instance = null; - - List enclosingInstanceFields = new ArrayList(); - // If we have a qualifier instance, we have to stash it in the constructor - if (hasQualifier) { - // this.$$outer = $$outer - JField outerField = createAndBindCapturedLambdaParameter(info, OUTER_LAMBDA_PARAM_NAME, - referredMethod.getEnclosingType(), ctor, ctorBody); - instance = new JFieldRef(info, - new JThisRef(info, innerLambdaClass), outerField, innerLambdaClass); - } else if (referredMethod instanceof JConstructor) { - // the method we are invoking is a constructor and may need enclosing instances passed to - // it. - // For example, an class Foo { class Inner { Inner(int x) { } } } needs - // it's constructor invoked with an enclosing instance, Inner::new - // Java8 doesn't allow the qualifified case, e.g. x.new Foo() -> x.Foo::new - ReferenceBinding targetBinding = referredMethodBinding.declaringClass; - if (targetBinding.syntheticEnclosingInstanceTypes() != null) { - for (ReferenceBinding argType : targetBinding.syntheticEnclosingInstanceTypes()) { - argType = (ReferenceBinding) argType.erasure(); - JExpression enclosingThisRef = resolveThisReference(info, argType, false, blockScope); - JField enclosingInstance = createAndBindCapturedLambdaParameter(info, - String.valueOf(argType.readableName()).replace('.', '_'), - enclosingThisRef.getType(), ctor, ctorBody); - enclosingInstanceFields.add(enclosingInstance); - enclosingThisRefs.add(enclosingThisRef); + JMethod referredMethod = typeMap.get(referredMethodBinding); + boolean hasQualifier = hasQualifier(x); + + // Constructors, overloading and generics means that the safest approach is to consider + // each different member reference as a different lambda implementation. + String lambdaImplementationClassShortName = + String.valueOf(nextReferenceExpressionId++) + "methodref$" + + (x.binding.isConstructor() ? "ctor" : String.valueOf(x.binding.selector)); + List enclosingThisRefs = Lists.newArrayList(); + + // Create an inner class to hold the implementation of the interface + JClassType innerLambdaClass = createInnerClass( + curClass.getClassOrInterface(), lambdaImplementationClassShortName, info, funcType); + newTypes.add(innerLambdaClass); + + JConstructor ctor = new JConstructor(info, innerLambdaClass, AccessModifier.PRIVATE); + + JMethodBody ctorBody = new JMethodBody(info); + JThisRef thisRef = new JThisRef(info, innerLambdaClass); + JExpression instance = null; + + List enclosingInstanceFields = new ArrayList(); + // If we have a qualifier instance, we have to stash it in the constructor + if (hasQualifier) { + // this.$$outer = $$outer + JField outerField = createAndBindCapturedLambdaParameter(info, OUTER_LAMBDA_PARAM_NAME, + referredMethod.getEnclosingType(), ctor, ctorBody); + instance = new JFieldRef(info, + new JThisRef(info, innerLambdaClass), outerField, innerLambdaClass); + } else if (referredMethod instanceof JConstructor) { + // the method we are invoking is a constructor and may need enclosing instances passed to + // it. + // For example, an class Foo { class Inner { Inner(int x) { } } } needs + // it's constructor invoked with an enclosing instance, Inner::new + // Java8 doesn't allow the qualifified case, e.g. x.new Foo() -> x.Foo::new + ReferenceBinding targetBinding = referredMethodBinding.declaringClass; + if (targetBinding.syntheticEnclosingInstanceTypes() != null) { + for (ReferenceBinding argType : targetBinding.syntheticEnclosingInstanceTypes()) { + argType = (ReferenceBinding) argType.erasure(); + JExpression enclosingThisRef = resolveThisReference(info, argType, false, blockScope); + JField enclosingInstance = createAndBindCapturedLambdaParameter(info, + String.valueOf(argType.readableName()).replace('.', '_'), + enclosingThisRef.getType(), ctor, ctorBody); + enclosingInstanceFields.add(enclosingInstance); + enclosingThisRefs.add(enclosingThisRef); + } } } - } - ctor.setBody(ctorBody); - innerLambdaClass.addMethod(ctor); - - // Create an implementation of the target interface that invokes the method referred to - // void onClick(ClickEvent e) { outer.referredMethod(e); } - JMethod samMethod = new JMethod(info, interfaceMethod.getName(), - innerLambdaClass, interfaceMethod.getType(), - false, false, true, interfaceMethod.getAccess()); - samMethod.setSynthetic(); - - for (JParameter origParam : interfaceMethod.getParams()) { - samMethod.cloneParameter(origParam); - } - JMethodBody samMethodBody = new JMethodBody(info); - - Iterator paramIt = samMethod.getParams().iterator(); - // here's where it gets tricky. A method can have an implicit qualifier, e.g. - // String::compareToIgnoreCase, it's non-static, it only has one argument, but it binds to - // Comparator. - // The first argument serves as the qualifier, so for example, the method dispatch looks - // like this: int compare(T a, T b) { a.compareTo(b); } - if (!hasQualifier - && !referredMethod.isStatic() - && !referredMethod.isConstructor() - && instance == null) { - // the instance qualifier is the first parameter in this case. - // Needs to be cast the actual type due to generics. - instance = new JCastOperation(info, typeMap.get(referredMethodBinding.declaringClass), - paramIt.next().makeRef(info)); - } - JMethodCall samCall = null; - - if (referredMethod.isConstructor()) { - // Constructors must be invoked with JNewInstance - samCall = new JNewInstance(info, (JConstructor) referredMethod); - for (JField enclosingInstance : enclosingInstanceFields) { - samCall.addArg(new JFieldRef(enclosingInstance.getSourceInfo(), thisRef, - enclosingInstance, innerLambdaClass)); + ctor.setBody(ctorBody); + innerLambdaClass.addMethod(ctor); + + // Create an implementation of the target interface that invokes the method referred to + // void onClick(ClickEvent e) { outer.referredMethod(e); } + JMethod samMethod = new JMethod(info, interfaceMethod.getName(), + innerLambdaClass, interfaceMethod.getType(), + false, false, true, interfaceMethod.getAccess()); + samMethod.setSynthetic(); + + for (JParameter origParam : interfaceMethod.getParams()) { + samMethod.cloneParameter(origParam); } - } else { - // For static methods, instance will be null - samCall = new JMethodCall(info, instance, referredMethod); - // if super::method, we need static dispatch - if (isSuperReference(x.lhs)) { - samCall.setStaticDispatchOnly(); + JMethodBody samMethodBody = new JMethodBody(info); + + Iterator paramIt = samMethod.getParams().iterator(); + // here's where it gets tricky. A method can have an implicit qualifier, e.g. + // String::compareToIgnoreCase, it's non-static, it only has one argument, but it binds to + // Comparator. + // The first argument serves as the qualifier, so for example, the method dispatch looks + // like this: int compare(T a, T b) { a.compareTo(b); } + if (!hasQualifier + && !referredMethod.isStatic() + && !referredMethod.isConstructor() + && instance == null) { + // the instance qualifier is the first parameter in this case. + // Needs to be cast the actual type due to generics. + instance = new JCastOperation(info, typeMap.get(referredMethodBinding.declaringClass), + paramIt.next().makeRef(info)); + } + JMethodCall samCall = null; + + if (referredMethod.isConstructor()) { + // Constructors must be invoked with JNewInstance + samCall = new JNewInstance(info, (JConstructor) referredMethod); + for (JField enclosingInstance : enclosingInstanceFields) { + samCall.addArg(new JFieldRef(enclosingInstance.getSourceInfo(), thisRef, + enclosingInstance, innerLambdaClass)); + } + } else { + // For static methods, instance will be null + samCall = new JMethodCall(info, instance, referredMethod); + // if super::method, we need static dispatch + if (isSuperReference(x.lhs)) { + samCall.setStaticDispatchOnly(); + } } - } - // Add the rest of the parameters from the interface method to methodcall - // boxing or unboxing and dealing with varargs - int paramNumber = 0; - - // need to build up an array of passed parameters if we have varargs - List varArgInitializers = null; - int varArg = referredMethodBinding.parameters.length - 1; - - // interface Foo { m(int x, int y); } bound to reference foo(int... args) - // if varargs and incoming param is not already a var-arg, we'll need to convert - // trailing args of the target interface into an array - boolean isVarargArgumentSuppliedDirectlyAsAnArray = - referredMethodBinding.isVarargs() - && samBinding.parameters.length == referredMethodBinding.parameters.length - && samBinding.parameters[varArg] - .isCompatibleWith(referredMethodBinding.parameters[varArg]); - - if (referredMethodBinding.isVarargs() - && !isVarargArgumentSuppliedDirectlyAsAnArray) { - varArgInitializers = Lists.newArrayList(); - } - - while (paramIt.hasNext()) { - JParameter param = paramIt.next(); - JExpression paramExpr = param.makeRef(info); - // params may need to be boxed or unboxed - TypeBinding destParam = null; - - int declarationParameterOffset = - declarationSamBinding.parameters.length - - referredMethodBinding.parameters.length; - // The method declared in the functional interface might have more or less parameters than - // the method referred by the method reference. In the case of an instance method without - // an explicit qualifier (A::m vs instance::m) the method in the functional interface will - // have an additional parameter for the instance preceding all the method parameters. - // So truncate the value of the index to refer to the right parameter. - int declarationParameterIndex = Math.max(0, - Math.min( - paramNumber - + declarationParameterOffset, - declarationSamBinding.parameters.length - 1) - ); - TypeBinding samParameterBinding = - declarationSamBinding.parameters[declarationParameterIndex]; - // if it is not the trailing param or varargs, or interface method is already varargs - if (varArgInitializers == null - || !referredMethodBinding.isVarargs() - || (paramNumber < varArg)) { - destParam = referredMethodBinding.parameters[paramNumber]; - paramExpr = maybeInsertCasts(paramExpr, samParameterBinding, destParam); - samCall.addArg(paramExpr); - } else if (!samParameterBinding.isArrayType()) { - // else add trailing parameters to var-args initializer list for an array - destParam = referredMethodBinding.parameters[varArg].leafComponentType(); - paramExpr = maybeInsertCasts(paramExpr, samParameterBinding, destParam); - varArgInitializers.add(paramExpr); + // Add the rest of the parameters from the interface method to methodcall + // boxing or unboxing and dealing with varargs + int paramNumber = 0; + + // need to build up an array of passed parameters if we have varargs + List varArgInitializers = null; + int varArg = referredMethodBinding.parameters.length - 1; + + // interface Foo { m(int x, int y); } bound to reference foo(int... args) + // if varargs and incoming param is not already a var-arg, we'll need to convert + // trailing args of the target interface into an array + boolean isVarargArgumentSuppliedDirectlyAsAnArray = + referredMethodBinding.isVarargs() + && samBinding.parameters.length == referredMethodBinding.parameters.length + && samBinding.parameters[varArg] + .isCompatibleWith(referredMethodBinding.parameters[varArg]); + + if (referredMethodBinding.isVarargs() + && !isVarargArgumentSuppliedDirectlyAsAnArray) { + varArgInitializers = Lists.newArrayList(); } - paramNumber++; - } - // add trailing new T[] { initializers } var-arg array - if (varArgInitializers != null) { - JArrayType lastParamType = - (JArrayType) typeMap.get( - referredMethodBinding.parameters[referredMethodBinding.parameters.length - 1]); - JNewArray newArray = - JNewArray.createArrayWithInitializers(info, lastParamType, varArgInitializers); - samCall.addArg(newArray); - } + while (paramIt.hasNext()) { + JParameter param = paramIt.next(); + JExpression paramExpr = param.makeRef(info); + // params may need to be boxed or unboxed + TypeBinding destParam = null; + + int declarationParameterOffset = + declarationSamBinding.parameters.length + - referredMethodBinding.parameters.length; + // The method declared in the functional interface might have more or less parameters than + // the method referred by the method reference. In the case of an instance method without + // an explicit qualifier (A::m vs instance::m) the method in the functional interface will + // have an additional parameter for the instance preceding all the method parameters. + // So truncate the value of the index to refer to the right parameter. + int declarationParameterIndex = Math.max(0, + Math.min( + paramNumber + + declarationParameterOffset, + declarationSamBinding.parameters.length - 1) + ); + TypeBinding samParameterBinding = + declarationSamBinding.parameters[declarationParameterIndex]; + // if it is not the trailing param or varargs, or interface method is already varargs + if (varArgInitializers == null + || !referredMethodBinding.isVarargs() + || (paramNumber < varArg)) { + destParam = referredMethodBinding.parameters[paramNumber]; + paramExpr = maybeInsertCasts(paramExpr, samParameterBinding, destParam); + samCall.addArg(paramExpr); + } else if (!samParameterBinding.isArrayType()) { + // else add trailing parameters to var-args initializer list for an array + destParam = referredMethodBinding.parameters[varArg].leafComponentType(); + paramExpr = maybeInsertCasts(paramExpr, samParameterBinding, destParam); + varArgInitializers.add(paramExpr); + } + paramNumber++; + } - // TODO(rluble): Make this a call to JjsUtils.makeMethodEndStatement once boxing/unboxing - // is handled there. - if (samMethod.getType() != JPrimitiveType.VOID) { - JExpression samExpression = maybeInsertCasts(samCall, referredMethodBinding.returnType, - declarationSamBinding.returnType); - samMethodBody.getBlock().addStmt(maybeBoxOrUnbox(samExpression, x).makeReturnStatement()); - } else { - samMethodBody.getBlock().addStmt(samCall.makeStatement()); - } - samMethod.setBody(samMethodBody); - innerLambdaClass.addMethod(samMethod); - ctor.freezeParamTypes(); - samMethod.freezeParamTypes(); + // add trailing new T[] { initializers } var-arg array + if (varArgInitializers != null) { + JArrayType lastParamType = + (JArrayType) typeMap.get( + referredMethodBinding.parameters[referredMethodBinding.parameters.length - 1]); + JNewArray newArray = + JNewArray.createArrayWithInitializers(info, lastParamType, varArgInitializers); + samCall.addArg(newArray); + } - createFunctionalExpressionBridges(innerLambdaClass, x, samMethod); + // TODO(rluble): Make this a call to JjsUtils.makeMethodEndStatement once boxing/unboxing + // is handled there. + if (samMethod.getType() != JPrimitiveType.VOID) { + JExpression samExpression = maybeInsertCasts(samCall, referredMethodBinding.returnType, + declarationSamBinding.returnType); + samMethodBody.getBlock().addStmt(maybeBoxOrUnbox(samExpression, x).makeReturnStatement()); + } else { + samMethodBody.getBlock().addStmt(samCall.makeStatement()); + } + samMethod.setBody(samMethodBody); + innerLambdaClass.addMethod(samMethod); + ctor.freezeParamTypes(); + samMethod.freezeParamTypes(); - JConstructor lambdaCtor = null; - for (JMethod method : innerLambdaClass.getMethods()) { - if (method instanceof JConstructor) { - lambdaCtor = (JConstructor) method; - break; + createFunctionalExpressionBridges(innerLambdaClass, x, samMethod); + + JConstructor lambdaCtor = null; + for (JMethod method : innerLambdaClass.getMethods()) { + if (method instanceof JConstructor) { + lambdaCtor = (JConstructor) method; + break; + } } - } - assert lambdaCtor != null; + assert lambdaCtor != null; - // Replace the ReferenceExpression qualifier::method with new lambdaType(qualifier) - assert lambdaCtor.getEnclosingType() == innerLambdaClass; - JNewInstance allocLambda = new JNewInstance(info, lambdaCtor); + // Replace the ReferenceExpression qualifier::method with new lambdaType(qualifier) + assert lambdaCtor.getEnclosingType() == innerLambdaClass; + JNewInstance allocLambda = new JNewInstance(info, lambdaCtor); - if (hasQualifier) { - JExpression qualifier = (JExpression) pop(); - // pop qualifier from stack - allocLambda.addArg(qualifier); - } else { - // you can't simultaneously have a qualifier, and have enclosing inner class refs - // because Java8 won't allow a qualified constructor method reference, e.g. x.Foo::new - for (JExpression enclosingRef : enclosingThisRefs) { - allocLambda.addArg(enclosingRef); + if (hasQualifier) { + JExpression qualifier = (JExpression) pop(); + // pop qualifier from stack + allocLambda.addArg(qualifier); + } else { + // you can't simultaneously have a qualifier, and have enclosing inner class refs + // because Java8 won't allow a qualified constructor method reference, e.g. x.Foo::new + for (JExpression enclosingRef : enclosingThisRefs) { + allocLambda.addArg(enclosingRef); + } } + push(allocLambda); + } catch (Throwable e) { + throw translateException(x, e); } - push(allocLambda); } /** @@ -2559,8 +2583,12 @@ public boolean visit(Argument x, BlockScope scope) { @Override public boolean visit(Block x, BlockScope scope) { - x.statements = reduceToReachable(x.statements); - return true; + try { + x.statements = reduceToReachable(x.statements); + return true; + } catch (Throwable e) { + throw translateException(x, e); + } } @Override @@ -2700,14 +2728,22 @@ public boolean visit(SingleMemberAnnotation annotation, BlockScope scope) { @Override public boolean visit(SwitchStatement x, BlockScope scope) { - x.statements = reduceToReachable(x.statements); - return true; + try { + x.statements = reduceToReachable(x.statements); + return true; + } catch (Throwable e) { + throw translateException(x, e); + } } @Override public boolean visit(SwitchExpression x, BlockScope blockScope) { - x.statements = reduceToReachable(x.statements); - return true; + try { + x.statements = reduceToReachable(x.statements); + return true; + } catch (Throwable e) { + throw translateException(x, e); + } } @Override @@ -2744,37 +2780,41 @@ public boolean visitValid(TypeDeclaration x, BlockScope scope) { } protected void endVisit(TypeDeclaration x) { - JDeclaredType type = curClass.type; + try { + JDeclaredType type = curClass.type; + + // Synthesize super clinit calls. + if (type instanceof JClassType) { + Iterable interfacesToInitialize = + Iterables.transform( + JdtUtil.getSuperInterfacesRequiringInitialization(x.binding), + new Function() { + @Override + public JInterfaceType apply(ReferenceBinding referenceBinding) { + return (JInterfaceType) typeMap.get(referenceBinding); + } + }); + JjsUtils.synthesizeStaticInitializerChain(type, interfacesToInitialize); + } - // Synthesize super clinit calls. - if (type instanceof JClassType) { - Iterable interfacesToInitialize = - Iterables.transform( - JdtUtil.getSuperInterfacesRequiringInitialization(x.binding), - new Function() { - @Override - public JInterfaceType apply(ReferenceBinding referenceBinding) { - return (JInterfaceType) typeMap.get(referenceBinding); - } - }); - JjsUtils.synthesizeStaticInitializerChain(type, interfacesToInitialize); - } + // Implement getClass() implementation for all non-Object classes. + if (isSyntheticGetClassNeeded(x, type) && !type.isAbstract()) { + implementGetClass(type); + } - // Implement getClass() implementation for all non-Object classes. - if (isSyntheticGetClassNeeded(x, type) && !type.isAbstract()) { - implementGetClass(type); - } + if (type instanceof JEnumType) { + processEnumType((JEnumType) type); + } - if (type instanceof JEnumType) { - processEnumType((JEnumType) type); - } + if (type instanceof JClassType && type.isJsNative()) { + maybeImplementJavaLangObjectMethodsOnNativeClass(type); + } + addBridgeMethods(x.binding); - if (type instanceof JClassType && type.isJsNative()) { - maybeImplementJavaLangObjectMethodsOnNativeClass(type); + curClass = classStack.pop(); + } catch (Throwable e) { + throw translateException(x, e); } - addBridgeMethods(x.binding); - - curClass = classStack.pop(); } protected JBlock pop(Block x) { @@ -2876,46 +2916,50 @@ protected void pushBinaryOp(BinaryExpression x, JBinaryOperator op) { } protected boolean visit(TypeDeclaration x) { - JDeclaredType type = (JDeclaredType) typeMap.get(x.binding); - assert !type.isExternal(); - classStack.push(curClass); - curClass = new ClassInfo(type, x); + try { + JDeclaredType type = (JDeclaredType) typeMap.get(x.binding); + assert !type.isExternal(); + classStack.push(curClass); + curClass = new ClassInfo(type, x); - /* - * It's okay to defer creation of synthetic fields, they can't be - * referenced until we analyze the code. - */ - SourceTypeBinding binding = x.binding; - if (JdtUtil.isInnerClass(binding)) { - // add synthetic fields for outer this and locals - assert (type instanceof JClassType); - NestedTypeBinding nestedBinding = (NestedTypeBinding) binding; - if (nestedBinding.enclosingInstances != null) { - for (SyntheticArgumentBinding argument : nestedBinding.enclosingInstances) { - createSyntheticField(argument, type, Disposition.THIS_REF); + /* + * It's okay to defer creation of synthetic fields, they can't be + * referenced until we analyze the code. + */ + SourceTypeBinding binding = x.binding; + if (JdtUtil.isInnerClass(binding)) { + // add synthetic fields for outer this and locals + assert (type instanceof JClassType); + NestedTypeBinding nestedBinding = (NestedTypeBinding) binding; + if (nestedBinding.enclosingInstances != null) { + for (SyntheticArgumentBinding argument : nestedBinding.enclosingInstances) { + createSyntheticField(argument, type, Disposition.THIS_REF); + } } - } - if (nestedBinding.outerLocalVariables != null) { - for (SyntheticArgumentBinding argument : nestedBinding.outerLocalVariables) { - // See InnerClassTest.testOuterThisFromSuperCall(). - boolean isReallyThisRef = false; - if (argument.actualOuterLocalVariable instanceof SyntheticArgumentBinding) { - SyntheticArgumentBinding outer = - (SyntheticArgumentBinding) argument.actualOuterLocalVariable; - if (outer.matchingField != null) { - JField field = typeMap.get(outer.matchingField); - if (field.isThisRef()) { - isReallyThisRef = true; + if (nestedBinding.outerLocalVariables != null) { + for (SyntheticArgumentBinding argument : nestedBinding.outerLocalVariables) { + // See InnerClassTest.testOuterThisFromSuperCall(). + boolean isReallyThisRef = false; + if (argument.actualOuterLocalVariable instanceof SyntheticArgumentBinding) { + SyntheticArgumentBinding outer = + (SyntheticArgumentBinding) argument.actualOuterLocalVariable; + if (outer.matchingField != null) { + JField field = typeMap.get(outer.matchingField); + if (field.isThisRef()) { + isReallyThisRef = true; + } } } + createSyntheticField(argument, type, isReallyThisRef ? Disposition.THIS_REF + : Disposition.FINAL); } - createSyntheticField(argument, type, isReallyThisRef ? Disposition.THIS_REF - : Disposition.FINAL); } } + return true; + } catch (Throwable e) { + throw translateException(x, e); } - return true; } /**