summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--jack-tests/Android.mk3
-rw-r--r--jack-tests/tests/com/android/jack/classpath/test003/jack/A.java27
-rw-r--r--jack-tests/tests/com/android/jack/classpath/test003/lib/HasInnersClasses.java30
-rw-r--r--jack/src/com/android/jack/CommandLine.java15
-rw-r--r--jack/src/com/android/jack/Jack.java19
-rw-r--r--jack/src/com/android/jack/backend/dex/DexFileWriter.java23
-rw-r--r--jack/src/com/android/jack/backend/dex/DexWritingTool.java85
-rw-r--r--jack/src/com/android/jack/backend/dex/MergingDexWritingTool.java204
-rw-r--r--jack/src/com/android/jack/backend/dex/MinimalMultiDexWritingTool.java75
-rw-r--r--jack/src/com/android/jack/backend/dex/SingleDexWritingTool.java76
-rw-r--r--jack/src/com/android/jack/backend/dex/StandardMultiDexWritingTool.java71
-rw-r--r--jack/src/com/android/jack/backend/jayce/JayceFileImporter.java20
-rw-r--r--jack/src/com/android/jack/ecj/loader/jast/JAstBinaryType.java30
-rw-r--r--jack/src/com/android/jack/ecj/loader/jast/JAstClasspath.java4
-rw-r--r--jack/src/com/android/jack/statistics/JNodeWatcher.java3
-rw-r--r--jack/src/com/android/jack/transformations/ast/TypeLegalizer.java20
-rw-r--r--jack/src/com/android/jack/transformations/parent/ParentChecker.java (renamed from jack/src/com/android/jack/transformations/parent/ParentSetterChecker.java)14
-rw-r--r--jack/src/com/android/jack/transformations/parent/TypeParentChecker.java81
-rw-r--r--jack/src/com/android/jack/util/PackageCodec.java9
-rw-r--r--jack/src/com/android/jack/util/filter/SignatureCodec.java8
-rw-r--r--jack/tests/com/android/jack/ClasspathTest.java37
-rw-r--r--jack/tests/com/android/jack/multidex/MultiDexTests.java22
-rw-r--r--jack/tests/com/android/jack/shrob/ShrinkMultiDexTest.java6
-rw-r--r--jack/tests/com/android/jack/statistics/BlockStatisticsOnCore.java4
-rw-r--r--jack/tests/com/android/jack/transformations/ast/ImplicitBlockTest.java4
-rw-r--r--jack/tests/com/android/jack/transformations/ast/SynchronizedTest.java4
-rw-r--r--jack/tests/com/android/jack/transformations/ast/TypeLegalizerTest.java2
-rw-r--r--sched/src/com/android/sched/item/ManagedItem.java5
-rw-r--r--sched/src/com/android/sched/marker/ManagedMarker.java4
-rw-r--r--sched/src/com/android/sched/scheduler/ManagedSchedulable.java4
-rw-r--r--sched/src/com/android/sched/scheduler/Plan.java2
-rw-r--r--sched/src/com/android/sched/util/HasDescription.java27
-rw-r--r--sched/src/com/android/sched/util/codec/DoubleCodec.java9
-rw-r--r--sched/src/com/android/sched/util/codec/EnumCodec.java24
-rw-r--r--sched/src/com/android/sched/util/codec/FileOrDirCodec.java9
-rw-r--r--sched/src/com/android/sched/util/codec/ImplementationName.java1
-rw-r--r--sched/src/com/android/sched/util/codec/KeyValueCodec.java33
-rw-r--r--sched/src/com/android/sched/util/codec/KeywordsCodec.java15
-rw-r--r--sched/src/com/android/sched/util/codec/ListCodec.java6
-rw-r--r--sched/src/com/android/sched/util/codec/LongCodec.java9
-rw-r--r--sched/src/com/android/sched/util/codec/Parser.java36
-rw-r--r--sched/src/com/android/sched/util/codec/PathCodec.java8
-rw-r--r--sched/src/com/android/sched/util/codec/Selector.java34
-rw-r--r--sched/src/com/android/sched/util/config/expression/Expression.java5
-rw-r--r--sched/src/com/android/sched/util/config/id/PropertyId.java4
-rw-r--r--sched/src/com/android/sched/util/location/Location.java6
-rw-r--r--sched/src/com/android/sched/util/log/StatisticOnlyTracer.java3
-rw-r--r--sched/src/com/android/sched/util/log/stats/Statistic.java6
-rw-r--r--sched/src/com/android/sched/util/log/stats/StatisticId.java4
-rw-r--r--sched/src/com/android/sched/util/log/tracer/ProbeManagerCodec.java6
-rw-r--r--sched/src/com/android/sched/util/log/tracer/filter/EventFilter.java5
-rw-r--r--sched/src/com/android/sched/util/log/tracer/probe/Probe.java5
-rw-r--r--sched/src/com/android/sched/util/log/tracer/probe/ThreadTimeProbe.java2
-rw-r--r--sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java3
-rw-r--r--sched/src/com/android/sched/util/log/tracer/watcher/ArrayListWatcher.java3
-rw-r--r--sched/src/com/android/sched/util/log/tracer/watcher/DetailedAllocationWatcher.java3
-rw-r--r--sched/src/com/android/sched/util/table/Report.java5
-rw-r--r--sched/src/com/android/sched/util/table/Table.java4
58 files changed, 876 insertions, 310 deletions
diff --git a/jack-tests/Android.mk b/jack-tests/Android.mk
index c982592..2255157 100644
--- a/jack-tests/Android.mk
+++ b/jack-tests/Android.mk
@@ -292,8 +292,7 @@ $(call declare-java7-test-with-name,java7/trywithresources/test001)
$(call declare-java7-test-with-name,java7/trywithresources/test002)
$(call declare-java7-test-with-name,java7/parser/literals/test001)
$(call declare-java7-test-with-name,java7/parser/literals/test002)
-# Known bug
-#$(call declare-java7-test-with-name,java7/boxing/test001)
+$(call declare-java7-test-with-name,java7/boxing/test001)
# define global regression test
include $(JACK_CLEAR_VARS)
diff --git a/jack-tests/tests/com/android/jack/classpath/test003/jack/A.java b/jack-tests/tests/com/android/jack/classpath/test003/jack/A.java
new file mode 100644
index 0000000..32109f6
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/classpath/test003/jack/A.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 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.classpath.test003.jack;
+
+import com.android.jack.classpath.test003.lib.HasInnersClasses;
+
+public class A {
+
+ public static int get() {
+ return HasInnersClasses.value;
+ }
+
+}
diff --git a/jack-tests/tests/com/android/jack/classpath/test003/lib/HasInnersClasses.java b/jack-tests/tests/com/android/jack/classpath/test003/lib/HasInnersClasses.java
new file mode 100644
index 0000000..bc360c1
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/classpath/test003/lib/HasInnersClasses.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 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.classpath.test003.lib;
+
+public class HasInnersClasses {
+
+ public static class InnerToDelete {
+
+ }
+
+ public static int value;
+
+ static {
+ value = 3;
+ }
+}
diff --git a/jack/src/com/android/jack/CommandLine.java b/jack/src/com/android/jack/CommandLine.java
index 3b4ba0c..3da2a03 100644
--- a/jack/src/com/android/jack/CommandLine.java
+++ b/jack/src/com/android/jack/CommandLine.java
@@ -20,6 +20,7 @@ import com.android.jack.frontend.FrontendCompilationException;
import com.android.jack.load.JackLoadingException;
import com.android.sched.util.TextUtils;
import com.android.sched.util.UnrecoverableException;
+import com.android.sched.util.codec.Parser.ValueDescription;
import com.android.sched.util.config.ChainedException;
import com.android.sched.util.config.ConfigurationException;
import com.android.sched.util.config.GatherConfigBuilder;
@@ -33,6 +34,7 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
+import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -171,6 +173,19 @@ public abstract class CommandLine {
sb.append(" ");
sb.append(property.getCodec().getUsage());
+ // Value descriptions
+ List<ValueDescription> descriptions = property.getCodec().getValueDescriptions();
+ if (descriptions.size() != 0) {
+ sb.append(" where");
+ for (ValueDescription entry : descriptions) {
+ sb.append(TextUtils.LINE_SEPARATOR);
+ sb.append(" ");
+ sb.append(entry.getValue());
+ sb.append(": ");
+ sb.append(entry.getDescription());
+ }
+ }
+
System.out.println(sb);
}
}
diff --git a/jack/src/com/android/jack/Jack.java b/jack/src/com/android/jack/Jack.java
index 81d4bfe..7fb8d4e 100644
--- a/jack/src/com/android/jack/Jack.java
+++ b/jack/src/com/android/jack/Jack.java
@@ -226,7 +226,8 @@ import com.android.jack.transformations.flow.FlowNormalizer;
import com.android.jack.transformations.flow.FlowNormalizerSchedulingSeparator;
import com.android.jack.transformations.parent.DeclaredTypePackageChecker;
import com.android.jack.transformations.parent.PackageChecker;
-import com.android.jack.transformations.parent.ParentSetterChecker;
+import com.android.jack.transformations.parent.ParentChecker;
+import com.android.jack.transformations.parent.TypeParentChecker;
import com.android.jack.transformations.renamepackage.PackageRenamer;
import com.android.jack.transformations.rop.cast.RopCastLegalizer;
import com.android.jack.transformations.threeaddresscode.ThreeAddressCodeBuilder;
@@ -872,7 +873,7 @@ public abstract class Jack {
}
if (hasSanityChecks) {
- planBuilder.append(ParentSetterChecker.class);
+ planBuilder.append(ParentChecker.class);
}
{
@@ -1116,11 +1117,14 @@ public abstract class Jack {
fieldPlan2.append(FieldAnnotationBuilder.class);
}
}
+ if (hasSanityChecks) {
+ typePlan5.append(TypeParentChecker.class);
+ }
typePlan5.append(OneDexPerTypeWriter.class);
}
if (hasSanityChecks) {
- planBuilder.append(ParentSetterChecker.class);
+ planBuilder.append(ParentChecker.class);
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
@@ -1151,7 +1155,7 @@ public abstract class Jack {
appendMultiDexAndShrobStartPlan(planBuilder);
if (hasSanityChecks) {
- planBuilder.append(ParentSetterChecker.class);
+ planBuilder.append(ParentChecker.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan7 =
@@ -1378,7 +1382,7 @@ public abstract class Jack {
appendMultiDexAndShrobStartPlan(planBuilder);
if (hasSanityChecks) {
- planBuilder.append(ParentSetterChecker.class);
+ planBuilder.append(ParentChecker.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan3 =
@@ -1510,11 +1514,14 @@ public abstract class Jack {
fieldPlan2.append(FieldAnnotationBuilder.class);
}
}
+ if (hasSanityChecks) {
+ typePlan5.append(TypeParentChecker.class);
+ }
typePlan5.append(OneDexPerTypeWriter.class);
}
if (hasSanityChecks) {
- planBuilder.append(ParentSetterChecker.class);
+ planBuilder.append(ParentChecker.class);
}
}
diff --git a/jack/src/com/android/jack/backend/dex/DexFileWriter.java b/jack/src/com/android/jack/backend/dex/DexFileWriter.java
index b1bf575..4fc75a5 100644
--- a/jack/src/com/android/jack/backend/dex/DexFileWriter.java
+++ b/jack/src/com/android/jack/backend/dex/DexFileWriter.java
@@ -26,14 +26,14 @@ import com.android.sched.schedulable.Produce;
import com.android.sched.schedulable.RunnableSchedulable;
import com.android.sched.util.config.HasKeyId;
import com.android.sched.util.config.ThreadConfig;
-import com.android.sched.util.config.id.BooleanPropertyId;
+import com.android.sched.util.config.id.ImplementationPropertyId;
import com.android.sched.vfs.Container;
import com.android.sched.vfs.OutputVDir;
import javax.annotation.Nonnull;
/**
- * Write dex into a file.
+ * Write dex to a file.
*/
@HasKeyId
@Description("Write dex into a file")
@@ -43,8 +43,7 @@ import javax.annotation.Nonnull;
public class DexFileWriter extends DexWriter implements RunnableSchedulable<JSession> {
/**
- * File name prefix of a {@code .dex} file automatically loaded in an
- * archive.
+ * File name prefix of a {@code .dex} file automatically loaded in an archive.
*/
static final String DEX_PREFIX = "classes";
@@ -52,14 +51,10 @@ public class DexFileWriter extends DexWriter implements RunnableSchedulable<JSes
public static final String DEX_FILENAME = DEX_PREFIX + DEX_FILE_EXTENSION;
@Nonnull
- public static final BooleanPropertyId MULTIDEX = BooleanPropertyId.create(
- "jack.dex.output.multidex", "Enable MultiDex output")
- .addDefaultValue(false);
-
- @Nonnull
- public static final BooleanPropertyId MINIMAL_MAIN_DEX = BooleanPropertyId.create(
- "jack.dex.output.multidex.minimalmaindex",
- "Keep main dex file as small as possible in MultiDex mode").addDefaultValue(false);
+ public static final
+ ImplementationPropertyId<DexWritingTool> DEX_WRITING_POLICY = ImplementationPropertyId.create(
+ "jack.dex.output.policy", "Define which policy will be used to emit dex files",
+ DexWritingTool.class).addDefaultValue("single-dex");
@Nonnull
private final OutputVDir outputVDir;
@@ -77,8 +72,8 @@ public class DexFileWriter extends DexWriter implements RunnableSchedulable<JSes
@Override
public void run(@Nonnull JSession session) throws Exception {
- DexWritingTool writingTool = new MergingDexWritingTool(outputVDir);
- writingTool.write();
+ DexWritingTool writingTool = ThreadConfig.get(DEX_WRITING_POLICY);
+ writingTool.write(outputVDir);
}
}
diff --git a/jack/src/com/android/jack/backend/dex/DexWritingTool.java b/jack/src/com/android/jack/backend/dex/DexWritingTool.java
index 5024a65..912d244 100644
--- a/jack/src/com/android/jack/backend/dex/DexWritingTool.java
+++ b/jack/src/com/android/jack/backend/dex/DexWritingTool.java
@@ -16,13 +16,28 @@
package com.android.jack.backend.dex;
+import com.android.jack.Jack;
+import com.android.jack.JackIOException;
+import com.android.jack.Options;
import com.android.jack.backend.dex.rop.CodeItemBuilder;
import com.android.jack.dx.dex.DexOptions;
import com.android.jack.dx.dex.file.DexFile;
+import com.android.jack.dx.io.DexBuffer;
+import com.android.jack.ir.ast.JDefinedClassOrInterface;
+import com.android.jack.tools.merger.JackMerger;
+import com.android.jack.tools.merger.MergeOverflow;
import com.android.sched.util.config.ThreadConfig;
+import com.android.sched.util.file.NotFileOrDirectoryException;
+import com.android.sched.vfs.InputRootVDir;
+import com.android.sched.vfs.InputVFile;
import com.android.sched.vfs.OutputVDir;
+import com.android.sched.vfs.OutputVFile;
+import com.android.sched.vfs.VPath;
+import java.io.BufferedOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
import javax.annotation.Nonnull;
@@ -32,14 +47,8 @@ import javax.annotation.Nonnull;
public abstract class DexWritingTool {
@Nonnull
- protected final OutputVDir outputVDir;
- @Nonnull
private final boolean forceJumbo = ThreadConfig.get(CodeItemBuilder.FORCE_JUMBO).booleanValue();
- public DexWritingTool(@Nonnull OutputVDir outputVDir) {
- this.outputVDir = outputVDir;
- }
-
@Nonnull
protected DexFile createDexFile() {
DexOptions options = new DexOptions();
@@ -47,6 +56,68 @@ public abstract class DexWritingTool {
return new DexFile(options);
}
- public abstract void write() throws IOException;
+ public abstract void write(@Nonnull OutputVDir outputVDir) throws JackIOException;
+
+ protected InputRootVDir getTypeDexDir() {
+ return (InputRootVDir) ThreadConfig.get(Options.TYPEDEX_DIR);
+ }
+
+ protected void finishMerge(@Nonnull JackMerger merger, @Nonnull OutputVFile out)
+ throws JackIOException {
+ OutputStream os = null;
+ try {
+ try {
+ os = new BufferedOutputStream(out.openWrite());
+ merger.finish(os);
+ } finally {
+ if (os != null) {
+ os.close();
+ }
+ }
+ } catch (IOException e) {
+ throw new JackIOException("Cannot write to output dex " + out, e);
+ }
+ }
+
+ protected void mergeDex(@Nonnull JackMerger merger, InputVFile inputDex) throws JackIOException,
+ MergeOverflow {
+ try {
+ merger.addDexFile(new DexBuffer(inputDex.openRead()));
+ } catch (IOException e) {
+ throw new JackIOException("Could not read Dex from " + inputDex, e);
+ }
+ }
+ protected OutputVFile getOutputDex(@Nonnull OutputVDir outputVDir, int dexCount)
+ throws JackIOException {
+ assert dexCount >= 1;
+ String dexName;
+ if (dexCount == 1) {
+ dexName = DexFileWriter.DEX_FILENAME;
+ } else {
+ dexName = DexFileWriter.DEX_PREFIX + dexCount + DexFileWriter.DEX_FILE_EXTENSION;
+ }
+ try {
+ return outputVDir.createOutputVFile(new VPath(dexName, '/'));
+ } catch (IOException e) {
+ throw new JackIOException("Cannot create dex file '" + dexName + "' in " + outputVDir, e);
+ }
+ }
+
+ protected void fillDexLists(List<InputVFile> mainDexList, List<InputVFile> anyDexList)
+ throws JackIOException {
+ for (JDefinedClassOrInterface type : Jack.getSession().getTypesToEmit()) {
+ try {
+ InputVFile inputVFile = getTypeDexDir().getInputVFile(DexWriter.getFilePath(type));
+ if (type.containsMarker(MainDexMarker.class)) {
+ mainDexList.add(inputVFile);
+ } else {
+ anyDexList.add(inputVFile);
+ }
+ } catch (NotFileOrDirectoryException e) {
+ throw new JackIOException("Error trying to read file for type '"
+ + Jack.getUserFriendlyFormatter().getName(type) + "'", e);
+ }
+ }
+ }
}
diff --git a/jack/src/com/android/jack/backend/dex/MergingDexWritingTool.java b/jack/src/com/android/jack/backend/dex/MergingDexWritingTool.java
deleted file mode 100644
index 652e428..0000000
--- a/jack/src/com/android/jack/backend/dex/MergingDexWritingTool.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2014 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.JackFileException;
-import com.android.jack.JackIOException;
-import com.android.jack.JackUserException;
-import com.android.jack.Options;
-import com.android.jack.dx.io.DexBuffer;
-import com.android.jack.ir.ast.JDefinedClassOrInterface;
-import com.android.jack.tools.merger.JackMerger;
-import com.android.jack.tools.merger.MergeOverflow;
-import com.android.sched.util.config.ThreadConfig;
-import com.android.sched.util.file.NotFileOrDirectoryException;
-import com.android.sched.util.location.Location;
-import com.android.sched.vfs.InputOutputVFile;
-import com.android.sched.vfs.InputRootVDir;
-import com.android.sched.vfs.InputVDir;
-import com.android.sched.vfs.InputVElement;
-import com.android.sched.vfs.InputVFile;
-import com.android.sched.vfs.OutputVDir;
-import com.android.sched.vfs.OutputVFile;
-import com.android.sched.vfs.VPath;
-
-import java.io.BufferedOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.Nonnegative;
-import javax.annotation.Nonnull;
-
-/**
- * A {@link DexWritingTool} that merges dex files, each one corresponding to a type.
- */
-public class MergingDexWritingTool extends DexWritingTool {
-
- @Nonnull
- private JackMerger merger;
- @Nonnegative
- private int dexCount = 1;
- @Nonnull
- private OutputVFile dexVFile;
-
- public MergingDexWritingTool(@Nonnull OutputVDir outputVDir) {
- super(outputVDir);
- merger = new JackMerger(createDexFile());
- try {
- dexVFile = getNextOutputDex();
- } catch (IOException e) {
- throw new JackIOException("Error creating output dex", e);
- }
- }
-
- @Override
- public void write() {
-
- InputRootVDir dexFileVDir = (InputRootVDir) ThreadConfig.get(Options.TYPEDEX_DIR);
- boolean isMultidex = ThreadConfig.get(DexFileWriter.MULTIDEX).booleanValue();
-
- try {
- if (isMultidex) {
-
- List<InputVFile> mainDexList = new ArrayList<InputVFile>();
- List<InputVFile> anyDexList = new ArrayList<InputVFile>();
- for (JDefinedClassOrInterface type : Jack.getSession().getTypesToEmit()) {
- try {
- InputVFile inputVFile = dexFileVDir.getInputVFile(DexWriter.getFilePath(type));
- if (type.containsMarker(MainDexMarker.class)) {
- mainDexList.add(inputVFile);
- } else {
- anyDexList.add(inputVFile);
- }
- } catch (NotFileOrDirectoryException e) {
- throw new JackFileException("Error trying to read file for type '"
- + Jack.getUserFriendlyFormatter().getName(type) + "'", e);
- }
- }
-
- mergeDexesFromList(mainDexList, OverflowPolicy.MULTIDEX_MAIN_DEX);
-
- if (ThreadConfig.get(DexFileWriter.MINIMAL_MAIN_DEX).booleanValue()) {
- finishMerge(merger, dexVFile, outputVDir.getLocation());
- dexVFile = getNextOutputDex();
- merger = new JackMerger(createDexFile());
- }
-
- assert anyDexList != null;
- mergeDexesFromList(anyDexList, OverflowPolicy.MULTIDEX_ANY_DEX);
-
- } else {
-
- List<InputVFile> dexList = new ArrayList<InputVFile>();
- getAllDexFilesFromDir(dexFileVDir, dexList);
- mergeDexesFromList(dexList, OverflowPolicy.SINGLE_DEX);
- }
-
- finishMerge(merger, dexVFile, outputVDir.getLocation());
- } catch (IOException e) {
- throw getWriteException(outputVDir.getLocation(), e);
- }
- }
-
- private void mergeDexesFromList(List<InputVFile> dexList, OverflowPolicy overflowPolicy)
- throws IOException {
- for (InputVFile currentDex : dexList) {
- try {
- merger.addDexFile(new DexBuffer(currentDex.openRead()));
- } catch (IOException e) {
- throw new JackIOException(
- "Could not read Dex file '" + currentDex.getLocation().getDescription() + "'", e);
- } catch (MergeOverflow e) {
- switch (overflowPolicy) {
- case SINGLE_DEX:
- throw new JackUserException(
- "Index overflow while merging dex files. Try using multidex.", e);
- case MULTIDEX_MAIN_DEX:
- throw new JackUserException(
- "Too many classes in main dex. Index overflow while merging dex files.", e);
- case MULTIDEX_ANY_DEX:
- finishMerge(merger, dexVFile, outputVDir.getLocation());
- dexVFile = getNextOutputDex();
- merger = new JackMerger(createDexFile());
- break;
- default:
- throw new AssertionError();
- }
- }
- }
-
- }
-
- private void getAllDexFilesFromDir(@Nonnull InputVDir dexFileVDir,
- @Nonnull List<InputVFile> dexFiles) {
- for (InputVElement subFile : dexFileVDir.list()) {
- if (subFile.isVDir()) {
- getAllDexFilesFromDir((InputVDir) subFile, dexFiles);
- } else if (subFile.getName().endsWith(DexFileWriter.DEX_FILE_EXTENSION)) {
- dexFiles.add((InputOutputVFile) subFile);
- }
- }
- }
-
- private void finishMerge(@Nonnull JackMerger merger, @Nonnull OutputVFile out,
- @Nonnull Location outputLocation) {
- OutputStream os;
- try {
- os = new BufferedOutputStream(out.openWrite());
- } catch (IOException e) {
- throw new JackIOException("Failed to read intermediate dex", e);
- }
- try {
- merger.finish(os);
- os.close();
- } catch (IOException e) {
- try {
- os.close();
- } catch (IOException close) {
- // let the Exception for the initial error be handled
- }
- throw getWriteException(outputLocation, e);
- }
- }
-
- private JackFileException getWriteException(@Nonnull Location outputLocation,
- @Nonnull IOException e) {
- return new JackFileException("Could not write Dex file to output '"
- + outputLocation.getDescription() + "'", e);
- }
-
- private OutputVFile getNextOutputDex() throws IOException {
- assert dexCount >= 1;
- if (dexCount == 1) {
- dexCount++;
- return outputVDir.createOutputVFile(new VPath(DexFileWriter.DEX_FILENAME, '/'));
- } else {
- return outputVDir.createOutputVFile(
- new VPath(DexFileWriter.DEX_PREFIX + dexCount++ + DexFileWriter.DEX_FILE_EXTENSION, '/'));
- }
- }
-
- private static enum OverflowPolicy {
- SINGLE_DEX,
- MULTIDEX_MAIN_DEX,
- MULTIDEX_ANY_DEX;
- }
-
-}
diff --git a/jack/src/com/android/jack/backend/dex/MinimalMultiDexWritingTool.java b/jack/src/com/android/jack/backend/dex/MinimalMultiDexWritingTool.java
new file mode 100644
index 0000000..89b9cf7
--- /dev/null
+++ b/jack/src/com/android/jack/backend/dex/MinimalMultiDexWritingTool.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 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.JackUserException;
+import com.android.jack.tools.merger.JackMerger;
+import com.android.jack.tools.merger.MergeOverflow;
+import com.android.sched.util.codec.ImplementationName;
+import com.android.sched.vfs.InputVFile;
+import com.android.sched.vfs.OutputVDir;
+import com.android.sched.vfs.OutputVFile;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A {@link DexWritingTool} that merges dex files, each one corresponding to a type, in several dex
+ * files, keeping the main dex as small as possible.
+ */
+@ImplementationName(iface = DexWritingTool.class, name = "minimal-multidex", description =
+ "allow emitting several dex files, keeping the first dex (main dex) as small as possible")
+public class MinimalMultiDexWritingTool extends DexWritingTool {
+
+ @Override
+ public void write(@Nonnull OutputVDir outputVDir) {
+ int dexCount = 1;
+ JackMerger merger = new JackMerger(createDexFile());
+ OutputVFile outputDex = getOutputDex(outputVDir, dexCount++);
+ List<InputVFile> mainDexList = new ArrayList<InputVFile>();
+ List<InputVFile> anyDexList = new ArrayList<InputVFile>();
+ fillDexLists(mainDexList, anyDexList);
+
+ for (InputVFile currentDex : mainDexList) {
+ try {
+ mergeDex(merger, currentDex);
+ } catch (MergeOverflow e) {
+ throw new JackUserException(
+ "Too many classes in main dex. Index overflow while merging dex files", e);
+ }
+ }
+
+ finishMerge(merger, outputDex);
+ outputDex = getOutputDex(outputVDir, dexCount++);
+ merger = new JackMerger(createDexFile());
+
+ for (InputVFile currentDex : anyDexList) {
+ try {
+ mergeDex(merger, currentDex);
+ } catch (MergeOverflow e) {
+ finishMerge(merger, outputDex);
+ outputDex = getOutputDex(outputVDir, dexCount++);
+ merger = new JackMerger(createDexFile());
+ }
+ }
+
+ finishMerge(merger, outputDex);
+ }
+
+}
diff --git a/jack/src/com/android/jack/backend/dex/SingleDexWritingTool.java b/jack/src/com/android/jack/backend/dex/SingleDexWritingTool.java
new file mode 100644
index 0000000..0f01d24
--- /dev/null
+++ b/jack/src/com/android/jack/backend/dex/SingleDexWritingTool.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2014 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.JackIOException;
+import com.android.jack.JackUserException;
+import com.android.jack.tools.merger.JackMerger;
+import com.android.jack.tools.merger.MergeOverflow;
+import com.android.sched.util.codec.ImplementationName;
+import com.android.sched.vfs.InputOutputVFile;
+import com.android.sched.vfs.InputVDir;
+import com.android.sched.vfs.InputVElement;
+import com.android.sched.vfs.InputVFile;
+import com.android.sched.vfs.OutputVDir;
+import com.android.sched.vfs.OutputVFile;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A {@link DexWritingTool} that merges dex files, each one corresponding to a type, to a single
+ * dex.
+ */
+@ImplementationName(iface = DexWritingTool.class, name = "single-dex",
+ description = "only emit one dex file")
+public class SingleDexWritingTool extends DexWritingTool {
+
+ @Override
+ public void write(@Nonnull OutputVDir outputVDir) throws JackIOException {
+ JackMerger merger = new JackMerger(createDexFile());
+ OutputVFile outputDex = getOutputDex(outputVDir);
+ List<InputVFile> dexList = new ArrayList<InputVFile>();
+ getAllDexFilesFromDir(getTypeDexDir(), dexList);
+
+ for (InputVFile currentDex : dexList) {
+ try {
+ mergeDex(merger, currentDex);
+ } catch (MergeOverflow e) {
+ throw new JackUserException("Index overflow while merging dex files. Try using multidex",
+ e);
+ }
+ }
+ finishMerge(merger, outputDex);
+ }
+
+ private void getAllDexFilesFromDir(@Nonnull InputVDir dexFileVDir,
+ @Nonnull List<InputVFile> dexFiles) {
+ for (InputVElement subFile : dexFileVDir.list()) {
+ if (subFile.isVDir()) {
+ getAllDexFilesFromDir((InputVDir) subFile, dexFiles);
+ } else if (subFile.getName().endsWith(DexFileWriter.DEX_FILE_EXTENSION)) {
+ dexFiles.add((InputOutputVFile) subFile);
+ }
+ }
+ }
+
+ private OutputVFile getOutputDex(@Nonnull OutputVDir outputVDir) {
+ return getOutputDex(outputVDir, 1);
+ }
+}
diff --git a/jack/src/com/android/jack/backend/dex/StandardMultiDexWritingTool.java b/jack/src/com/android/jack/backend/dex/StandardMultiDexWritingTool.java
new file mode 100644
index 0000000..86c0295
--- /dev/null
+++ b/jack/src/com/android/jack/backend/dex/StandardMultiDexWritingTool.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 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.JackIOException;
+import com.android.jack.JackUserException;
+import com.android.jack.tools.merger.JackMerger;
+import com.android.jack.tools.merger.MergeOverflow;
+import com.android.sched.util.codec.ImplementationName;
+import com.android.sched.vfs.InputVFile;
+import com.android.sched.vfs.OutputVDir;
+import com.android.sched.vfs.OutputVFile;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A {@link DexWritingTool} that merges dex files, each one corresponding to a type, in several dex
+ * files.
+ */
+@ImplementationName(iface = DexWritingTool.class, name = "multidex",
+ description = "allow emitting several dex files")
+public class StandardMultiDexWritingTool extends DexWritingTool {
+
+ @Override
+ public void write(@Nonnull OutputVDir outputVDir) throws JackIOException {
+ int dexCount = 1;
+ JackMerger merger = new JackMerger(createDexFile());
+ OutputVFile outputDex = getOutputDex(outputVDir, dexCount++);
+ List<InputVFile> mainDexList = new ArrayList<InputVFile>();
+ List<InputVFile> anyDexList = new ArrayList<InputVFile>();
+ fillDexLists(mainDexList, anyDexList);
+
+ for (InputVFile currentDex : mainDexList) {
+ try {
+ mergeDex(merger, currentDex);
+ } catch (MergeOverflow e) {
+ throw new JackUserException(
+ "Too many classes in main dex. Index overflow while merging dex files", e);
+ }
+ }
+
+ for (InputVFile currentDex : anyDexList) {
+ try {
+ mergeDex(merger, currentDex);
+ } catch (MergeOverflow e) {
+ finishMerge(merger, outputDex);
+ outputDex = getOutputDex(outputVDir, dexCount++);
+ merger = new JackMerger(createDexFile());
+ }
+ }
+
+ finishMerge(merger, outputDex);
+ }
+}
diff --git a/jack/src/com/android/jack/backend/jayce/JayceFileImporter.java b/jack/src/com/android/jack/backend/jayce/JayceFileImporter.java
index f172d9b..a56afcc 100644
--- a/jack/src/com/android/jack/backend/jayce/JayceFileImporter.java
+++ b/jack/src/com/android/jack/backend/jayce/JayceFileImporter.java
@@ -24,6 +24,7 @@ import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JTypeLookupException;
import com.android.jack.ir.ast.Resource;
import com.android.jack.lookup.JLookup;
+import com.android.sched.util.HasDescription;
import com.android.sched.util.codec.EnumCodec;
import com.android.sched.util.config.HasKeyId;
import com.android.sched.util.config.ThreadConfig;
@@ -65,9 +66,22 @@ public class JayceFileImporter {
private static final char VPATH_SEPARATOR = JLookup.PACKAGE_SEPARATOR;
- private enum CollisionPolicy {
- KEEP_FIRST,
- FAIL
+ private enum CollisionPolicy implements HasDescription {
+ KEEP_FIRST("keep the first element encountered"),
+ FAIL("fail when a collision occured");
+
+ @Nonnull
+ private String description;
+
+ private CollisionPolicy(@Nonnull String description) {
+ this.description = description;
+ }
+
+ @Override
+ @Nonnull
+ public String getDescription() {
+ return description;
+ }
}
@Nonnull
diff --git a/jack/src/com/android/jack/ecj/loader/jast/JAstBinaryType.java b/jack/src/com/android/jack/ecj/loader/jast/JAstBinaryType.java
index e8a06ba..d71297d 100644
--- a/jack/src/com/android/jack/ecj/loader/jast/JAstBinaryType.java
+++ b/jack/src/com/android/jack/ecj/loader/jast/JAstBinaryType.java
@@ -91,8 +91,14 @@ class JAstBinaryType implements IBinaryType {
modifiers &= ~JModifier.ANONYMOUS_TYPE;
JClassOrInterface enclosingType = jDeclaredType.getEnclosingType();
- if (enclosingType != null && !isAnonymous()) {
- JAstBinaryType enclosing = classpathLocation.findType(enclosingType);
+ if (enclosingType != null && !isAnonymous()
+ && enclosingType instanceof JDefinedClassOrInterface) {
+ /* If the enclosing is not in the classpath, just skip. This should be with no bad consequence
+ * since ECJ is refusing to compile a source referencing an inner class when its enclosing
+ * class is missing.
+ */
+ JAstBinaryType enclosing =
+ classpathLocation.findType((JDefinedClassOrInterface) enclosingType);
if (enclosing != null) {
if (LoaderUtils.isDeprecated(enclosing)) {
modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly;
@@ -227,14 +233,18 @@ class JAstBinaryType implements IBinaryType {
for (JClassOrInterface jNested : members) {
- /* According to a note in a comment on the interface, we have to filter out local types
- * found in the member types list. Tests have shown that, in this note, "local" means also
- * anonymous.
- */
- JAstBinaryType nested = classpathLocation.findType(jNested);
- assert nested != null;
- if (!(nested.isAnonymous() || nested.isLocal())) {
- nestedTypes.add(new JAstBinaryNestedType(nested.jDeclaredType));
+ /* If the inner is not in the classpath, just skip it. This should not have consequence in
+ * Jack context, since we are unable to present the missing class to ECJ anyway. */
+ if (jNested instanceof JDefinedClassOrInterface) {
+ /* According to a note in a comment on the interface, we have to filter out local types
+ * found in the member types list. Tests have shown that, in this note, "local" means also
+ * anonymous.
+ */
+ JAstBinaryType nested = classpathLocation.findType((JDefinedClassOrInterface) jNested);
+ assert nested != null;
+ if (!(nested.isAnonymous() || nested.isLocal())) {
+ nestedTypes.add(new JAstBinaryNestedType(nested.jDeclaredType));
+ }
}
}
if (!nestedTypes.isEmpty()) {
diff --git a/jack/src/com/android/jack/ecj/loader/jast/JAstClasspath.java b/jack/src/com/android/jack/ecj/loader/jast/JAstClasspath.java
index b4290c5..60ee5aa 100644
--- a/jack/src/com/android/jack/ecj/loader/jast/JAstClasspath.java
+++ b/jack/src/com/android/jack/ecj/loader/jast/JAstClasspath.java
@@ -166,8 +166,8 @@ public class JAstClasspath extends ClasspathLocation {
}
@CheckForNull
- JAstBinaryType findType(@Nonnull JType type) {
- return new JAstBinaryType((JDefinedClassOrInterface) type, this);
+ JAstBinaryType findType(@Nonnull JDefinedClassOrInterface type) {
+ return new JAstBinaryType(type, this);
}
/**
diff --git a/jack/src/com/android/jack/statistics/JNodeWatcher.java b/jack/src/com/android/jack/statistics/JNodeWatcher.java
index ec85b0b..4d9c54e 100644
--- a/jack/src/com/android/jack/statistics/JNodeWatcher.java
+++ b/jack/src/com/android/jack/statistics/JNodeWatcher.java
@@ -84,7 +84,8 @@ public class JNodeWatcher implements ObjectWatcher<JNode> {
/**
* Install a {@link JNodeWatcher}
*/
- @ImplementationName(iface = WatcherInstaller.class, name = "jnode-alloc")
+ @ImplementationName(iface = WatcherInstaller.class, name = "jnode-alloc",
+ description = "record all JNode allocations")
public static class JNodeWatcherInstaller implements WatcherInstaller {
@Override
public void install(@Nonnull Tracer tracer) {
diff --git a/jack/src/com/android/jack/transformations/ast/TypeLegalizer.java b/jack/src/com/android/jack/transformations/ast/TypeLegalizer.java
index bbd6190..7e2f69b 100644
--- a/jack/src/com/android/jack/transformations/ast/TypeLegalizer.java
+++ b/jack/src/com/android/jack/transformations/ast/TypeLegalizer.java
@@ -22,6 +22,7 @@ import com.android.jack.ir.SideEffectOperation;
import com.android.jack.ir.ast.JAbsentArrayDimension;
import com.android.jack.ir.ast.JArrayRef;
import com.android.jack.ir.ast.JBinaryOperation;
+import com.android.jack.ir.ast.JClass;
import com.android.jack.ir.ast.JClassOrInterface;
import com.android.jack.ir.ast.JConditionalExpression;
import com.android.jack.ir.ast.JDoStatement;
@@ -78,9 +79,13 @@ import javax.annotation.Nonnull;
public class TypeLegalizer implements RunnableSchedulable<JMethod> {
@Nonnull
+ private final JClass javaLangObject =
+ Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT);
+
+ @Nonnull
private final Filter<JMethod> filter = ThreadConfig.get(Options.METHOD_FILTER);
- static class TypeLegalizerVisitor extends JVisitor {
+ class TypeLegalizerVisitor extends JVisitor {
@Nonnull
private final TransformationRequest tr;
@@ -146,7 +151,18 @@ public class TypeLegalizer implements RunnableSchedulable<JMethod> {
@Override
public void endVisit(@Nonnull JDynamicCastOperation cast) {
- maybeBoxOrUnbox(cast.getExpr(), cast.getCastType());
+ JExpression expr = cast.getExpr();
+ if (cast.getExpr().getType().isSameType(javaLangObject)
+ && cast.getCastType() instanceof JPrimitiveType) {
+ assert cast.getCastType() != JPrimitiveTypeEnum.VOID.getType();
+
+ JDynamicCastOperation castToWrapperType = new JDynamicCastOperation(expr.getSourceInfo(),
+ ((JPrimitiveType) cast.getCastType()).getWrapperType(),
+ expr);
+ tr.append(new Replace(expr, castToWrapperType));
+ expr = castToWrapperType;
+ }
+ maybeBoxOrUnbox(expr, cast.getCastType());
super.endVisit(cast);
}
diff --git a/jack/src/com/android/jack/transformations/parent/ParentSetterChecker.java b/jack/src/com/android/jack/transformations/parent/ParentChecker.java
index 53bd662..984bc2d 100644
--- a/jack/src/com/android/jack/transformations/parent/ParentSetterChecker.java
+++ b/jack/src/com/android/jack/transformations/parent/ParentChecker.java
@@ -21,7 +21,6 @@ import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JVisitor;
import com.android.jack.transformations.SanityChecks;
import com.android.sched.item.Description;
-import com.android.sched.item.Name;
import com.android.sched.schedulable.RunnableSchedulable;
import com.android.sched.schedulable.Support;
@@ -30,18 +29,17 @@ import java.util.Stack;
import javax.annotation.Nonnull;
/**
- * Check that parent of {@link JNode} are correctly set.
+ * Check that parents of {@link JNode}s are correctly set.
*/
-@Description("Check that parent of JNode are correctly set.")
-@Name("ParentSetterChecker")
+@Description("Check that parents of JNodes are correctly set.")
@Support(SanityChecks.class)
-public class ParentSetterChecker implements RunnableSchedulable<JSession> {
+public class ParentChecker implements RunnableSchedulable<JSession> {
- private static class ParentSetterCheckerVisitor extends JVisitor {
+ private static class ParentCheckerVisitor extends JVisitor {
@Nonnull
private final Stack<JNode> nodes = new Stack<JNode>();
- private ParentSetterCheckerVisitor() {
+ private ParentCheckerVisitor() {
super(false /* needLoading */);
}
@@ -72,7 +70,7 @@ public class ParentSetterChecker implements RunnableSchedulable<JSession> {
@Override
public void run(@Nonnull JSession session) throws Exception {
- ParentSetterCheckerVisitor checker = new ParentSetterCheckerVisitor();
+ ParentCheckerVisitor checker = new ParentCheckerVisitor();
checker.accept(session);
}
} \ No newline at end of file
diff --git a/jack/src/com/android/jack/transformations/parent/TypeParentChecker.java b/jack/src/com/android/jack/transformations/parent/TypeParentChecker.java
new file mode 100644
index 0000000..98470d9
--- /dev/null
+++ b/jack/src/com/android/jack/transformations/parent/TypeParentChecker.java
@@ -0,0 +1,81 @@
+/*
+ * 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.transformations.parent;
+
+import com.android.jack.ir.ast.JDefinedClassOrInterface;
+import com.android.jack.ir.ast.JNode;
+import com.android.jack.ir.ast.JSession;
+import com.android.jack.ir.ast.JVisitor;
+import com.android.jack.transformations.SanityChecks;
+import com.android.sched.item.Description;
+import com.android.sched.schedulable.RunnableSchedulable;
+import com.android.sched.schedulable.Support;
+
+import java.util.Stack;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Check that parents of {@link JNode}s are correctly set, running on
+ * {@link JDefinedClassOrInterface}s.
+ */
+@Description(
+ "Check that parents of JNodes are correctly set, running on JDefinedClassOrInterfaces.")
+@Support(SanityChecks.class)
+public class TypeParentChecker implements RunnableSchedulable<JDefinedClassOrInterface> {
+
+ private static class Visitor extends JVisitor {
+ @Nonnull
+ private final Stack<JNode> nodes = new Stack<JNode>();
+
+ private Visitor() {
+ super(false /* needLoading */);
+ }
+
+ @Override
+ public boolean visit(@Nonnull JNode node) {
+ assert !(node instanceof JSession);
+ if (node instanceof JDefinedClassOrInterface) {
+ if (node.getParent() == null) {
+ throw new AssertionError(
+ "Parent of " + JDefinedClassOrInterface.class.getName() + " must not be null.");
+ }
+ } else {
+ if (node.getParent() != nodes.peek()) {
+ throw new AssertionError("Node with wrong parent.");
+ }
+ }
+
+ nodes.push(node);
+
+ return super.visit(node);
+ }
+
+ @Override
+ public void endVisit(@Nonnull JNode node) {
+ nodes.pop();
+
+ super.endVisit(node);
+ }
+ }
+
+ @Override
+ public void run(@Nonnull JDefinedClassOrInterface type) throws Exception {
+ Visitor checker = new Visitor();
+ checker.accept(type);
+ }
+} \ No newline at end of file
diff --git a/jack/src/com/android/jack/util/PackageCodec.java b/jack/src/com/android/jack/util/PackageCodec.java
index 5532cee..2be9f3c 100644
--- a/jack/src/com/android/jack/util/PackageCodec.java
+++ b/jack/src/com/android/jack/util/PackageCodec.java
@@ -21,6 +21,9 @@ import com.android.sched.util.codec.CodecContext;
import com.android.sched.util.codec.ParsingException;
import com.android.sched.util.codec.StringCodec;
+import java.util.Collections;
+import java.util.List;
+
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -38,6 +41,12 @@ public class PackageCodec implements StringCodec<String>{
@Override
@Nonnull
+ public List<ValueDescription> getValueDescriptions() {
+ return Collections.<ValueDescription> emptyList();
+ }
+
+ @Override
+ @Nonnull
public String parseString(@Nonnull CodecContext context, @Nonnull String string) {
return string;
}
diff --git a/jack/src/com/android/jack/util/filter/SignatureCodec.java b/jack/src/com/android/jack/util/filter/SignatureCodec.java
index 69776bc..dde1236 100644
--- a/jack/src/com/android/jack/util/filter/SignatureCodec.java
+++ b/jack/src/com/android/jack/util/filter/SignatureCodec.java
@@ -19,6 +19,9 @@ package com.android.jack.util.filter;
import com.android.sched.util.codec.CodecContext;
import com.android.sched.util.codec.StringCodec;
+import java.util.Collections;
+import java.util.List;
+
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -36,6 +39,11 @@ public class SignatureCodec implements StringCodec<String>{
@Override
@Nonnull
+ public List<ValueDescription> getValueDescriptions() {
+ return Collections.<ValueDescription> emptyList();
+ }
+ @Override
+ @Nonnull
public String parseString(@Nonnull CodecContext context, @Nonnull String string) {
return string;
}
diff --git a/jack/tests/com/android/jack/ClasspathTest.java b/jack/tests/com/android/jack/ClasspathTest.java
index e655f8d..dc521c9 100644
--- a/jack/tests/com/android/jack/ClasspathTest.java
+++ b/jack/tests/com/android/jack/ClasspathTest.java
@@ -16,6 +16,8 @@
package com.android.jack;
+import junit.framework.Assert;
+
import org.junit.BeforeClass;
import org.junit.Test;
@@ -91,6 +93,41 @@ public class ClasspathTest {
}
@Test
+ public void test003() throws Exception {
+ File libOut = TestTools.createTempDir("ClasspathTest", "lib");
+
+ Options libOptions = TestTools.buildCommandLineArgs(
+ TestTools.getJackTestLibFolder("classpath/test003"));
+ libOptions.setJayceOutputDir(libOut);
+ TestTools.runCompilation(libOptions);
+
+ {
+ // reference compilation
+ File testOut = TestTools.createTempDir("ClasspathTest", "test");
+ Options testOptions = TestTools.buildCommandLineArgs(
+ TestTools.getJackTestsWithJackFolder("classpath/test003"));
+ testOptions.setJayceOutputDir(testOut);
+ testOptions.setClasspath(libOut.getAbsolutePath());
+ TestTools.runCompilation(testOptions);
+ }
+
+ {
+ // delete unused inner in classpath and check we can still compile with it
+ boolean deleted =
+ new File(libOut,
+ "com/android/jack/classpath/test003/lib/HasInnersClasses$InnerToDelete.jack")
+ .delete();
+ Assert.assertTrue(deleted);
+ File testOut = TestTools.createTempDir("ClasspathTest", "test");
+ Options testOptions = TestTools.buildCommandLineArgs(
+ TestTools.getJackTestsWithJackFolder("classpath/test003"));
+ testOptions.setJayceOutputDir(testOut);
+ testOptions.setClasspath(libOut.getAbsolutePath());
+ TestTools.runCompilation(testOptions);
+ }
+ }
+
+ @Test
public void libOfLib() throws Exception {
String defaultClasspath = TestTools.getDefaultBootclasspathString();
diff --git a/jack/tests/com/android/jack/multidex/MultiDexTests.java b/jack/tests/com/android/jack/multidex/MultiDexTests.java
index da69bb3..0202116 100644
--- a/jack/tests/com/android/jack/multidex/MultiDexTests.java
+++ b/jack/tests/com/android/jack/multidex/MultiDexTests.java
@@ -55,7 +55,9 @@ public class MultiDexTests {
File testFolder = TestTools.getJackTestsWithJackFolder("multidex/test001");
File out = TestTools.createTempDir("out", "");
- Options app1Options = createMultiDexEnabledOption(new File(testFolder, "config-001.jpp"));
+ Options app1Options = createCommonOptionsForMultiDex(new File(testFolder, "config-001.jpp"));
+
+ app1Options.addProperty(DexFileWriter.DEX_WRITING_POLICY.getName(), "multidex");
TestTools.compileSourceToDex(app1Options, testFolder, TestTools.getDefaultBootclasspathString()
+ File.pathSeparator + annotations.getPath() + File.pathSeparator + frameworks.getPath(),
@@ -72,9 +74,9 @@ public class MultiDexTests {
File testFolder = TestTools.getJackTestsWithJackFolder("multidex/test001");
File out = TestTools.createTempDir("out", "");
- Options app1Options = createMultiDexEnabledOption(new File(testFolder, "config-001.jpp"));
+ Options app1Options = createCommonOptionsForMultiDex(new File(testFolder, "config-001.jpp"));
- app1Options.addProperty(DexFileWriter.MINIMAL_MAIN_DEX.getName(), "true");
+ app1Options.addProperty(DexFileWriter.DEX_WRITING_POLICY.getName(), "minimal-multidex");
TestTools.compileSourceToDex(app1Options, testFolder, TestTools.getDefaultBootclasspathString()
+ File.pathSeparator + annotations.getPath() + File.pathSeparator + frameworks.getPath(),
@@ -93,9 +95,9 @@ public class MultiDexTests {
File testFolder = TestTools.getJackTestsWithJackFolder("multidex/test001");
File out = TestTools.createTempDir("out", "");
- Options app1Options = createMultiDexEnabledOption(new File(testFolder, "config-003.jpp"));
+ Options app1Options = createCommonOptionsForMultiDex(new File(testFolder, "config-003.jpp"));
- app1Options.addProperty(DexFileWriter.MINIMAL_MAIN_DEX.getName(), "true");
+ app1Options.addProperty(DexFileWriter.DEX_WRITING_POLICY.getName(), "minimal-multidex");
TestTools.compileSourceToDex(app1Options, testFolder, TestTools.getDefaultBootclasspathString()
+ File.pathSeparator + annotations.getPath() + File.pathSeparator + frameworks.getPath(),
@@ -109,11 +111,10 @@ public class MultiDexTests {
return;
}
- private Options createMultiDexEnabledOption(@Nonnull File configFile) throws IOException {
+ private Options createCommonOptionsForMultiDex(@Nonnull File configFile) throws IOException {
File tmpOut = TestTools.createTempDir("tmp", "");
Options app1Options = new Options();
app1Options.addProperty(Options.TYPEDEX_DIR.getName(), tmpOut.getPath());
- app1Options.addProperty(DexFileWriter.MULTIDEX.getName(), "true");
app1Options.addProperty(MultiDexLegacy.MULTIDEX_LEGACY.getName(), "true");
app1Options.addProperty(PreProcessor.ENABLE.getName(), "true");
app1Options.addProperty(PreProcessor.FILE.getName(), configFile.getAbsolutePath());
@@ -168,8 +169,9 @@ public class MultiDexTests {
File testFolder = TestTools.getJackTestsWithJackFolder("multidex/test002");
File out = TestTools.createTempDir("out", "");
- Options app1Options = createMultiDexEnabledOption(
+ Options app1Options = createCommonOptionsForMultiDex(
new File(testFolder,"config-001.jpp"));
+ app1Options.addProperty(DexFileWriter.DEX_WRITING_POLICY.getName(), "multidex");
TestTools.compileSourceToDex(app1Options, testFolder, TestTools.getDefaultBootclasspathString()
+ File.pathSeparator + annotations.getPath() + File.pathSeparator + frameworks.getPath()
@@ -186,9 +188,9 @@ public class MultiDexTests {
File testFolder = TestTools.getJackTestsWithJackFolder("multidex/test002");
File out = TestTools.createTempDir("out", "");
- Options app1Options = createMultiDexEnabledOption(
+ Options app1Options = createCommonOptionsForMultiDex(
new File(testFolder,"config-001.jpp"));
- app1Options.addProperty(DexFileWriter.MINIMAL_MAIN_DEX.getName(), "true");
+ app1Options.addProperty(DexFileWriter.DEX_WRITING_POLICY.getName(), "minimal-multidex");
app1Options.addJayceImport(library);
TestTools.compileSourceToDex(app1Options, testFolder, TestTools.getDefaultBootclasspathString()
diff --git a/jack/tests/com/android/jack/shrob/ShrinkMultiDexTest.java b/jack/tests/com/android/jack/shrob/ShrinkMultiDexTest.java
index 8d97f1f..4b2fc57 100644
--- a/jack/tests/com/android/jack/shrob/ShrinkMultiDexTest.java
+++ b/jack/tests/com/android/jack/shrob/ShrinkMultiDexTest.java
@@ -60,11 +60,11 @@ public class ShrinkMultiDexTest extends AbstractTest {
new ProguardFlags(testFolder, "proguard.flags" + flagNumber)};
File refFolder = new File(testFolder, "refsShrinking");
Options options = new Options();
- options.addProperty(DexFileWriter.MULTIDEX.getName(), "true");
+ options.addProperty(DexFileWriter.DEX_WRITING_POLICY.getName(), "multidex");
options.addProperty(MultiDexLegacy.MULTIDEX_LEGACY.getName(), "true");
options.addProperty(PreProcessor.ENABLE.getName(), "true");
- options.addProperty(PreProcessor.FILE.getName(),
- new File(TestTools.getJackTestFolder("shrob"),"legacyMainDexClasses.jpp").getAbsolutePath());
+ options.addProperty(PreProcessor.FILE.getName(), new File(TestTools.getJackTestFolder("shrob"),
+ "legacyMainDexClasses.jpp").getAbsolutePath());
TestTools.checkListingWhenMultiDex(options,
bootclasspath,
classpath,
diff --git a/jack/tests/com/android/jack/statistics/BlockStatisticsOnCore.java b/jack/tests/com/android/jack/statistics/BlockStatisticsOnCore.java
index 17acfa9..3ba6e52 100644
--- a/jack/tests/com/android/jack/statistics/BlockStatisticsOnCore.java
+++ b/jack/tests/com/android/jack/statistics/BlockStatisticsOnCore.java
@@ -24,7 +24,7 @@ import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JSession;
import com.android.jack.scheduling.adapter.JDefinedClassOrInterfaceAdapter;
import com.android.jack.scheduling.adapter.JMethodAdapter;
-import com.android.jack.transformations.parent.ParentSetterChecker;
+import com.android.jack.transformations.parent.ParentChecker;
import com.android.sched.scheduler.PlanBuilder;
import com.android.sched.scheduler.Request;
import com.android.sched.scheduler.SchedulableManager;
@@ -89,7 +89,7 @@ public class BlockStatisticsOnCore {
sr.addInitialTagOrMarker(JavaSourceIr.class);
PlanBuilder<JSession> planBuilder = sr.getPlanBuilder(JSession.class);
- planBuilder.append(ParentSetterChecker.class);
+ planBuilder.append(ParentChecker.class);
SubPlanBuilder<JDefinedClassOrInterface> typePlan = planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(BlockStatistics.class);
diff --git a/jack/tests/com/android/jack/transformations/ast/ImplicitBlockTest.java b/jack/tests/com/android/jack/transformations/ast/ImplicitBlockTest.java
index 74381e5..edfd77c 100644
--- a/jack/tests/com/android/jack/transformations/ast/ImplicitBlockTest.java
+++ b/jack/tests/com/android/jack/transformations/ast/ImplicitBlockTest.java
@@ -25,7 +25,7 @@ import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JSession;
import com.android.jack.scheduling.adapter.JDefinedClassOrInterfaceAdapter;
import com.android.jack.scheduling.adapter.JMethodAdapter;
-import com.android.jack.transformations.parent.ParentSetterChecker;
+import com.android.jack.transformations.parent.ParentChecker;
import com.android.jack.util.filter.SignatureMethodFilter;
import com.android.sched.scheduler.PlanBuilder;
import com.android.sched.scheduler.Request;
@@ -120,7 +120,7 @@ public class ImplicitBlockTest {
sr.addInitialTagOrMarker(JavaSourceIr.class);
PlanBuilder<JSession> planBuilder = sr.getPlanBuilder(JSession.class);
- planBuilder.append(ParentSetterChecker.class);
+ planBuilder.append(ParentChecker.class);
SubPlanBuilder<JDefinedClassOrInterface> typePlan = planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(ImplicitBlocks.class);
diff --git a/jack/tests/com/android/jack/transformations/ast/SynchronizedTest.java b/jack/tests/com/android/jack/transformations/ast/SynchronizedTest.java
index 551910b..47bb69f 100644
--- a/jack/tests/com/android/jack/transformations/ast/SynchronizedTest.java
+++ b/jack/tests/com/android/jack/transformations/ast/SynchronizedTest.java
@@ -32,7 +32,7 @@ import com.android.jack.ir.ast.JUnlock;
import com.android.jack.ir.ast.JVariableRef;
import com.android.jack.scheduling.adapter.JDefinedClassOrInterfaceAdapter;
import com.android.jack.scheduling.adapter.JMethodAdapter;
-import com.android.jack.transformations.parent.ParentSetterChecker;
+import com.android.jack.transformations.parent.ParentChecker;
import com.android.jack.util.filter.SignatureMethodFilter;
import com.android.sched.scheduler.PlanBuilder;
import com.android.sched.scheduler.Request;
@@ -154,7 +154,7 @@ public class SynchronizedTest {
sr.addInitialTagsOrMarkers(Jack.getJavaSourceInitialTagSet());
PlanBuilder<JSession> planBuilder = sr.getPlanBuilder(JSession.class);
- planBuilder.append(ParentSetterChecker.class);
+ planBuilder.append(ParentChecker.class);
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
diff --git a/jack/tests/com/android/jack/transformations/ast/TypeLegalizerTest.java b/jack/tests/com/android/jack/transformations/ast/TypeLegalizerTest.java
index c0c5750..0207a4e 100644
--- a/jack/tests/com/android/jack/transformations/ast/TypeLegalizerTest.java
+++ b/jack/tests/com/android/jack/transformations/ast/TypeLegalizerTest.java
@@ -58,7 +58,7 @@ public class TypeLegalizerTest {
parentSetter.accept(methodBody);
TransformationRequest tr = new TransformationRequest(methodBody);
- TypeLegalizer.TypeLegalizerVisitor visitor = new TypeLegalizer.TypeLegalizerVisitor(tr);
+ TypeLegalizer.TypeLegalizerVisitor visitor = new TypeLegalizer().new TypeLegalizerVisitor(tr);
visitor.accept(methodBody);
tr.commit();
diff --git a/sched/src/com/android/sched/item/ManagedItem.java b/sched/src/com/android/sched/item/ManagedItem.java
index 3e69e75..dd42e28 100644
--- a/sched/src/com/android/sched/item/ManagedItem.java
+++ b/sched/src/com/android/sched/item/ManagedItem.java
@@ -16,13 +16,15 @@
package com.android.sched.item;
+import com.android.sched.util.HasDescription;
+
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
* Represents an {@link Item} composed of other items.
*/
-public class ManagedItem {
+public class ManagedItem implements HasDescription {
// Bitmap, representing this item in conjunction with @ComposedOf, inheritance or inner
@CheckForNull
protected long[] bitmap;
@@ -62,6 +64,7 @@ public class ManagedItem {
return name;
}
+ @Override
@Nonnull
public String getDescription() {
return description;
diff --git a/sched/src/com/android/sched/marker/ManagedMarker.java b/sched/src/com/android/sched/marker/ManagedMarker.java
index 3496f49..7b75f11 100644
--- a/sched/src/com/android/sched/marker/ManagedMarker.java
+++ b/sched/src/com/android/sched/marker/ManagedMarker.java
@@ -18,6 +18,7 @@ package com.android.sched.marker;
import com.android.sched.item.Description;
import com.android.sched.item.Items;
+import com.android.sched.util.HasDescription;
import com.android.sched.util.findbugs.SuppressFBWarnings;
import com.android.sched.util.log.LoggerFactory;
@@ -33,7 +34,7 @@ import javax.annotation.Nonnull;
/**
* Represents a {@link Marker} with all annotations extracted.
*/
-public class ManagedMarker {
+public class ManagedMarker implements HasDescription {
private static final Logger logger = LoggerFactory.getLogger();
// @Name
@@ -108,6 +109,7 @@ public class ManagedMarker {
return name;
}
+ @Override
@Nonnull
public String getDescription() {
return description;
diff --git a/sched/src/com/android/sched/scheduler/ManagedSchedulable.java b/sched/src/com/android/sched/scheduler/ManagedSchedulable.java
index fd0390d..24dae82 100644
--- a/sched/src/com/android/sched/scheduler/ManagedSchedulable.java
+++ b/sched/src/com/android/sched/scheduler/ManagedSchedulable.java
@@ -21,13 +21,14 @@ import com.android.sched.item.Description;
import com.android.sched.item.Items;
import com.android.sched.item.Synchronized;
import com.android.sched.schedulable.Schedulable;
+import com.android.sched.util.HasDescription;
import javax.annotation.Nonnull;
/**
* Represents a {@link Schedulable} with all annotations and signatures extracted.
*/
-public abstract class ManagedSchedulable {
+public abstract class ManagedSchedulable implements HasDescription {
@Nonnull
private final Class<? extends Schedulable> schedulable;
@@ -92,6 +93,7 @@ public abstract class ManagedSchedulable {
@Nonnull
public abstract Class<? extends Component> getRunOn();
+ @Override
@Nonnull
public String getDescription() {
return description;
diff --git a/sched/src/com/android/sched/scheduler/Plan.java b/sched/src/com/android/sched/scheduler/Plan.java
index 6c6e945..8299f65 100644
--- a/sched/src/com/android/sched/scheduler/Plan.java
+++ b/sched/src/com/android/sched/scheduler/Plan.java
@@ -38,7 +38,7 @@ import javax.annotation.Nonnull;
*
* @param <T> the type of the root <i>data</i>
*/
-public class Plan<T extends Component> implements Iterable<PlanStep> {
+public class Plan<T extends Component> implements Iterable<PlanStep> {
@Nonnull
private final Logger logger = LoggerFactory.getLogger();
diff --git a/sched/src/com/android/sched/util/HasDescription.java b/sched/src/com/android/sched/util/HasDescription.java
new file mode 100644
index 0000000..095a703
--- /dev/null
+++ b/sched/src/com/android/sched/util/HasDescription.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 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.sched.util;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Interface implemented by descriptive classes.
+ */
+public interface HasDescription {
+ @Nonnull
+ String getDescription();
+} \ No newline at end of file
diff --git a/sched/src/com/android/sched/util/codec/DoubleCodec.java b/sched/src/com/android/sched/util/codec/DoubleCodec.java
index a2be42f..6fc2277 100644
--- a/sched/src/com/android/sched/util/codec/DoubleCodec.java
+++ b/sched/src/com/android/sched/util/codec/DoubleCodec.java
@@ -18,6 +18,9 @@ package com.android.sched.util.codec;
import com.android.sched.util.config.ConfigurationError;
+import java.util.Collections;
+import java.util.List;
+
import javax.annotation.Nonnull;
/**
@@ -48,6 +51,12 @@ public class DoubleCodec implements StringCodec<Double> {
@Override
@Nonnull
+ public List<ValueDescription> getValueDescriptions() {
+ return Collections.<ValueDescription> emptyList();
+ }
+
+ @Override
+ @Nonnull
public Double checkString(@Nonnull CodecContext context, @Nonnull String string)
throws ParsingException {
try {
diff --git a/sched/src/com/android/sched/util/codec/EnumCodec.java b/sched/src/com/android/sched/util/codec/EnumCodec.java
index 5c74e28..b31b245 100644
--- a/sched/src/com/android/sched/util/codec/EnumCodec.java
+++ b/sched/src/com/android/sched/util/codec/EnumCodec.java
@@ -16,8 +16,11 @@
package com.android.sched.util.codec;
+import com.android.sched.util.HasDescription;
import com.android.sched.util.codec.KeyValueCodec.Entry;
+import java.util.List;
+
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -31,12 +34,23 @@ public class EnumCodec<T extends Enum<T>> implements StringCodec<T> {
KeyValueCodec<T> parser;
public EnumCodec(@Nonnull T[] values) {
+ assert values.length > 0;
+
@SuppressWarnings("unchecked")
Entry<T>[] entries = new Entry[values.length];
int idx = 0;
- for (T value : values) {
- entries[idx++] = new Entry<T>(value.name().replace('_', '-'), value);
+ if (values instanceof HasDescription[]) {
+ for (T value : values) {
+ entries[idx++] =
+ new Entry<T>(value.name().replace('_', '-'), value,
+ ((HasDescription) value).getDescription());
+ }
+ } else {
+ for (T value : values) {
+
+ entries[idx++] = new Entry<T>(value.name().replace('_', '-'), value);
+ }
}
parser = new KeyValueCodec<T>(entries);
@@ -83,6 +97,12 @@ public class EnumCodec<T extends Enum<T>> implements StringCodec<T> {
@Override
@Nonnull
+ public List<ValueDescription> getValueDescriptions() {
+ return parser.getValueDescriptions();
+ }
+
+ @Override
+ @Nonnull
public String formatValue(@Nonnull T value) {
return parser.formatValue(value);
}
diff --git a/sched/src/com/android/sched/util/codec/FileOrDirCodec.java b/sched/src/com/android/sched/util/codec/FileOrDirCodec.java
index 67e07a2..fa5d77a 100644
--- a/sched/src/com/android/sched/util/codec/FileOrDirCodec.java
+++ b/sched/src/com/android/sched/util/codec/FileOrDirCodec.java
@@ -16,9 +16,13 @@
package com.android.sched.util.codec;
+import com.android.sched.util.codec.Parser.ValueDescription;
import com.android.sched.util.file.FileOrDirectory.ChangePermission;
import com.android.sched.util.file.FileOrDirectory.Existence;
+import java.util.Collections;
+import java.util.List;
+
import javax.annotation.Nonnull;
/**
@@ -81,4 +85,9 @@ public abstract class FileOrDirCodec {
return sb.toString();
}
}
+
+ @Nonnull
+ public List<ValueDescription> getValueDescriptions() {
+ return Collections.<ValueDescription> emptyList();
+ }
}
diff --git a/sched/src/com/android/sched/util/codec/ImplementationName.java b/sched/src/com/android/sched/util/codec/ImplementationName.java
index 01a53fc..d072ca6 100644
--- a/sched/src/com/android/sched/util/codec/ImplementationName.java
+++ b/sched/src/com/android/sched/util/codec/ImplementationName.java
@@ -29,5 +29,6 @@ import java.lang.annotation.Target;
public @interface ImplementationName {
Class<?> iface();
String name();
+ String description() default "";
Class<? extends ImplementationFilter> filter() default ImplementationAlwaysValid.class;
}
diff --git a/sched/src/com/android/sched/util/codec/KeyValueCodec.java b/sched/src/com/android/sched/util/codec/KeyValueCodec.java
index 4f16b47..c8923fb 100644
--- a/sched/src/com/android/sched/util/codec/KeyValueCodec.java
+++ b/sched/src/com/android/sched/util/codec/KeyValueCodec.java
@@ -18,11 +18,14 @@ package com.android.sched.util.codec;
import com.android.sched.util.config.ConfigurationError;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
@@ -34,6 +37,8 @@ public class KeyValueCodec<T> implements StringCodec<T> {
private boolean ignoreCase = false;
@Nonnull
private final Entry<T>[] entries;
+ @CheckForNull
+ private List<ValueDescription> descriptions;
public KeyValueCodec(@Nonnull Entry<T>[] entries) {
this.entries = Arrays.copyOf(entries, entries.length);
@@ -86,6 +91,23 @@ public class KeyValueCodec<T> implements StringCodec<T> {
@Override
@Nonnull
+ public List<ValueDescription> getValueDescriptions() {
+ if (descriptions == null) {
+ descriptions = new ArrayList<ValueDescription>(entries.length);
+
+ for (Entry<T> entry : entries) {
+ if (entry.description != null) {
+ descriptions.add(new ValueDescription(entry.key, entry.description));
+ }
+ }
+ }
+
+ assert descriptions != null;
+ return descriptions;
+ }
+
+ @Override
+ @Nonnull
public T checkString(@Nonnull CodecContext context, @Nonnull String string)
throws ParsingException {
if (ignoreCase) {
@@ -153,11 +175,22 @@ public class KeyValueCodec<T> implements StringCodec<T> {
String key;
@Nonnull
T value;
+ @CheckForNull
+ String description;
public Entry (@Nonnull String key, @Nonnull T value) {
this.key = key;
this.value = value;
}
+
+ public Entry (@Nonnull String key, @Nonnull T value, @CheckForNull String description) {
+ this.key = key;
+ this.value = value;
+
+ if (description != null && !description.isEmpty()) {
+ this.description = description;
+ }
+ }
}
@Override
diff --git a/sched/src/com/android/sched/util/codec/KeywordsCodec.java b/sched/src/com/android/sched/util/codec/KeywordsCodec.java
index d75d3c4..d990975 100644
--- a/sched/src/com/android/sched/util/codec/KeywordsCodec.java
+++ b/sched/src/com/android/sched/util/codec/KeywordsCodec.java
@@ -18,6 +18,8 @@ package com.android.sched.util.codec;
import com.android.sched.util.codec.KeyValueCodec.Entry;
+import java.util.List;
+
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -29,12 +31,17 @@ public class KeywordsCodec implements StringCodec<String> {
KeyValueCodec<String> parser;
public KeywordsCodec(@Nonnull String[] keywords) {
+ this(keywords, new String[keywords.length]);
+ }
+
+ public KeywordsCodec(@Nonnull String[] keywords, @Nonnull String[] descriptions) {
@SuppressWarnings("unchecked")
Entry<String>[] entries = new Entry[keywords.length];
int idx = 0;
for (String keyword : keywords) {
- entries[idx++] = new Entry<String>(keyword, keyword);
+ entries[idx] = new Entry<String>(keyword, keyword, descriptions[idx]);
+ idx++;
}
parser = new KeyValueCodec<String>(entries);
@@ -81,6 +88,12 @@ public class KeywordsCodec implements StringCodec<String> {
@Override
@Nonnull
+ public List<ValueDescription> getValueDescriptions() {
+ return parser.getValueDescriptions();
+ }
+
+ @Override
+ @Nonnull
public String formatValue(@Nonnull String value) {
return parser.formatValue(value);
}
diff --git a/sched/src/com/android/sched/util/codec/ListCodec.java b/sched/src/com/android/sched/util/codec/ListCodec.java
index 01d106e..25f5c75 100644
--- a/sched/src/com/android/sched/util/codec/ListCodec.java
+++ b/sched/src/com/android/sched/util/codec/ListCodec.java
@@ -237,6 +237,12 @@ public class ListCodec<T> implements StringCodec<List<T>> {
@Override
@Nonnull
+ public List<ValueDescription> getValueDescriptions() {
+ return parser.getValueDescriptions();
+ }
+
+ @Override
+ @Nonnull
public String formatValue(@Nonnull List<T> list) {
StringBuilder sb = new StringBuilder();
diff --git a/sched/src/com/android/sched/util/codec/LongCodec.java b/sched/src/com/android/sched/util/codec/LongCodec.java
index cf9b8da..8bdd98c 100644
--- a/sched/src/com/android/sched/util/codec/LongCodec.java
+++ b/sched/src/com/android/sched/util/codec/LongCodec.java
@@ -18,6 +18,9 @@ package com.android.sched.util.codec;
import com.android.sched.util.config.ConfigurationError;
+import java.util.Collections;
+import java.util.List;
+
import javax.annotation.Nonnull;
/**
@@ -52,6 +55,12 @@ public class LongCodec implements StringCodec<Long>{
@Override
@Nonnull
+ public List<ValueDescription> getValueDescriptions() {
+ return Collections.<ValueDescription> emptyList();
+ }
+
+ @Override
+ @Nonnull
public Long checkString(@Nonnull CodecContext context, @Nonnull String string)
throws ParsingException {
try {
diff --git a/sched/src/com/android/sched/util/codec/Parser.java b/sched/src/com/android/sched/util/codec/Parser.java
index 35871fd..0b72823 100644
--- a/sched/src/com/android/sched/util/codec/Parser.java
+++ b/sched/src/com/android/sched/util/codec/Parser.java
@@ -16,6 +16,10 @@
package com.android.sched.util.codec;
+import com.android.sched.util.HasDescription;
+
+import java.util.List;
+
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -49,4 +53,36 @@ public interface Parser<T> {
*/
@Nonnull
public String getUsage();
+
+ /**
+ * @return a description for some possible values.
+ */
+ @Nonnull
+ public List<ValueDescription> getValueDescriptions();
+
+ /**
+ * Description of a value.
+ */
+ public static class ValueDescription implements HasDescription {
+ @Nonnull
+ private final String value;
+ @Nonnull
+ private final String description;
+
+ public ValueDescription(@Nonnull String value, @Nonnull String description) {
+ this.value = value;
+ this.description = description;
+ }
+
+ @Nonnull
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ @Nonnull
+ public String getDescription() {
+ return description;
+ }
+ }
}
diff --git a/sched/src/com/android/sched/util/codec/PathCodec.java b/sched/src/com/android/sched/util/codec/PathCodec.java
index a1b2485..c221fb7 100644
--- a/sched/src/com/android/sched/util/codec/PathCodec.java
+++ b/sched/src/com/android/sched/util/codec/PathCodec.java
@@ -18,6 +18,8 @@ package com.android.sched.util.codec;
import java.io.File;
+import java.util.Collections;
+import java.util.List;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -33,6 +35,12 @@ public class PathCodec implements StringCodec<File> {
}
@Override
+ @Nonnull
+ public List<ValueDescription> getValueDescriptions() {
+ return Collections.<ValueDescription> emptyList();
+ }
+
+ @Override
@CheckForNull
public File checkString(@Nonnull CodecContext context, @Nonnull String value) {
return null;
diff --git a/sched/src/com/android/sched/util/codec/Selector.java b/sched/src/com/android/sched/util/codec/Selector.java
index 3e4d90e..4b3046f 100644
--- a/sched/src/com/android/sched/util/codec/Selector.java
+++ b/sched/src/com/android/sched/util/codec/Selector.java
@@ -20,6 +20,7 @@ import com.google.common.base.Joiner;
import com.android.sched.reflections.ReflectionFactory;
import com.android.sched.reflections.ReflectionManager;
+import com.android.sched.util.codec.Parser.ValueDescription;
import com.android.sched.util.config.ConfigurationError;
import com.android.sched.util.config.ReflectDefaultCtorFactory;
@@ -47,6 +48,8 @@ public abstract class Selector<T> {
private final Class<T> type;
@CheckForNull
private Map<String, Class<? extends T>> propertyValues;
+ @CheckForNull
+ private List<ValueDescription> descriptions;
public Selector(@Nonnull Class<T> type) {
this.type = type;
@@ -69,9 +72,39 @@ public abstract class Selector<T> {
}
@Nonnull
+ public List<ValueDescription> getValueDescriptions() {
+ if (descriptions == null) {
+ ensureScan();
+ assert propertyValues != null;
+
+ descriptions = new ArrayList<ValueDescription>(propertyValues.size());
+
+ for (Class<? extends T> subClass : propertyValues.values()) {
+ ImplementationName value = subClass.getAnnotation(ImplementationName.class);
+ assert value != null;
+
+ if (!value.description().isEmpty()) {
+ descriptions.add(new ValueDescription(value.name(), value.description()));
+ }
+ }
+
+ Collections.sort(descriptions, new Comparator<ValueDescription>(){
+ @Override
+ public int compare(ValueDescription o1, ValueDescription o2) {
+ return o1.getValue().compareToIgnoreCase(o2.getValue());
+ }});
+
+ }
+
+ assert descriptions != null;
+ return descriptions;
+ }
+
+ @Nonnull
public Class<? extends T> getClass(@Nonnull String string) throws ParsingException {
ensureScan();
assert propertyValues != null;
+
Class<? extends T> value = propertyValues.get(string);
if (value == null) {
@@ -143,6 +176,7 @@ public abstract class Selector<T> {
private synchronized void ensureScan() {
if (propertyValues == null) {
propertyValues = new HashMap<String, Class<? extends T>>();
+
ReflectionManager reflectionManager = ReflectionFactory.getManager();
Set<Class<? extends T>> propertyValueClasses = reflectionManager.getSubTypesOf(type);
propertyValueClasses.add(type);
diff --git a/sched/src/com/android/sched/util/config/expression/Expression.java b/sched/src/com/android/sched/util/config/expression/Expression.java
index d2fbf5d..4dc3c31 100644
--- a/sched/src/com/android/sched/util/config/expression/Expression.java
+++ b/sched/src/com/android/sched/util/config/expression/Expression.java
@@ -16,6 +16,7 @@
package com.android.sched.util.config.expression;
+import com.android.sched.util.HasDescription;
import com.android.sched.util.config.ConfigChecker;
import com.android.sched.util.config.PropertyIdException;
import com.android.sched.util.config.id.PropertyId;
@@ -27,9 +28,7 @@ import javax.annotation.Nonnull;
/**
* Abstract class representing an expression.
*/
-public abstract class Expression {
- @Nonnull
- public abstract String getDescription();
+public abstract class Expression implements HasDescription {
@Nonnull
public abstract String getCause(@Nonnull ConfigChecker checker) throws PropertyIdException;
diff --git a/sched/src/com/android/sched/util/config/id/PropertyId.java b/sched/src/com/android/sched/util/config/id/PropertyId.java
index c2579ee..e567b4f 100644
--- a/sched/src/com/android/sched/util/config/id/PropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/PropertyId.java
@@ -17,6 +17,7 @@
package com.android.sched.util.config.id;
+import com.android.sched.util.HasDescription;
import com.android.sched.util.codec.CodecContext;
import com.android.sched.util.codec.ParsingException;
import com.android.sched.util.codec.StringCodec;
@@ -33,7 +34,7 @@ import javax.annotation.Nonnull;
* An instance of this type identifies a particular configuration property.
* @param <T> Type of the configuration property.
*/
-public class PropertyId<T> extends KeyId<T, String> {
+public class PropertyId<T> extends KeyId<T, String> implements HasDescription {
@Nonnull
private final String description;
@@ -105,6 +106,7 @@ public class PropertyId<T> extends KeyId<T, String> {
return defaultValues;
}
+ @Override
@Nonnull
public String getDescription() {
return description;
diff --git a/sched/src/com/android/sched/util/location/Location.java b/sched/src/com/android/sched/util/location/Location.java
index 2fa2fed..f3a2208 100644
--- a/sched/src/com/android/sched/util/location/Location.java
+++ b/sched/src/com/android/sched/util/location/Location.java
@@ -16,12 +16,10 @@
package com.android.sched.util.location;
-import javax.annotation.Nonnull;
+import com.android.sched.util.HasDescription;
/**
* Base class to describe a location.
*/
-public abstract class Location {
- @Nonnull
- public abstract String getDescription();
+public abstract class Location implements HasDescription {
}
diff --git a/sched/src/com/android/sched/util/log/StatisticOnlyTracer.java b/sched/src/com/android/sched/util/log/StatisticOnlyTracer.java
index 81095e5..a3c2be1 100644
--- a/sched/src/com/android/sched/util/log/StatisticOnlyTracer.java
+++ b/sched/src/com/android/sched/util/log/StatisticOnlyTracer.java
@@ -60,7 +60,8 @@ import javax.annotation.Nonnull;
/**
* Tracer implementation which only collects statistics on a pseudo-single event.
*/
-@ImplementationName(iface = Tracer.class, name = "stat-only")
+@ImplementationName(iface = Tracer.class, name = "stat-only",
+ description = "collect statistics without event information")
public final class StatisticOnlyTracer implements Tracer {
@Nonnull
private final Logger logger = LoggerFactory.getLogger();
diff --git a/sched/src/com/android/sched/util/log/stats/Statistic.java b/sched/src/com/android/sched/util/log/stats/Statistic.java
index 93d2535..0ece4eb 100644
--- a/sched/src/com/android/sched/util/log/stats/Statistic.java
+++ b/sched/src/com/android/sched/util/log/stats/Statistic.java
@@ -18,6 +18,7 @@ package com.android.sched.util.log.stats;
import com.google.common.collect.Iterators;
+import com.android.sched.util.HasDescription;
import com.android.sched.util.codec.Formatter;
import com.android.sched.util.codec.ToStringFormatter;
import com.android.sched.util.table.DataHeader;
@@ -29,7 +30,7 @@ import javax.annotation.Nonnull;
/**
* Represents a statistic.
*/
-public abstract class Statistic implements DataHeader {
+public abstract class Statistic implements DataHeader, HasDescription {
@Nonnull
private final StatisticId<? extends Statistic> id;
@@ -44,9 +45,6 @@ public abstract class Statistic implements DataHeader {
return id;
}
- @Nonnull
- public abstract String getDescription();
-
@Override
@Nonnull
public String toString() {
diff --git a/sched/src/com/android/sched/util/log/stats/StatisticId.java b/sched/src/com/android/sched/util/log/stats/StatisticId.java
index 30444c5..181e5d0 100644
--- a/sched/src/com/android/sched/util/log/stats/StatisticId.java
+++ b/sched/src/com/android/sched/util/log/stats/StatisticId.java
@@ -16,6 +16,7 @@
package com.android.sched.util.log.stats;
+import com.android.sched.util.HasDescription;
import com.android.sched.util.config.ReflectFactory;
import java.util.Collection;
@@ -29,7 +30,7 @@ import javax.annotation.Nonnull;
*
* @param <T> Type of the statistic.
*/
-public class StatisticId<T extends Statistic> {
+public class StatisticId<T extends Statistic> implements HasDescription {
@Nonnull
private static Map<Class<? extends Statistic>, Statistic> dummies =
new ConcurrentHashMap<Class<? extends Statistic>, Statistic>();
@@ -75,6 +76,7 @@ public class StatisticId<T extends Statistic> {
return name;
}
+ @Override
@Nonnull
public String getDescription() {
return description;
diff --git a/sched/src/com/android/sched/util/log/tracer/ProbeManagerCodec.java b/sched/src/com/android/sched/util/log/tracer/ProbeManagerCodec.java
index 2b20ef2..7a5b471 100644
--- a/sched/src/com/android/sched/util/log/tracer/ProbeManagerCodec.java
+++ b/sched/src/com/android/sched/util/log/tracer/ProbeManagerCodec.java
@@ -83,6 +83,12 @@ public class ProbeManagerCodec implements StringCodec<ProbeManager> {
@Override
@Nonnull
+ public List<com.android.sched.util.codec.Parser.ValueDescription> getValueDescriptions() {
+ return parser.getValueDescriptions();
+ }
+
+ @Override
+ @Nonnull
public String formatValue(@Nonnull ProbeManager data) {
return parser.formatValue(data.getProbes());
}
diff --git a/sched/src/com/android/sched/util/log/tracer/filter/EventFilter.java b/sched/src/com/android/sched/util/log/tracer/filter/EventFilter.java
index c2eb616..7586046 100644
--- a/sched/src/com/android/sched/util/log/tracer/filter/EventFilter.java
+++ b/sched/src/com/android/sched/util/log/tracer/filter/EventFilter.java
@@ -16,6 +16,7 @@
package com.android.sched.util.log.tracer.filter;
+import com.android.sched.util.HasDescription;
import com.android.sched.util.log.EventType;
import javax.annotation.Nonnull;
@@ -23,8 +24,6 @@ import javax.annotation.Nonnull;
/**
* Interface of a {@link EventType} filter.
*/
-public interface EventFilter {
+public interface EventFilter extends HasDescription {
public boolean isEnabled(@Nonnull EventType type);
- @Nonnull
- public String getDescription();
}
diff --git a/sched/src/com/android/sched/util/log/tracer/probe/Probe.java b/sched/src/com/android/sched/util/log/tracer/probe/Probe.java
index d311e9f..df937e5 100644
--- a/sched/src/com/android/sched/util/log/tracer/probe/Probe.java
+++ b/sched/src/com/android/sched/util/log/tracer/probe/Probe.java
@@ -16,6 +16,8 @@
package com.android.sched.util.log.tracer.probe;
+import com.android.sched.util.HasDescription;
+
import javax.annotation.CheckForNull;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
@@ -23,7 +25,7 @@ import javax.annotation.Nonnull;
/**
* Abstract class for a Probe.
*/
-public abstract class Probe implements Comparable<Probe> {
+public abstract class Probe implements Comparable<Probe>, HasDescription {
public static final int MAX_PRIORITY = 0;
public static final int MIN_PRIORITY = 12;
@@ -55,6 +57,7 @@ public abstract class Probe implements Comparable<Probe> {
this.priority = priority;
}
+ @Override
@Nonnull
public String getDescription() {
return this.description;
diff --git a/sched/src/com/android/sched/util/log/tracer/probe/ThreadTimeProbe.java b/sched/src/com/android/sched/util/log/tracer/probe/ThreadTimeProbe.java
index 1a180f2..f1d2de9 100644
--- a/sched/src/com/android/sched/util/log/tracer/probe/ThreadTimeProbe.java
+++ b/sched/src/com/android/sched/util/log/tracer/probe/ThreadTimeProbe.java
@@ -27,7 +27,7 @@ import javax.annotation.Nonnull;
/**
* Probe which take the usage of per thread CPU time.
*/
-@ImplementationName(iface = Probe.class, name = "thread-time")
+@ImplementationName(iface = Probe.class, name = "thread-cpu-time")
public class ThreadTimeProbe extends TimeNanosProbe {
@Nonnull
private final ThreadMXBean threadMXBean;
diff --git a/sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java b/sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java
index 78fd9b8..af85d00 100644
--- a/sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java
+++ b/sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java
@@ -89,7 +89,8 @@ public class AllocationWatcher implements ObjectWatcher<Object> {
/**
* Install a {@link AllocationWatcher}
*/
- @ImplementationName(iface = WatcherInstaller.class, name = "object-alloc")
+ @ImplementationName(iface = WatcherInstaller.class, name = "object-alloc",
+ description = "record object and array allocations globally")
public static class AllocationWatcherInstaller implements WatcherInstaller {
@Override
public void install(@Nonnull Tracer tracer) {
diff --git a/sched/src/com/android/sched/util/log/tracer/watcher/ArrayListWatcher.java b/sched/src/com/android/sched/util/log/tracer/watcher/ArrayListWatcher.java
index 76db58a..65862a0 100644
--- a/sched/src/com/android/sched/util/log/tracer/watcher/ArrayListWatcher.java
+++ b/sched/src/com/android/sched/util/log/tracer/watcher/ArrayListWatcher.java
@@ -152,7 +152,8 @@ public class ArrayListWatcher implements ObjectWatcher<ArrayList<?>> {
/**
* Install a {@link ArrayListWatcher}
*/
- @ImplementationName(iface = WatcherInstaller.class, name = "arraylist-capacity")
+ @ImplementationName(iface = WatcherInstaller.class, name = "arraylist-capacity",
+ description = "record state of the array backed by ArrayList")
public static class ArrayListWatcherInstaller implements WatcherInstaller {
@Override
public void install(@Nonnull Tracer tracer) {
diff --git a/sched/src/com/android/sched/util/log/tracer/watcher/DetailedAllocationWatcher.java b/sched/src/com/android/sched/util/log/tracer/watcher/DetailedAllocationWatcher.java
index f8a97e3..0349359 100644
--- a/sched/src/com/android/sched/util/log/tracer/watcher/DetailedAllocationWatcher.java
+++ b/sched/src/com/android/sched/util/log/tracer/watcher/DetailedAllocationWatcher.java
@@ -122,7 +122,8 @@ public class DetailedAllocationWatcher implements ObjectWatcher<Object> {
/**
* Install a {@link DetailedAllocationWatcher}
*/
- @ImplementationName(iface = WatcherInstaller.class, name = "detailed-object-alloc")
+ @ImplementationName(iface = WatcherInstaller.class, name = "detailed-object-alloc",
+ description = "record object and array allocations type by type")
public static class DetailedAllocationWatcherInstaller implements WatcherInstaller {
@Override
public void install(@Nonnull Tracer tracer) {
diff --git a/sched/src/com/android/sched/util/table/Report.java b/sched/src/com/android/sched/util/table/Report.java
index 32b75d5..7c0e8d9 100644
--- a/sched/src/com/android/sched/util/table/Report.java
+++ b/sched/src/com/android/sched/util/table/Report.java
@@ -16,6 +16,8 @@
package com.android.sched.util.table;
+import com.android.sched.util.HasDescription;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
@@ -26,7 +28,7 @@ import javax.annotation.Nonnull;
/**
* A collection of {@link Table}s.
*/
-public class Report implements Iterable<Table> {
+public class Report implements Iterable<Table>, HasDescription {
@Nonnull
private final String name;
@Nonnull
@@ -63,6 +65,7 @@ public class Report implements Iterable<Table> {
return name;
}
+ @Override
@Nonnull
public String getDescription() {
return description;
diff --git a/sched/src/com/android/sched/util/table/Table.java b/sched/src/com/android/sched/util/table/Table.java
index 5468dc6..6f1b02f 100644
--- a/sched/src/com/android/sched/util/table/Table.java
+++ b/sched/src/com/android/sched/util/table/Table.java
@@ -16,6 +16,7 @@
package com.android.sched.util.table;
+import com.android.sched.util.HasDescription;
import com.android.sched.util.codec.Formatter;
import java.util.Iterator;
@@ -26,7 +27,7 @@ import javax.annotation.Nonnull;
/**
* Interface representing a table.
*/
-public interface Table extends Iterable<Iterable<String>> {
+public interface Table extends Iterable<Iterable<String>>, HasDescription {
@Nonnull
public Formatter<?>[] getFormatters();
@@ -34,6 +35,7 @@ public interface Table extends Iterable<Iterable<String>> {
public String getName();
public void setName(@Nonnull String name);
+ @Override
@Nonnull
public String getDescription();
public void setDescription(@Nonnull String description);