/* * Copyright 2011 Google Inc. All Rights Reserved. * * 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.devtools.j2objc.types; import com.google.devtools.j2objc.ast.AnnotationTypeDeclaration; import com.google.devtools.j2objc.ast.Assignment; import com.google.devtools.j2objc.ast.CastExpression; import com.google.devtools.j2objc.ast.CatchClause; import com.google.devtools.j2objc.ast.CompilationUnit; import com.google.devtools.j2objc.ast.EnhancedForStatement; import com.google.devtools.j2objc.ast.EnumDeclaration; import com.google.devtools.j2objc.ast.Expression; import com.google.devtools.j2objc.ast.FieldAccess; import com.google.devtools.j2objc.ast.FieldDeclaration; import com.google.devtools.j2objc.ast.FunctionInvocation; import com.google.devtools.j2objc.ast.InstanceofExpression; import com.google.devtools.j2objc.ast.LambdaExpression; import com.google.devtools.j2objc.ast.MarkerAnnotation; import com.google.devtools.j2objc.ast.MethodDeclaration; import com.google.devtools.j2objc.ast.MethodInvocation; import com.google.devtools.j2objc.ast.NativeDeclaration; import com.google.devtools.j2objc.ast.NativeExpression; import com.google.devtools.j2objc.ast.NormalAnnotation; import com.google.devtools.j2objc.ast.QualifiedName; import com.google.devtools.j2objc.ast.ReturnStatement; import com.google.devtools.j2objc.ast.SimpleName; import com.google.devtools.j2objc.ast.SingleMemberAnnotation; import com.google.devtools.j2objc.ast.SingleVariableDeclaration; import com.google.devtools.j2objc.ast.TreeUtil; import com.google.devtools.j2objc.ast.TryStatement; import com.google.devtools.j2objc.ast.Type; import com.google.devtools.j2objc.ast.TypeDeclaration; import com.google.devtools.j2objc.ast.TypeLiteral; import com.google.devtools.j2objc.ast.UnionType; import com.google.devtools.j2objc.ast.UnitTreeVisitor; import com.google.devtools.j2objc.ast.VariableDeclarationExpression; import com.google.devtools.j2objc.ast.VariableDeclarationStatement; import com.google.devtools.j2objc.util.ElementUtil; import com.google.devtools.j2objc.util.TypeUtil; import java.lang.reflect.Modifier; import java.util.LinkedHashSet; import java.util.Set; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.ArrayType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; /** * Collects the set of imports needed to resolve type references in an * implementation (.m) file. * * @author Tom Ball */ public class ImplementationImportCollector extends UnitTreeVisitor { private Set<Import> imports = new LinkedHashSet<>(); public ImplementationImportCollector(CompilationUnit unit) { super(unit); } public Set<Import> getImports() { return imports; } private void addImports(Type type) { if (type instanceof UnionType) { for (Type t : ((UnionType) type).getTypes()) { addImports(t); } } else if (type != null) { addImports(type.getTypeMirror()); } } private void addImports(TypeElement type) { if (type != null) { addImports(type.asType()); } } private void addImports(TypeMirror type) { Import.addImports(type, imports, unit.getEnv()); } private void addImports(Iterable<TypeMirror> types) { for (TypeMirror type : types) { addImports(type); } } @Override public boolean visit(AnnotationTypeDeclaration node) { addImports(node.getTypeElement()); return true; } @Override public boolean visit(CastExpression node) { addImports(node.getType()); return true; } @Override public boolean visit(CatchClause node) { addImports(node.getException().getType()); return true; } @Override public void endVisit(EnhancedForStatement node) { addImports(node.getExpression().getTypeMirror()); } @Override public boolean visit(EnumDeclaration node) { addImports(node.getTypeElement()); return true; } @Override public boolean visit(FieldAccess node) { addImports(node.getExpression().getTypeMirror()); return true; } @Override public boolean visit(FieldDeclaration node) { addImports(node.getTypeMirror()); return true; } @Override public boolean visit(FunctionInvocation node) { FunctionElement element = node.getFunctionElement(); addImports(element.getDeclaringClass()); for (Expression arg : node.getArguments()) { addImports(arg.getTypeMirror()); } addImports(element.getReturnType()); return true; } @Override public void endVisit(Assignment node) { addImports(node.getRightHandSide().getTypeMirror()); } @Override public boolean visit(InstanceofExpression node) { addImports(node.getRightOperand().getTypeMirror()); return true; } @Override public void endVisit(LambdaExpression node) { addImports(node.getTypeMirror()); } @Override public boolean visit(MarkerAnnotation node) { return false; } @Override public boolean visit(MethodDeclaration node) { if (Modifier.isAbstract(node.getModifiers())) { return false; } addImports(node.getReturnTypeMirror()); return true; } @Override public boolean visit(MethodInvocation node) { addImports(node.getExecutableType().getReturnType()); Expression receiver = node.getExpression(); if (receiver != null) { addImports(receiver.getTypeMirror()); } for (Expression arg : node.getArguments()) { addImports(arg.getTypeMirror()); } return true; } @Override public boolean visit(NativeDeclaration node) { addImports(node.getImplementationImportTypes()); return true; } @Override public boolean visit(NativeExpression node) { addImports(node.getImportTypes()); return true; } @Override public boolean visit(NormalAnnotation node) { return false; } @Override public boolean visit(QualifiedName node) { VariableElement var = TreeUtil.getVariableElement(node); if (var != null) { if (ElementUtil.isGlobalVar(var)) { addImports(ElementUtil.getDeclaringClass(var)); return false; } else { addImports(node.getQualifier().getTypeMirror()); } } return true; } @Override public void endVisit(ReturnStatement node) { Expression expr = node.getExpression(); if (expr != null) { addImports(expr.getTypeMirror()); } } @Override public boolean visit(SimpleName node) { VariableElement var = TreeUtil.getVariableElement(node); if (var != null && ElementUtil.isGlobalVar(var)) { addImports(ElementUtil.getDeclaringClass(var)); } return true; } @Override public boolean visit(SingleMemberAnnotation node) { return false; } @Override public boolean visit(SingleVariableDeclaration node) { addImports(node.getVariableElement().asType()); return true; } @Override public boolean visit(TryStatement node) { if (!node.getResources().isEmpty()) { addImports(typeUtil.resolveJavaType("java.lang.Throwable")); } return true; } @Override public boolean visit(TypeDeclaration node) { addImports(node.getTypeElement()); return true; } @Override public boolean visit(TypeLiteral node) { TypeMirror type = node.getType().getTypeMirror(); if (type.getKind().isPrimitive()) { addImports(TypeUtil.IOS_CLASS); } else if (type.getKind().equals(TypeKind.ARRAY)) { addImports(TypeUtil.IOS_CLASS); addImports(((ArrayType) type).getComponentType()); } else { addImports(node.getType()); } return false; } @Override public boolean visit(VariableDeclarationExpression node) { addImports(node.getType()); return true; } @Override public boolean visit(VariableDeclarationStatement node) { addImports(node.getTypeMirror()); return true; } }