| /* |
| * 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. |
| } |
| } |
| } |