From fb9836300797c3068a2ff07e818cdd7bbd7d4f56 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Fri, 13 Jul 2018 13:18:50 -0700 Subject: [PATCH 1/5] Separate PainlessLookup into PainlessLookup and PainlessLookupBuilder. --- .../painless/AnalyzerCaster.java | 2 +- .../elasticsearch/painless/MethodWriter.java | 2 +- .../painless/PainlessScriptEngine.java | 7 +- .../painless/lookup/PainlessLookup.java | 692 +--------------- .../lookup/PainlessLookupBuilder.java | 774 ++++++++++++++++++ .../elasticsearch/painless/lookup/def.java | 28 + .../painless/node/EAssignment.java | 2 +- .../elasticsearch/painless/node/EBinary.java | 2 +- .../painless/node/ECapturingFunctionRef.java | 2 +- .../elasticsearch/painless/node/EComp.java | 2 +- .../elasticsearch/painless/node/ELambda.java | 2 +- .../painless/node/EListInit.java | 2 +- .../elasticsearch/painless/node/EMapInit.java | 2 +- .../elasticsearch/painless/node/EUnary.java | 2 +- .../elasticsearch/painless/node/PBrace.java | 2 +- .../painless/node/PCallInvoke.java | 2 +- .../elasticsearch/painless/node/PField.java | 2 +- .../painless/node/PSubDefArray.java | 2 +- .../painless/node/PSubDefCall.java | 2 +- .../painless/node/PSubDefField.java | 2 +- .../elasticsearch/painless/node/SEach.java | 2 +- .../painless/node/SSubEachIterable.java | 2 +- .../painless/BaseClassTests.java | 3 +- .../elasticsearch/painless/DebugTests.java | 3 +- .../org/elasticsearch/painless/Debugger.java | 3 +- .../painless/DefBootstrapTests.java | 3 +- .../painless/PainlessDocGenerator.java | 5 +- .../painless/ScriptTestCase.java | 3 +- .../painless/node/NodeToStringTests.java | 3 +- 29 files changed, 844 insertions(+), 716 deletions(-) create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/def.java diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java index 69ef57faad63e..457ec82a5e429 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java @@ -21,7 +21,7 @@ import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.lookup.PainlessCast; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import java.util.Objects; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java index e0a780d418843..9a79ac54f81c8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java @@ -20,7 +20,7 @@ package org.elasticsearch.painless; import org.elasticsearch.painless.lookup.PainlessCast; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java index ae1944c9bd3a9..6c976f2606e3b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java @@ -25,6 +25,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.painless.Compiler.Loader; import org.elasticsearch.painless.lookup.PainlessLookup; +import org.elasticsearch.painless.lookup.PainlessLookupBuilder; import org.elasticsearch.painless.spi.Whitelist; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.ScriptContext; @@ -102,9 +103,11 @@ public PainlessScriptEngine(Settings settings, Map, List, List> entry : contexts.entrySet()) { ScriptContext context = entry.getKey(); if (context.instanceClazz.equals(SearchScript.class) || context.instanceClazz.equals(ExecutableScript.class)) { - contextsToCompilers.put(context, new Compiler(GenericElasticsearchScript.class, new PainlessLookup(entry.getValue()))); + contextsToCompilers.put(context, new Compiler(GenericElasticsearchScript.class, + new PainlessLookupBuilder(entry.getValue()).build())); } else { - contextsToCompilers.put(context, new Compiler(context.instanceClazz, new PainlessLookup(entry.getValue()))); + contextsToCompilers.put(context, new Compiler(context.instanceClazz, + new PainlessLookupBuilder(entry.getValue()).build())); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookup.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookup.java index 5833767fbd3d2..feeaf4d34bcdd 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookup.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookup.java @@ -19,25 +19,10 @@ package org.elasticsearch.painless.lookup; -import org.elasticsearch.painless.spi.Whitelist; -import org.elasticsearch.painless.spi.WhitelistClass; -import org.elasticsearch.painless.spi.WhitelistConstructor; -import org.elasticsearch.painless.spi.WhitelistField; -import org.elasticsearch.painless.spi.WhitelistMethod; -import org.objectweb.asm.Type; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Modifier; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.Stack; -import java.util.regex.Pattern; /** * The entire API for Painless. Also used as a whitelist for checking for legal @@ -45,18 +30,6 @@ */ public final class PainlessLookup { - private static final Map methodCache = new HashMap<>(); - private static final Map fieldCache = new HashMap<>(); - - private static final Pattern TYPE_NAME_PATTERN = Pattern.compile("^[_a-zA-Z][._a-zA-Z0-9]*$"); - - /** Marker class for def type to be used during type analysis. */ - public static final class def { - private def() { - - } - } - public static Class getBoxedType(Class clazz) { if (clazz == boolean.class) { return Boolean.class; @@ -205,22 +178,6 @@ public static String ClassToName(Class clazz) { return clazz.getCanonicalName().replace('$', '.'); } - private static String buildMethodCacheKey(String structName, String methodName, List> arguments) { - StringBuilder key = new StringBuilder(); - key.append(structName); - key.append(methodName); - - for (Class argument : arguments) { - key.append(argument.getName()); - } - - return key.toString(); - } - - private static String buildFieldCacheKey(String structName, String fieldName, String typeName) { - return structName + fieldName + typeName; - } - public Collection getStructs() { return javaClassesToPainlessStructs.values(); } @@ -228,652 +185,9 @@ public Collection getStructs() { private final Map> painlessTypesToJavaClasses; private final Map, PainlessClass> javaClassesToPainlessStructs; - public PainlessLookup(List whitelists) { - painlessTypesToJavaClasses = new HashMap<>(); - javaClassesToPainlessStructs = new HashMap<>(); - - String origin = null; - - painlessTypesToJavaClasses.put("def", def.class); - javaClassesToPainlessStructs.put(def.class, new PainlessClass("def", Object.class, Type.getType(Object.class))); - - try { - // first iteration collects all the Painless type names that - // are used for validation during the second iteration - for (Whitelist whitelist : whitelists) { - for (WhitelistClass whitelistStruct : whitelist.whitelistStructs) { - String painlessTypeName = whitelistStruct.javaClassName.replace('$', '.'); - PainlessClass painlessStruct = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(painlessTypeName)); - - if (painlessStruct != null && painlessStruct.clazz.getName().equals(whitelistStruct.javaClassName) == false) { - throw new IllegalArgumentException("struct [" + painlessStruct.name + "] cannot represent multiple classes " + - "[" + painlessStruct.clazz.getName() + "] and [" + whitelistStruct.javaClassName + "]"); - } - - origin = whitelistStruct.origin; - addStruct(whitelist.javaClassLoader, whitelistStruct); - - painlessStruct = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(painlessTypeName)); - javaClassesToPainlessStructs.put(painlessStruct.clazz, painlessStruct); - } - } - - // second iteration adds all the constructors, methods, and fields that will - // be available in Painless along with validating they exist and all their types have - // been white-listed during the first iteration - for (Whitelist whitelist : whitelists) { - for (WhitelistClass whitelistStruct : whitelist.whitelistStructs) { - String painlessTypeName = whitelistStruct.javaClassName.replace('$', '.'); - - for (WhitelistConstructor whitelistConstructor : whitelistStruct.whitelistConstructors) { - origin = whitelistConstructor.origin; - addConstructor(painlessTypeName, whitelistConstructor); - } - - for (WhitelistMethod whitelistMethod : whitelistStruct.whitelistMethods) { - origin = whitelistMethod.origin; - addMethod(whitelist.javaClassLoader, painlessTypeName, whitelistMethod); - } - - for (WhitelistField whitelistField : whitelistStruct.whitelistFields) { - origin = whitelistField.origin; - addField(painlessTypeName, whitelistField); - } - } - } - } catch (Exception exception) { - throw new IllegalArgumentException("error loading whitelist(s) " + origin, exception); - } - - // goes through each Painless struct and determines the inheritance list, - // and then adds all inherited types to the Painless struct's whitelist - for (Class javaClass : javaClassesToPainlessStructs.keySet()) { - PainlessClass painlessStruct = javaClassesToPainlessStructs.get(javaClass); - - List painlessSuperStructs = new ArrayList<>(); - Class javaSuperClass = painlessStruct.clazz.getSuperclass(); - - Stack> javaInteraceLookups = new Stack<>(); - javaInteraceLookups.push(painlessStruct.clazz); - - // adds super classes to the inheritance list - if (javaSuperClass != null && javaSuperClass.isInterface() == false) { - while (javaSuperClass != null) { - PainlessClass painlessSuperStruct = javaClassesToPainlessStructs.get(javaSuperClass); - - if (painlessSuperStruct != null) { - painlessSuperStructs.add(painlessSuperStruct.name); - } - - javaInteraceLookups.push(javaSuperClass); - javaSuperClass = javaSuperClass.getSuperclass(); - } - } - - // adds all super interfaces to the inheritance list - while (javaInteraceLookups.isEmpty() == false) { - Class javaInterfaceLookup = javaInteraceLookups.pop(); - - for (Class javaSuperInterface : javaInterfaceLookup.getInterfaces()) { - PainlessClass painlessInterfaceStruct = javaClassesToPainlessStructs.get(javaSuperInterface); - - if (painlessInterfaceStruct != null) { - String painlessInterfaceStructName = painlessInterfaceStruct.name; - - if (painlessSuperStructs.contains(painlessInterfaceStructName) == false) { - painlessSuperStructs.add(painlessInterfaceStructName); - } - - for (Class javaPushInterface : javaInterfaceLookup.getInterfaces()) { - javaInteraceLookups.push(javaPushInterface); - } - } - } - } - - // copies methods and fields from super structs to the parent struct - copyStruct(painlessStruct.name, painlessSuperStructs); - - // copies methods and fields from Object into interface types - if (painlessStruct.clazz.isInterface() || (def.class.getSimpleName()).equals(painlessStruct.name)) { - PainlessClass painlessObjectStruct = javaClassesToPainlessStructs.get(Object.class); - - if (painlessObjectStruct != null) { - copyStruct(painlessStruct.name, Collections.singletonList(painlessObjectStruct.name)); - } - } - } - - // precompute runtime classes - for (PainlessClass painlessStruct : javaClassesToPainlessStructs.values()) { - addRuntimeClass(painlessStruct); - } - - // copy all structs to make them unmodifiable for outside users: - for (Map.Entry,PainlessClass> entry : javaClassesToPainlessStructs.entrySet()) { - entry.setValue(entry.getValue().freeze(computeFunctionalInterfaceMethod(entry.getValue()))); - } - } - - private void addStruct(ClassLoader whitelistClassLoader, WhitelistClass whitelistStruct) { - String painlessTypeName = whitelistStruct.javaClassName.replace('$', '.'); - String importedPainlessTypeName = painlessTypeName; - - if (TYPE_NAME_PATTERN.matcher(painlessTypeName).matches() == false) { - throw new IllegalArgumentException("invalid struct type name [" + painlessTypeName + "]"); - } - - int index = whitelistStruct.javaClassName.lastIndexOf('.'); - - if (index != -1) { - importedPainlessTypeName = whitelistStruct.javaClassName.substring(index + 1).replace('$', '.'); - } - - Class javaClass; - - if ("void".equals(whitelistStruct.javaClassName)) javaClass = void.class; - else if ("boolean".equals(whitelistStruct.javaClassName)) javaClass = boolean.class; - else if ("byte".equals(whitelistStruct.javaClassName)) javaClass = byte.class; - else if ("short".equals(whitelistStruct.javaClassName)) javaClass = short.class; - else if ("char".equals(whitelistStruct.javaClassName)) javaClass = char.class; - else if ("int".equals(whitelistStruct.javaClassName)) javaClass = int.class; - else if ("long".equals(whitelistStruct.javaClassName)) javaClass = long.class; - else if ("float".equals(whitelistStruct.javaClassName)) javaClass = float.class; - else if ("double".equals(whitelistStruct.javaClassName)) javaClass = double.class; - else { - try { - javaClass = Class.forName(whitelistStruct.javaClassName, true, whitelistClassLoader); - } catch (ClassNotFoundException cnfe) { - throw new IllegalArgumentException("invalid java class name [" + whitelistStruct.javaClassName + "]" + - " for struct [" + painlessTypeName + "]"); - } - } - - PainlessClass existingStruct = javaClassesToPainlessStructs.get(javaClass); - - if (existingStruct == null) { - PainlessClass struct = new PainlessClass(painlessTypeName, javaClass, org.objectweb.asm.Type.getType(javaClass)); - painlessTypesToJavaClasses.put(painlessTypeName, javaClass); - javaClassesToPainlessStructs.put(javaClass, struct); - } else if (existingStruct.clazz.equals(javaClass) == false) { - throw new IllegalArgumentException("struct [" + painlessTypeName + "] is used to " + - "illegally represent multiple java classes [" + whitelistStruct.javaClassName + "] and " + - "[" + existingStruct.clazz.getName() + "]"); - } - - if (painlessTypeName.equals(importedPainlessTypeName)) { - if (whitelistStruct.onlyFQNJavaClassName == false) { - throw new IllegalArgumentException("must use only_fqn parameter on type [" + painlessTypeName + "] with no package"); - } - } else { - Class importedJavaClass = painlessTypesToJavaClasses.get(importedPainlessTypeName); - - if (importedJavaClass == null) { - if (whitelistStruct.onlyFQNJavaClassName == false) { - if (existingStruct != null) { - throw new IllegalArgumentException("inconsistent only_fqn parameters found for type [" + painlessTypeName + "]"); - } - - painlessTypesToJavaClasses.put(importedPainlessTypeName, javaClass); - } - } else if (importedJavaClass.equals(javaClass) == false) { - throw new IllegalArgumentException("imported name [" + painlessTypeName + "] is used to " + - "illegally represent multiple java classes [" + whitelistStruct.javaClassName + "] " + - "and [" + importedJavaClass.getName() + "]"); - } else if (whitelistStruct.onlyFQNJavaClassName) { - throw new IllegalArgumentException("inconsistent only_fqn parameters found for type [" + painlessTypeName + "]"); - } - } - } - - private void addConstructor(String ownerStructName, WhitelistConstructor whitelistConstructor) { - PainlessClass ownerStruct = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(ownerStructName)); - - if (ownerStruct == null) { - throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for constructor with " + - "parameters " + whitelistConstructor.painlessParameterTypeNames); - } - - List> painlessParametersTypes = new ArrayList<>(whitelistConstructor.painlessParameterTypeNames.size()); - Class[] javaClassParameters = new Class[whitelistConstructor.painlessParameterTypeNames.size()]; - - for (int parameterCount = 0; parameterCount < whitelistConstructor.painlessParameterTypeNames.size(); ++parameterCount) { - String painlessParameterTypeName = whitelistConstructor.painlessParameterTypeNames.get(parameterCount); - - try { - Class painlessParameterClass = getJavaClassFromPainlessType(painlessParameterTypeName); - - painlessParametersTypes.add(painlessParameterClass); - javaClassParameters[parameterCount] = defClassToObjectClass(painlessParameterClass); - } catch (IllegalArgumentException iae) { - throw new IllegalArgumentException("struct not defined for constructor parameter [" + painlessParameterTypeName + "] " + - "with owner struct [" + ownerStructName + "] and constructor parameters " + - whitelistConstructor.painlessParameterTypeNames, iae); - } - } - - java.lang.reflect.Constructor javaConstructor; - - try { - javaConstructor = ownerStruct.clazz.getConstructor(javaClassParameters); - } catch (NoSuchMethodException exception) { - throw new IllegalArgumentException("constructor not defined for owner struct [" + ownerStructName + "] " + - " with constructor parameters " + whitelistConstructor.painlessParameterTypeNames, exception); - } - - PainlessMethodKey painlessMethodKey = new PainlessMethodKey("", whitelistConstructor.painlessParameterTypeNames.size()); - PainlessMethod painlessConstructor = ownerStruct.constructors.get(painlessMethodKey); - - if (painlessConstructor == null) { - org.objectweb.asm.commons.Method asmConstructor = org.objectweb.asm.commons.Method.getMethod(javaConstructor); - MethodHandle javaHandle; - - try { - javaHandle = MethodHandles.publicLookup().in(ownerStruct.clazz).unreflectConstructor(javaConstructor); - } catch (IllegalAccessException exception) { - throw new IllegalArgumentException("constructor not defined for owner struct [" + ownerStructName + "] " + - " with constructor parameters " + whitelistConstructor.painlessParameterTypeNames); - } - - painlessConstructor = methodCache.computeIfAbsent(buildMethodCacheKey(ownerStruct.name, "", painlessParametersTypes), - key -> new PainlessMethod("", ownerStruct, null, void.class, painlessParametersTypes, - asmConstructor, javaConstructor.getModifiers(), javaHandle)); - ownerStruct.constructors.put(painlessMethodKey, painlessConstructor); - } else if (painlessConstructor.arguments.equals(painlessParametersTypes) == false){ - throw new IllegalArgumentException( - "illegal duplicate constructors [" + painlessMethodKey + "] found within the struct [" + ownerStruct.name + "] " + - "with parameters " + painlessParametersTypes + " and " + painlessConstructor.arguments); - } - } - - private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName, WhitelistMethod whitelistMethod) { - PainlessClass ownerStruct = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(ownerStructName)); - - if (ownerStruct == null) { - throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for method with " + - "name [" + whitelistMethod.javaMethodName + "] and parameters " + whitelistMethod.painlessParameterTypeNames); - } - - if (TYPE_NAME_PATTERN.matcher(whitelistMethod.javaMethodName).matches() == false) { - throw new IllegalArgumentException("invalid method name" + - " [" + whitelistMethod.javaMethodName + "] for owner struct [" + ownerStructName + "]."); - } - - Class javaAugmentedClass; - - if (whitelistMethod.javaAugmentedClassName != null) { - try { - javaAugmentedClass = Class.forName(whitelistMethod.javaAugmentedClassName, true, whitelistClassLoader); - } catch (ClassNotFoundException cnfe) { - throw new IllegalArgumentException("augmented class [" + whitelistMethod.javaAugmentedClassName + "] " + - "not found for method with name [" + whitelistMethod.javaMethodName + "] " + - "and parameters " + whitelistMethod.painlessParameterTypeNames, cnfe); - } - } else { - javaAugmentedClass = null; - } - - int augmentedOffset = javaAugmentedClass == null ? 0 : 1; - - List> painlessParametersTypes = new ArrayList<>(whitelistMethod.painlessParameterTypeNames.size()); - Class[] javaClassParameters = new Class[whitelistMethod.painlessParameterTypeNames.size() + augmentedOffset]; - - if (javaAugmentedClass != null) { - javaClassParameters[0] = ownerStruct.clazz; - } - - for (int parameterCount = 0; parameterCount < whitelistMethod.painlessParameterTypeNames.size(); ++parameterCount) { - String painlessParameterTypeName = whitelistMethod.painlessParameterTypeNames.get(parameterCount); - - try { - Class painlessParameterClass = getJavaClassFromPainlessType(painlessParameterTypeName); - - painlessParametersTypes.add(painlessParameterClass); - javaClassParameters[parameterCount + augmentedOffset] = defClassToObjectClass(painlessParameterClass); - } catch (IllegalArgumentException iae) { - throw new IllegalArgumentException("struct not defined for method parameter [" + painlessParameterTypeName + "] " + - "with owner struct [" + ownerStructName + "] and method with name [" + whitelistMethod.javaMethodName + "] " + - "and parameters " + whitelistMethod.painlessParameterTypeNames, iae); - } - } - - Class javaImplClass = javaAugmentedClass == null ? ownerStruct.clazz : javaAugmentedClass; - java.lang.reflect.Method javaMethod; - - try { - javaMethod = javaImplClass.getMethod(whitelistMethod.javaMethodName, javaClassParameters); - } catch (NoSuchMethodException nsme) { - throw new IllegalArgumentException("method with name [" + whitelistMethod.javaMethodName + "] " + - "and parameters " + whitelistMethod.painlessParameterTypeNames + " not found for class [" + - javaImplClass.getName() + "]", nsme); - } - - Class painlessReturnClass; - - try { - painlessReturnClass = getJavaClassFromPainlessType(whitelistMethod.painlessReturnTypeName); - } catch (IllegalArgumentException iae) { - throw new IllegalArgumentException("struct not defined for return type [" + whitelistMethod.painlessReturnTypeName + "] " + - "with owner struct [" + ownerStructName + "] and method with name [" + whitelistMethod.javaMethodName + "] " + - "and parameters " + whitelistMethod.painlessParameterTypeNames, iae); - } - - if (javaMethod.getReturnType() != defClassToObjectClass(painlessReturnClass)) { - throw new IllegalArgumentException("specified return type class [" + painlessReturnClass + "] " + - "does not match the return type class [" + javaMethod.getReturnType() + "] for the " + - "method with name [" + whitelistMethod.javaMethodName + "] " + - "and parameters " + whitelistMethod.painlessParameterTypeNames); - } - - PainlessMethodKey painlessMethodKey = - new PainlessMethodKey(whitelistMethod.javaMethodName, whitelistMethod.painlessParameterTypeNames.size()); - - if (javaAugmentedClass == null && Modifier.isStatic(javaMethod.getModifiers())) { - PainlessMethod painlessMethod = ownerStruct.staticMethods.get(painlessMethodKey); - - if (painlessMethod == null) { - org.objectweb.asm.commons.Method asmMethod = org.objectweb.asm.commons.Method.getMethod(javaMethod); - MethodHandle javaMethodHandle; - - try { - javaMethodHandle = MethodHandles.publicLookup().in(javaImplClass).unreflect(javaMethod); - } catch (IllegalAccessException exception) { - throw new IllegalArgumentException("method handle not found for method with name " + - "[" + whitelistMethod.javaMethodName + "] and parameters " + whitelistMethod.painlessParameterTypeNames); - } - - painlessMethod = methodCache.computeIfAbsent( - buildMethodCacheKey(ownerStruct.name, whitelistMethod.javaMethodName, painlessParametersTypes), - key -> new PainlessMethod(whitelistMethod.javaMethodName, ownerStruct, null, painlessReturnClass, - painlessParametersTypes, asmMethod, javaMethod.getModifiers(), javaMethodHandle)); - ownerStruct.staticMethods.put(painlessMethodKey, painlessMethod); - } else if ((painlessMethod.name.equals(whitelistMethod.javaMethodName) && painlessMethod.rtn == painlessReturnClass && - painlessMethod.arguments.equals(painlessParametersTypes)) == false) { - throw new IllegalArgumentException("illegal duplicate static methods [" + painlessMethodKey + "] " + - "found within the struct [" + ownerStruct.name + "] with name [" + whitelistMethod.javaMethodName + "], " + - "return types [" + painlessReturnClass + "] and [" + painlessMethod.rtn + "], " + - "and parameters " + painlessParametersTypes + " and " + painlessMethod.arguments); - } - } else { - PainlessMethod painlessMethod = ownerStruct.methods.get(painlessMethodKey); - - if (painlessMethod == null) { - org.objectweb.asm.commons.Method asmMethod = org.objectweb.asm.commons.Method.getMethod(javaMethod); - MethodHandle javaMethodHandle; - - try { - javaMethodHandle = MethodHandles.publicLookup().in(javaImplClass).unreflect(javaMethod); - } catch (IllegalAccessException exception) { - throw new IllegalArgumentException("method handle not found for method with name " + - "[" + whitelistMethod.javaMethodName + "] and parameters " + whitelistMethod.painlessParameterTypeNames); - } - - painlessMethod = methodCache.computeIfAbsent( - buildMethodCacheKey(ownerStruct.name, whitelistMethod.javaMethodName, painlessParametersTypes), - key -> new PainlessMethod(whitelistMethod.javaMethodName, ownerStruct, javaAugmentedClass, painlessReturnClass, - painlessParametersTypes, asmMethod, javaMethod.getModifiers(), javaMethodHandle)); - ownerStruct.methods.put(painlessMethodKey, painlessMethod); - } else if ((painlessMethod.name.equals(whitelistMethod.javaMethodName) && painlessMethod.rtn.equals(painlessReturnClass) && - painlessMethod.arguments.equals(painlessParametersTypes)) == false) { - throw new IllegalArgumentException("illegal duplicate member methods [" + painlessMethodKey + "] " + - "found within the struct [" + ownerStruct.name + "] with name [" + whitelistMethod.javaMethodName + "], " + - "return types [" + painlessReturnClass + "] and [" + painlessMethod.rtn + "], " + - "and parameters " + painlessParametersTypes + " and " + painlessMethod.arguments); - } - } - } - - private void addField(String ownerStructName, WhitelistField whitelistField) { - PainlessClass ownerStruct = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(ownerStructName)); - - if (ownerStruct == null) { - throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for method with " + - "name [" + whitelistField.javaFieldName + "] and type " + whitelistField.painlessFieldTypeName); - } - - if (TYPE_NAME_PATTERN.matcher(whitelistField.javaFieldName).matches() == false) { - throw new IllegalArgumentException("invalid field name " + - "[" + whitelistField.painlessFieldTypeName + "] for owner struct [" + ownerStructName + "]."); - } - - java.lang.reflect.Field javaField; - - try { - javaField = ownerStruct.clazz.getField(whitelistField.javaFieldName); - } catch (NoSuchFieldException exception) { - throw new IllegalArgumentException("field [" + whitelistField.javaFieldName + "] " + - "not found for class [" + ownerStruct.clazz.getName() + "]."); - } - - Class painlessFieldClass; - - try { - painlessFieldClass = getJavaClassFromPainlessType(whitelistField.painlessFieldTypeName); - } catch (IllegalArgumentException iae) { - throw new IllegalArgumentException("struct not defined for return type [" + whitelistField.painlessFieldTypeName + "] " + - "with owner struct [" + ownerStructName + "] and field with name [" + whitelistField.javaFieldName + "]", iae); - } - - if (Modifier.isStatic(javaField.getModifiers())) { - if (Modifier.isFinal(javaField.getModifiers()) == false) { - throw new IllegalArgumentException("static [" + whitelistField.javaFieldName + "] " + - "with owner struct [" + ownerStruct.name + "] is not final"); - } - - PainlessField painlessField = ownerStruct.staticMembers.get(whitelistField.javaFieldName); - - if (painlessField == null) { - painlessField = fieldCache.computeIfAbsent( - buildFieldCacheKey(ownerStruct.name, whitelistField.javaFieldName, painlessFieldClass.getName()), - key -> new PainlessField(whitelistField.javaFieldName, javaField.getName(), - ownerStruct, painlessFieldClass, javaField.getModifiers(), null, null)); - ownerStruct.staticMembers.put(whitelistField.javaFieldName, painlessField); - } else if (painlessField.clazz != painlessFieldClass) { - throw new IllegalArgumentException("illegal duplicate static fields [" + whitelistField.javaFieldName + "] " + - "found within the struct [" + ownerStruct.name + "] with type [" + whitelistField.painlessFieldTypeName + "]"); - } - } else { - MethodHandle javaMethodHandleGetter; - MethodHandle javaMethodHandleSetter; - - try { - if (Modifier.isStatic(javaField.getModifiers()) == false) { - javaMethodHandleGetter = MethodHandles.publicLookup().unreflectGetter(javaField); - javaMethodHandleSetter = MethodHandles.publicLookup().unreflectSetter(javaField); - } else { - javaMethodHandleGetter = null; - javaMethodHandleSetter = null; - } - } catch (IllegalAccessException exception) { - throw new IllegalArgumentException("getter/setter [" + whitelistField.javaFieldName + "]" + - " not found for class [" + ownerStruct.clazz.getName() + "]."); - } - - PainlessField painlessField = ownerStruct.members.get(whitelistField.javaFieldName); - - if (painlessField == null) { - painlessField = fieldCache.computeIfAbsent( - buildFieldCacheKey(ownerStruct.name, whitelistField.javaFieldName, painlessFieldClass.getName()), - key -> new PainlessField(whitelistField.javaFieldName, javaField.getName(), - ownerStruct, painlessFieldClass, javaField.getModifiers(), javaMethodHandleGetter, javaMethodHandleSetter)); - ownerStruct.members.put(whitelistField.javaFieldName, painlessField); - } else if (painlessField.clazz != painlessFieldClass) { - throw new IllegalArgumentException("illegal duplicate member fields [" + whitelistField.javaFieldName + "] " + - "found within the struct [" + ownerStruct.name + "] with type [" + whitelistField.painlessFieldTypeName + "]"); - } - } - } - - private void copyStruct(String struct, List children) { - final PainlessClass owner = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(struct)); - - if (owner == null) { - throw new IllegalArgumentException("Owner struct [" + struct + "] not defined for copy."); - } - - for (int count = 0; count < children.size(); ++count) { - final PainlessClass child = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(children.get(count))); - - if (child == null) { - throw new IllegalArgumentException("Child struct [" + children.get(count) + "]" + - " not defined for copy to owner struct [" + owner.name + "]."); - } - - if (!child.clazz.isAssignableFrom(owner.clazz)) { - throw new ClassCastException("Child struct [" + child.name + "]" + - " is not a super type of owner struct [" + owner.name + "] in copy."); - } - - for (Map.Entry kvPair : child.methods.entrySet()) { - PainlessMethodKey methodKey = kvPair.getKey(); - PainlessMethod method = kvPair.getValue(); - if (owner.methods.get(methodKey) == null) { - // TODO: some of these are no longer valid or outright don't work - // TODO: since classes may not come from the Painless classloader - // TODO: and it was dependent on the order of the extends which - // TODO: which no longer exists since this is generated automatically - // sanity check, look for missing covariant/generic override - /*if (owner.clazz.isInterface() && child.clazz == Object.class) { - // ok - } else if (child.clazz == Spliterator.OfPrimitive.class || child.clazz == PrimitiveIterator.class) { - // ok, we rely on generics erasure for these (its guaranteed in the javadocs though!!!!) - } else if (Constants.JRE_IS_MINIMUM_JAVA9 && owner.clazz == LocalDate.class) { - // ok, java 9 added covariant override for LocalDate.getEra() to return IsoEra: - // https://bugs.openjdk.java.net/browse/JDK-8072746 - } else { - try { - // TODO: we *have* to remove all these public members and use getter methods to encapsulate! - final Class impl; - final Class arguments[]; - if (method.augmentation != null) { - impl = method.augmentation; - arguments = new Class[method.arguments.size() + 1]; - arguments[0] = method.owner.clazz; - for (int i = 0; i < method.arguments.size(); i++) { - arguments[i + 1] = method.arguments.get(i).clazz; - } - } else { - impl = owner.clazz; - arguments = new Class[method.arguments.size()]; - for (int i = 0; i < method.arguments.size(); i++) { - arguments[i] = method.arguments.get(i).clazz; - } - } - java.lang.reflect.Method m = impl.getMethod(method.method.getName(), arguments); - if (m.getReturnType() != method.rtn.clazz) { - throw new IllegalStateException("missing covariant override for: " + m + " in " + owner.name); - } - if (m.isBridge() && !Modifier.isVolatile(method.modifiers)) { - // its a bridge in the destination, but not in the source, but it might still be ok, check generics: - java.lang.reflect.Method source = child.clazz.getMethod(method.method.getName(), arguments); - if (!Arrays.equals(source.getGenericParameterTypes(), source.getParameterTypes())) { - throw new IllegalStateException("missing generic override for: " + m + " in " + owner.name); - } - } - } catch (ReflectiveOperationException e) { - throw new AssertionError(e); - } - }*/ - owner.methods.put(methodKey, method); - } - } - - for (PainlessField field : child.members.values()) { - if (owner.members.get(field.name) == null) { - owner.members.put(field.name, - new PainlessField(field.name, field.javaName, owner, field.clazz, field.modifiers, field.getter, field.setter)); - } - } - } - } - - /** - * Precomputes a more efficient structure for dynamic method/field access. - */ - private void addRuntimeClass(final PainlessClass struct) { - // add all getters/setters - for (Map.Entry method : struct.methods.entrySet()) { - String name = method.getKey().name; - PainlessMethod m = method.getValue(); - - if (m.arguments.size() == 0 && - name.startsWith("get") && - name.length() > 3 && - Character.isUpperCase(name.charAt(3))) { - StringBuilder newName = new StringBuilder(); - newName.append(Character.toLowerCase(name.charAt(3))); - newName.append(name.substring(4)); - struct.getters.putIfAbsent(newName.toString(), m.handle); - } else if (m.arguments.size() == 0 && - name.startsWith("is") && - name.length() > 2 && - Character.isUpperCase(name.charAt(2))) { - StringBuilder newName = new StringBuilder(); - newName.append(Character.toLowerCase(name.charAt(2))); - newName.append(name.substring(3)); - struct.getters.putIfAbsent(newName.toString(), m.handle); - } - - if (m.arguments.size() == 1 && - name.startsWith("set") && - name.length() > 3 && - Character.isUpperCase(name.charAt(3))) { - StringBuilder newName = new StringBuilder(); - newName.append(Character.toLowerCase(name.charAt(3))); - newName.append(name.substring(4)); - struct.setters.putIfAbsent(newName.toString(), m.handle); - } - } - - // add all members - for (Map.Entry member : struct.members.entrySet()) { - struct.getters.put(member.getKey(), member.getValue().getter); - struct.setters.put(member.getKey(), member.getValue().setter); - } - } - - /** computes the functional interface method for a class, or returns null */ - private PainlessMethod computeFunctionalInterfaceMethod(PainlessClass clazz) { - if (!clazz.clazz.isInterface()) { - return null; - } - // if its marked with this annotation, we fail if the conditions don't hold (means whitelist bug) - // otherwise, this annotation is pretty useless. - boolean hasAnnotation = clazz.clazz.isAnnotationPresent(FunctionalInterface.class); - List methods = new ArrayList<>(); - for (java.lang.reflect.Method m : clazz.clazz.getMethods()) { - // default interface methods don't count - if (m.isDefault()) { - continue; - } - // static methods don't count - if (Modifier.isStatic(m.getModifiers())) { - continue; - } - // if its from Object, it doesn't count - try { - Object.class.getMethod(m.getName(), m.getParameterTypes()); - continue; - } catch (ReflectiveOperationException e) { - // it counts - } - methods.add(m); - } - if (methods.size() != 1) { - if (hasAnnotation) { - throw new IllegalArgumentException("Class: " + clazz.name + - " is marked with FunctionalInterface but doesn't fit the bill: " + methods); - } - return null; - } - // inspect the one method found from the reflection API, it should match the whitelist! - java.lang.reflect.Method oneMethod = methods.get(0); - PainlessMethod painless = clazz.methods.get(new PainlessMethodKey(oneMethod.getName(), oneMethod.getParameterCount())); - if (painless == null || painless.method.equals(org.objectweb.asm.commons.Method.getMethod(oneMethod)) == false) { - throw new IllegalArgumentException("Class: " + clazz.name + " is functional but the functional " + - "method is not whitelisted!"); - } - return painless; + PainlessLookup(Map> painlessTypesToJavaClasses, Map, PainlessClass> javaClassesToPainlessStructs) { + this.painlessTypesToJavaClasses = Collections.unmodifiableMap(painlessTypesToJavaClasses); + this.javaClassesToPainlessStructs = Collections.unmodifiableMap(javaClassesToPainlessStructs); } public boolean isSimplePainlessType(String painlessType) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java new file mode 100644 index 0000000000000..1dadce318d672 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java @@ -0,0 +1,774 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.painless.lookup; + +import org.elasticsearch.painless.spi.Whitelist; +import org.elasticsearch.painless.spi.WhitelistClass; +import org.elasticsearch.painless.spi.WhitelistConstructor; +import org.elasticsearch.painless.spi.WhitelistField; +import org.elasticsearch.painless.spi.WhitelistMethod; +import org.objectweb.asm.Type; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; +import java.util.regex.Pattern; + +public class PainlessLookupBuilder { + private static final Pattern TYPE_NAME_PATTERN = Pattern.compile("^[_a-zA-Z][._a-zA-Z0-9]*$"); + + private static final Map methodCache = new HashMap<>(); + private static final Map fieldCache = new HashMap<>(); + + private static String buildMethodCacheKey(String structName, String methodName, List> arguments) { + StringBuilder key = new StringBuilder(); + key.append(structName); + key.append(methodName); + + for (Class argument : arguments) { + key.append(argument.getName()); + } + + return key.toString(); + } + + private static String buildFieldCacheKey(String structName, String fieldName, String typeName) { + return structName + fieldName + typeName; + } + + private final Map> painlessTypesToJavaClasses; + private final Map, PainlessClass> javaClassesToPainlessStructs; + + public PainlessLookupBuilder(List whitelists) { + painlessTypesToJavaClasses = new HashMap<>(); + javaClassesToPainlessStructs = new HashMap<>(); + + String origin = null; + + painlessTypesToJavaClasses.put("def", def.class); + javaClassesToPainlessStructs.put(def.class, new PainlessClass("def", Object.class, Type.getType(Object.class))); + + try { + // first iteration collects all the Painless type names that + // are used for validation during the second iteration + for (Whitelist whitelist : whitelists) { + for (WhitelistClass whitelistStruct : whitelist.whitelistStructs) { + String painlessTypeName = whitelistStruct.javaClassName.replace('$', '.'); + PainlessClass painlessStruct = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(painlessTypeName)); + + if (painlessStruct != null && painlessStruct.clazz.getName().equals(whitelistStruct.javaClassName) == false) { + throw new IllegalArgumentException("struct [" + painlessStruct.name + "] cannot represent multiple classes " + + "[" + painlessStruct.clazz.getName() + "] and [" + whitelistStruct.javaClassName + "]"); + } + + origin = whitelistStruct.origin; + addStruct(whitelist.javaClassLoader, whitelistStruct); + + painlessStruct = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(painlessTypeName)); + javaClassesToPainlessStructs.put(painlessStruct.clazz, painlessStruct); + } + } + + // second iteration adds all the constructors, methods, and fields that will + // be available in Painless along with validating they exist and all their types have + // been white-listed during the first iteration + for (Whitelist whitelist : whitelists) { + for (WhitelistClass whitelistStruct : whitelist.whitelistStructs) { + String painlessTypeName = whitelistStruct.javaClassName.replace('$', '.'); + + for (WhitelistConstructor whitelistConstructor : whitelistStruct.whitelistConstructors) { + origin = whitelistConstructor.origin; + addConstructor(painlessTypeName, whitelistConstructor); + } + + for (WhitelistMethod whitelistMethod : whitelistStruct.whitelistMethods) { + origin = whitelistMethod.origin; + addMethod(whitelist.javaClassLoader, painlessTypeName, whitelistMethod); + } + + for (WhitelistField whitelistField : whitelistStruct.whitelistFields) { + origin = whitelistField.origin; + addField(painlessTypeName, whitelistField); + } + } + } + } catch (Exception exception) { + throw new IllegalArgumentException("error loading whitelist(s) " + origin, exception); + } + + // goes through each Painless struct and determines the inheritance list, + // and then adds all inherited types to the Painless struct's whitelist + for (Class javaClass : javaClassesToPainlessStructs.keySet()) { + PainlessClass painlessStruct = javaClassesToPainlessStructs.get(javaClass); + + List painlessSuperStructs = new ArrayList<>(); + Class javaSuperClass = painlessStruct.clazz.getSuperclass(); + + Stack> javaInteraceLookups = new Stack<>(); + javaInteraceLookups.push(painlessStruct.clazz); + + // adds super classes to the inheritance list + if (javaSuperClass != null && javaSuperClass.isInterface() == false) { + while (javaSuperClass != null) { + PainlessClass painlessSuperStruct = javaClassesToPainlessStructs.get(javaSuperClass); + + if (painlessSuperStruct != null) { + painlessSuperStructs.add(painlessSuperStruct.name); + } + + javaInteraceLookups.push(javaSuperClass); + javaSuperClass = javaSuperClass.getSuperclass(); + } + } + + // adds all super interfaces to the inheritance list + while (javaInteraceLookups.isEmpty() == false) { + Class javaInterfaceLookup = javaInteraceLookups.pop(); + + for (Class javaSuperInterface : javaInterfaceLookup.getInterfaces()) { + PainlessClass painlessInterfaceStruct = javaClassesToPainlessStructs.get(javaSuperInterface); + + if (painlessInterfaceStruct != null) { + String painlessInterfaceStructName = painlessInterfaceStruct.name; + + if (painlessSuperStructs.contains(painlessInterfaceStructName) == false) { + painlessSuperStructs.add(painlessInterfaceStructName); + } + + for (Class javaPushInterface : javaInterfaceLookup.getInterfaces()) { + javaInteraceLookups.push(javaPushInterface); + } + } + } + } + + // copies methods and fields from super structs to the parent struct + copyStruct(painlessStruct.name, painlessSuperStructs); + + // copies methods and fields from Object into interface types + if (painlessStruct.clazz.isInterface() || (def.class.getSimpleName()).equals(painlessStruct.name)) { + PainlessClass painlessObjectStruct = javaClassesToPainlessStructs.get(Object.class); + + if (painlessObjectStruct != null) { + copyStruct(painlessStruct.name, Collections.singletonList(painlessObjectStruct.name)); + } + } + } + + // precompute runtime classes + for (PainlessClass painlessStruct : javaClassesToPainlessStructs.values()) { + addRuntimeClass(painlessStruct); + } + + // copy all structs to make them unmodifiable for outside users: + for (Map.Entry,PainlessClass> entry : javaClassesToPainlessStructs.entrySet()) { + entry.setValue(entry.getValue().freeze(computeFunctionalInterfaceMethod(entry.getValue()))); + } + } + + private void addStruct(ClassLoader whitelistClassLoader, WhitelistClass whitelistStruct) { + String painlessTypeName = whitelistStruct.javaClassName.replace('$', '.'); + String importedPainlessTypeName = painlessTypeName; + + if (TYPE_NAME_PATTERN.matcher(painlessTypeName).matches() == false) { + throw new IllegalArgumentException("invalid struct type name [" + painlessTypeName + "]"); + } + + int index = whitelistStruct.javaClassName.lastIndexOf('.'); + + if (index != -1) { + importedPainlessTypeName = whitelistStruct.javaClassName.substring(index + 1).replace('$', '.'); + } + + Class javaClass; + + if ("void".equals(whitelistStruct.javaClassName)) javaClass = void.class; + else if ("boolean".equals(whitelistStruct.javaClassName)) javaClass = boolean.class; + else if ("byte".equals(whitelistStruct.javaClassName)) javaClass = byte.class; + else if ("short".equals(whitelistStruct.javaClassName)) javaClass = short.class; + else if ("char".equals(whitelistStruct.javaClassName)) javaClass = char.class; + else if ("int".equals(whitelistStruct.javaClassName)) javaClass = int.class; + else if ("long".equals(whitelistStruct.javaClassName)) javaClass = long.class; + else if ("float".equals(whitelistStruct.javaClassName)) javaClass = float.class; + else if ("double".equals(whitelistStruct.javaClassName)) javaClass = double.class; + else { + try { + javaClass = Class.forName(whitelistStruct.javaClassName, true, whitelistClassLoader); + } catch (ClassNotFoundException cnfe) { + throw new IllegalArgumentException("invalid java class name [" + whitelistStruct.javaClassName + "]" + + " for struct [" + painlessTypeName + "]"); + } + } + + PainlessClass existingStruct = javaClassesToPainlessStructs.get(javaClass); + + if (existingStruct == null) { + PainlessClass struct = new PainlessClass(painlessTypeName, javaClass, org.objectweb.asm.Type.getType(javaClass)); + painlessTypesToJavaClasses.put(painlessTypeName, javaClass); + javaClassesToPainlessStructs.put(javaClass, struct); + } else if (existingStruct.clazz.equals(javaClass) == false) { + throw new IllegalArgumentException("struct [" + painlessTypeName + "] is used to " + + "illegally represent multiple java classes [" + whitelistStruct.javaClassName + "] and " + + "[" + existingStruct.clazz.getName() + "]"); + } + + if (painlessTypeName.equals(importedPainlessTypeName)) { + if (whitelistStruct.onlyFQNJavaClassName == false) { + throw new IllegalArgumentException("must use only_fqn parameter on type [" + painlessTypeName + "] with no package"); + } + } else { + Class importedJavaClass = painlessTypesToJavaClasses.get(importedPainlessTypeName); + + if (importedJavaClass == null) { + if (whitelistStruct.onlyFQNJavaClassName == false) { + if (existingStruct != null) { + throw new IllegalArgumentException("inconsistent only_fqn parameters found for type [" + painlessTypeName + "]"); + } + + painlessTypesToJavaClasses.put(importedPainlessTypeName, javaClass); + } + } else if (importedJavaClass.equals(javaClass) == false) { + throw new IllegalArgumentException("imported name [" + painlessTypeName + "] is used to " + + "illegally represent multiple java classes [" + whitelistStruct.javaClassName + "] " + + "and [" + importedJavaClass.getName() + "]"); + } else if (whitelistStruct.onlyFQNJavaClassName) { + throw new IllegalArgumentException("inconsistent only_fqn parameters found for type [" + painlessTypeName + "]"); + } + } + } + + private void addConstructor(String ownerStructName, WhitelistConstructor whitelistConstructor) { + PainlessClass ownerStruct = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(ownerStructName)); + + if (ownerStruct == null) { + throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for constructor with " + + "parameters " + whitelistConstructor.painlessParameterTypeNames); + } + + List> painlessParametersTypes = new ArrayList<>(whitelistConstructor.painlessParameterTypeNames.size()); + Class[] javaClassParameters = new Class[whitelistConstructor.painlessParameterTypeNames.size()]; + + for (int parameterCount = 0; parameterCount < whitelistConstructor.painlessParameterTypeNames.size(); ++parameterCount) { + String painlessParameterTypeName = whitelistConstructor.painlessParameterTypeNames.get(parameterCount); + + try { + Class painlessParameterClass = getJavaClassFromPainlessType(painlessParameterTypeName); + + painlessParametersTypes.add(painlessParameterClass); + javaClassParameters[parameterCount] = PainlessLookup.defClassToObjectClass(painlessParameterClass); + } catch (IllegalArgumentException iae) { + throw new IllegalArgumentException("struct not defined for constructor parameter [" + painlessParameterTypeName + "] " + + "with owner struct [" + ownerStructName + "] and constructor parameters " + + whitelistConstructor.painlessParameterTypeNames, iae); + } + } + + java.lang.reflect.Constructor javaConstructor; + + try { + javaConstructor = ownerStruct.clazz.getConstructor(javaClassParameters); + } catch (NoSuchMethodException exception) { + throw new IllegalArgumentException("constructor not defined for owner struct [" + ownerStructName + "] " + + " with constructor parameters " + whitelistConstructor.painlessParameterTypeNames, exception); + } + + PainlessMethodKey painlessMethodKey = new PainlessMethodKey("", whitelistConstructor.painlessParameterTypeNames.size()); + PainlessMethod painlessConstructor = ownerStruct.constructors.get(painlessMethodKey); + + if (painlessConstructor == null) { + org.objectweb.asm.commons.Method asmConstructor = org.objectweb.asm.commons.Method.getMethod(javaConstructor); + MethodHandle javaHandle; + + try { + javaHandle = MethodHandles.publicLookup().in(ownerStruct.clazz).unreflectConstructor(javaConstructor); + } catch (IllegalAccessException exception) { + throw new IllegalArgumentException("constructor not defined for owner struct [" + ownerStructName + "] " + + " with constructor parameters " + whitelistConstructor.painlessParameterTypeNames); + } + + painlessConstructor = methodCache.computeIfAbsent(buildMethodCacheKey(ownerStruct.name, "", painlessParametersTypes), + key -> new PainlessMethod("", ownerStruct, null, void.class, painlessParametersTypes, + asmConstructor, javaConstructor.getModifiers(), javaHandle)); + ownerStruct.constructors.put(painlessMethodKey, painlessConstructor); + } else if (painlessConstructor.arguments.equals(painlessParametersTypes) == false){ + throw new IllegalArgumentException( + "illegal duplicate constructors [" + painlessMethodKey + "] found within the struct [" + ownerStruct.name + "] " + + "with parameters " + painlessParametersTypes + " and " + painlessConstructor.arguments); + } + } + + private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName, WhitelistMethod whitelistMethod) { + PainlessClass ownerStruct = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(ownerStructName)); + + if (ownerStruct == null) { + throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for method with " + + "name [" + whitelistMethod.javaMethodName + "] and parameters " + whitelistMethod.painlessParameterTypeNames); + } + + if (TYPE_NAME_PATTERN.matcher(whitelistMethod.javaMethodName).matches() == false) { + throw new IllegalArgumentException("invalid method name" + + " [" + whitelistMethod.javaMethodName + "] for owner struct [" + ownerStructName + "]."); + } + + Class javaAugmentedClass; + + if (whitelistMethod.javaAugmentedClassName != null) { + try { + javaAugmentedClass = Class.forName(whitelistMethod.javaAugmentedClassName, true, whitelistClassLoader); + } catch (ClassNotFoundException cnfe) { + throw new IllegalArgumentException("augmented class [" + whitelistMethod.javaAugmentedClassName + "] " + + "not found for method with name [" + whitelistMethod.javaMethodName + "] " + + "and parameters " + whitelistMethod.painlessParameterTypeNames, cnfe); + } + } else { + javaAugmentedClass = null; + } + + int augmentedOffset = javaAugmentedClass == null ? 0 : 1; + + List> painlessParametersTypes = new ArrayList<>(whitelistMethod.painlessParameterTypeNames.size()); + Class[] javaClassParameters = new Class[whitelistMethod.painlessParameterTypeNames.size() + augmentedOffset]; + + if (javaAugmentedClass != null) { + javaClassParameters[0] = ownerStruct.clazz; + } + + for (int parameterCount = 0; parameterCount < whitelistMethod.painlessParameterTypeNames.size(); ++parameterCount) { + String painlessParameterTypeName = whitelistMethod.painlessParameterTypeNames.get(parameterCount); + + try { + Class painlessParameterClass = getJavaClassFromPainlessType(painlessParameterTypeName); + + painlessParametersTypes.add(painlessParameterClass); + javaClassParameters[parameterCount + augmentedOffset] = PainlessLookup.defClassToObjectClass(painlessParameterClass); + } catch (IllegalArgumentException iae) { + throw new IllegalArgumentException("struct not defined for method parameter [" + painlessParameterTypeName + "] " + + "with owner struct [" + ownerStructName + "] and method with name [" + whitelistMethod.javaMethodName + "] " + + "and parameters " + whitelistMethod.painlessParameterTypeNames, iae); + } + } + + Class javaImplClass = javaAugmentedClass == null ? ownerStruct.clazz : javaAugmentedClass; + java.lang.reflect.Method javaMethod; + + try { + javaMethod = javaImplClass.getMethod(whitelistMethod.javaMethodName, javaClassParameters); + } catch (NoSuchMethodException nsme) { + throw new IllegalArgumentException("method with name [" + whitelistMethod.javaMethodName + "] " + + "and parameters " + whitelistMethod.painlessParameterTypeNames + " not found for class [" + + javaImplClass.getName() + "]", nsme); + } + + Class painlessReturnClass; + + try { + painlessReturnClass = getJavaClassFromPainlessType(whitelistMethod.painlessReturnTypeName); + } catch (IllegalArgumentException iae) { + throw new IllegalArgumentException("struct not defined for return type [" + whitelistMethod.painlessReturnTypeName + "] " + + "with owner struct [" + ownerStructName + "] and method with name [" + whitelistMethod.javaMethodName + "] " + + "and parameters " + whitelistMethod.painlessParameterTypeNames, iae); + } + + if (javaMethod.getReturnType() != PainlessLookup.defClassToObjectClass(painlessReturnClass)) { + throw new IllegalArgumentException("specified return type class [" + painlessReturnClass + "] " + + "does not match the return type class [" + javaMethod.getReturnType() + "] for the " + + "method with name [" + whitelistMethod.javaMethodName + "] " + + "and parameters " + whitelistMethod.painlessParameterTypeNames); + } + + PainlessMethodKey painlessMethodKey = + new PainlessMethodKey(whitelistMethod.javaMethodName, whitelistMethod.painlessParameterTypeNames.size()); + + if (javaAugmentedClass == null && Modifier.isStatic(javaMethod.getModifiers())) { + PainlessMethod painlessMethod = ownerStruct.staticMethods.get(painlessMethodKey); + + if (painlessMethod == null) { + org.objectweb.asm.commons.Method asmMethod = org.objectweb.asm.commons.Method.getMethod(javaMethod); + MethodHandle javaMethodHandle; + + try { + javaMethodHandle = MethodHandles.publicLookup().in(javaImplClass).unreflect(javaMethod); + } catch (IllegalAccessException exception) { + throw new IllegalArgumentException("method handle not found for method with name " + + "[" + whitelistMethod.javaMethodName + "] and parameters " + whitelistMethod.painlessParameterTypeNames); + } + + painlessMethod = methodCache.computeIfAbsent( + buildMethodCacheKey(ownerStruct.name, whitelistMethod.javaMethodName, painlessParametersTypes), + key -> new PainlessMethod(whitelistMethod.javaMethodName, ownerStruct, null, painlessReturnClass, + painlessParametersTypes, asmMethod, javaMethod.getModifiers(), javaMethodHandle)); + ownerStruct.staticMethods.put(painlessMethodKey, painlessMethod); + } else if ((painlessMethod.name.equals(whitelistMethod.javaMethodName) && painlessMethod.rtn == painlessReturnClass && + painlessMethod.arguments.equals(painlessParametersTypes)) == false) { + throw new IllegalArgumentException("illegal duplicate static methods [" + painlessMethodKey + "] " + + "found within the struct [" + ownerStruct.name + "] with name [" + whitelistMethod.javaMethodName + "], " + + "return types [" + painlessReturnClass + "] and [" + painlessMethod.rtn + "], " + + "and parameters " + painlessParametersTypes + " and " + painlessMethod.arguments); + } + } else { + PainlessMethod painlessMethod = ownerStruct.methods.get(painlessMethodKey); + + if (painlessMethod == null) { + org.objectweb.asm.commons.Method asmMethod = org.objectweb.asm.commons.Method.getMethod(javaMethod); + MethodHandle javaMethodHandle; + + try { + javaMethodHandle = MethodHandles.publicLookup().in(javaImplClass).unreflect(javaMethod); + } catch (IllegalAccessException exception) { + throw new IllegalArgumentException("method handle not found for method with name " + + "[" + whitelistMethod.javaMethodName + "] and parameters " + whitelistMethod.painlessParameterTypeNames); + } + + painlessMethod = methodCache.computeIfAbsent( + buildMethodCacheKey(ownerStruct.name, whitelistMethod.javaMethodName, painlessParametersTypes), + key -> new PainlessMethod(whitelistMethod.javaMethodName, ownerStruct, javaAugmentedClass, painlessReturnClass, + painlessParametersTypes, asmMethod, javaMethod.getModifiers(), javaMethodHandle)); + ownerStruct.methods.put(painlessMethodKey, painlessMethod); + } else if ((painlessMethod.name.equals(whitelistMethod.javaMethodName) && painlessMethod.rtn.equals(painlessReturnClass) && + painlessMethod.arguments.equals(painlessParametersTypes)) == false) { + throw new IllegalArgumentException("illegal duplicate member methods [" + painlessMethodKey + "] " + + "found within the struct [" + ownerStruct.name + "] with name [" + whitelistMethod.javaMethodName + "], " + + "return types [" + painlessReturnClass + "] and [" + painlessMethod.rtn + "], " + + "and parameters " + painlessParametersTypes + " and " + painlessMethod.arguments); + } + } + } + + private void addField(String ownerStructName, WhitelistField whitelistField) { + PainlessClass ownerStruct = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(ownerStructName)); + + if (ownerStruct == null) { + throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for method with " + + "name [" + whitelistField.javaFieldName + "] and type " + whitelistField.painlessFieldTypeName); + } + + if (TYPE_NAME_PATTERN.matcher(whitelistField.javaFieldName).matches() == false) { + throw new IllegalArgumentException("invalid field name " + + "[" + whitelistField.painlessFieldTypeName + "] for owner struct [" + ownerStructName + "]."); + } + + java.lang.reflect.Field javaField; + + try { + javaField = ownerStruct.clazz.getField(whitelistField.javaFieldName); + } catch (NoSuchFieldException exception) { + throw new IllegalArgumentException("field [" + whitelistField.javaFieldName + "] " + + "not found for class [" + ownerStruct.clazz.getName() + "]."); + } + + Class painlessFieldClass; + + try { + painlessFieldClass = getJavaClassFromPainlessType(whitelistField.painlessFieldTypeName); + } catch (IllegalArgumentException iae) { + throw new IllegalArgumentException("struct not defined for return type [" + whitelistField.painlessFieldTypeName + "] " + + "with owner struct [" + ownerStructName + "] and field with name [" + whitelistField.javaFieldName + "]", iae); + } + + if (Modifier.isStatic(javaField.getModifiers())) { + if (Modifier.isFinal(javaField.getModifiers()) == false) { + throw new IllegalArgumentException("static [" + whitelistField.javaFieldName + "] " + + "with owner struct [" + ownerStruct.name + "] is not final"); + } + + PainlessField painlessField = ownerStruct.staticMembers.get(whitelistField.javaFieldName); + + if (painlessField == null) { + painlessField = fieldCache.computeIfAbsent( + buildFieldCacheKey(ownerStruct.name, whitelistField.javaFieldName, painlessFieldClass.getName()), + key -> new PainlessField(whitelistField.javaFieldName, javaField.getName(), + ownerStruct, painlessFieldClass, javaField.getModifiers(), null, null)); + ownerStruct.staticMembers.put(whitelistField.javaFieldName, painlessField); + } else if (painlessField.clazz != painlessFieldClass) { + throw new IllegalArgumentException("illegal duplicate static fields [" + whitelistField.javaFieldName + "] " + + "found within the struct [" + ownerStruct.name + "] with type [" + whitelistField.painlessFieldTypeName + "]"); + } + } else { + MethodHandle javaMethodHandleGetter; + MethodHandle javaMethodHandleSetter; + + try { + if (Modifier.isStatic(javaField.getModifiers()) == false) { + javaMethodHandleGetter = MethodHandles.publicLookup().unreflectGetter(javaField); + javaMethodHandleSetter = MethodHandles.publicLookup().unreflectSetter(javaField); + } else { + javaMethodHandleGetter = null; + javaMethodHandleSetter = null; + } + } catch (IllegalAccessException exception) { + throw new IllegalArgumentException("getter/setter [" + whitelistField.javaFieldName + "]" + + " not found for class [" + ownerStruct.clazz.getName() + "]."); + } + + PainlessField painlessField = ownerStruct.members.get(whitelistField.javaFieldName); + + if (painlessField == null) { + painlessField = fieldCache.computeIfAbsent( + buildFieldCacheKey(ownerStruct.name, whitelistField.javaFieldName, painlessFieldClass.getName()), + key -> new PainlessField(whitelistField.javaFieldName, javaField.getName(), + ownerStruct, painlessFieldClass, javaField.getModifiers(), javaMethodHandleGetter, javaMethodHandleSetter)); + ownerStruct.members.put(whitelistField.javaFieldName, painlessField); + } else if (painlessField.clazz != painlessFieldClass) { + throw new IllegalArgumentException("illegal duplicate member fields [" + whitelistField.javaFieldName + "] " + + "found within the struct [" + ownerStruct.name + "] with type [" + whitelistField.painlessFieldTypeName + "]"); + } + } + } + + private void copyStruct(String struct, List children) { + final PainlessClass owner = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(struct)); + + if (owner == null) { + throw new IllegalArgumentException("Owner struct [" + struct + "] not defined for copy."); + } + + for (int count = 0; count < children.size(); ++count) { + final PainlessClass child = javaClassesToPainlessStructs.get(painlessTypesToJavaClasses.get(children.get(count))); + + if (child == null) { + throw new IllegalArgumentException("Child struct [" + children.get(count) + "]" + + " not defined for copy to owner struct [" + owner.name + "]."); + } + + if (!child.clazz.isAssignableFrom(owner.clazz)) { + throw new ClassCastException("Child struct [" + child.name + "]" + + " is not a super type of owner struct [" + owner.name + "] in copy."); + } + + for (Map.Entry kvPair : child.methods.entrySet()) { + PainlessMethodKey methodKey = kvPair.getKey(); + PainlessMethod method = kvPair.getValue(); + if (owner.methods.get(methodKey) == null) { + // TODO: some of these are no longer valid or outright don't work + // TODO: since classes may not come from the Painless classloader + // TODO: and it was dependent on the order of the extends which + // TODO: which no longer exists since this is generated automatically + // sanity check, look for missing covariant/generic override + /*if (owner.clazz.isInterface() && child.clazz == Object.class) { + // ok + } else if (child.clazz == Spliterator.OfPrimitive.class || child.clazz == PrimitiveIterator.class) { + // ok, we rely on generics erasure for these (its guaranteed in the javadocs though!!!!) + } else if (Constants.JRE_IS_MINIMUM_JAVA9 && owner.clazz == LocalDate.class) { + // ok, java 9 added covariant override for LocalDate.getEra() to return IsoEra: + // https://bugs.openjdk.java.net/browse/JDK-8072746 + } else { + try { + // TODO: we *have* to remove all these public members and use getter methods to encapsulate! + final Class impl; + final Class arguments[]; + if (method.augmentation != null) { + impl = method.augmentation; + arguments = new Class[method.arguments.size() + 1]; + arguments[0] = method.owner.clazz; + for (int i = 0; i < method.arguments.size(); i++) { + arguments[i + 1] = method.arguments.get(i).clazz; + } + } else { + impl = owner.clazz; + arguments = new Class[method.arguments.size()]; + for (int i = 0; i < method.arguments.size(); i++) { + arguments[i] = method.arguments.get(i).clazz; + } + } + java.lang.reflect.Method m = impl.getMethod(method.method.getName(), arguments); + if (m.getReturnType() != method.rtn.clazz) { + throw new IllegalStateException("missing covariant override for: " + m + " in " + owner.name); + } + if (m.isBridge() && !Modifier.isVolatile(method.modifiers)) { + // its a bridge in the destination, but not in the source, but it might still be ok, check generics: + java.lang.reflect.Method source = child.clazz.getMethod(method.method.getName(), arguments); + if (!Arrays.equals(source.getGenericParameterTypes(), source.getParameterTypes())) { + throw new IllegalStateException("missing generic override for: " + m + " in " + owner.name); + } + } + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + }*/ + owner.methods.put(methodKey, method); + } + } + + for (PainlessField field : child.members.values()) { + if (owner.members.get(field.name) == null) { + owner.members.put(field.name, + new PainlessField(field.name, field.javaName, owner, field.clazz, field.modifiers, field.getter, field.setter)); + } + } + } + } + + /** + * Precomputes a more efficient structure for dynamic method/field access. + */ + private void addRuntimeClass(final PainlessClass struct) { + // add all getters/setters + for (Map.Entry method : struct.methods.entrySet()) { + String name = method.getKey().name; + PainlessMethod m = method.getValue(); + + if (m.arguments.size() == 0 && + name.startsWith("get") && + name.length() > 3 && + Character.isUpperCase(name.charAt(3))) { + StringBuilder newName = new StringBuilder(); + newName.append(Character.toLowerCase(name.charAt(3))); + newName.append(name.substring(4)); + struct.getters.putIfAbsent(newName.toString(), m.handle); + } else if (m.arguments.size() == 0 && + name.startsWith("is") && + name.length() > 2 && + Character.isUpperCase(name.charAt(2))) { + StringBuilder newName = new StringBuilder(); + newName.append(Character.toLowerCase(name.charAt(2))); + newName.append(name.substring(3)); + struct.getters.putIfAbsent(newName.toString(), m.handle); + } + + if (m.arguments.size() == 1 && + name.startsWith("set") && + name.length() > 3 && + Character.isUpperCase(name.charAt(3))) { + StringBuilder newName = new StringBuilder(); + newName.append(Character.toLowerCase(name.charAt(3))); + newName.append(name.substring(4)); + struct.setters.putIfAbsent(newName.toString(), m.handle); + } + } + + // add all members + for (Map.Entry member : struct.members.entrySet()) { + struct.getters.put(member.getKey(), member.getValue().getter); + struct.setters.put(member.getKey(), member.getValue().setter); + } + } + + /** computes the functional interface method for a class, or returns null */ + private PainlessMethod computeFunctionalInterfaceMethod(PainlessClass clazz) { + if (!clazz.clazz.isInterface()) { + return null; + } + // if its marked with this annotation, we fail if the conditions don't hold (means whitelist bug) + // otherwise, this annotation is pretty useless. + boolean hasAnnotation = clazz.clazz.isAnnotationPresent(FunctionalInterface.class); + List methods = new ArrayList<>(); + for (java.lang.reflect.Method m : clazz.clazz.getMethods()) { + // default interface methods don't count + if (m.isDefault()) { + continue; + } + // static methods don't count + if (Modifier.isStatic(m.getModifiers())) { + continue; + } + // if its from Object, it doesn't count + try { + Object.class.getMethod(m.getName(), m.getParameterTypes()); + continue; + } catch (ReflectiveOperationException e) { + // it counts + } + methods.add(m); + } + if (methods.size() != 1) { + if (hasAnnotation) { + throw new IllegalArgumentException("Class: " + clazz.name + + " is marked with FunctionalInterface but doesn't fit the bill: " + methods); + } + return null; + } + // inspect the one method found from the reflection API, it should match the whitelist! + java.lang.reflect.Method oneMethod = methods.get(0); + PainlessMethod painless = clazz.methods.get(new PainlessMethodKey(oneMethod.getName(), oneMethod.getParameterCount())); + if (painless == null || painless.method.equals(org.objectweb.asm.commons.Method.getMethod(oneMethod)) == false) { + throw new IllegalArgumentException("Class: " + clazz.name + " is functional but the functional " + + "method is not whitelisted!"); + } + return painless; + } + + public Class getJavaClassFromPainlessType(String painlessType) { + Class javaClass = painlessTypesToJavaClasses.get(painlessType); + + if (javaClass != null) { + return javaClass; + } + int arrayDimensions = 0; + int arrayIndex = painlessType.indexOf('['); + + if (arrayIndex != -1) { + int length = painlessType.length(); + + while (arrayIndex < length) { + if (painlessType.charAt(arrayIndex) == '[' && ++arrayIndex < length && painlessType.charAt(arrayIndex++) == ']') { + ++arrayDimensions; + } else { + throw new IllegalArgumentException("invalid painless type [" + painlessType + "]."); + } + } + + painlessType = painlessType.substring(0, painlessType.indexOf('[')); + javaClass = painlessTypesToJavaClasses.get(painlessType); + + char braces[] = new char[arrayDimensions]; + Arrays.fill(braces, '['); + String descriptor = new String(braces); + + if (javaClass == boolean.class) { + descriptor += "Z"; + } else if (javaClass == byte.class) { + descriptor += "B"; + } else if (javaClass == short.class) { + descriptor += "S"; + } else if (javaClass == char.class) { + descriptor += "C"; + } else if (javaClass == int.class) { + descriptor += "I"; + } else if (javaClass == long.class) { + descriptor += "J"; + } else if (javaClass == float.class) { + descriptor += "F"; + } else if (javaClass == double.class) { + descriptor += "D"; + } else { + descriptor += "L" + javaClass.getName() + ";"; + } + + try { + return Class.forName(descriptor); + } catch (ClassNotFoundException cnfe) { + throw new IllegalStateException("invalid painless type [" + painlessType + "]", cnfe); + } + } + + throw new IllegalArgumentException("invalid painless type [" + painlessType + "]"); + } + + public PainlessLookup build() { + return new PainlessLookup(painlessTypesToJavaClasses, javaClassesToPainlessStructs); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/def.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/def.java new file mode 100644 index 0000000000000..4336236be3f12 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/def.java @@ -0,0 +1,28 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.painless.lookup; + +/** Marker class for def type to be used during type analysis. */ +public final class def { + + private def() { + + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java index dda246b5f6cda..a0a29ed59ddde 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java @@ -23,7 +23,7 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.lookup.PainlessCast; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java index 46fbeefd6f557..422300072dc2f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java @@ -22,7 +22,7 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java index a3e1b4bde6a86..c0345b6308c3e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java @@ -22,7 +22,7 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java index c0fccab8e8a8e..806204d051ae0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java @@ -22,7 +22,7 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java index a7b7a41fe051a..8977f4f0ef329 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java @@ -22,7 +22,7 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java index 518f1953525a6..820cce685edcd 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java @@ -21,7 +21,7 @@ import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.PainlessMethodKey; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java index 45158aedcf787..b6c7fb80af95f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java @@ -21,7 +21,7 @@ import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.PainlessMethodKey; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java index 8e293556eac01..3a5102ebdc99c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java @@ -22,7 +22,7 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java index ec7d0f6d7bb7a..5b282abdce9fa 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java @@ -20,7 +20,7 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java index 12ff483248367..f23ae9f188704 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java @@ -23,7 +23,7 @@ import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.PainlessMethodKey; import org.elasticsearch.painless.lookup.PainlessClass; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java index 8d27162fc367b..78a18b91ab2c6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java @@ -23,7 +23,7 @@ import org.elasticsearch.painless.lookup.PainlessField; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.PainlessClass; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java index 8e30d43432953..ccbc25db4f25e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java @@ -20,7 +20,7 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java index 0882f19177006..a9021000e2dad 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java @@ -20,7 +20,7 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java index 41fcf563d241c..1c081c9422ecb 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java @@ -20,7 +20,7 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java index e7d18ece0590d..c402d8982d89e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java @@ -20,7 +20,7 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java index faee2ed74a6d0..cfc87536b6b7b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java @@ -25,7 +25,7 @@ import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.PainlessMethodKey; -import org.elasticsearch.painless.lookup.PainlessLookup.def; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/BaseClassTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/BaseClassTests.java index 78e5814e963f7..c0e0bd7ed9d05 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/BaseClassTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/BaseClassTests.java @@ -24,6 +24,7 @@ import java.util.Map; import org.elasticsearch.painless.lookup.PainlessLookup; +import org.elasticsearch.painless.lookup.PainlessLookupBuilder; import org.elasticsearch.painless.spi.Whitelist; import static java.util.Collections.emptyMap; @@ -37,7 +38,7 @@ */ public class BaseClassTests extends ScriptTestCase { - private final PainlessLookup painlessLookup = new PainlessLookup(Whitelist.BASE_WHITELISTS); + private final PainlessLookup painlessLookup = new PainlessLookupBuilder(Whitelist.BASE_WHITELISTS).build(); public abstract static class Gets { diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DebugTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DebugTests.java index 987eef31eeeaf..7edc90bb0a001 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DebugTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DebugTests.java @@ -23,6 +23,7 @@ import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.painless.lookup.PainlessLookup; +import org.elasticsearch.painless.lookup.PainlessLookupBuilder; import org.elasticsearch.painless.spi.Whitelist; import org.elasticsearch.script.ScriptException; @@ -36,7 +37,7 @@ import static org.hamcrest.Matchers.not; public class DebugTests extends ScriptTestCase { - private final PainlessLookup painlessLookup = new PainlessLookup(Whitelist.BASE_WHITELISTS); + private final PainlessLookup painlessLookup = new PainlessLookupBuilder(Whitelist.BASE_WHITELISTS).build(); public void testExplain() { // Debug.explain can explain an object diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/Debugger.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/Debugger.java index 0d5e2748b7b32..59b634629580d 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/Debugger.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/Debugger.java @@ -20,6 +20,7 @@ package org.elasticsearch.painless; import org.elasticsearch.painless.lookup.PainlessLookup; +import org.elasticsearch.painless.lookup.PainlessLookupBuilder; import org.elasticsearch.painless.spi.Whitelist; import org.objectweb.asm.util.Textifier; @@ -40,7 +41,7 @@ static String toString(Class iface, String source, CompilerSettings settings) PrintWriter outputWriter = new PrintWriter(output); Textifier textifier = new Textifier(); try { - new Compiler(iface, new PainlessLookup(Whitelist.BASE_WHITELISTS)) + new Compiler(iface, new PainlessLookupBuilder(Whitelist.BASE_WHITELISTS).build()) .compile("", source, settings, textifier); } catch (RuntimeException e) { textifier.print(outputWriter); diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java index ab4844dd58bd9..07f45ff67c07d 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java @@ -28,11 +28,12 @@ import java.util.HashMap; import org.elasticsearch.painless.lookup.PainlessLookup; +import org.elasticsearch.painless.lookup.PainlessLookupBuilder; import org.elasticsearch.painless.spi.Whitelist; import org.elasticsearch.test.ESTestCase; public class DefBootstrapTests extends ESTestCase { - private final PainlessLookup painlessLookup = new PainlessLookup(Whitelist.BASE_WHITELISTS); + private final PainlessLookup painlessLookup = new PainlessLookupBuilder(Whitelist.BASE_WHITELISTS).build(); /** calls toString() on integers, twice */ public void testOneType() throws Throwable { diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/PainlessDocGenerator.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/PainlessDocGenerator.java index 5177d64cbdb06..4426ec0515445 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/PainlessDocGenerator.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/PainlessDocGenerator.java @@ -25,8 +25,11 @@ import org.elasticsearch.common.logging.ESLoggerFactory; import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.lookup.PainlessField; +import org.elasticsearch.painless.lookup.PainlessLookupBuilder; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.PainlessClass; +import org.elasticsearch.painless.spi.Whitelist; + import java.io.IOException; import java.io.PrintStream; import java.lang.reflect.Modifier; @@ -49,7 +52,7 @@ */ public class PainlessDocGenerator { - private static final PainlessLookup PAINLESS_LOOKUP = new PainlessLookup(BASE_WHITELISTS); + private static final PainlessLookup PAINLESS_LOOKUP = new PainlessLookupBuilder(Whitelist.BASE_WHITELISTS).build(); private static final Logger logger = ESLoggerFactory.getLogger(PainlessDocGenerator.class); private static final Comparator FIELD_NAME = comparing(f -> f.name); private static final Comparator METHOD_NAME = comparing(m -> m.name); diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptTestCase.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptTestCase.java index 1a4770e560a7e..eebf1d701ee32 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptTestCase.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptTestCase.java @@ -25,6 +25,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.painless.antlr.Walker; import org.elasticsearch.painless.lookup.PainlessLookup; +import org.elasticsearch.painless.lookup.PainlessLookupBuilder; import org.elasticsearch.painless.spi.Whitelist; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.ScriptContext; @@ -91,7 +92,7 @@ public Object exec(String script, Map vars, boolean picky) { public Object exec(String script, Map vars, Map compileParams, Scorer scorer, boolean picky) { // test for ambiguity errors before running the actual script if picky is true if (picky) { - PainlessLookup painlessLookup = new PainlessLookup(Whitelist.BASE_WHITELISTS); + PainlessLookup painlessLookup = new PainlessLookupBuilder(Whitelist.BASE_WHITELISTS).build(); ScriptClassInfo scriptClassInfo = new ScriptClassInfo(painlessLookup, GenericElasticsearchScript.class); CompilerSettings pickySettings = new CompilerSettings(); pickySettings.setPicky(true); diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java index 3e9f724743faa..86d365e0fcc7a 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessField; +import org.elasticsearch.painless.lookup.PainlessLookupBuilder; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.PainlessMethodKey; import org.elasticsearch.painless.lookup.PainlessClass; @@ -48,7 +49,7 @@ * Tests {@link Object#toString} implementations on all extensions of {@link ANode}. */ public class NodeToStringTests extends ESTestCase { - private final PainlessLookup painlessLookup = new PainlessLookup(Whitelist.BASE_WHITELISTS); + private final PainlessLookup painlessLookup = new PainlessLookupBuilder(Whitelist.BASE_WHITELISTS).build(); public void testEAssignment() { assertToString( From e22011cd295d8ecf76c2a778f7d2ec7a7c92bb8e Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Fri, 13 Jul 2018 14:05:41 -0700 Subject: [PATCH 2/5] Fix imports. --- .../java/org/elasticsearch/painless/PainlessScriptEngine.java | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java index 6c976f2606e3b..384c36c6adfac 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java @@ -24,7 +24,6 @@ import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.painless.Compiler.Loader; -import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.lookup.PainlessLookupBuilder; import org.elasticsearch.painless.spi.Whitelist; import org.elasticsearch.script.ExecutableScript; From 635fbc413176f13cb47eb52d86afcf49528de086 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Fri, 13 Jul 2018 15:04:28 -0700 Subject: [PATCH 3/5] Fix more imports. --- .../src/test/java/org/elasticsearch/painless/Debugger.java | 1 - .../org/elasticsearch/painless/PainlessDocGenerator.java | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/Debugger.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/Debugger.java index 59b634629580d..73adf92779d48 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/Debugger.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/Debugger.java @@ -19,7 +19,6 @@ package org.elasticsearch.painless; -import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.lookup.PainlessLookupBuilder; import org.elasticsearch.painless.spi.Whitelist; import org.objectweb.asm.util.Textifier; diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/PainlessDocGenerator.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/PainlessDocGenerator.java index 4426ec0515445..5e8e6ad47d813 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/PainlessDocGenerator.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/PainlessDocGenerator.java @@ -20,14 +20,14 @@ package org.elasticsearch.painless; import org.apache.logging.log4j.Logger; -import org.elasticsearch.core.internal.io.IOUtils; import org.elasticsearch.common.io.PathUtils; import org.elasticsearch.common.logging.ESLoggerFactory; -import org.elasticsearch.painless.lookup.PainlessLookup; +import org.elasticsearch.core.internal.io.IOUtils; +import org.elasticsearch.painless.lookup.PainlessClass; import org.elasticsearch.painless.lookup.PainlessField; +import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.lookup.PainlessLookupBuilder; import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.PainlessClass; import org.elasticsearch.painless.spi.Whitelist; import java.io.IOException; @@ -45,7 +45,6 @@ import static java.util.Comparator.comparing; import static java.util.stream.Collectors.toList; -import static org.elasticsearch.painless.spi.Whitelist.BASE_WHITELISTS; /** * Generates an API reference from the method and type whitelists in {@link PainlessLookup}. From 801e5dbab6d72a3a185dbbe14a6e65810f4e1975 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Fri, 13 Jul 2018 16:25:41 -0700 Subject: [PATCH 4/5] Painless: Move several shared static methods into PainlessLookupUtility. --- .../painless/AnalyzerCaster.java | 7 +- .../java/org/elasticsearch/painless/Def.java | 7 +- .../elasticsearch/painless/FunctionRef.java | 3 +- .../org/elasticsearch/painless/Locals.java | 5 +- .../painless/ScriptClassInfo.java | 3 +- .../painless/antlr/EnhancedPainlessLexer.java | 2 +- .../elasticsearch/painless/antlr/Walker.java | 2 +- .../painless/lookup/PainlessLookup.java | 208 +------------ .../lookup/PainlessLookupBuilder.java | 69 +---- .../lookup/PainlessLookupUtility.java | 280 ++++++++++++++++++ .../painless/lookup/PainlessMethod.java | 14 +- .../painless/node/AExpression.java | 6 +- .../painless/node/EAssignment.java | 4 +- .../elasticsearch/painless/node/EBinary.java | 37 ++- .../painless/node/ECallLocal.java | 4 +- .../painless/node/ECapturingFunctionRef.java | 11 +- .../elasticsearch/painless/node/ECast.java | 6 +- .../elasticsearch/painless/node/EComp.java | 28 +- .../painless/node/EFunctionRef.java | 10 +- .../painless/node/EInstanceof.java | 7 +- .../elasticsearch/painless/node/ELambda.java | 20 +- .../painless/node/EListInit.java | 6 +- .../elasticsearch/painless/node/EMapInit.java | 6 +- .../elasticsearch/painless/node/ENewObj.java | 4 +- .../elasticsearch/painless/node/ENull.java | 4 +- .../elasticsearch/painless/node/EUnary.java | 15 +- .../elasticsearch/painless/node/PBrace.java | 8 +- .../painless/node/PCallInvoke.java | 12 +- .../elasticsearch/painless/node/PField.java | 16 +- .../painless/node/PSubCallInvoke.java | 2 +- .../painless/node/PSubDefArray.java | 2 +- .../painless/node/PSubDefCall.java | 2 +- .../painless/node/PSubDefField.java | 2 +- .../painless/node/PSubField.java | 8 +- .../painless/node/PSubListShortcut.java | 4 +- .../painless/node/PSubMapShortcut.java | 4 +- .../painless/node/PSubShortcut.java | 2 +- .../elasticsearch/painless/node/SEach.java | 8 +- .../painless/node/SFunction.java | 11 +- .../elasticsearch/painless/node/SSource.java | 6 +- .../painless/node/SSubEachArray.java | 6 +- .../painless/node/SSubEachIterable.java | 16 +- 42 files changed, 467 insertions(+), 410 deletions(-) create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java index 457ec82a5e429..6cfc7ff6ebfd2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java @@ -19,8 +19,8 @@ package org.elasticsearch.painless; -import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.lookup.PainlessCast; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; import java.util.Objects; @@ -465,8 +465,9 @@ public static PainlessCast getLegalCast(Location location, Class actual, Clas (actual.isAssignableFrom(expected) && explicit)) { return PainlessCast.standard(actual, expected, explicit); } else { - throw location.createError(new ClassCastException( - "Cannot cast from [" + PainlessLookup.ClassToName(actual) + "] to [" + PainlessLookup.ClassToName(expected) + "].")); + throw location.createError(new ClassCastException("Cannot cast from " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(actual) + "] to " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(expected) + "].")); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java index f006b57f46bad..78db712d183d2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java @@ -19,9 +19,10 @@ package org.elasticsearch.painless; +import org.elasticsearch.painless.lookup.PainlessClass; import org.elasticsearch.painless.lookup.PainlessLookup; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.PainlessClass; import org.elasticsearch.painless.lookup.PainlessMethodKey; import java.lang.invoke.CallSite; @@ -302,7 +303,7 @@ static MethodHandle lookupMethod(PainlessLookup painlessLookup, MethodHandles.Lo nestedType, 0, DefBootstrap.REFERENCE, - PainlessLookup.ClassToName(interfaceType)); + PainlessLookupUtility.anyTypeToPainlessTypeName(interfaceType)); filter = nested.dynamicInvoker(); } else { throw new AssertionError(); @@ -347,7 +348,7 @@ private static MethodHandle lookupReferenceInternal(PainlessLookup painlessLooku PainlessMethod interfaceMethod = painlessLookup.getPainlessStructFromJavaClass(clazz).functionalMethod; if (interfaceMethod == null) { throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " + - "to [" + PainlessLookup.ClassToName(clazz) + "], not a functional interface"); + "to [" + PainlessLookupUtility.anyTypeToPainlessTypeName(clazz) + "], not a functional interface"); } int arity = interfaceMethod.arguments.size() + captures.length; final MethodHandle handle; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java index 6ab7292c7f65b..9e72dc2c83576 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java @@ -21,6 +21,7 @@ import org.elasticsearch.painless.lookup.PainlessClass; import org.elasticsearch.painless.lookup.PainlessLookup; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.PainlessMethodKey; import org.objectweb.asm.Type; @@ -168,7 +169,7 @@ private static PainlessMethod lookup(PainlessLookup painlessLookup, Class exp PainlessMethod method = painlessLookup.getPainlessStructFromJavaClass(expected).functionalMethod; if (method == null) { throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " + - "to [" + PainlessLookup.ClassToName(expected) + "], not a functional interface"); + "to [" + PainlessLookupUtility.anyTypeToPainlessTypeName(expected) + "], not a functional interface"); } // lookup requested method diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Locals.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Locals.java index bab1b7942d657..e797740fed185 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Locals.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Locals.java @@ -19,10 +19,11 @@ package org.elasticsearch.painless; +import org.elasticsearch.painless.ScriptClassInfo.MethodArgument; import org.elasticsearch.painless.lookup.PainlessLookup; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.PainlessMethodKey; -import org.elasticsearch.painless.ScriptClassInfo.MethodArgument; import java.util.Arrays; import java.util.Collection; @@ -292,7 +293,7 @@ public int getSlot() { @Override public String toString() { StringBuilder b = new StringBuilder(); - b.append("Variable[type=").append(PainlessLookup.ClassToName(clazz)); + b.append("Variable[type=").append(PainlessLookupUtility.anyTypeToPainlessTypeName(clazz)); b.append(",name=").append(name); b.append(",slot=").append(slot); if (readonly) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java index df43dba7b3476..ff2061a9a4b92 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptClassInfo.java @@ -20,6 +20,7 @@ package org.elasticsearch.painless; import org.elasticsearch.painless.lookup.PainlessLookup; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import java.lang.invoke.MethodType; import java.lang.reflect.Field; @@ -182,7 +183,7 @@ private MethodArgument methodArgument(PainlessLookup painlessLookup, Class cl private static Class definitionTypeForClass(PainlessLookup painlessLookup, Class type, Function, String> unknownErrorMessageSource) { - type = PainlessLookup.ObjectClassTodefClass(type); + type = PainlessLookupUtility.javaObjectTypeToPainlessDefType(type); Class componentType = type; while (componentType.isArray()) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/EnhancedPainlessLexer.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/EnhancedPainlessLexer.java index e6c5da057980f..f1db35636b41c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/EnhancedPainlessLexer.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/EnhancedPainlessLexer.java @@ -23,8 +23,8 @@ import org.antlr.v4.runtime.LexerNoViableAltException; import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.misc.Interval; -import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.lookup.PainlessLookup; /** * A lexer that is customized for painless. It: diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java index e2742ffb9936d..067319c942c98 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java @@ -29,7 +29,6 @@ import org.antlr.v4.runtime.atn.PredictionMode; import org.antlr.v4.runtime.tree.TerminalNode; import org.elasticsearch.painless.CompilerSettings; -import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.Operation; @@ -107,6 +106,7 @@ import org.elasticsearch.painless.antlr.PainlessParser.TryContext; import org.elasticsearch.painless.antlr.PainlessParser.VariableContext; import org.elasticsearch.painless.antlr.PainlessParser.WhileContext; +import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.node.AExpression; import org.elasticsearch.painless.node.ANode; import org.elasticsearch.painless.node.AStatement; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookup.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookup.java index feeaf4d34bcdd..6111d12317b18 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookup.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookup.java @@ -19,7 +19,6 @@ package org.elasticsearch.painless.lookup; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Map; @@ -30,154 +29,6 @@ */ public final class PainlessLookup { - public static Class getBoxedType(Class clazz) { - if (clazz == boolean.class) { - return Boolean.class; - } else if (clazz == byte.class) { - return Byte.class; - } else if (clazz == short.class) { - return Short.class; - } else if (clazz == char.class) { - return Character.class; - } else if (clazz == int.class) { - return Integer.class; - } else if (clazz == long.class) { - return Long.class; - } else if (clazz == float.class) { - return Float.class; - } else if (clazz == double.class) { - return Double.class; - } - - return clazz; - } - - public static Class getUnboxedype(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } - - return clazz; - } - - public static boolean isConstantType(Class clazz) { - return clazz == boolean.class || - clazz == byte.class || - clazz == short.class || - clazz == char.class || - clazz == int.class || - clazz == long.class || - clazz == float.class || - clazz == double.class || - clazz == String.class; - } - - public Class getClassFromBinaryName(String painlessType) { - return painlessTypesToJavaClasses.get(painlessType.replace('$', '.')); - } - - public static Class ObjectClassTodefClass(Class clazz) { - if (clazz.isArray()) { - Class component = clazz.getComponentType(); - int dimensions = 1; - - while (component.isArray()) { - component = component.getComponentType(); - ++dimensions; - } - - if (component == Object.class) { - char[] braces = new char[dimensions]; - Arrays.fill(braces, '['); - - String descriptor = new String(braces) + org.objectweb.asm.Type.getType(def.class).getDescriptor(); - org.objectweb.asm.Type type = org.objectweb.asm.Type.getType(descriptor); - - try { - return Class.forName(type.getInternalName().replace('/', '.')); - } catch (ClassNotFoundException exception) { - throw new IllegalStateException("internal error", exception); - } - } - } else if (clazz == Object.class) { - return def.class; - } - - return clazz; - } - - public static Class defClassToObjectClass(Class clazz) { - if (clazz.isArray()) { - Class component = clazz.getComponentType(); - int dimensions = 1; - - while (component.isArray()) { - component = component.getComponentType(); - ++dimensions; - } - - if (component == def.class) { - char[] braces = new char[dimensions]; - Arrays.fill(braces, '['); - - String descriptor = new String(braces) + org.objectweb.asm.Type.getType(Object.class).getDescriptor(); - org.objectweb.asm.Type type = org.objectweb.asm.Type.getType(descriptor); - - try { - return Class.forName(type.getInternalName().replace('/', '.')); - } catch (ClassNotFoundException exception) { - throw new IllegalStateException("internal error", exception); - } - } - } else if (clazz == def.class) { - return Object.class; - } - - return clazz; - } - - public static String ClassToName(Class clazz) { - if (clazz.isLocalClass() || clazz.isAnonymousClass()) { - return null; - } else if (clazz.isArray()) { - Class component = clazz.getComponentType(); - int dimensions = 1; - - while (component.isArray()) { - component = component.getComponentType(); - ++dimensions; - } - - if (component == def.class) { - StringBuilder builder = new StringBuilder(def.class.getSimpleName()); - - for (int dimension = 0; dimension < dimensions; dimension++) { - builder.append("[]"); - } - - return builder.toString(); - } - } else if (clazz == def.class) { - return def.class.getSimpleName(); - } - - return clazz.getCanonicalName().replace('$', '.'); - } - public Collection getStructs() { return javaClassesToPainlessStructs.values(); } @@ -190,6 +41,10 @@ public Collection getStructs() { this.javaClassesToPainlessStructs = Collections.unmodifiableMap(javaClassesToPainlessStructs); } + public Class getClassFromBinaryName(String painlessType) { + return painlessTypesToJavaClasses.get(painlessType.replace('$', '.')); + } + public boolean isSimplePainlessType(String painlessType) { return painlessTypesToJavaClasses.containsKey(painlessType); } @@ -199,59 +54,6 @@ public PainlessClass getPainlessStructFromJavaClass(Class clazz) { } public Class getJavaClassFromPainlessType(String painlessType) { - Class javaClass = painlessTypesToJavaClasses.get(painlessType); - - if (javaClass != null) { - return javaClass; - } - int arrayDimensions = 0; - int arrayIndex = painlessType.indexOf('['); - - if (arrayIndex != -1) { - int length = painlessType.length(); - - while (arrayIndex < length) { - if (painlessType.charAt(arrayIndex) == '[' && ++arrayIndex < length && painlessType.charAt(arrayIndex++) == ']') { - ++arrayDimensions; - } else { - throw new IllegalArgumentException("invalid painless type [" + painlessType + "]."); - } - } - - painlessType = painlessType.substring(0, painlessType.indexOf('[')); - javaClass = painlessTypesToJavaClasses.get(painlessType); - - char braces[] = new char[arrayDimensions]; - Arrays.fill(braces, '['); - String descriptor = new String(braces); - - if (javaClass == boolean.class) { - descriptor += "Z"; - } else if (javaClass == byte.class) { - descriptor += "B"; - } else if (javaClass == short.class) { - descriptor += "S"; - } else if (javaClass == char.class) { - descriptor += "C"; - } else if (javaClass == int.class) { - descriptor += "I"; - } else if (javaClass == long.class) { - descriptor += "J"; - } else if (javaClass == float.class) { - descriptor += "F"; - } else if (javaClass == double.class) { - descriptor += "D"; - } else { - descriptor += "L" + javaClass.getName() + ";"; - } - - try { - return Class.forName(descriptor); - } catch (ClassNotFoundException cnfe) { - throw new IllegalStateException("invalid painless type [" + painlessType + "]", cnfe); - } - } - - throw new IllegalArgumentException("invalid painless type [" + painlessType + "]"); + return PainlessLookupUtility.painlessTypeNameToPainlessType(painlessType, painlessTypesToJavaClasses); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java index 1dadce318d672..9a5e08d65a754 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java @@ -30,7 +30,6 @@ import java.lang.invoke.MethodHandles; import java.lang.reflect.Modifier; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -279,7 +278,7 @@ private void addConstructor(String ownerStructName, WhitelistConstructor whiteli Class painlessParameterClass = getJavaClassFromPainlessType(painlessParameterTypeName); painlessParametersTypes.add(painlessParameterClass); - javaClassParameters[parameterCount] = PainlessLookup.defClassToObjectClass(painlessParameterClass); + javaClassParameters[parameterCount] = PainlessLookupUtility.painlessDefTypeToJavaObjectType(painlessParameterClass); } catch (IllegalArgumentException iae) { throw new IllegalArgumentException("struct not defined for constructor parameter [" + painlessParameterTypeName + "] " + "with owner struct [" + ownerStructName + "] and constructor parameters " + @@ -364,7 +363,8 @@ private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName, Class painlessParameterClass = getJavaClassFromPainlessType(painlessParameterTypeName); painlessParametersTypes.add(painlessParameterClass); - javaClassParameters[parameterCount + augmentedOffset] = PainlessLookup.defClassToObjectClass(painlessParameterClass); + javaClassParameters[parameterCount + augmentedOffset] = + PainlessLookupUtility.painlessDefTypeToJavaObjectType(painlessParameterClass); } catch (IllegalArgumentException iae) { throw new IllegalArgumentException("struct not defined for method parameter [" + painlessParameterTypeName + "] " + "with owner struct [" + ownerStructName + "] and method with name [" + whitelistMethod.javaMethodName + "] " + @@ -393,7 +393,7 @@ private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName, "and parameters " + whitelistMethod.painlessParameterTypeNames, iae); } - if (javaMethod.getReturnType() != PainlessLookup.defClassToObjectClass(painlessReturnClass)) { + if (javaMethod.getReturnType() != PainlessLookupUtility.painlessDefTypeToJavaObjectType(painlessReturnClass)) { throw new IllegalArgumentException("specified return type class [" + painlessReturnClass + "] " + "does not match the return type class [" + javaMethod.getReturnType() + "] for the " + "method with name [" + whitelistMethod.javaMethodName + "] " + @@ -711,64 +711,11 @@ private PainlessMethod computeFunctionalInterfaceMethod(PainlessClass clazz) { return painless; } - public Class getJavaClassFromPainlessType(String painlessType) { - Class javaClass = painlessTypesToJavaClasses.get(painlessType); - - if (javaClass != null) { - return javaClass; - } - int arrayDimensions = 0; - int arrayIndex = painlessType.indexOf('['); - - if (arrayIndex != -1) { - int length = painlessType.length(); - - while (arrayIndex < length) { - if (painlessType.charAt(arrayIndex) == '[' && ++arrayIndex < length && painlessType.charAt(arrayIndex++) == ']') { - ++arrayDimensions; - } else { - throw new IllegalArgumentException("invalid painless type [" + painlessType + "]."); - } - } - - painlessType = painlessType.substring(0, painlessType.indexOf('[')); - javaClass = painlessTypesToJavaClasses.get(painlessType); - - char braces[] = new char[arrayDimensions]; - Arrays.fill(braces, '['); - String descriptor = new String(braces); - - if (javaClass == boolean.class) { - descriptor += "Z"; - } else if (javaClass == byte.class) { - descriptor += "B"; - } else if (javaClass == short.class) { - descriptor += "S"; - } else if (javaClass == char.class) { - descriptor += "C"; - } else if (javaClass == int.class) { - descriptor += "I"; - } else if (javaClass == long.class) { - descriptor += "J"; - } else if (javaClass == float.class) { - descriptor += "F"; - } else if (javaClass == double.class) { - descriptor += "D"; - } else { - descriptor += "L" + javaClass.getName() + ";"; - } - - try { - return Class.forName(descriptor); - } catch (ClassNotFoundException cnfe) { - throw new IllegalStateException("invalid painless type [" + painlessType + "]", cnfe); - } - } - - throw new IllegalArgumentException("invalid painless type [" + painlessType + "]"); - } - public PainlessLookup build() { return new PainlessLookup(painlessTypesToJavaClasses, javaClassesToPainlessStructs); } + + public Class getJavaClassFromPainlessType(String painlessType) { + return PainlessLookupUtility.painlessTypeNameToPainlessType(painlessType, painlessTypesToJavaClasses); + } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java new file mode 100644 index 0000000000000..a5d1054448b0c --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java @@ -0,0 +1,280 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.painless.lookup; + +import org.objectweb.asm.Type; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; + +public final class PainlessLookupUtility { + + // The following terminology is used for variable names throughout the lookup package: + // + // - javaClass (Class) - a java class including def and excluding array type java classes + // - javaClassName (String) - the fully qualified java class name for a javaClass + // - painlessClassName (String) - the fully qualified painless name or imported painless name for a painlessClass + // - anyClassName (String) - either a javaClassName or a painlessClassName + // - javaType (Class) - a java class excluding def and array type java classes + // - painlessType (Class) - a java class including def and array type java classes + // - javaTypeName (String) - the fully qualified java Type name for a javaType + // - painlessTypeName (String) - the fully qualified painless name or imported painless name for a painlessType + // - anyTypeName (String) - either a javaTypeName or a painlessTypeName + // - painlessClass (PainlessClass) - a painless class object + // + // Under ambiguous circumstances most variable names are prefixed with asm, java, or painless. + // If the variable name is the same for asm, java, and painless, no prefix is used. + + public static Class javaObjectTypeToPainlessDefType(Class javaType) { + if (javaType.isArray()) { + Class javaTypeComponent = javaType.getComponentType(); + int arrayDimensions = 1; + + while (javaTypeComponent.isArray()) { + javaTypeComponent = javaTypeComponent.getComponentType(); + ++arrayDimensions; + } + + if (javaTypeComponent == Object.class) { + char[] asmDescriptorBraces = new char[arrayDimensions]; + Arrays.fill(asmDescriptorBraces, '['); + + String asmDescriptor = new String(asmDescriptorBraces) + Type.getType(def.class).getDescriptor(); + Type asmType = Type.getType(asmDescriptor); + + try { + return Class.forName(asmType.getInternalName().replace('/', '.')); + } catch (ClassNotFoundException cnfe) { + throw new IllegalStateException("internal error", cnfe); + } + } + } else if (javaType == Object.class) { + return def.class; + } + + return javaType; + } + + public static Class painlessDefTypeToJavaObjectType(Class painlessType) { + if (painlessType.isArray()) { + Class painlessTypeComponent = painlessType.getComponentType(); + int arrayDimensions = 1; + + while (painlessTypeComponent.isArray()) { + painlessTypeComponent = painlessTypeComponent.getComponentType(); + ++arrayDimensions; + } + + if (painlessTypeComponent == def.class) { + char[] asmDescriptorBraces = new char[arrayDimensions]; + Arrays.fill(asmDescriptorBraces, '['); + + String asmDescriptor = new String(asmDescriptorBraces) + Type.getType(Object.class).getDescriptor(); + Type asmType = Type.getType(asmDescriptor); + + try { + return Class.forName(asmType.getInternalName().replace('/', '.')); + } catch (ClassNotFoundException exception) { + throw new IllegalStateException("internal error", exception); + } + } + } else if (painlessType == def.class) { + return Object.class; + } + + return painlessType; + } + + public static String anyTypeNameToPainlessTypeName(String anyTypeName) { + return anyTypeName.replace(def.class.getName(), DEF_PAINLESS_CLASS_NAME).replace('$', '.'); + } + + public static String anyTypeToPainlessTypeName(Class anyType) { + if (anyType.isLocalClass() || anyType.isAnonymousClass()) { + return null; + } else if (anyType.isArray()) { + Class anyTypeComponent = anyType.getComponentType(); + int arrayDimensions = 1; + + while (anyTypeComponent.isArray()) { + anyTypeComponent = anyTypeComponent.getComponentType(); + ++arrayDimensions; + } + + if (anyTypeComponent == def.class) { + StringBuilder painlessDefTypeNameArrayBuilder = new StringBuilder(DEF_PAINLESS_CLASS_NAME); + + for (int dimension = 0; dimension < arrayDimensions; dimension++) { + painlessDefTypeNameArrayBuilder.append("[]"); + } + + return painlessDefTypeNameArrayBuilder.toString(); + } + } else if (anyType == def.class) { + return DEF_PAINLESS_CLASS_NAME; + } + + return anyType.getCanonicalName().replace('$', '.'); + } + + public static Class painlessTypeNameToPainlessType(String painlessTypeName, Map> painlessClassNamesToJavaClasses) { + Class javaClass = painlessClassNamesToJavaClasses.get(painlessTypeName); + + if (javaClass != null) { + return javaClass; + } + + int arrayDimensions = 0; + int arrayIndex = painlessTypeName.indexOf('['); + + if (arrayIndex != -1) { + int painlessTypeNameLength = painlessTypeName.length(); + + while (arrayIndex < painlessTypeNameLength) { + if (painlessTypeName.charAt(arrayIndex) == '[' && + ++arrayIndex < painlessTypeNameLength && + painlessTypeName.charAt(arrayIndex++) == ']') { + ++arrayDimensions; + } else { + throw new IllegalArgumentException("invalid painless type [" + painlessTypeName + "]."); + } + } + + painlessTypeName = painlessTypeName.substring(0, painlessTypeName.indexOf('[')); + javaClass = painlessClassNamesToJavaClasses.get(painlessTypeName); + + char javaDescriptorBraces[] = new char[arrayDimensions]; + Arrays.fill(javaDescriptorBraces, '['); + String javaDescriptor = new String(javaDescriptorBraces); + + if (javaClass == boolean.class) { + javaDescriptor += "Z"; + } else if (javaClass == byte.class) { + javaDescriptor += "B"; + } else if (javaClass == short.class) { + javaDescriptor += "S"; + } else if (javaClass == char.class) { + javaDescriptor += "C"; + } else if (javaClass == int.class) { + javaDescriptor += "I"; + } else if (javaClass == long.class) { + javaDescriptor += "J"; + } else if (javaClass == float.class) { + javaDescriptor += "F"; + } else if (javaClass == double.class) { + javaDescriptor += "D"; + } else { + javaDescriptor += "L" + javaClass.getName() + ";"; + } + + try { + return Class.forName(javaDescriptor); + } catch (ClassNotFoundException cnfe) { + throw new IllegalStateException("painless type [" + painlessTypeName + "] not found", cnfe); + } + } + + throw new IllegalArgumentException("painless type [" + painlessTypeName + "] not found"); + } + + public static void validatePainlessType(Class painlessType, Collection> javaClasses) { + String painlessTypeName = anyTypeNameToPainlessTypeName(painlessType.getName()); + + while (painlessType.getComponentType() != null) { + painlessType = painlessType.getComponentType(); + } + + if (javaClasses.contains(painlessType) == false) { + throw new IllegalStateException("painless type [" + painlessTypeName + "] not found"); + } + } + + public static String buildPainlessMethodKey(String methodName, int methodArity) { + return methodName + "/" + methodArity; + } + + public static String buildPainlessFieldKey(String fieldName) { + return fieldName; + } + + public static Class getBoxedAnyType(Class anyType) { + if (anyType == boolean.class) { + return Boolean.class; + } else if (anyType == byte.class) { + return Byte.class; + } else if (anyType == short.class) { + return Short.class; + } else if (anyType == char.class) { + return Character.class; + } else if (anyType == int.class) { + return Integer.class; + } else if (anyType == long.class) { + return Long.class; + } else if (anyType == float.class) { + return Float.class; + } else if (anyType == double.class) { + return Double.class; + } + + return anyType; + } + + public static Class getUnboxedAnyType(Class anyType) { + if (anyType == Boolean.class) { + return boolean.class; + } else if (anyType == Byte.class) { + return byte.class; + } else if (anyType == Short.class) { + return short.class; + } else if (anyType == Character.class) { + return char.class; + } else if (anyType == Integer.class) { + return int.class; + } else if (anyType == Long.class) { + return long.class; + } else if (anyType == Float.class) { + return float.class; + } else if (anyType == Double.class) { + return double.class; + } + + return anyType; + } + + public static boolean isAnyTypeConstant(Class anyType) { + return anyType == boolean.class || + anyType == byte.class || + anyType == short.class || + anyType == char.class || + anyType == int.class || + anyType == long.class || + anyType == float.class || + anyType == double.class || + anyType == String.class; + } + + public static final String DEF_PAINLESS_CLASS_NAME = def.class.getSimpleName(); + public static final String CONSTRUCTOR_ANY_NAME = ""; + + private PainlessLookupUtility() { + + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessMethod.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessMethod.java index e87e1d4bf38fc..8d8a7f691fecd 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessMethod.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessMethod.java @@ -69,21 +69,21 @@ public MethodType getMethodType() { params = new Class[1 + arguments.size()]; params[0] = augmentation; for (int i = 0; i < arguments.size(); i++) { - params[i + 1] = PainlessLookup.defClassToObjectClass(arguments.get(i)); + params[i + 1] = PainlessLookupUtility.painlessDefTypeToJavaObjectType(arguments.get(i)); } - returnValue = PainlessLookup.defClassToObjectClass(rtn); + returnValue = PainlessLookupUtility.painlessDefTypeToJavaObjectType(rtn); } else if (Modifier.isStatic(modifiers)) { // static method: straightforward copy params = new Class[arguments.size()]; for (int i = 0; i < arguments.size(); i++) { - params[i] = PainlessLookup.defClassToObjectClass(arguments.get(i)); + params[i] = PainlessLookupUtility.painlessDefTypeToJavaObjectType(arguments.get(i)); } - returnValue = PainlessLookup.defClassToObjectClass(rtn); + returnValue = PainlessLookupUtility.painlessDefTypeToJavaObjectType(rtn); } else if ("".equals(name)) { // constructor: returns the owner class params = new Class[arguments.size()]; for (int i = 0; i < arguments.size(); i++) { - params[i] = PainlessLookup.defClassToObjectClass(arguments.get(i)); + params[i] = PainlessLookupUtility.painlessDefTypeToJavaObjectType(arguments.get(i)); } returnValue = owner.clazz; } else { @@ -91,9 +91,9 @@ public MethodType getMethodType() { params = new Class[1 + arguments.size()]; params[0] = owner.clazz; for (int i = 0; i < arguments.size(); i++) { - params[i + 1] = PainlessLookup.defClassToObjectClass(arguments.get(i)); + params[i + 1] = PainlessLookupUtility.painlessDefTypeToJavaObjectType(arguments.get(i)); } - returnValue = PainlessLookup.defClassToObjectClass(rtn); + returnValue = PainlessLookupUtility.painlessDefTypeToJavaObjectType(rtn); } return MethodType.methodType(returnValue, params); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java index 0dfcf4d409335..dd813f73c3dfc 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java @@ -20,10 +20,10 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; +import org.elasticsearch.painless.lookup.PainlessCast; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import java.util.Objects; @@ -157,7 +157,7 @@ AExpression cast(Locals locals) { return ecast; } else { - if (PainlessLookup.isConstantType(expected)) { + if (PainlessLookupUtility.isAnyTypeConstant(expected)) { // For the case where a cast is required, a constant is set, // and the constant can be immediately cast to the expected type. // An EConstant replaces this node with the constant cast appropriately diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java index a0a29ed59ddde..584e5df6342ab 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java @@ -22,13 +22,13 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.lookup.PainlessCast; -import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; +import org.elasticsearch.painless.lookup.PainlessCast; +import org.elasticsearch.painless.lookup.def; import java.util.ArrayList; import java.util.List; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java index 422300072dc2f..65776ca76f117 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java @@ -21,14 +21,14 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.WriterConstants; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.def; import java.util.Objects; import java.util.Set; @@ -106,7 +106,8 @@ private void analyzeMul(Locals variables) { if (promote == null) { throw createError(new ClassCastException("Cannot apply multiply [*] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } actual = promote; @@ -148,7 +149,8 @@ private void analyzeDiv(Locals variables) { if (promote == null) { throw createError(new ClassCastException("Cannot apply divide [/] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } actual = promote; @@ -195,7 +197,8 @@ private void analyzeRem(Locals variables) { if (promote == null) { throw createError(new ClassCastException("Cannot apply remainder [%] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } actual = promote; @@ -242,7 +245,8 @@ private void analyzeAdd(Locals variables) { if (promote == null) { throw createError(new ClassCastException("Cannot apply add [+] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } actual = promote; @@ -300,7 +304,8 @@ private void analyzeSub(Locals variables) { if (promote == null) { throw createError(new ClassCastException("Cannot apply subtract [-] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } actual = promote; @@ -358,7 +363,8 @@ private void analyzeLSH(Locals variables) { if (lhspromote == null || rhspromote == null) { throw createError(new ClassCastException("Cannot apply left shift [<<] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } actual = promote = lhspromote; @@ -405,7 +411,8 @@ private void analyzeRSH(Locals variables) { if (lhspromote == null || rhspromote == null) { throw createError(new ClassCastException("Cannot apply right shift [>>] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } actual = promote = lhspromote; @@ -455,7 +462,8 @@ private void analyzeUSH(Locals variables) { if (lhspromote == null || rhspromote == null) { throw createError(new ClassCastException("Cannot apply unsigned shift [>>>] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } if (lhspromote == def.class || rhspromote == def.class) { @@ -498,7 +506,8 @@ private void analyzeBWAnd(Locals variables) { if (promote == null) { throw createError(new ClassCastException("Cannot apply and [&] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } actual = promote; @@ -537,7 +546,8 @@ private void analyzeXor(Locals variables) { if (promote == null) { throw createError(new ClassCastException("Cannot apply xor [^] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } actual = promote; @@ -577,7 +587,8 @@ private void analyzeBWOr(Locals variables) { if (promote == null) { throw createError(new ClassCastException("Cannot apply or [|] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } actual = promote; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java index ede1a2a6b9c36..dfed0ca47b482 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java @@ -19,12 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.PainlessMethodKey; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.lookup.PainlessMethodKey; import java.util.List; import java.util.Objects; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java index c0345b6308c3e..e8ad9d85ed698 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java @@ -21,14 +21,14 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; @@ -69,7 +69,7 @@ void analyze(Locals locals) { defPointer = "D" + variable + "." + call + ",1"; } else { // typed implementation - defPointer = "S" + PainlessLookup.ClassToName(captured.clazz) + "." + call + ",1"; + defPointer = "S" + PainlessLookupUtility.anyTypeToPainlessTypeName(captured.clazz) + "." + call + ",1"; } actual = String.class; } else { @@ -77,7 +77,8 @@ void analyze(Locals locals) { // static case if (captured.clazz != def.class) { try { - ref = new FunctionRef(locals.getPainlessLookup(), expected, PainlessLookup.ClassToName(captured.clazz), call, 1); + ref = new FunctionRef( + locals.getPainlessLookup(), expected, PainlessLookupUtility.anyTypeToPainlessTypeName(captured.clazz), call, 1); // check casts between the interface method and the delegate method are legal for (int i = 0; i < ref.interfaceMethod.arguments.size(); ++i) { @@ -109,7 +110,7 @@ void write(MethodWriter writer, Globals globals) { // typed interface, dynamic implementation writer.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); Type methodType = Type.getMethodType(MethodWriter.getType(expected), MethodWriter.getType(captured.clazz)); - writer.invokeDefCall(call, methodType, DefBootstrap.REFERENCE, PainlessLookup.ClassToName(expected)); + writer.invokeDefCall(call, methodType, DefBootstrap.REFERENCE, PainlessLookupUtility.anyTypeToPainlessTypeName(expected)); } else { // typed interface, typed implementation writer.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java index 55a9dbf71c891..b0451b685b57d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java @@ -19,12 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessCast; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import java.util.Objects; import java.util.Set; @@ -63,6 +63,6 @@ void write(MethodWriter writer, Globals globals) { @Override public String toString() { - return singleLineToString(PainlessLookup.ClassToName(cast.to), child); + return singleLineToString(PainlessLookupUtility.anyTypeToPainlessTypeName(cast.to), child); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java index 806204d051ae0..edf18f501bc77 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java @@ -21,13 +21,13 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Label; import org.objectweb.asm.Type; @@ -93,7 +93,8 @@ private void analyzeEq(Locals variables) { if (promotedType == null) { throw createError(new ClassCastException("Cannot apply equals [==] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } if (promotedType == def.class) { @@ -142,7 +143,8 @@ private void analyzeEqR(Locals variables) { if (promotedType == null) { throw createError(new ClassCastException("Cannot apply reference equals [===] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } left.expected = promotedType; @@ -182,7 +184,8 @@ private void analyzeNE(Locals variables) { if (promotedType == null) { throw createError(new ClassCastException("Cannot apply not equals [!=] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } if (promotedType == def.class) { @@ -231,7 +234,8 @@ private void analyzeNER(Locals variables) { if (promotedType == null) { throw createError(new ClassCastException("Cannot apply reference not equals [!==] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } left.expected = promotedType; @@ -271,7 +275,8 @@ private void analyzeGTE(Locals variables) { if (promotedType == null) { throw createError(new ClassCastException("Cannot apply greater than or equals [>=] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } if (promotedType == def.class) { @@ -310,7 +315,8 @@ private void analyzeGT(Locals variables) { if (promotedType == null) { throw createError(new ClassCastException("Cannot apply greater than [>] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } if (promotedType == def.class) { @@ -349,7 +355,8 @@ private void analyzeLTE(Locals variables) { if (promotedType == null) { throw createError(new ClassCastException("Cannot apply less than or equals [<=] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } if (promotedType == def.class) { @@ -388,7 +395,8 @@ private void analyzeLT(Locals variables) { if (promotedType == null) { throw createError(new ClassCastException("Cannot apply less than [>=] to types " + - "[" + PainlessLookup.ClassToName(left.actual) + "] and [" + PainlessLookup.ClassToName(right.actual) + "].")); + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "].")); } if (promotedType == def.class) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java index 82c24e27c5d16..d4eddb059a847 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java @@ -20,14 +20,14 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.PainlessMethodKey; import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.lookup.PainlessMethodKey; import org.objectweb.asm.Type; import java.util.Objects; @@ -69,12 +69,12 @@ void analyze(Locals locals) { PainlessMethod interfaceMethod = locals.getPainlessLookup().getPainlessStructFromJavaClass(expected).functionalMethod; if (interfaceMethod == null) { throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " + - "to [" + PainlessLookup.ClassToName(expected) + "], not a functional interface"); + "to [" + PainlessLookupUtility.anyTypeToPainlessTypeName(expected) + "], not a functional interface"); } PainlessMethod delegateMethod = locals.getMethod(new PainlessMethodKey(call, interfaceMethod.arguments.size())); if (delegateMethod == null) { throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " + - "to [" + PainlessLookup.ClassToName(expected) + "], function not found"); + "to [" + PainlessLookupUtility.anyTypeToPainlessTypeName(expected) + "], function not found"); } ref = new FunctionRef(expected, interfaceMethod, delegateMethod, 0); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java index a3835cbc21372..05564a2952e6f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java @@ -19,11 +19,11 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import java.util.Objects; import java.util.Set; @@ -64,7 +64,8 @@ void analyze(Locals locals) { } // map to wrapped type for primitive types - resolvedType = clazz.isPrimitive() ? PainlessLookup.getBoxedType(clazz) : PainlessLookup.defClassToObjectClass(clazz); + resolvedType = clazz.isPrimitive() ? PainlessLookupUtility.getBoxedAnyType(clazz) : + PainlessLookupUtility.painlessDefTypeToJavaObjectType(clazz); // analyze and cast the expression expression.analyze(locals); @@ -75,7 +76,7 @@ void analyze(Locals locals) { primitiveExpression = expression.actual.isPrimitive(); // map to wrapped type for primitive types expressionType = expression.actual.isPrimitive() ? - PainlessLookup.getBoxedType(expression.actual) : PainlessLookup.defClassToObjectClass(clazz); + PainlessLookupUtility.getBoxedAnyType(expression.actual) : PainlessLookupUtility.painlessDefTypeToJavaObjectType(clazz); actual = boolean.class; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java index 8977f4f0ef329..8e8d164b03d62 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java @@ -20,15 +20,15 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.node.SFunction.FunctionReserved; import org.objectweb.asm.Opcodes; @@ -122,13 +122,13 @@ void analyze(Locals locals) { // we know the method statically, infer return type and any unknown/def types interfaceMethod = locals.getPainlessLookup().getPainlessStructFromJavaClass(expected).functionalMethod; if (interfaceMethod == null) { - throw createError(new IllegalArgumentException("Cannot pass lambda to [" + PainlessLookup.ClassToName(expected) + - "], not a functional interface")); + throw createError(new IllegalArgumentException("Cannot pass lambda to " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(expected) + "], not a functional interface")); } // check arity before we manipulate parameters if (interfaceMethod.arguments.size() != paramTypeStrs.size()) throw new IllegalArgumentException("Incorrect number of parameters for [" + interfaceMethod.name + - "] in [" + PainlessLookup.ClassToName(expected) + "]"); + "] in [" + PainlessLookupUtility.anyTypeToPainlessTypeName(expected) + "]"); // for method invocation, its allowed to ignore the return value if (interfaceMethod.rtn == void.class) { returnType = def.class; @@ -140,7 +140,7 @@ void analyze(Locals locals) { for (int i = 0; i < paramTypeStrs.size(); i++) { String paramType = paramTypeStrs.get(i); if (paramType == null) { - actualParamTypeStrs.add(PainlessLookup.ClassToName(interfaceMethod.arguments.get(i))); + actualParamTypeStrs.add(PainlessLookupUtility.anyTypeToPainlessTypeName(interfaceMethod.arguments.get(i))); } else { actualParamTypeStrs.add(paramType); } @@ -162,15 +162,15 @@ void analyze(Locals locals) { List paramTypes = new ArrayList<>(captures.size() + actualParamTypeStrs.size()); List paramNames = new ArrayList<>(captures.size() + paramNameStrs.size()); for (Variable var : captures) { - paramTypes.add(PainlessLookup.ClassToName(var.clazz)); + paramTypes.add(PainlessLookupUtility.anyTypeToPainlessTypeName(var.clazz)); paramNames.add(var.name); } paramTypes.addAll(actualParamTypeStrs); paramNames.addAll(paramNameStrs); // desugar lambda body into a synthetic method - desugared = new SFunction(reserved, location, PainlessLookup.ClassToName(returnType), name, - paramTypes, paramNames, statements, true); + desugared = new SFunction(reserved, location, PainlessLookupUtility.anyTypeToPainlessTypeName(returnType), name, + paramTypes, paramNames, statements, true); desugared.generateSignature(locals.getPainlessLookup()); desugared.analyze(Locals.newLambdaScope(locals.getProgramScope(), returnType, desugared.parameters, captures.size(), reserved.getMaxLoopCounter())); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java index 820cce685edcd..90475419b3260 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java @@ -19,13 +19,13 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.PainlessMethodKey; -import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.lookup.PainlessMethodKey; +import org.elasticsearch.painless.lookup.def; import java.util.ArrayList; import java.util.List; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java index b6c7fb80af95f..c6474846d4c7a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java @@ -19,13 +19,13 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.PainlessMethodKey; -import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.lookup.PainlessMethodKey; +import org.elasticsearch.painless.lookup.def; import java.util.HashMap; import java.util.List; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java index 197e2fcb7fd42..a780ea3e05be8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java @@ -19,12 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.PainlessClass; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessClass; +import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.PainlessMethodKey; import java.util.List; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java index 983819b6b2bf9..6bc5331cb1d84 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java @@ -19,11 +19,11 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.objectweb.asm.Opcodes; import java.util.Set; @@ -53,7 +53,7 @@ void analyze(Locals locals) { if (expected != null) { if (expected.isPrimitive()) { throw createError(new IllegalArgumentException( - "Cannot cast null to a primitive type [" + PainlessLookup.ClassToName(expected) + "].")); + "Cannot cast null to a primitive type [" + PainlessLookupUtility.anyTypeToPainlessTypeName(expected) + "].")); } actual = expected; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java index 3a5102ebdc99c..d34399db779df 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java @@ -21,13 +21,13 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; @@ -93,7 +93,8 @@ void analyzeBWNot(Locals variables) { promote = AnalyzerCaster.promoteNumeric(child.actual, false); if (promote == null) { - throw createError(new ClassCastException("Cannot apply not [~] to type [" + PainlessLookup.ClassToName(child.actual) + "].")); + throw createError(new ClassCastException("Cannot apply not [~] to type " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(child.actual) + "].")); } child.expected = promote; @@ -122,8 +123,8 @@ void analyzerAdd(Locals variables) { promote = AnalyzerCaster.promoteNumeric(child.actual, true); if (promote == null) { - throw createError( - new ClassCastException("Cannot apply positive [+] to type [" + PainlessLookup.ClassToName(child.actual) + "].")); + throw createError(new ClassCastException("Cannot apply positive [+] to type " + + "[" + PainlessLookupUtility.painlessDefTypeToJavaObjectType(child.actual) + "].")); } child.expected = promote; @@ -156,8 +157,8 @@ void analyzerSub(Locals variables) { promote = AnalyzerCaster.promoteNumeric(child.actual, true); if (promote == null) { - throw createError( - new ClassCastException("Cannot apply negative [-] to type [" + PainlessLookup.ClassToName(child.actual) + "].")); + throw createError(new ClassCastException("Cannot apply negative [-] to type " + + "[" + PainlessLookupUtility.painlessDefTypeToJavaObjectType(child.actual) + "].")); } child.expected = promote; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java index 5b282abdce9fa..c45107a37ac21 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java @@ -19,12 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.def; import java.util.List; import java.util.Map; @@ -67,8 +67,8 @@ void analyze(Locals locals) { } else if (List.class.isAssignableFrom(prefix.actual)) { sub = new PSubListShortcut(location, locals.getPainlessLookup().getPainlessStructFromJavaClass(prefix.actual), index); } else { - throw createError( - new IllegalArgumentException("Illegal array access on type [" + PainlessLookup.ClassToName(prefix.actual) + "].")); + throw createError(new IllegalArgumentException("Illegal array access on type " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(prefix.actual) + "].")); } sub.write = write; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java index f23ae9f188704..445c053347ec3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java @@ -19,15 +19,15 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.PainlessMethodKey; -import org.elasticsearch.painless.lookup.PainlessClass; -import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessClass; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.lookup.PainlessMethodKey; +import org.elasticsearch.painless.lookup.def; import java.util.List; import java.util.Objects; @@ -74,7 +74,7 @@ void analyze(Locals locals) { PainlessClass struct = locals.getPainlessLookup().getPainlessStructFromJavaClass(prefix.actual); if (prefix.actual.isPrimitive()) { - struct = locals.getPainlessLookup().getPainlessStructFromJavaClass(PainlessLookup.getBoxedType(prefix.actual)); + struct = locals.getPainlessLookup().getPainlessStructFromJavaClass(PainlessLookupUtility.getBoxedAnyType(prefix.actual)); } PainlessMethodKey methodKey = new PainlessMethodKey(name, arguments.size()); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java index 78a18b91ab2c6..3f2f887956491 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java @@ -19,16 +19,16 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessField; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.PainlessClass; -import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessClass; +import org.elasticsearch.painless.lookup.PainlessField; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.PainlessMethodKey; +import org.elasticsearch.painless.lookup.def; import java.util.List; import java.util.Map; @@ -64,7 +64,7 @@ void analyze(Locals locals) { prefix = prefix.cast(locals); if (prefix.actual.isArray()) { - sub = new PSubArrayLength(location, PainlessLookup.ClassToName(prefix.actual), value); + sub = new PSubArrayLength(location, PainlessLookupUtility.anyTypeToPainlessTypeName(prefix.actual), value); } else if (prefix.actual == def.class) { sub = new PSubDefField(location, value); } else { @@ -86,7 +86,7 @@ void analyze(Locals locals) { new PainlessMethodKey("set" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 1)); if (getter != null || setter != null) { - sub = new PSubShortcut(location, value, PainlessLookup.ClassToName(prefix.actual), getter, setter); + sub = new PSubShortcut(location, value, PainlessLookupUtility.anyTypeToPainlessTypeName(prefix.actual), getter, setter); } else { EConstant index = new EConstant(location, value); index.analyze(locals); @@ -104,7 +104,7 @@ void analyze(Locals locals) { if (sub == null) { throw createError(new IllegalArgumentException( - "Unknown field [" + value + "] for type [" + PainlessLookup.ClassToName(prefix.actual) + "].")); + "Unknown field [" + value + "] for type [" + PainlessLookupUtility.anyTypeToPainlessTypeName(prefix.actual) + "].")); } if (nullSafe) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java index 66ad0ecff1b89..237efa61ffa7d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java @@ -19,11 +19,11 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessMethod; import java.util.List; import java.util.Objects; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java index ccbc25db4f25e..afad497dec7d9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java @@ -20,11 +20,11 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Type; import java.util.Objects; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java index a9021000e2dad..7f4e253b4090d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java @@ -20,11 +20,11 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Type; import java.util.ArrayList; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java index 1c081c9422ecb..bf00d8d859988 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java @@ -20,11 +20,11 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.def; import java.util.Objects; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java index d6c367cfeabec..8eb154e745bf7 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java @@ -19,12 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessField; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessField; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import java.lang.reflect.Modifier; import java.util.Objects; @@ -51,8 +51,8 @@ void extractVariables(Set variables) { @Override void analyze(Locals locals) { if (write && Modifier.isFinal(field.modifiers)) { - throw createError(new IllegalArgumentException( - "Cannot write to read-only field [" + field.name + "] for type [" + PainlessLookup.ClassToName(field.clazz) + "].")); + throw createError(new IllegalArgumentException("Cannot write to read-only field [" + field.name + "] for type " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(field.clazz) + "].")); } actual = field.clazz; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java index 5d881b30db22d..0a3ab142ddc7c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java @@ -19,13 +19,13 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.PainlessClass; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.WriterConstants; +import org.elasticsearch.painless.lookup.PainlessClass; +import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.PainlessMethodKey; import java.util.Objects; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java index 4875d55cbeb58..f71e2ac5d1fa0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java @@ -19,12 +19,12 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.PainlessClass; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessClass; +import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.PainlessMethodKey; import java.util.Objects; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java index 4b2910dbc010e..eb5668c554c20 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java @@ -19,11 +19,11 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessMethod; import java.util.Set; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java index c402d8982d89e..de1a7062a24f2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java @@ -19,13 +19,13 @@ package org.elasticsearch.painless.node; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.def; import java.util.Objects; import java.util.Set; @@ -84,8 +84,8 @@ void analyze(Locals locals) { } else if (expression.actual == def.class || Iterable.class.isAssignableFrom(expression.actual)) { sub = new SSubEachIterable(location, variable, expression, block); } else { - throw createError( - new IllegalArgumentException("Illegal for each type [" + PainlessLookup.ClassToName(expression.actual) + "].")); + throw createError(new IllegalArgumentException("Illegal for each type " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(expression.actual) + "].")); } sub.analyze(locals); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java index 628bb1d32d59e..1c801d509b581 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java @@ -22,8 +22,6 @@ import org.elasticsearch.painless.CompilerSettings; import org.elasticsearch.painless.Constant; import org.elasticsearch.painless.Def; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Parameter; @@ -31,6 +29,9 @@ import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.WriterConstants; +import org.elasticsearch.painless.lookup.PainlessLookup; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.node.SSource.Reserved; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Handle; @@ -135,7 +136,7 @@ void generateSignature(PainlessLookup painlessLookup) { try { Class paramType = painlessLookup.getJavaClassFromPainlessType(this.paramTypeStrs.get(param)); - paramClasses[param] = PainlessLookup.defClassToObjectClass(paramType); + paramClasses[param] = PainlessLookupUtility.painlessDefTypeToJavaObjectType(paramType); paramTypes.add(paramType); parameters.add(new Parameter(location, paramNameStrs.get(param), paramType)); } catch (IllegalArgumentException exception) { @@ -144,8 +145,8 @@ void generateSignature(PainlessLookup painlessLookup) { } } - org.objectweb.asm.commons.Method method = new org.objectweb.asm.commons.Method( - name, MethodType.methodType(PainlessLookup.defClassToObjectClass(rtnType), paramClasses).toMethodDescriptorString()); + org.objectweb.asm.commons.Method method = new org.objectweb.asm.commons.Method(name, MethodType.methodType( + PainlessLookupUtility.painlessDefTypeToJavaObjectType(rtnType), paramClasses).toMethodDescriptorString()); this.method = new PainlessMethod(name, null, null, rtnType, paramTypes, method, Modifier.STATIC | Modifier.PRIVATE, null); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java index 4781457a57dfa..b8f41f0df4c82 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java @@ -21,9 +21,6 @@ import org.elasticsearch.painless.CompilerSettings; import org.elasticsearch.painless.Constant; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.PainlessMethodKey; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; @@ -32,6 +29,9 @@ import org.elasticsearch.painless.ScriptClassInfo; import org.elasticsearch.painless.SimpleChecksAdapter; import org.elasticsearch.painless.WriterConstants; +import org.elasticsearch.painless.lookup.PainlessLookup; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.lookup.PainlessMethodKey; import org.elasticsearch.painless.node.SFunction.FunctionReserved; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java index 5db161b8002a4..fea8c8953b67f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java @@ -20,13 +20,13 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.AnalyzerCaster; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessCast; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -109,6 +109,6 @@ void write(MethodWriter writer, Globals globals) { @Override public String toString() { - return singleLineToString(PainlessLookup.ClassToName(variable.clazz), variable.name, expression, block); + return singleLineToString(PainlessLookupUtility.anyTypeToPainlessTypeName(variable.clazz), variable.name, expression, block); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java index cfc87536b6b7b..cec1297a4c41c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java @@ -21,16 +21,16 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.DefBootstrap; -import org.elasticsearch.painless.lookup.PainlessLookup; -import org.elasticsearch.painless.lookup.PainlessCast; -import org.elasticsearch.painless.lookup.PainlessMethod; -import org.elasticsearch.painless.lookup.PainlessMethodKey; -import org.elasticsearch.painless.lookup.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessCast; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.lookup.PainlessMethodKey; +import org.elasticsearch.painless.lookup.def; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -81,8 +81,8 @@ void analyze(Locals locals) { getPainlessStructFromJavaClass(expression.actual).methods.get(new PainlessMethodKey("iterator", 0)); if (method == null) { - throw createError(new IllegalArgumentException( - "Unable to create iterator for the type [" + PainlessLookup.ClassToName(expression.actual) + "].")); + throw createError(new IllegalArgumentException("Unable to create iterator for the type " + + "[" + PainlessLookupUtility.anyTypeToPainlessTypeName(expression.actual) + "].")); } } @@ -133,6 +133,6 @@ void write(MethodWriter writer, Globals globals) { @Override public String toString() { - return singleLineToString(PainlessLookup.ClassToName(variable.clazz), variable.name, expression, block); + return singleLineToString(PainlessLookupUtility.anyTypeToPainlessTypeName(variable.clazz), variable.name, expression, block); } } From 11c5119ee83c9917746d8fd704c4f478dcdd9b5f Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Mon, 16 Jul 2018 12:50:56 -0700 Subject: [PATCH 5/5] Moved comments into javadoc form. --- .../lookup/PainlessLookupUtility.java | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java index a5d1054448b0c..d1f3ee4ece3e0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java @@ -25,24 +25,28 @@ import java.util.Collection; import java.util.Map; +/** + * This class contains methods shared by {@link PainlessLookupBuilder}, {@link PainlessLookup}, and other classes within + * Painless for conversion between type names and types along with some other various utility methods. + * + * The following terminology is used for variable names throughout the lookup package: + * + * - javaClass (Class) - a java class including def and excluding array type java classes + * - javaClassName (String) - the fully qualified java class name for a javaClass + * - painlessClassName (String) - the fully qualified painless name or imported painless name for a painlessClass + * - anyClassName (String) - either a javaClassName or a painlessClassName + * - javaType (Class) - a java class excluding def and array type java classes + * - painlessType (Class) - a java class including def and array type java classes + * - javaTypeName (String) - the fully qualified java Type name for a javaType + * - painlessTypeName (String) - the fully qualified painless name or imported painless name for a painlessType + * - anyTypeName (String) - either a javaTypeName or a painlessTypeName + * - painlessClass (PainlessClass) - a painless class object + * + * Under ambiguous circumstances most variable names are prefixed with asm, java, or painless. + * If the variable name is the same for asm, java, and painless, no prefix is used. + */ public final class PainlessLookupUtility { - // The following terminology is used for variable names throughout the lookup package: - // - // - javaClass (Class) - a java class including def and excluding array type java classes - // - javaClassName (String) - the fully qualified java class name for a javaClass - // - painlessClassName (String) - the fully qualified painless name or imported painless name for a painlessClass - // - anyClassName (String) - either a javaClassName or a painlessClassName - // - javaType (Class) - a java class excluding def and array type java classes - // - painlessType (Class) - a java class including def and array type java classes - // - javaTypeName (String) - the fully qualified java Type name for a javaType - // - painlessTypeName (String) - the fully qualified painless name or imported painless name for a painlessType - // - anyTypeName (String) - either a javaTypeName or a painlessTypeName - // - painlessClass (PainlessClass) - a painless class object - // - // Under ambiguous circumstances most variable names are prefixed with asm, java, or painless. - // If the variable name is the same for asm, java, and painless, no prefix is used. - public static Class javaObjectTypeToPainlessDefType(Class javaType) { if (javaType.isArray()) { Class javaTypeComponent = javaType.getComponentType(); @@ -261,14 +265,14 @@ public static Class getUnboxedAnyType(Class anyType) { public static boolean isAnyTypeConstant(Class anyType) { return anyType == boolean.class || - anyType == byte.class || - anyType == short.class || - anyType == char.class || - anyType == int.class || - anyType == long.class || - anyType == float.class || - anyType == double.class || - anyType == String.class; + anyType == byte.class || + anyType == short.class || + anyType == char.class || + anyType == int.class || + anyType == long.class || + anyType == float.class || + anyType == double.class || + anyType == String.class; } public static final String DEF_PAINLESS_CLASS_NAME = def.class.getSimpleName();