001: /*
002: * Copyright 2006 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev.jdt;
017:
018: import org.eclipse.jdt.core.compiler.CharOperation;
019: import org.eclipse.jdt.core.compiler.IProblem;
020: import org.eclipse.jdt.internal.compiler.ASTVisitor;
021: import org.eclipse.jdt.internal.compiler.CompilationResult;
022: import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
023: import org.eclipse.jdt.internal.compiler.ast.Expression;
024: import org.eclipse.jdt.internal.compiler.ast.MessageSend;
025: import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
026: import org.eclipse.jdt.internal.compiler.lookup.Scope;
027: import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
028: import org.eclipse.jdt.internal.compiler.problem.ProblemHandler;
029: import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
030: import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
031:
032: import java.util.Map;
033:
034: /**
035: * Walks a
036: * {@link org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration} to
037: * find <code>GWT.create()</code> class so that we can eagerly complain about
038: * deferred binding problems.
039: */
040: public class FindDeferredBindingSitesVisitor extends ASTVisitor {
041:
042: /**
043: * Information about the site at which a rebind request was found, used to
044: * report problems.
045: */
046: public static class DeferredBindingSite {
047: public final MessageSend messageSend;
048:
049: public final Scope scope;
050:
051: public DeferredBindingSite(MessageSend messageSend, Scope scope) {
052: this .messageSend = messageSend;
053: this .scope = scope;
054: }
055: }
056:
057: public static final String REBIND_MAGIC_CLASS = "com.google.gwt.core.client.GWT";
058: public static final String REBIND_MAGIC_METHOD = "create";
059:
060: public static void reportRebindProblem(DeferredBindingSite site,
061: String message) {
062: MessageSend messageSend = site.messageSend;
063: Scope scope = site.scope;
064: CompilationResult compResult = scope.compilationUnitScope()
065: .referenceContext().compilationResult();
066: int startLine = ProblemHandler.searchLineNumber(
067: compResult.lineSeparatorPositions, messageSend
068: .sourceStart());
069: DefaultProblem problem = new DefaultProblem(
070: compResult.fileName, message, IProblem.Unclassified,
071: null, ProblemSeverities.Error, messageSend.sourceStart,
072: messageSend.sourceEnd, startLine);
073: compResult.record(problem, scope.referenceContext());
074: }
075:
076: private final Map results;
077:
078: public FindDeferredBindingSitesVisitor(Map requestedTypes) {
079: this .results = requestedTypes;
080: }
081:
082: public void endVisit(MessageSend messageSend, BlockScope scope) {
083: final ProblemReporter problemReporter = scope.problemReporter();
084:
085: if (messageSend.binding == null) {
086: // Some sort of problem.
087: //
088: return;
089: }
090:
091: String methodName = String.valueOf(messageSend.selector);
092: if (!methodName.equals(REBIND_MAGIC_METHOD)) {
093: // Not the create() method.
094: //
095: return;
096: }
097:
098: char[][] targetClass = messageSend.binding.declaringClass.compoundName;
099: String targetClassName = CharOperation.toString(targetClass);
100: if (!targetClassName.equals(REBIND_MAGIC_CLASS)) {
101: // Not being called on the Rebind class.
102: return;
103: }
104:
105: DeferredBindingSite site = new DeferredBindingSite(messageSend,
106: scope);
107:
108: Expression[] args = messageSend.arguments;
109: if (args.length != 1) {
110: reportRebindProblem(site,
111: "GWT.create() should take exactly one argument");
112: return;
113: }
114:
115: Expression arg = args[0];
116: if (!(arg instanceof ClassLiteralAccess)) {
117: reportRebindProblem(site,
118: "Only class literals may be used as arguments to GWT.create()");
119: return;
120: }
121:
122: ClassLiteralAccess cla = (ClassLiteralAccess) arg;
123: String typeName = String.valueOf(cla.targetType.readableName());
124: if (!results.containsKey(typeName)) {
125: results.put(typeName, site);
126: }
127: }
128: }
|