/* * Copyright Red Hat Inc. and/or its affiliates and other contributors * as indicated by the authors tag. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License version 2. * * This particular file is subject to the "Classpath" exception as provided in the * LICENSE file that accompanied this code. * * This program is distributed in the hope that it will be useful, but WITHOUT A * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License, * along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package com.redhat.ceylon.compiler.java.loader.mirror; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import com.redhat.ceylon.compiler.java.util.Util; import com.redhat.ceylon.model.loader.AbstractModelLoader; import com.redhat.ceylon.model.loader.mirror.AnnotationMirror; import com.redhat.ceylon.model.loader.mirror.ClassMirror; import com.redhat.ceylon.model.loader.mirror.FieldMirror; import com.redhat.ceylon.model.loader.mirror.MethodMirror; import com.redhat.ceylon.model.loader.mirror.PackageMirror; import com.redhat.ceylon.model.loader.mirror.TypeMirror; import com.redhat.ceylon.model.loader.mirror.TypeParameterMirror; import com.redhat.ceylon.model.typechecker.model.Module; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.CompletionFailure; import com.sun.tools.javac.code.Symbol.MethodSymbol; import com.sun.tools.javac.code.Symbol.VarSymbol; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.TypeTags; public class JavacClass implements ClassMirror { public ClassSymbol classSymbol; private PackageMirror pkg; private TypeMirror superclass; private List<MethodMirror> methods; private List<TypeMirror> interfaces; private Map<String, AnnotationMirror> annotations; private List<TypeParameterMirror> typeParams; private ClassMirror enclosingClass; private boolean enclosingClassSet; private MethodMirror enclosingMethod; private boolean enclosingMethodSet; private List<FieldMirror> fields; private LinkedList<ClassMirror> innerClasses; private String cacheKey; public JavacClass(ClassSymbol classSymbol){ this.classSymbol = classSymbol; } public String toString() { return getClass().getSimpleName() + " of " + classSymbol; } @Override public boolean isPublic() { return (classSymbol.flags() & Flags.PUBLIC) != 0; } @Override public boolean isProtected() { return (classSymbol.flags() & Flags.PROTECTED) != 0; } @Override public boolean isDefaultAccess() { return (classSymbol.flags() & (Flags.PROTECTED | Flags.PUBLIC | Flags.PRIVATE)) == 0; } @Override public String getQualifiedName() { // as taken from ClassSymbol.className(): if(classSymbol.name.length() == 0) return classSymbol.flatname.toString(); else return classSymbol.getQualifiedName().toString(); } @Override public String getFlatName() { return classSymbol.flatname.toString(); } @Override public PackageMirror getPackage() { if (pkg == null) { pkg = new JavacPackage(classSymbol.packge()); } return pkg; } @Override public boolean isInterface() { return classSymbol.isInterface(); } @Override public boolean isAnnotationType() { return (classSymbol.flags()& Flags.ANNOTATION) != 0; } @Override public boolean isCeylonToplevelAttribute() { return !isInnerClass() && getAnnotation(AbstractModelLoader.CEYLON_ATTRIBUTE_ANNOTATION) != null; } @Override public boolean isCeylonToplevelObject() { return !isInnerClass() && getAnnotation(AbstractModelLoader.CEYLON_OBJECT_ANNOTATION) != null; } @Override public boolean isCeylonToplevelMethod() { return !isInnerClass() && getAnnotation(AbstractModelLoader.CEYLON_METHOD_ANNOTATION) != null; } @Override public AnnotationMirror getAnnotation(String type) { if (annotations == null) { annotations = JavacUtil.getAnnotations(classSymbol); } return annotations.get(type); } @Override public boolean isLoadedFromSource() { return Util.isLoadedFromSource(classSymbol); } @Override public String getName() { return classSymbol.getSimpleName().toString(); } @Override public boolean isAbstract() { return (classSymbol.flags() & Flags.ABSTRACT) != 0; } @Override public boolean isStatic() { return (classSymbol.flags() & Flags.STATIC) != 0; } @Override public boolean isFinal() { return (classSymbol.flags() & Flags.FINAL) != 0; } @Override public List<MethodMirror> getDirectMethods() { if (methods == null) { List<MethodMirror> ret = new LinkedList<MethodMirror>(); for(Symbol sym : classSymbol.getEnclosedElements()){ if(sym instanceof MethodSymbol && (sym.flags() & Flags.PRIVATE) == 0){ ret.add(new JavacMethod(this, (MethodSymbol)sym)); } } methods = Collections.unmodifiableList(ret); } return methods; } @Override public List<FieldMirror> getDirectFields() { if(fields == null){ List<FieldMirror> ret = new LinkedList<FieldMirror>(); for(Symbol sym : classSymbol.getEnclosedElements()){ if(sym instanceof VarSymbol && (sym.flags() & Flags.PRIVATE) == 0){ ret.add(new JavacField((VarSymbol)sym)); } } fields = Collections.unmodifiableList(ret); } return fields; } @Override public TypeMirror getSuperclass() { if (superclass == null) { Type supercls = classSymbol.getSuperclass(); if (supercls != null && supercls.tag != TypeTags.NONE) { superclass = new JavacType(supercls); } } return superclass; } @Override public List<TypeMirror> getInterfaces() { if (interfaces == null) { List<TypeMirror> ret = new ArrayList<TypeMirror>(classSymbol.getInterfaces().size()); for(Type interfce : classSymbol.getInterfaces()) ret.add(new JavacType(interfce)); interfaces = Collections.unmodifiableList(ret); } return interfaces; } @Override public List<TypeParameterMirror> getTypeParameters() { if (typeParams == null) { typeParams = Collections.unmodifiableList(JavacUtil.getTypeParameters(classSymbol)); } return typeParams; } @Override public boolean isInnerClass() { return getAnnotation(AbstractModelLoader.CEYLON_CONTAINER_ANNOTATION) != null || classSymbol.owner instanceof ClassSymbol; } @Override public boolean isLocalClass() { return getAnnotation(AbstractModelLoader.CEYLON_LOCAL_DECLARATION_ANNOTATION) != null || classSymbol.owner instanceof MethodSymbol; } @Override public List<ClassMirror> getDirectInnerClasses() { if(innerClasses == null){ innerClasses = new LinkedList<ClassMirror>(); for(Symbol elem : classSymbol.getEnclosedElements()){ if(elem instanceof ClassSymbol) innerClasses.add(new JavacClass((ClassSymbol) elem)); } } return innerClasses; } @Override public boolean isAnonymous() { return classSymbol.name.isEmpty(); } @Override public boolean isJavaSource() { return Util.isJavaSource(classSymbol); } @Override public ClassMirror getEnclosingClass() { if (!enclosingClassSet) { Symbol encl = classSymbol.getEnclosingElement(); if (encl != null && encl instanceof ClassSymbol) { enclosingClass = new JavacClass((ClassSymbol)encl); } enclosingClassSet = true; } return enclosingClass; } @Override public MethodMirror getEnclosingMethod() { if (!enclosingMethodSet) { Symbol encl = classSymbol.getEnclosingElement(); if (encl != null && encl instanceof MethodSymbol) { // it's a method, it must be in a Class ClassSymbol enclosingClass = (ClassSymbol) encl.getEnclosingElement(); JavacClass enclosingClassMirror = new JavacClass(enclosingClass); enclosingMethod = new JavacMethod(enclosingClassMirror, (MethodSymbol)encl); } enclosingMethodSet = true; } return enclosingMethod; } @Override public boolean isEnum() { try{ return (classSymbol.flags() & Flags.ENUM) != 0; }catch(CompletionFailure x){ // make sure we don't throw for this, the error will be reported anyways somewhere else return false; } } @Override public String getCacheKey(Module module) { if(cacheKey == null){ String className = getQualifiedName(); cacheKey = AbstractModelLoader.getCacheKeyByModule(module, className); } return cacheKey; } }