| /* |
| * Copyright 2008 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.gwt.dev.jdt; |
| |
| import com.google.gwt.dev.javac.GWTProblem; |
| |
| import org.eclipse.jdt.core.compiler.CharOperation; |
| import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess; |
| import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.Expression; |
| import org.eclipse.jdt.internal.compiler.ast.MessageSend; |
| import org.eclipse.jdt.internal.compiler.lookup.BlockScope; |
| import org.eclipse.jdt.internal.compiler.lookup.Scope; |
| |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| /** |
| * Walks a |
| * {@link org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration} to |
| * find <code>GWT.create()</code> class so that we can eagerly complain about |
| * deferred binding problems. |
| */ |
| public class FindDeferredBindingSitesVisitor extends SafeASTVisitor { |
| |
| /** |
| * Information about the site at which a rebind request was found, used to |
| * report problems. |
| */ |
| public static class MessageSendSite { |
| public final MessageSend messageSend; |
| |
| public final Scope scope; |
| |
| public MessageSendSite(MessageSend messageSend, Scope scope) { |
| this.messageSend = messageSend; |
| this.scope = scope; |
| } |
| } |
| |
| public static final String MAGIC_CLASS = "com.google.gwt.core.client.GWT"; |
| public static final String REBIND_MAGIC_METHOD = "create"; |
| |
| public static void reportRebindProblem(MessageSendSite site, String message) { |
| MessageSend messageSend = site.messageSend; |
| Scope scope = site.scope; |
| // Safe since CUS.referenceContext is set in its constructor. |
| CompilationUnitDeclaration cud = scope.compilationUnitScope().referenceContext; |
| GWTProblem.recordError(messageSend, cud, message, null); |
| } |
| |
| private final Map<String, MessageSendSite> results = new HashMap<String, MessageSendSite>(); |
| |
| @Override |
| public void endVisit(MessageSend messageSend, BlockScope scope) { |
| if (messageSend.binding == null) { |
| // Some sort of problem. |
| return; |
| } |
| |
| String methodName = String.valueOf(messageSend.selector); |
| if (!methodName.equals(REBIND_MAGIC_METHOD)) { |
| // Not the create() method. |
| return; |
| } |
| |
| char[][] targetClass = messageSend.binding.declaringClass.compoundName; |
| String targetClassName = CharOperation.toString(targetClass); |
| if (!targetClassName.equals(MAGIC_CLASS)) { |
| // Not being called on the Rebind class. |
| return; |
| } |
| |
| MessageSendSite site = new MessageSendSite(messageSend, scope); |
| |
| Expression[] args = messageSend.arguments; |
| if (args.length != 1) { |
| reportRebindProblem(site, "GWT.create() should take exactly one argument"); |
| return; |
| } |
| |
| if (!(args[0] instanceof ClassLiteralAccess)) { |
| reportRebindProblem(site, "Only class literals may be used as arguments to GWT.create()"); |
| return; |
| } |
| |
| ClassLiteralAccess cla = (ClassLiteralAccess) args[0]; |
| String typeName = String.valueOf(cla.targetType.readableName()); |
| |
| if (!results.containsKey(typeName)) { |
| results.put(typeName, site); |
| } |
| } |
| |
| public Map<String, MessageSendSite> getSites() { |
| return Collections.unmodifiableMap(results); |
| } |
| } |