Cleanup in UnifyAST. Change-Id: Ie0c5a85f9334a4582498818c5f4e3bebedf974b6
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java index 4851be5..b2ec0d0 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java
@@ -224,6 +224,7 @@ return isCompileTimeConstant; } + @Override public boolean isExternal() { return getEnclosingType().isExternal(); }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMember.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMember.java index c0ab0e3..cc4e6dc 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMember.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMember.java
@@ -31,5 +31,7 @@ boolean isSynthetic(); + boolean isExternal(); + String getQualifiedName(); }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java index 41f4bda..511b10f 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
@@ -644,6 +644,7 @@ return access == AccessModifier.DEFAULT.ordinal(); } + @Override public boolean isExternal() { return getEnclosingType().isExternal(); }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaAstVerifier.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaAstVerifier.java index 7537714..0cf679e 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaAstVerifier.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaAstVerifier.java
@@ -54,7 +54,7 @@ JavaAstVerifier(JProgram program) { this.program = program; - for (JDeclaredType type :program.getModuleDeclaredTypes()) { + for (JDeclaredType type :program.getDeclaredTypes()) { membersByType.putAll(type, type.getMethods()); membersByType.putAll(type, type.getFields()); }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java index 9e902b0..ae9af27 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
@@ -18,6 +18,7 @@ import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.TreeLogger.Type; import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.linker.ArtifactSet; import com.google.gwt.dev.CompilerContext; import com.google.gwt.dev.MinimalRebuildCache; import com.google.gwt.dev.cfg.ConfigurationProperty; @@ -27,8 +28,8 @@ import com.google.gwt.dev.javac.CompilationUnit; import com.google.gwt.dev.javac.CompiledClass; import com.google.gwt.dev.jdt.RebindPermutationOracle; -import com.google.gwt.dev.jjs.InternalCompilerException; import com.google.gwt.dev.jjs.PrecompilationContext; +import com.google.gwt.dev.jjs.SourceInfo; import com.google.gwt.dev.jjs.SourceOrigin; import com.google.gwt.dev.jjs.ast.Context; import com.google.gwt.dev.jjs.ast.HasName; @@ -48,6 +49,7 @@ import com.google.gwt.dev.jjs.ast.JFieldRef; import com.google.gwt.dev.jjs.ast.JInstanceOf; import com.google.gwt.dev.jjs.ast.JInterfaceType; +import com.google.gwt.dev.jjs.ast.JMember; import com.google.gwt.dev.jjs.ast.JMethod; import com.google.gwt.dev.jjs.ast.JMethod.Specialization; import com.google.gwt.dev.jjs.ast.JMethodBody; @@ -84,6 +86,7 @@ import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger; import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event; import com.google.gwt.thirdparty.guava.common.base.Predicates; +import com.google.gwt.thirdparty.guava.common.collect.ImmutableMap; import com.google.gwt.thirdparty.guava.common.collect.Iterables; import com.google.gwt.thirdparty.guava.common.collect.LinkedListMultimap; import com.google.gwt.thirdparty.guava.common.collect.Lists; @@ -236,25 +239,13 @@ } @Override - public void endVisit(JExpressionStatement x, Context ctx) { - if (x.getExpr() instanceof JMethodCall) { - JMethodCall call = (JMethodCall) x.getExpr(); - JMethod target = call.getTarget(); - if (GWT_DEBUGGER_METHOD_CALLS.contains(target.getQualifiedName())) { - // We should see all calls here because GWT.debugger() returns void. - ctx.replaceMe(new JDebuggerStatement(x.getSourceInfo())); - } - } - } - - @Override public void endVisit(JField x, Context ctx) { assert false : "Should not get here"; } @Override public void endVisit(JFieldRef x, Context ctx) { - JField field = translate(x.getField()); + JField field = translate(x.getSourceInfo(), x.getField()); flowInto(field); x.resolve(field); // Should not have an overridden type at this point. @@ -285,21 +276,7 @@ assert errorsFound; return; } - String targetSignature = target.getQualifiedName(); - if (MAGIC_METHOD_CALLS.contains(targetSignature)) { - if (GWT_DEBUGGER_METHOD_CALLS.contains(targetSignature)) { - return; // handled in endVisit for JExpressionStatement - } - JExpression result = handleMagicMethodCall(x, targetSignature); - if (result == null) { - // Error of some sort. - result = JNullLiteral.INSTANCE; - } - result = this.accept(result); - ctx.replaceMe(result); - return; - } - // Should not have an overridden type at this point. + // Should not have an overridden type at this point. assert x instanceof JNewInstance || x.getType() == target.getType(); flowInto(target); @@ -310,10 +287,8 @@ HasName node = x.getNode(); if (node instanceof JType) { node = translate((JType) node); - } else if (node instanceof JField) { - node = translate((JField) node); - } else if (node instanceof JMethod) { - node = translate((JMethod) node); + } else if (node instanceof JMember) { + node = translate(x.getSourceInfo(), (JMember) node); } else { assert false : "Should not get here"; } @@ -349,7 +324,7 @@ @Override public void endVisit(JsniMethodRef x, Context ctx) { - JMethod target = translate(x.getTarget()); + JMethod target = translate(x.getSourceInfo(), x.getTarget()); x.resolve(target, program.getJavaScriptObject()); flowInto(target); } @@ -391,6 +366,19 @@ } @Override + public boolean visit(JExpressionStatement x, Context ctx) { + if (x.getExpr() instanceof JMethodCall) { + JMethodCall call = (JMethodCall) x.getExpr(); + JMethod target = call.getTarget(); + if (GWT_DEBUGGER_METHOD_CALLS.contains(target.getQualifiedName())) { + // We should see all calls here because GWT.debugger() returns void. + ctx.replaceMe(new JDebuggerStatement(x.getSourceInfo())); + } + } + return true; + } + + @Override public boolean visit(JMethod x, Context ctx) { currentMethod = x; // Only visit contents of methods defined in types which are part of this compile. Visit @@ -402,10 +390,40 @@ @Override public boolean visit(JMethodCall x, Context ctx) { - JMethod target = translate(x.getTarget()); + JMethod target = translate(x.getSourceInfo(), x.getTarget()); x.resolve(target); - // Special handling. - return !MAGIC_METHOD_CALLS.contains(target.getQualifiedName()); + // Special handling for magic method calls. + JExpression replacement = maybeHandleMagicMethodCall(x); + if (replacement != null) { + ctx.replaceMe(accept(replacement)); + return false; + } + return true; + } + + private JExpression maybeHandleMagicMethodCall(JMethodCall methodCall) { + JExpression result; + switch (methodCall.getTarget().getQualifiedName()) { + case GWT_CREATE: + case OLD_GWT_CREATE: + result = createRebindExpression(methodCall); + break; + case IMPL_GET_NAME_OF: + result = handleImplNameOf(methodCall); + break; + case SYSTEM_GET_PROPERTY: + case SYSTEM_GET_PROPERTY_WITH_DEFAULT: + result = handleSystemGetProperty(methodCall); + break; + default: + // Not a magic method call, return null so that it does not get replaced. + return null; + } + if (result == null) { + // Handled magic call possibly with an error. + return JNullLiteral.INSTANCE; + } + return result; } private JExpression handleSystemGetProperty(JMethodCall gwtGetPropertyCall) { @@ -485,18 +503,21 @@ } minimalRebuildCache.recordRebinderTypeForReboundType(reboundTypeName, currentMethod.getEnclosingType().getName()); - rpo.getGeneratorContext().setCurrentRebindBinaryTypeName(reboundTypeName); + rebindPermutationOracle + .getGeneratorContext().setCurrentRebindBinaryTypeName(reboundTypeName); } - String reqType = BinaryName.toSourceName(reboundTypeName); + String requestedType = BinaryName.toSourceName(reboundTypeName); List<String> answers; try { - answers = Lists.newArrayList(rpo.getAllPossibleRebindAnswers(logger, reqType)); + answers = Lists.newArrayList( + rebindPermutationOracle.getAllPossibleRebindAnswers(logger, requestedType)); if (incrementalCompile) { // Accumulate generated artifacts so that they can be output on recompiles even if no // generators are run. - minimalRebuildCache.addGeneratedArtifacts(rpo.getGeneratorContext().getArtifacts()); + ArtifactSet artifacts = rebindPermutationOracle.getGeneratorContext().getArtifacts(); + minimalRebuildCache.addGeneratedArtifacts(artifacts); } - rpo.getGeneratorContext().finish(logger); + rebindPermutationOracle.getGeneratorContext().finish(logger); if (incrementalCompile) { // There may be more types known to be modified after Generator execution, which would // mean the previous stale types calculation was too small. Redo it. @@ -506,7 +527,7 @@ fullFlowIntoRemainingStaleTypes(); } } catch (UnableToCompleteException e) { - error(gwtCreateCall, "Failed to resolve '" + reqType + "' via deferred binding"); + error(gwtCreateCall, "Failed to resolve '" + requestedType + "' via deferred binding"); return null; } @@ -545,7 +566,7 @@ return instantiationExpressions.get(0); } return JPermutationDependentValue - .createTypeRebind(program, gwtCreateCall.getSourceInfo(), reqType, + .createTypeRebind(program, gwtCreateCall.getSourceInfo(), requestedType, answers, instantiationExpressions); } @@ -580,20 +601,6 @@ } return new JNameOf(x.getSourceInfo(), program.getTypeJavaLangString(), (HasName) node); } - - private JExpression handleMagicMethodCall(JMethodCall x, String targetSignature) { - switch (targetSignature) { - case GWT_CREATE: - case OLD_GWT_CREATE: - return createRebindExpression(x); - case IMPL_GET_NAME_OF: - return handleImplNameOf(x); - case SYSTEM_GET_PROPERTY: - case SYSTEM_GET_PROPERTY_WITH_DEFAULT: - return handleSystemGetProperty(x); - } - throw new InternalCompilerException("Unknown magic method"); - } } private boolean isMultivaluedProperty(String propertyName) { @@ -654,19 +661,9 @@ Sets.newLinkedHashSet(Arrays.asList(GWT_DEBUGGER_SHARED, GWT_DEBUGGER_CLIENT)); /** - * Methods for which the call site must be replaced with magic AST nodes. - */ - private static final Set<String> MAGIC_METHOD_CALLS = Sets.newLinkedHashSet(Arrays.asList( - GWT_CREATE, GWT_DEBUGGER_SHARED, GWT_DEBUGGER_CLIENT, SYSTEM_GET_PROPERTY, - SYSTEM_GET_PROPERTY_WITH_DEFAULT, - OLD_GWT_CREATE, IMPL_GET_NAME_OF)); - - /** * Methods with magic implementations that the compiler must insert. */ - private static final Set<String> MAGIC_METHOD_IMPLS = Sets.newLinkedHashSet(Arrays.asList( - GWT_IS_CLIENT, OLD_GWT_IS_CLIENT, GWT_IS_PROD_MODE, OLD_GWT_IS_PROD_MODE, GWT_IS_SCRIPT, - OLD_GWT_IS_SCRIPT, CLASS_DESIRED_ASSERTION_STATUS, CLASS_IS_CLASS_METADATA_ENABLED)); + private final Map<String, JBooleanLiteral> replacementValueByMagicMethodQualifiedName; private final CompilationState compilationState; private final Map<String, CompiledClass> compiledClassesByInternalName; @@ -680,7 +677,6 @@ */ private boolean errorsFound = false; private final Set<CompilationUnit> unitsWithErrorsAlreadyReported = Sets.newIdentityHashSet(); - private final Map<String, JField> fieldMap = Maps.newHashMap(); /** * The set of types currently known to be instantiable. Like @@ -705,9 +701,9 @@ private final TreeLogger logger; private final CompilerContext compilerContext; - private final Map<String, JMethod> methodMap = Maps.newHashMap(); + private final Map<String, JMember> resolvedMembersByQualifiedName = Maps.newHashMap(); private final JProgram program; - private final RebindPermutationOracle rpo; + private final RebindPermutationOracle rebindPermutationOracle; private final Set<String> reboundTypeNames = Sets.newHashSet(); /** @@ -728,10 +724,11 @@ * A work queue of methods whose bodies we need to traverse. Prevents * excessive stack use. */ - private final Queue<JMethod> todo = Lists.newLinkedList(); + private final Queue<JMethod> methodsPending = Lists.newLinkedList(); - private final Set<String> virtualMethodsLive = Sets.newHashSet(); - private final Multimap<String, JMethod> virtualMethodsPending = LinkedListMultimap.create(); + private final Set<String> liveVirtualMethods = Sets.newHashSet(); + private final Multimap<String, JMethod> pendingVirtualMethodsBySignature = + LinkedListMultimap.create(); private NameBasedTypeLocator sourceNameBasedTypeLocator; private NameBasedTypeLocator binaryNameBasedTypeLocator; @@ -750,8 +747,8 @@ this.compilerContext = compilerContext; this.program = program; this.jsProgram = jsProgram; - this.rpo = precompilationContext.getRebindPermutationOracle(); - this.compilationState = rpo.getCompilationState(); + this.rebindPermutationOracle = precompilationContext.getRebindPermutationOracle(); + this.compilationState = rebindPermutationOracle.getCompilationState(); this.compiledClassesByInternalName = compilationState.getClassFileMap(); this.compiledClassesBySourceName = compilationState.getClassFileMapBySource(); initializeNameBasedLocators(); @@ -761,6 +758,23 @@ minimalRebuildCache.computeAndClearStaleTypesCache(logger, program.typeOracle); checkPreambleTypesStillFresh(logger); } + + // Magical methods are implemented by replacing their bodies during unification. + replacementValueByMagicMethodQualifiedName = + ImmutableMap.<String, JBooleanLiteral>builder() + .put(GWT_IS_CLIENT, JBooleanLiteral.TRUE) + .put(OLD_GWT_IS_CLIENT, JBooleanLiteral.TRUE) + .put(GWT_IS_PROD_MODE, JBooleanLiteral.TRUE) + .put(OLD_GWT_IS_PROD_MODE, JBooleanLiteral.TRUE) + .put(GWT_IS_SCRIPT, JBooleanLiteral.TRUE) + .put(OLD_GWT_IS_SCRIPT, JBooleanLiteral.TRUE) + .put( + CLASS_DESIRED_ASSERTION_STATUS, + JBooleanLiteral.get(compilerContext.getOptions().isEnableAssertions())) + .put( + CLASS_IS_CLASS_METADATA_ENABLED, + JBooleanLiteral.get(!compilerContext.getOptions().isClassMetadataDisabled())) + .build(); } public void addRootTypes(Collection<String> rootTypeSourceNames) { @@ -788,6 +802,7 @@ if (errorsFound) { throw new UnableToCompleteException(); } + JavaAstVerifier.assertProgramIsConsistent(program); } /** @@ -812,7 +827,6 @@ if (rootType == null) { continue; } - rootTypeBinaryNames.add(rootType.getName()); if (rootType.hasJsInteropEntryPoints()) { fullFlowIntoType(rootType); @@ -847,8 +861,8 @@ instantiate(program.getTypeJavaLangString()); // ControlFlowAnalyzer.rescueByConcat(). flowInto(program.getIndexedMethod(RuntimeConstants.OBJECT_TO_STRING)); - mapApi(program.getTypeJavaLangString()); - flowInto(methodMap.get("java.lang.String.valueOf(C)Ljava/lang/String;")); + flowInto((JMethod) + resolvedMembersByQualifiedName.get("java.lang.String.valueOf(C)Ljava/lang/String;")); // FixAssignmentsToUnboxOrCast AutoboxUtils autoboxUtils = new AutoboxUtils(program); @@ -904,7 +918,7 @@ // pruned. for (JMethod method : newStubMethods) { if (instantiatedTypes.contains(method.getEnclosingType()) && - virtualMethodsLive.contains(method.getSignature())) { + liveVirtualMethods.contains(method.getSignature())) { liveFieldsAndMethods.add(method); } } @@ -917,6 +931,7 @@ // Already logged. throw new UnableToCompleteException(); } + JavaAstVerifier.assertProgramIsConsistent(program); } /** @@ -1000,16 +1015,17 @@ // TODO(zundel): ask for a recompile if deserialization fails? List<JDeclaredType> types = unit.getTypes(); assert containsAllTypes(unit, types); - for (JDeclaredType t : types) { - program.addType(t); + for (JDeclaredType type : types) { + program.addType(type); // If we're compiling per file and we already have currently valid output for this type. - if (incrementalCompile && !needsNewJs(t)) { + if (incrementalCompile && !needsNewJs(type)) { // Then make sure we don't output new Js for this type. - program.addReferenceOnlyType(t); + program.addReferenceOnlyType(type); } } - for (JDeclaredType t : types) { - resolveType(t); + for (JDeclaredType type : types) { + resolveType(type); + processType(type); } // When compiling per file. if (incrementalCompile) { @@ -1090,13 +1106,17 @@ } private void error(JNode x, String errorMessage) { + error(x.getSourceInfo(), errorMessage); + } + + private void error(SourceInfo sourceInfo, String errorMessage) { errorsFound = true; TreeLogger branch = logger - .branch(TreeLogger.ERROR, "Errors in '" + x.getSourceInfo().getFileName() + "'", null); + .branch(TreeLogger.ERROR, "Errors in '" + sourceInfo.getFileName() + "'", null); // Append 'Line #: msg' to the error message. StringBuilder msgBuf = new StringBuilder(); - int line = x.getSourceInfo().getStartLine(); + int line = sourceInfo.getStartLine(); if (line > 0) { msgBuf.append("Line "); msgBuf.append(line); @@ -1169,36 +1189,29 @@ } liveFieldsAndMethods.add(method); - JType originalReturnType = translate(method.getOriginalReturnType()); - List<JType> originalParamTypes = - Lists.newArrayListWithCapacity(method.getOriginalParamTypes().size()); - for (JType originalParamType : method.getOriginalParamTypes()) { - originalParamTypes.add(translate(originalParamType)); - } - JType returnType = translate(method.getType()); - List<JClassType> thrownExceptions = - Lists.newArrayListWithCapacity(method.getThrownExceptions().size()); - for (JClassType thrownException : method.getThrownExceptions()) { - thrownExceptions.add(translate(thrownException)); - } - method.resolve(originalReturnType, originalParamTypes, returnType, thrownExceptions); + + method.resolve( + translate(method.getOriginalReturnType()), + translate(method.getOriginalParamTypes()), + translate(method.getType()), + translate(method.getThrownExceptions())); + if (method.isStatic()) { staticInitialize(method.getEnclosingType()); } else if (method.canBePolymorphic()) { String signature = method.getSignature(); - if (!virtualMethodsLive.contains(signature)) { - virtualMethodsLive.add(signature); - Iterable<JMethod> pending = virtualMethodsPending.removeAll(signature); - for (JMethod p : pending) { - assert instantiatedTypes.contains(p.getEnclosingType()); - flowInto(p); + if (!liveVirtualMethods.contains(signature)) { + liveVirtualMethods.add(signature); + for (JMethod pendingMethod : pendingVirtualMethodsBySignature.removeAll(signature)) { + assert instantiatedTypes.contains(pendingMethod.getEnclosingType()); + flowInto(pendingMethod); } } } resolveSpecialization(method); - // Queue up visit / resolve on the body. - todo.add(method); + // Queue up the method to resolve the method body. + methodsPending.add(method); } private void resolveSpecialization(JMethod method) { @@ -1207,7 +1220,6 @@ return; } Specialization specialization = method.getSpecialization(); - List<JType> resolvedParams = Lists.newArrayList(); if (specialization.getParams() == null) { logger.log(Type.ERROR, "Missing 'params' attribute at @SpecializeMethod for method " + method.getQualifiedName()); @@ -1215,26 +1227,25 @@ return; } - for (JType param : specialization.getParams()) { - resolvedParams.add(translate(param)); - } + List<JType> resolvedParams = translate(specialization.getParams()); + JType resolvedReturn = translate(specialization.getReturns()); String targetMethodSignature = JjsUtils.computeSignature( specialization.getTarget(), resolvedParams, resolvedReturn, false); - JMethod targetMethod = translate(JMethod.getExternalizedMethod( - method.getEnclosingType().getName(), targetMethodSignature, false)); + JMethod targetMethod = JMethod.getExternalizedMethod( + method.getEnclosingType().getName(), targetMethodSignature, false); + JMethod resolvedTargetMethod = translate(method.getSourceInfo(), targetMethod); - if (targetMethod == null) { - errorsFound = true; - logger.log(Type.ERROR, "Unable to locate @SpecializeMethod target " + if (resolvedTargetMethod.isExternal()) { + error(method.getSourceInfo(), "Unable to locate @SpecializeMethod target " + targetMethodSignature + " for method " + method.getQualifiedName()); return; } - flowInto(targetMethod); - specialization.resolve(resolvedParams, resolvedReturn, targetMethod); + flowInto(resolvedTargetMethod); + specialization.resolve(resolvedParams, resolvedReturn, resolvedTargetMethod); } public NameBasedTypeLocator getSourceNameBasedTypeLocator() { @@ -1344,11 +1355,11 @@ } String signature = method.getSignature(); - if (virtualMethodsLive.contains(signature)) { - assert !virtualMethodsPending.containsKey(signature); + if (liveVirtualMethods.contains(signature)) { + assert !pendingVirtualMethodsBySignature.containsKey(signature); flowInto(method); } else { - virtualMethodsPending.put(signature, method); + pendingVirtualMethodsBySignature.put(signature, method); } } @@ -1380,40 +1391,28 @@ */ private void mainLoop() { UnifyVisitor visitor = new UnifyVisitor(); - while (!todo.isEmpty()) { - visitor.accept(todo.poll()); + while (!methodsPending.isEmpty()) { + visitor.accept(methodsPending.poll()); } } - private void mapApi(JDeclaredType type) { + private void processType(JDeclaredType type) { assert !type.isExternal(); - for (JField field : type.getFields()) { - String sig = type.getName() + '.' + field.getSignature(); - fieldMap.put(sig, field); + for (JMember member : type.getMembers()) { + String qualifiedName = member.getQualifiedName(); + resolvedMembersByQualifiedName.put(qualifiedName, member); + replaceMagicMethodBodies(member); } - for (JMethod method : type.getMethods()) { - String methodSignature = method.getQualifiedName(); - methodMap.put(methodSignature, method); - if (!MAGIC_METHOD_IMPLS.contains(methodSignature)) { - continue; - } - if (methodSignature.startsWith("com.google.gwt.core.client.GWT.") - || methodSignature.startsWith("com.google.gwt.core.shared.GWT.")) { - // GWT.isClient, GWT.isScript, GWT.isProdMode all true. - JjsUtils.replaceMethodBody(method, JBooleanLiteral.TRUE); - continue; - } - assert methodSignature.startsWith("java.lang.Class."); - if (CLASS_DESIRED_ASSERTION_STATUS.equals(methodSignature)) { - JjsUtils.replaceMethodBody(method, - JBooleanLiteral.get(compilerContext.getOptions().isEnableAssertions())); - } else if (CLASS_IS_CLASS_METADATA_ENABLED.equals(methodSignature)) { - JjsUtils.replaceMethodBody(method, - JBooleanLiteral.get(!compilerContext.getOptions().isClassMetadataDisabled())); - } else { - assert false; - } + } + + private void replaceMagicMethodBodies(JMember member) { + JExpression replacementExpression = + replacementValueByMagicMethodQualifiedName.get(member.getQualifiedName()); + if (replacementExpression == null) { + // Not a special method that needs replacement + return; } + JjsUtils.replaceMethodBody((JMethod) member, replacementExpression); } /** @@ -1512,95 +1511,47 @@ } /** - * Replaces an external (stub) reference node to a particular class by the actual AST node if - * necessary. - */ - private JClassType translate(JClassType type) { - return (JClassType) translate((JDeclaredType) type); - } - - /** * Replaces an external (stub) reference node to a particular type by the actual AST node if * necessary. */ - private JDeclaredType translate(JDeclaredType type) { + private <T extends JDeclaredType> T translate(T type) { if (!type.isExternal()) { return type; } - String typeName = type.getName(); - JDeclaredType newType = internalFindType(typeName, binaryNameBasedTypeLocator, true); - if (newType == null) { + + T resolvedType = (T) internalFindType(type.getName(), binaryNameBasedTypeLocator, true); + if (resolvedType == null) { assert errorsFound; return type; } - assert !newType.isExternal(); - return newType; + assert !resolvedType.isExternal(); + return resolvedType; } /** - * Replaces an external (stub) reference node to a particular field by the actual AST node if + * Replaces an external (stub) reference node to a particular member by the actual AST node if * necessary. */ - private JField translate(JField field) { - if (!field.isExternal()) { - return field; + private <T extends JMember> T translate(SourceInfo sourceInfo, T member) { + if (!member.isExternal()) { + return member; } - JDeclaredType enclosingType = field.getEnclosingType(); - String sig = enclosingType.getName() + '.' + field.getSignature(); - JField newField = fieldMap.get(sig); - if (newField != null) { - return newField; - } - - enclosingType = translate(enclosingType); + JDeclaredType enclosingType = translate(member.getEnclosingType()); if (enclosingType.isExternal()) { assert errorsFound; - return field; - } - mapApi(enclosingType); - - // Now the field should be there. - field = fieldMap.get(sig); - if (field == null) { - // TODO: error logging - throw new NoSuchFieldError(sig); + return member; } - assert !field.isExternal(); - return field; - } - - /** - * Replaces an external (stub) reference node to a particular method by the actual AST node if - * necessary. - */ - private JMethod translate(JMethod method) { - if (!method.isExternal()) { - return method; + String qualifiedName = member.getQualifiedName(); + T resolvedMember = (T) resolvedMembersByQualifiedName.get(qualifiedName); + if (resolvedMember == null) { + error(sourceInfo, "Reference to '" + qualifiedName + "' could not be resolved"); + return member; } - String sig = method.getQualifiedName(); - JMethod newMethod = methodMap.get(sig); - if (newMethod != null) { - return newMethod; - } - - JDeclaredType enclosingType = translate(method.getEnclosingType()); - if (enclosingType.isExternal()) { - assert errorsFound; - return method; - } - mapApi(enclosingType); - - // Now the method should be there. - method = methodMap.get(sig); - if (method == null) { - // TODO: error logging - throw new NoSuchMethodError(sig); - } - assert !method.isExternal(); - return method; + assert !resolvedMember.isExternal(); + return resolvedMember; } /** @@ -1632,4 +1583,12 @@ } return translate((JReferenceType) type); } + + private <T extends JType> List<T> translate(List<T> types) { + List<T> translatedTypes = Lists.newArrayListWithCapacity(types.size()); + for (T type : types) { + translatedTypes.add((T) translate(type)); + } + return translatedTypes; + } }