blob: fe180a10a70edba0a8d42dfc8c06fe717b2a8500 [file] [log] [blame]
/*
* 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);
}
}