blob: 548c50365b63d3064f721cdd0d01a35bb11e853c [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* 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.android.jack.backend.dex;
import com.android.jack.Jack;
import com.android.jack.Options;
import com.android.jack.backend.dex.rop.RopHelper;
import com.android.jack.dx.dex.file.ClassDefItem;
import com.android.jack.dx.rop.code.AccessFlags;
import com.android.jack.dx.rop.cst.CstString;
import com.android.jack.dx.rop.type.Type;
import com.android.jack.dx.rop.type.TypeList;
import com.android.jack.ir.ast.JClass;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JDefinedInterface;
import com.android.jack.ir.ast.JInterface;
import com.android.jack.ir.ast.JModifier;
import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JTypeLookupException;
import com.android.jack.ir.sourceinfo.SourceInfo;
import com.android.jack.lookup.CommonTypes;
import com.android.jack.scheduling.filter.TypeWithoutPrebuiltFilter;
import com.android.jack.scheduling.marker.ClassDefItemMarker;
import com.android.sched.item.Description;
import com.android.sched.item.Name;
import com.android.sched.item.Synchronized;
import com.android.sched.schedulable.Access;
import com.android.sched.schedulable.Filter;
import com.android.sched.schedulable.Protect;
import com.android.sched.schedulable.RunnableSchedulable;
import com.android.sched.schedulable.Transform;
import com.android.sched.util.config.ThreadConfig;
import java.io.File;
import java.util.List;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
* Builds a {@code ClassDefItem} instance from a {@code JDefinedClassOrInterface} and
* adds it to the {@code DexFile} currently being built.
*
* <p>The {@code ClassDefItem} instance is initialized with name, modifiers,
* superclass, interfaces and source file information. It does not contain any
* field or method.
*
* <p>Its {@code EncodedMethod}s are created by the {@code EncodedMethodBuilder}
* class.
*
* @see EncodedMethodBuilder
*/
@Description("Builds ClassDefItem from JDeclaredType.")
@Name("ClassDefItemBuilder")
@Synchronized
@Transform(add = ClassDefItemMarker.class)
@Protect(add = JDefinedClassOrInterface.class, modify = JDefinedClassOrInterface.class,
remove = JDefinedClassOrInterface.class)
@Filter(TypeWithoutPrebuiltFilter.class)
//Access isAnonymous which may depend on TypeName that is accessing enclosing type name.
@Access(JSession.class)
public class ClassDefItemBuilder implements RunnableSchedulable<JDefinedClassOrInterface> {
private final boolean emitSourceFileInfo =
ThreadConfig.get(Options.EMIT_SOURCE_FILE_DEBUG_INFO).booleanValue();
/**
* Creates the {@code ClassDefItem} for the given {@code JDeclaredType}. The
* created {@code ClassDefItem} instance is then attached to the {@code JDeclaredType}
* in a {@code ClassDefItemMarker} to be accessible from other schedulables.
*
* <p>If the given type is external (not declared in the source files being
* compiled), it is ignored. No {@code ClassDefItem} is created for it and no
* marker is attached to it.
*
* @param declaredType a non-null {@code JDeclaredType} for which a {@code ClassDefItem}
* is created.
*/
@Override
public synchronized void run(@Nonnull JDefinedClassOrInterface declaredType) {
ClassDefItem classDefItem = createClassDefItem(declaredType);
ClassDefItemMarker classDefItemMarker = new ClassDefItemMarker(classDefItem);
declaredType.addMarker(classDefItemMarker);
}
@Nonnull
private ClassDefItem createClassDefItem(@Nonnull JDefinedClassOrInterface type)
throws JTypeLookupException {
CstString sourceFile = null;
if (emitSourceFileInfo) {
sourceFile = createSourceFile(type);
}
return new ClassDefItem(RopHelper.convertTypeToDx(type), getDxAccessFlagsForType(type),
createSuperClass(type), createInterfacesList(type), sourceFile);
}
@CheckForNull
private static Type createSuperClass(@Nonnull JDefinedClassOrInterface type)
throws JTypeLookupException {
JClass superClass = type.getSuperClass();
if (superClass == null) {
if (type instanceof JDefinedInterface) {
superClass = Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
} else {
assert type.isSameType(
Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT));
return null;
}
}
return RopHelper.convertTypeToDx(superClass);
}
@Nonnull
private static TypeList createInterfacesList(@Nonnull JDefinedClassOrInterface type) {
List<JInterface> interfacesList = type.getImplements();
return RopHelper.createTypeList(interfacesList);
}
@CheckForNull
private static CstString createSourceFile(@Nonnull JDefinedClassOrInterface type) {
CstString sourceFile = null;
SourceInfo sourceInfo = type.getSourceInfo();
if (sourceInfo != SourceInfo.UNKNOWN) {
// Only keep filename without the path
String sourceFileName = sourceInfo.getFileName();
int separatorPos = sourceFileName.lastIndexOf(File.separatorChar);
if (separatorPos > 0) {
sourceFileName = sourceFileName.substring(separatorPos + 1);
}
sourceFile = new CstString(sourceFileName);
}
return sourceFile;
}
private int getDxAccessFlagsForType(@Nonnull JDefinedClassOrInterface type) {
int accessFlags = type.getModifier();
boolean isInner = type.getEnclosingType() != null;
// A protected inner class becomes public
if (isInner && type.isProtected()) {
accessFlags |= JModifier.PUBLIC;
}
// An anonymous class should not be flagged as final unless it is static
if (type.isAnonymous()) {
if (!type.isStatic()) {
accessFlags &= ~JModifier.FINAL;
}
}
// Remove GWT-specific flags and flags that are not allowed in a class_def_item
// If it is an inner class, this will remove its static, private or protected flags.
// Those should only be found in InnerClass annotations.
accessFlags &= AccessFlags.CLASS_FLAGS;
return accessFlags;
}
}