Merge "Fix bug when renaming masked members with the same name" into ub-jack
diff --git a/jack-tests/tests/com/android/jack/shrob/ObfuscationWithoutMappingTests.java b/jack-tests/tests/com/android/jack/shrob/ObfuscationWithoutMappingTests.java
index 94ca2e2..c80e559 100644
--- a/jack-tests/tests/com/android/jack/shrob/ObfuscationWithoutMappingTests.java
+++ b/jack-tests/tests/com/android/jack/shrob/ObfuscationWithoutMappingTests.java
@@ -216,4 +216,9 @@
env.runTest(new ComparatorMapping(refOutputMapping, candidateOutputMapping));
}
+
+ @Test
+ public void test56_001() throws Exception {
+ runTest("056", "001", "");
+ }
}
diff --git a/jack-tests/tests/com/android/jack/shrob/test056/info.txt b/jack-tests/tests/com/android/jack/shrob/test056/info.txt
new file mode 100644
index 0000000..cbc8c94
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test056/info.txt
@@ -0,0 +1,2 @@
+This contains a class which masks its superclass field
+and uses -useuniqueclassmembernames.
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test056/jack/A.java b/jack-tests/tests/com/android/jack/shrob/test056/jack/A.java
new file mode 100644
index 0000000..36b97f1
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test056/jack/A.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 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.shrob.test056.jack;
+
+public class A {
+ int f;
+}
diff --git a/jack-tests/tests/com/android/jack/shrob/test056/jack/B.java b/jack-tests/tests/com/android/jack/shrob/test056/jack/B.java
new file mode 100644
index 0000000..9c1f306
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test056/jack/B.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2015 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.shrob.test056.jack;
+
+public class B extends A {
+ int f;
+}
diff --git a/jack-tests/tests/com/android/jack/shrob/test056/proguard.flags001 b/jack-tests/tests/com/android/jack/shrob/test056/proguard.flags001
new file mode 100644
index 0000000..7dd76d0
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test056/proguard.flags001
@@ -0,0 +1,2 @@
+-dontshrink
+-useuniqueclassmembernames
\ No newline at end of file
diff --git a/jack-tests/tests/com/android/jack/shrob/test056/refsObfuscationWithoutMapping/expected-001.txt b/jack-tests/tests/com/android/jack/shrob/test056/refsObfuscationWithoutMapping/expected-001.txt
new file mode 100644
index 0000000..f195ec5
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/shrob/test056/refsObfuscationWithoutMapping/expected-001.txt
@@ -0,0 +1,6 @@
+com.android.jack.shrob.test056.jack.A -> pcz.nbqfcvq.wnpx.gufco.hrgh056.wnpx.N:
+ int f -> s:V
+ void <init>() -> <init>
+com.android.jack.shrob.test056.jack.B -> pcz.nbqfcvq.wnpx.gufco.hrgh056.wnpx.O:
+ int f -> s:V
+ void <init>() -> <init>
diff --git a/jack/src/com/android/jack/shrob/obfuscation/MaskedHierarchy.java b/jack/src/com/android/jack/shrob/obfuscation/MaskedHierarchy.java
new file mode 100644
index 0000000..5f9a323
--- /dev/null
+++ b/jack/src/com/android/jack/shrob/obfuscation/MaskedHierarchy.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 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.shrob.obfuscation;
+
+import com.android.jack.ir.ast.JClassOrInterface;
+import com.android.jack.ir.formatter.UserFriendlyFormatter;
+
+import javax.annotation.Nonnull;
+
+/**
+ * An {@link Exception} that occurs when we rename a field or method with a name already used in
+ * the hierarchy.
+ */
+public class MaskedHierarchy extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ @Nonnull
+ private final String oldName;
+
+ @Nonnull
+ private final String newName;
+
+ @Nonnull
+ private final JClassOrInterface enclosingType;
+
+ public MaskedHierarchy(
+ @Nonnull String oldName,
+ @Nonnull JClassOrInterface enclosingType,
+ @Nonnull String newName) {
+ this.oldName = oldName;
+ this.newName = newName;
+ this.enclosingType = enclosingType;
+ }
+
+ @Override
+ public String getMessage() {
+ return oldName
+ + " in "
+ + UserFriendlyFormatter.getFormatter().getName(enclosingType)
+ + " was renamed to "
+ + newName
+ + " while the name already exists in the hierarchy.";
+ }
+}
+
diff --git a/jack/src/com/android/jack/shrob/obfuscation/MethodInHierarchyFinder.java b/jack/src/com/android/jack/shrob/obfuscation/MethodInHierarchyFinder.java
index af330ae..8d5b3f5 100644
--- a/jack/src/com/android/jack/shrob/obfuscation/MethodInHierarchyFinder.java
+++ b/jack/src/com/android/jack/shrob/obfuscation/MethodInHierarchyFinder.java
@@ -47,6 +47,7 @@
}
}
}
+ visit(type);
visitSuperTypes(type);
visitSubTypes(type);
}
diff --git a/jack/src/com/android/jack/shrob/obfuscation/ObfuscationContextInfo.java b/jack/src/com/android/jack/shrob/obfuscation/ObfuscationContextInfo.java
new file mode 100644
index 0000000..5c65803
--- /dev/null
+++ b/jack/src/com/android/jack/shrob/obfuscation/ObfuscationContextInfo.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 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.shrob.obfuscation;
+
+import com.android.jack.reporting.Reportable;
+import com.android.sched.util.location.Location;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A {@link Reportable} information that occurs during the obfuscation phase.
+ */
+public class ObfuscationContextInfo implements Reportable {
+
+ @Nonnull
+ private final Location location;
+
+ @Nonnull
+ private final ProblemLevel level;
+
+ @Nonnull
+ private final Throwable cause;
+
+ public ObfuscationContextInfo(
+ @Nonnull Location location, @Nonnull ProblemLevel level, @Nonnull Throwable cause) {
+ this.location = location;
+ this.cause = cause;
+ this.level = level;
+ }
+
+ @Override
+ @Nonnull
+ public String getMessage() {
+ return location.getDescription() + ": Obfuscation: " + cause.getMessage();
+ }
+
+ @Override
+ @Nonnull
+ public ProblemLevel getDefaultProblemLevel() {
+ return level;
+ }
+
+}
diff --git a/jack/src/com/android/jack/shrob/obfuscation/Renamer.java b/jack/src/com/android/jack/shrob/obfuscation/Renamer.java
index 43271ab..5ba3059 100644
--- a/jack/src/com/android/jack/shrob/obfuscation/Renamer.java
+++ b/jack/src/com/android/jack/shrob/obfuscation/Renamer.java
@@ -29,8 +29,12 @@
import com.android.jack.ir.ast.JMethodIdWide;
import com.android.jack.ir.ast.JPackage;
import com.android.jack.ir.ast.JSession;
+import com.android.jack.ir.ast.JType;
import com.android.jack.ir.ast.JVisitor;
+import com.android.jack.ir.sourceinfo.SourceInfo;
import com.android.jack.library.DumpInLibrary;
+import com.android.jack.reporting.Reportable.ProblemLevel;
+import com.android.jack.reporting.Reporter.Severity;
import com.android.jack.shrob.obfuscation.nameprovider.NameProvider;
import com.android.jack.shrob.proguard.GrammarActions;
import com.android.jack.transformations.request.ChangeEnclosingPackage;
@@ -48,6 +52,8 @@
import com.android.sched.util.config.ThreadConfig;
import com.android.sched.util.config.id.BooleanPropertyId;
import com.android.sched.util.config.id.PropertyId;
+import com.android.sched.util.location.FileLocation;
+import com.android.sched.util.location.LineLocation;
import java.io.File;
import java.util.Collection;
@@ -155,6 +161,16 @@
}
@Nonnull
+ static String getFieldKey(@Nonnull String name, @Nonnull JType type) {
+ return name + ':' + GrammarActions.getSignatureFormatter().getName(type);
+ }
+
+ @Nonnull
+ static String getMethodKey(@Nonnull String name, @Nonnull List<? extends JType> argumentTypes) {
+ return GrammarActions.getSignatureFormatter().getNameWithoutReturnType(name, argumentTypes);
+ }
+
+ @Nonnull
static String getKey(@Nonnull HasName namedElement) {
if (namedElement instanceof JFieldId) {
return Renamer.getFieldKey((JFieldId) namedElement);
@@ -174,6 +190,14 @@
}
}
+ private static void rename(
+ @Nonnull CanBeRenamed node, @Nonnull String newName) {
+ if (mustBeRenamed((MarkerManager) node)) {
+ ((MarkerManager) node).addMarker(new OriginalNameMarker(node.getName()));
+ node.setName(newName);
+ }
+ }
+
private class Visitor extends JVisitor {
@Override
@@ -201,11 +225,33 @@
for (JField field : type.getFields()) {
JFieldId fieldId = field.getId();
if (mustBeRenamed(fieldId)) {
- String name;
- do {
- name = fieldNameProvider.getNewName(getKey(fieldId));
- } while (FieldInHierarchyFinderVisitor.containsFieldKey(name, field));
- rename(fieldId, fieldNameProvider);
+ String name = null;
+ boolean foundName;
+ try {
+ do {
+ String oldFieldKey = getKey(fieldId);
+ name = fieldNameProvider.getNewName(oldFieldKey);
+ foundName =
+ FieldInHierarchyFinderVisitor.containsFieldKey(
+ getFieldKey(name, field.getType()), field);
+ if (foundName && !fieldNameProvider.hasAlternativeName(oldFieldKey)) {
+ throw new MaskedHierarchy(field.getName(), type, name);
+ }
+ } while (foundName);
+ } catch (MaskedHierarchy e) {
+ SourceInfo sourceInfo = field.getSourceInfo();
+ Jack.getSession()
+ .getReporter()
+ .report(
+ Severity.NON_FATAL,
+ new ObfuscationContextInfo(
+ new LineLocation(
+ new FileLocation(sourceInfo.getFileName()),
+ sourceInfo.getStartLine()),
+ ProblemLevel.INFO,
+ e));
+ }
+ rename(fieldId, name);
}
}
@@ -213,11 +259,33 @@
for (JMethod method : type.getMethods()) {
JMethodIdWide methodId = method.getMethodId().getMethodIdWide();
if (mustBeRenamed(methodId)) {
- String name;
- do {
- name = methodNameProvider.getNewName(getKey(methodId));
- } while (MethodInHierarchyFinder.containsMethodKey(name, methodId));
- rename(methodId, methodNameProvider);
+ String name = null;
+ boolean foundName;
+ try {
+ do {
+ String oldMethodKey = getKey(methodId);
+ name = methodNameProvider.getNewName(oldMethodKey);
+ foundName =
+ MethodInHierarchyFinder.containsMethodKey(
+ getMethodKey(name, methodId.getParamTypes()), methodId);
+ if (foundName && !methodNameProvider.hasAlternativeName(oldMethodKey)) {
+ throw new MaskedHierarchy(methodId.getName(), type, name);
+ }
+ } while (foundName);
+ } catch (MaskedHierarchy e) {
+ SourceInfo sourceInfo = method.getSourceInfo();
+ Jack.getSession()
+ .getReporter()
+ .report(
+ Severity.NON_FATAL,
+ new ObfuscationContextInfo(
+ new LineLocation(
+ new FileLocation(sourceInfo.getFileName()),
+ sourceInfo.getStartLine()),
+ ProblemLevel.INFO,
+ e));
+ }
+ rename(methodId, name);
}
}
}
diff --git a/jack/src/com/android/jack/shrob/obfuscation/nameprovider/AlphabeticalNameProvider.java b/jack/src/com/android/jack/shrob/obfuscation/nameprovider/AlphabeticalNameProvider.java
index aeaa6ac..5acc72a 100644
--- a/jack/src/com/android/jack/shrob/obfuscation/nameprovider/AlphabeticalNameProvider.java
+++ b/jack/src/com/android/jack/shrob/obfuscation/nameprovider/AlphabeticalNameProvider.java
@@ -46,4 +46,9 @@
}
protected abstract char getFirstChar();
+
+ @Override
+ public boolean hasAlternativeName(@Nonnull String oldName) {
+ return true;
+ }
}
diff --git a/jack/src/com/android/jack/shrob/obfuscation/nameprovider/DictionaryNameProvider.java b/jack/src/com/android/jack/shrob/obfuscation/nameprovider/DictionaryNameProvider.java
index c0d58fc..b1b8635 100644
--- a/jack/src/com/android/jack/shrob/obfuscation/nameprovider/DictionaryNameProvider.java
+++ b/jack/src/com/android/jack/shrob/obfuscation/nameprovider/DictionaryNameProvider.java
@@ -106,4 +106,9 @@
br = null;
}
}
+
+ @Override
+ public boolean hasAlternativeName(@Nonnull String oldName) {
+ return br != null && defaultNameProvider.hasAlternativeName(oldName);
+ }
}
diff --git a/jack/src/com/android/jack/shrob/obfuscation/nameprovider/MappingNameProvider.java b/jack/src/com/android/jack/shrob/obfuscation/nameprovider/MappingNameProvider.java
index f390659..2570645 100644
--- a/jack/src/com/android/jack/shrob/obfuscation/nameprovider/MappingNameProvider.java
+++ b/jack/src/com/android/jack/shrob/obfuscation/nameprovider/MappingNameProvider.java
@@ -46,4 +46,9 @@
}
return defaultNameProvider.getNewName(oldName);
}
+
+ @Override
+ public boolean hasAlternativeName(@Nonnull String oldName) {
+ return !names.containsKey(oldName) && defaultNameProvider.hasAlternativeName(oldName);
+ }
}
\ No newline at end of file
diff --git a/jack/src/com/android/jack/shrob/obfuscation/nameprovider/NameProvider.java b/jack/src/com/android/jack/shrob/obfuscation/nameprovider/NameProvider.java
index 4b85eee..1890453 100644
--- a/jack/src/com/android/jack/shrob/obfuscation/nameprovider/NameProvider.java
+++ b/jack/src/com/android/jack/shrob/obfuscation/nameprovider/NameProvider.java
@@ -27,4 +27,6 @@
public interface NameProvider {
@Nonnull
public String getNewName(@Nonnull String oldName);
+
+ public boolean hasAlternativeName(@Nonnull String oldName);
}
diff --git a/jack/src/com/android/jack/shrob/obfuscation/nameprovider/UniqueNameProvider.java b/jack/src/com/android/jack/shrob/obfuscation/nameprovider/UniqueNameProvider.java
index a758b8e..6d238a8 100644
--- a/jack/src/com/android/jack/shrob/obfuscation/nameprovider/UniqueNameProvider.java
+++ b/jack/src/com/android/jack/shrob/obfuscation/nameprovider/UniqueNameProvider.java
@@ -49,4 +49,9 @@
names.add(newName);
return newName;
}
+
+ @Override
+ public boolean hasAlternativeName(@Nonnull String oldName) {
+ return nameProvider.hasAlternativeName(oldName);
+ }
}
diff --git a/jack/tests/com/android/jack/shrob/obfuscation/nameprovider/Rot13NameProvider.java b/jack/tests/com/android/jack/shrob/obfuscation/nameprovider/Rot13NameProvider.java
index 7a989e8..8b91db9 100644
--- a/jack/tests/com/android/jack/shrob/obfuscation/nameprovider/Rot13NameProvider.java
+++ b/jack/tests/com/android/jack/shrob/obfuscation/nameprovider/Rot13NameProvider.java
@@ -76,4 +76,9 @@
return sb.toString();
}
+ @Override
+ public boolean hasAlternativeName(@Nonnull String oldName) {
+ return false;
+ }
+
}