From 5cf6311da198837770582e5f6df9abe1582e4123 Mon Sep 17 00:00:00 2001 From: Yigit Boyar Date: Tue, 16 Oct 2018 01:08:55 -0700 Subject: Move imports to a concrete class This CL moves Map imports to a concrete ImportBag class. It is mostly a cleanup so that in a follow-up CL, we can start caching findClass calls based on available imports. Right now it is not possible since imports are all bloated with java.lang. This CL also stops adding all java.lang.* as static identifiers to every single model. Instead, it lazily registers it if an identifier expression cannot be found and name matches a java.lang class. Bug: 117808327 Test: ImportBagTest, existing tests pass Change-Id: Ideb41ab8cfc68aa4c7b55e84ffa218ba65558eb3 --- .../databinding/tool/reflection/ImportBag.kt | 171 +++++++++++++++++++++ .../databinding/tool/reflection/InjectedClass.java | 2 +- .../tool/reflection/InjectedMethod.java | 4 +- .../databinding/tool/reflection/ModelAnalyzer.java | 5 +- .../reflection/annotation/AnnotationAnalyzer.java | 9 +- 5 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 compiler/src/main/java/android/databinding/tool/reflection/ImportBag.kt (limited to 'compiler/src/main/java/android/databinding/tool/reflection') diff --git a/compiler/src/main/java/android/databinding/tool/reflection/ImportBag.kt b/compiler/src/main/java/android/databinding/tool/reflection/ImportBag.kt new file mode 100644 index 00000000..8b6fae1a --- /dev/null +++ b/compiler/src/main/java/android/databinding/tool/reflection/ImportBag.kt @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2018 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 android.databinding.tool.reflection + +class MutableImportBag : ImportBag() { + open fun put(alias : String, qName : String) { + imports.putIfAbsent(alias, qName) + } +} + +private class ImmutableImportBag : ImportBag() { + +} + +/** + * A class that can keep a list of imports and also run an equals check against itself. + * + * We do import everything in java.lang which is a waste of memory and killer for equals + * check. Instead, this class optimizes that part automatically. + * + * Equals on ImportBag is important because we resolve classes based on imports. + */ +sealed class ImportBag { + // alias to Import mapping + protected val imports = mutableMapOf() + + fun find(alias: String) : String? { + return imports[alias] ?: importJavaLang(alias) + } + + fun contains(alias: String) = find(alias) != null + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is ImportBag) return false + + if (imports != other.imports) return false + + return true + } + + override fun hashCode(): Int { + return imports.hashCode() + } + + companion object { + @JvmField + val EMPTY : ImportBag = ImmutableImportBag() + @JvmField + val JAVA_LANG_IMPORTS = setOf( + "Deprecated", + "Override", + "SafeVarargs", + "SuppressWarnings", + "Appendable", + "AutoCloseable", + "CharSequence", + "Cloneable", + "Comparable", + "Iterable", + "Readable", + "Runnable", + "Thread.UncaughtExceptionHandler", + "Boolean", + "Byte", + "Character", + "Character.Subset", + "Character.UnicodeBlock", + "Class", + "ClassLoader", + "Compiler", + "Double", + "Enum", + "Float", + "InheritableThreadLocal", + "Integer", + "Long", + "Math", + "Number", + "Object", + "Package", + "Process", + "ProcessBuilder", + "Runtime", + "RuntimePermission", + "SecurityManager", + "Short", + "StackTraceElement", + "StrictMath", + "String", + "StringBuffer", + "StringBuilder", + "System", + "Thread", + "ThreadGroup", + "ThreadLocal", + "Throwable", + "Void", + "Thread.State", + "ArithmeticException", + "ArrayIndexOutOfBoundsException", + "ArrayStoreException", + "ClassCastException", + "ClassNotFoundException", + "CloneNotSupportedException", + "EnumConstantNotPresentException", + "Exception", + "IllegalAccessException", + "IllegalArgumentException", + "IllegalMonitorStateException", + "IllegalStateException", + "IllegalThreadStateException", + "IndexOutOfBoundsException", + "InstantiationException", + "InterruptedException", + "NegativeArraySizeException", + "NoSuchFieldException", + "NoSuchMethodException", + "NullPointerException", + "NumberFormatException", + "ReflectiveOperationException", + "RuntimeException", + "SecurityException", + "StringIndexOutOfBoundsException", + "TypeNotPresentException", + "UnsupportedOperationException", + "AbstractMethodError", + "AssertionError", + "ClassCircularityError", + "ClassFormatError", + "Error", + "ExceptionInInitializerError", + "IllegalAccessError", + "IncompatibleClassChangeError", + "InstantiationError", + "InternalError", + "LinkageError", + "NoClassDefFoundError", + "NoSuchFieldError", + "NoSuchMethodError", + "OutOfMemoryError", + "StackOverflowError", + "ThreadDeath", + "UnknownError", + "UnsatisfiedLinkError", + "UnsupportedClassVersionError", + "VerifyError", + "VirtualMachineError" + ) + private fun importJavaLang(alias : String) : String? { + return if (JAVA_LANG_IMPORTS.contains(alias)) { + "java.lang.$alias" + } else { + null + } + } + } +} \ No newline at end of file diff --git a/compiler/src/main/java/android/databinding/tool/reflection/InjectedClass.java b/compiler/src/main/java/android/databinding/tool/reflection/InjectedClass.java index 45bedcb0..1ae22afa 100644 --- a/compiler/src/main/java/android/databinding/tool/reflection/InjectedClass.java +++ b/compiler/src/main/java/android/databinding/tool/reflection/InjectedClass.java @@ -46,7 +46,7 @@ public class InjectedClass extends ModelClass { mSuperClass = superClass; } - public void addVariable(String name, String type, Map imports) { + public void addVariable(String name, String type, ImportBag imports) { String capName = StringUtils.capitalize(name); String setName = "set" + capName; String getName = "get" + capName; diff --git a/compiler/src/main/java/android/databinding/tool/reflection/InjectedMethod.java b/compiler/src/main/java/android/databinding/tool/reflection/InjectedMethod.java index be1f8d79..0a9f3ce5 100644 --- a/compiler/src/main/java/android/databinding/tool/reflection/InjectedMethod.java +++ b/compiler/src/main/java/android/databinding/tool/reflection/InjectedMethod.java @@ -31,13 +31,13 @@ public class InjectedMethod extends ModelMethod { private final String mName; private final String mReturnTypeName; private final String[] mParameterTypeNames; - private final Map mImports; + private final ImportBag mImports; private ModelClass[] mParameterTypes; private ModelClass mReturnType; private boolean mIsStatic; public InjectedMethod(InjectedClass containingClass, boolean isStatic, String name, - Map imports, String returnType, String... parameters) { + ImportBag imports, String returnType, String... parameters) { mContainingClass = containingClass; mName = name; mIsStatic = isStatic; diff --git a/compiler/src/main/java/android/databinding/tool/reflection/ModelAnalyzer.java b/compiler/src/main/java/android/databinding/tool/reflection/ModelAnalyzer.java index f650b9c5..0671165d 100644 --- a/compiler/src/main/java/android/databinding/tool/reflection/ModelAnalyzer.java +++ b/compiler/src/main/java/android/databinding/tool/reflection/ModelAnalyzer.java @@ -19,7 +19,6 @@ import android.databinding.tool.Context; import android.databinding.tool.LibTypes; import android.databinding.tool.util.L; import android.databinding.tool.util.Preconditions; -import com.android.annotations.Nullable; import java.util.HashMap; import java.util.List; @@ -251,14 +250,14 @@ public abstract class ModelAnalyzer { return "null"; } - public final ModelClass findClass(String className, Map imports) { + public final ModelClass findClass(String className, ImportBag imports) { if (mInjectedClasses.containsKey(className)) { return mInjectedClasses.get(className); } return findClassInternal(className, imports); } - public abstract ModelClass findClassInternal(String className, Map imports); + public abstract ModelClass findClassInternal(String className, ImportBag importBag); public abstract ModelClass findClass(Class classType); diff --git a/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationAnalyzer.java b/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationAnalyzer.java index 7ef7585c..ec7b872e 100644 --- a/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationAnalyzer.java +++ b/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationAnalyzer.java @@ -16,6 +16,7 @@ package android.databinding.tool.reflection.annotation; import android.databinding.tool.LibTypes; +import android.databinding.tool.reflection.ImportBag; import android.databinding.tool.reflection.ModelAnalyzer; import android.databinding.tool.reflection.ModelClass; import android.databinding.tool.reflection.TypeUtil; @@ -71,7 +72,7 @@ public class AnnotationAnalyzer extends ModelAnalyzer { } @Override - public ModelClass findClassInternal(String className, Map imports) { + public ModelClass findClassInternal(String className, ImportBag imports) { className = className.trim(); int numDimensions = 0; while (className.endsWith("[]")) { @@ -130,12 +131,12 @@ public class AnnotationAnalyzer extends ModelAnalyzer { return new AnnotationClass(type); } - private TypeElement getTypeElement(String className, Map imports) { + private TypeElement getTypeElement(String className, ImportBag imports) { Elements elementUtils = getElementUtils(); final boolean hasDot = className.indexOf('.') >= 0; if (!hasDot && imports != null) { // try the imports - String importedClass = imports.get(className); + String importedClass = imports.find(className); if (importedClass != null) { className = importedClass; } @@ -177,7 +178,7 @@ public class AnnotationAnalyzer extends ModelAnalyzer { } private ArrayList splitTemplateParameters(String templateParameters) { - ArrayList list = new ArrayList(); + ArrayList list = new ArrayList<>(); int index = 0; int openCount = 0; StringBuilder arg = new StringBuilder(); -- cgit v1.2.3