check if a static final field is set within the static constructor, and if so, add a comment stating such if it makes sense to do so (for primitive types, or reference/array types that have a non-null initializer)

git-svn-id: https://smali.googlecode.com/svn/trunk@481 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com 2009-09-19 04:48:50 +00:00
parent 05c9404ecd
commit 090e553f34
3 changed files with 86 additions and 6 deletions

View File

@ -30,6 +30,10 @@ package org.jf.baksmali.Adaptors;
import org.jf.dexlib.EncodedValue.EncodedValue; import org.jf.dexlib.EncodedValue.EncodedValue;
import org.jf.dexlib.*; import org.jf.dexlib.*;
import org.jf.dexlib.Code.InstructionIterator;
import org.jf.dexlib.Code.Opcode;
import org.jf.dexlib.Code.Format.Format;
import org.jf.dexlib.Code.Format.Instruction21c;
import org.jf.dexlib.Util.AccessFlags; import org.jf.dexlib.Util.AccessFlags;
import org.jf.dexlib.Util.SparseArray; import org.jf.dexlib.Util.SparseArray;
import org.antlr.stringtemplate.StringTemplate; import org.antlr.stringtemplate.StringTemplate;
@ -46,11 +50,14 @@ public class ClassDefinition {
private SparseArray<AnnotationSetItem> fieldAnnotationsMap; private SparseArray<AnnotationSetItem> fieldAnnotationsMap;
private SparseArray<AnnotationSetRefList> parameterAnnotationsMap; private SparseArray<AnnotationSetRefList> parameterAnnotationsMap;
private SparseArray<FieldIdItem> fieldsSetInStaticConstructor;
public ClassDefinition(StringTemplateGroup stg, ClassDefItem classDefItem) { public ClassDefinition(StringTemplateGroup stg, ClassDefItem classDefItem) {
this.stg = stg; this.stg = stg;
this.classDefItem = classDefItem; this.classDefItem = classDefItem;
this.classDataItem = classDefItem.getClassData(); this.classDataItem = classDefItem.getClassData();
buildAnnotationMaps(); buildAnnotationMaps();
findFieldsSetInStaticConstructor();
} }
public StringTemplate makeTemplate() { public StringTemplate makeTemplate() {
@ -103,6 +110,52 @@ public class ClassDefinition {
}); });
} }
private void findFieldsSetInStaticConstructor() {
fieldsSetInStaticConstructor = new SparseArray<FieldIdItem>();
if (classDataItem == null) {
return;
}
for (ClassDataItem.EncodedMethod directMethod: classDataItem.getDirectMethods()) {
if (directMethod.method.getMethodName().getStringValue().equals("<clinit>")) {
final byte[] encodedInstructions = directMethod.codeItem.getEncodedInstructions();
InstructionIterator.IterateInstructions(encodedInstructions,
new InstructionIterator.ProcessRawInstructionDelegate() {
public void ProcessNormalInstruction(Opcode opcode, int index) {
}
public void ProcessReferenceInstruction(Opcode opcode, int index) {
switch (opcode) {
case SPUT:
case SPUT_BOOLEAN:
case SPUT_BYTE:
case SPUT_CHAR:
case SPUT_OBJECT:
case SPUT_SHORT:
case SPUT_WIDE:
Instruction21c ins = (Instruction21c)Format.Format21c.Factory.makeInstruction(
classDefItem.getDexFile(), opcode, encodedInstructions, index);
FieldIdItem fieldIdItem = (FieldIdItem)ins.getReferencedItem();
fieldsSetInStaticConstructor.put(fieldIdItem.getIndex(), fieldIdItem);
}
}
public void ProcessPackedSwitchInstruction(int index, int targetCount, int instructionLength) {
}
public void ProcessSparseSwitchInstruction(int index, int targetCount, int instructionLength) {
}
public void ProcessFillArrayDataInstruction(int index, int elementWidth, int elementCount, int instructionLength) {
}
});
}
}
}
private List<String> getAccessFlags() { private List<String> getAccessFlags() {
List<String> accessFlags = new ArrayList<String>(); List<String> accessFlags = new ArrayList<String>();
@ -141,7 +194,7 @@ public class ClassDefinition {
interfaces.add(typeIdItem.getTypeDescriptor()); interfaces.add(typeIdItem.getTypeDescriptor());
} }
} }
return interfaces; return interfaces;
} }
@ -185,7 +238,11 @@ public class ClassDefinition {
} }
AnnotationSetItem annotationSet = fieldAnnotationsMap.get(field.field.getIndex()); AnnotationSetItem annotationSet = fieldAnnotationsMap.get(field.field.getIndex());
staticFields.add(FieldDefinition.createTemplate(stg, field, encodedValue, annotationSet)); boolean setInStaticConstructor =
fieldsSetInStaticConstructor.get(field.field.getIndex()) != null;
staticFields.add(FieldDefinition.createTemplate(stg, field, encodedValue, annotationSet,
setInStaticConstructor));
i++; i++;
} }
} }
@ -202,7 +259,7 @@ public class ClassDefinition {
} }
} }
return instanceFields; return instanceFields;
} }
private List<StringTemplate> getDirectMethods() { private List<StringTemplate> getDirectMethods() {

View File

@ -31,6 +31,7 @@ package org.jf.baksmali.Adaptors;
import org.jf.baksmali.Adaptors.EncodedValue.EncodedValueAdaptor; import org.jf.baksmali.Adaptors.EncodedValue.EncodedValueAdaptor;
import org.jf.dexlib.ClassDataItem; import org.jf.dexlib.ClassDataItem;
import org.jf.dexlib.EncodedValue.EncodedValue; import org.jf.dexlib.EncodedValue.EncodedValue;
import org.jf.dexlib.EncodedValue.NullEncodedValue;
import org.jf.dexlib.AnnotationSetItem; import org.jf.dexlib.AnnotationSetItem;
import org.jf.dexlib.AnnotationItem; import org.jf.dexlib.AnnotationItem;
import org.jf.dexlib.Util.AccessFlags; import org.jf.dexlib.Util.AccessFlags;
@ -42,13 +43,32 @@ import java.util.List;
public class FieldDefinition { public class FieldDefinition {
public static StringTemplate createTemplate(StringTemplateGroup stg, ClassDataItem.EncodedField encodedField, public static StringTemplate createTemplate(StringTemplateGroup stg, ClassDataItem.EncodedField encodedField,
EncodedValue initialValue, AnnotationSetItem annotationSet) { EncodedValue initialValue, AnnotationSetItem annotationSet,
boolean setInStaticConstructor) {
StringTemplate template = stg.getInstanceOf("field"); StringTemplate template = stg.getInstanceOf("field");
String fieldTypeDescriptor = encodedField.field.getFieldType().getTypeDescriptor();
template.setAttribute("AccessFlags", getAccessFlags(encodedField)); template.setAttribute("AccessFlags", getAccessFlags(encodedField));
template.setAttribute("FieldName", encodedField.field.getFieldName().getStringValue()); template.setAttribute("FieldName", encodedField.field.getFieldName().getStringValue());
template.setAttribute("FieldType", encodedField.field.getFieldType().getTypeDescriptor()); template.setAttribute("FieldType", encodedField.field.getFieldType().getTypeDescriptor());
template.setAttribute("Annotations", getAnnotations(stg, annotationSet)); template.setAttribute("Annotations", getAnnotations(stg, annotationSet));
if (setInStaticConstructor &&
encodedField.isStatic() &&
(encodedField.accessFlags & AccessFlags.FINAL.getValue()) != 0 &&
initialValue != null &&
(
//it's a primitive type, or it's an array/reference type and the initial value isn't null
fieldTypeDescriptor.length() == 1 ||
initialValue != NullEncodedValue.NullValue
)) {
template.setAttribute("Comments",
new String[]{"the value of this static final field might be set in the static constructor"});
} else {
template.setAttribute("Comments", null);
}
if (initialValue != null) { if (initialValue != null) {
template.setAttribute("InitialValue", EncodedValueAdaptor.make(stg, initialValue)); template.setAttribute("InitialValue", EncodedValueAdaptor.make(stg, initialValue));
@ -59,7 +79,7 @@ public class FieldDefinition {
public static StringTemplate createTemplate(StringTemplateGroup stg, ClassDataItem.EncodedField encodedField, public static StringTemplate createTemplate(StringTemplateGroup stg, ClassDataItem.EncodedField encodedField,
AnnotationSetItem annotationSet) { AnnotationSetItem annotationSet) {
return createTemplate(stg, encodedField, null, annotationSet); return createTemplate(stg, encodedField, null, annotationSet, false);
} }
private static List<String> getAccessFlags(ClassDataItem.EncodedField encodedField) { private static List<String> getAccessFlags(ClassDataItem.EncodedField encodedField) {

View File

@ -80,8 +80,11 @@ annotation(Visibility, AnnotationType, Elements) ::=
field(AccessFlags, FieldName, FieldType, Annotations, InitialValue) ::= field(AccessFlags, FieldName, FieldType, Annotations, InitialValue, Comments) ::=
<< <<
<if(Comments)><Comments: {#<it>} ; separator="\n">
<endif>
.field <AccessFlags: {<it> }><FieldName>:<FieldType><if(InitialValue)> = <InitialValue><endif> .field <AccessFlags: {<it> }><FieldName>:<FieldType><if(InitialValue)> = <InitialValue><endif>
<if(Annotations)> <if(Annotations)>
<Annotations; separator="\n\n"> <Annotations; separator="\n\n">