/* * 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 org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference; 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.ast.ParameterizedQualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; /** * Walks the AST to determine every location from which a type is referenced. */ public abstract class TypeRefVisitor extends SafeASTVisitor { private final CompilationUnitDeclaration cud; public TypeRefVisitor(CompilationUnitDeclaration cud) { assert (cud != null); this.cud = cud; } @Override public void endVisit(ArrayQualifiedTypeReference x, BlockScope scope) { maybeDispatch(x, x.resolvedType); } @Override public void endVisit(ArrayQualifiedTypeReference x, ClassScope scope) { maybeDispatch(x, x.resolvedType); } @Override public void endVisit(ArrayTypeReference x, BlockScope scope) { maybeDispatch(x, x.resolvedType); } @Override public void endVisit(ArrayTypeReference x, ClassScope scope) { maybeDispatch(x, x.resolvedType); } @Override public void endVisit(MessageSend messageSend, BlockScope scope) { /* * Counterintuitive: there's a reason we only need to record a reference for * static method calls. For any non-static method call, there must be a * qualifying instance expression. When that instance expression is visited, * the type reference to its declared type will be recorded. Thus, recording * for each instance call is unnecessary. * * Note: when we tried recording for instance calls, we would get a null * scope in some cases, which would cause compiler errors. */ if (messageSend.binding != null && messageSend.binding.isStatic()) { maybeDispatch(messageSend, messageSend.actualReceiverType); } } @Override public void endVisit(ParameterizedQualifiedTypeReference x, BlockScope scope) { maybeDispatch(x, x.resolvedType); } @Override public void endVisit(ParameterizedQualifiedTypeReference x, ClassScope scope) { maybeDispatch(x, x.resolvedType); } @Override public void endVisit(ParameterizedSingleTypeReference x, BlockScope scope) { maybeDispatch(x, x.resolvedType); } @Override public void endVisit(ParameterizedSingleTypeReference x, ClassScope scope) { maybeDispatch(x, x.resolvedType); } @Override public void endVisit(QualifiedNameReference x, BlockScope scope) { if (x.binding instanceof FieldBinding) { maybeDispatch(x, x.fieldBinding().declaringClass); } } @Override public void endVisit(QualifiedTypeReference x, BlockScope scope) { maybeDispatch(x, x.resolvedType); } @Override public void endVisit(QualifiedTypeReference x, ClassScope scope) { maybeDispatch(x, x.resolvedType); } @Override public void endVisit(SingleTypeReference x, BlockScope scope) { maybeDispatch(x, x.resolvedType); } @Override public void endVisit(SingleTypeReference x, ClassScope scope) { maybeDispatch(x, x.resolvedType); } @Override public void endVisit(Wildcard x, BlockScope scope) { maybeDispatch(x, x.resolvedType); } @Override public void endVisit(Wildcard x, ClassScope scope) { maybeDispatch(x, x.resolvedType); } @Override public boolean visit(CompilationUnitDeclaration cud, CompilationUnitScope scope) { if (this.cud != cud) { throw new IllegalStateException("I will only visit the cud I was initialized with"); } return true; } /** * @param referencedType * @param unitOfReferrer * @param expression */ protected void onBinaryTypeRef(BinaryTypeBinding referencedType, CompilationUnitDeclaration unitOfReferrer, Expression expression) { } protected abstract void onTypeRef(SourceTypeBinding referencedType, CompilationUnitDeclaration unitOfReferrer); private void maybeDispatch(Expression expression, TypeBinding binding) { assert (binding != null); if (binding instanceof SourceTypeBinding) { SourceTypeBinding type = (SourceTypeBinding) binding; onTypeRef(type, cud); } else if (binding instanceof ArrayBinding) { maybeDispatch(expression, ((ArrayBinding) binding).leafComponentType); } else if (binding instanceof BinaryTypeBinding) { onBinaryTypeRef((BinaryTypeBinding) binding, cud, expression); } else if (binding instanceof ParameterizedTypeBinding) { // Make sure that we depend on the generic version of the class. ParameterizedTypeBinding ptBinding = (ParameterizedTypeBinding) binding; maybeDispatch(expression, ptBinding.genericType()); } else if (binding instanceof RawTypeBinding) { // Make sure that we depend on the generic version of the class. RawTypeBinding rawTypeBinding = (RawTypeBinding) binding; maybeDispatch(expression, rawTypeBinding.genericType()); } else { // We don't care about other cases. } } }