1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package compiler.compilercontrol.share.method; 25 26 import compiler.compilercontrol.share.method.MethodDescriptor.PatternType; 27 import compiler.compilercontrol.share.method.MethodDescriptor.Separator; 28 import jdk.test.lib.Pair; 29 import jdk.test.lib.Triple; 30 import jdk.test.lib.Utils; 31 import pool.PoolHelper; 32 33 import java.lang.reflect.Executable; 34 import java.util.ArrayList; 35 import java.util.EnumSet; 36 import java.util.List; 37 import java.util.concurrent.Callable; 38 import java.util.function.Function; 39 40 /** 41 * Generates combinations of method descriptors from the pool of methods 42 */ 43 public class MethodGenerator { 44 private static final List<Pair<Executable, Callable<?>>> METHODS = 45 new PoolHelper().getAllMethods(PoolHelper.METHOD_FILTER); 46 // Different combinations of patterns 47 private static final List<Combination<PatternType>> PATTERNS_LIST; 48 // Different combinations of separators 49 private static final List<Combination<Separator>> SEPARATORS_LIST; 50 // List of functions that modify elements 51 private static final List<Function<String, String>> ELEMENT_MUTATORS; 52 53 static { 54 PATTERNS_LIST = 55 generate(EnumSet.allOf(PatternType.class), 56 EnumSet.allOf(PatternType.class), 57 EnumSet.of(PatternType.ANY, PatternType.EXACT)); 58 SEPARATORS_LIST = 59 generate(EnumSet.of(Separator.SLASH, Separator.DOT), 60 EnumSet.complementOf(EnumSet.of(Separator.NONE)), 61 EnumSet.of(Separator.COMMA, Separator.SPACE, 62 Separator.NONE)); 63 ELEMENT_MUTATORS = generateMutators(); 64 } 65 66 // Test method 67 public static void main(String[] args) { 68 MethodGenerator methodGenerator = new MethodGenerator(); 69 List<MethodDescriptor> tests = methodGenerator.getTests(); 70 tests.forEach(System.out::println); 71 } 72 73 /** 74 * Generates random method descriptor 75 * 76 * @param executable executable used to generate descriptor 77 * @return MethodDescriptor instance 78 */ 79 public MethodDescriptor generateRandomDescriptor(Executable executable) { 80 Combination<PatternType> patterns = 81 Utils.getRandomElement(PATTERNS_LIST); 82 Combination<Separator> separators = 83 Utils.getRandomElement(SEPARATORS_LIST); 84 // Create simple mutators for signature generation 85 List<Function<String, String>> signMutators = new ArrayList<>(); 86 signMutators.add(input -> input); 87 signMutators.add(input -> ""); 88 Combination<Function<String, String>> mutators = new Combination<>( 89 Utils.getRandomElement(ELEMENT_MUTATORS), 90 Utils.getRandomElement(ELEMENT_MUTATORS), 91 // use only this type of mutators 92 Utils.getRandomElement(signMutators)); 93 return makeMethodDescriptor(executable, patterns, 94 separators, mutators); 95 } 96 97 /** 98 * Compile command signature that looks like java/lang/String.indexOf 99 * http://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html#BABDDFII 100 * 101 * @param executable executable used to generate descriptor 102 * @return MethodDescriptor instance 103 */ 104 public static MethodDescriptor commandDescriptor(Executable executable) { 105 MethodDescriptor md = new MethodDescriptor(executable); 106 md.aClass.setSeparator(Separator.SLASH); 107 md.aMethod.setSeparator(Separator.DOT); 108 md.aSignature.setSeparator(Separator.NONE); 109 return md; 110 } 111 112 /** 113 * Compile command signature that looks like java.lang.String::indexOf 114 * 115 * @param executable executable used to generate descriptor 116 * @return MethodDescriptor instance 117 */ 118 public static MethodDescriptor logDescriptor(Executable executable) { 119 MethodDescriptor md = new MethodDescriptor(executable); 120 md.aClass.setSeparator(Separator.DOT); 121 md.aMethod.setSeparator(Separator.DOUBLECOLON); 122 md.aSignature.setSeparator(Separator.NONE); 123 return md; 124 } 125 126 /** 127 * Method descriptor that matches any method. Its full signature is *.* 128 * 129 * @param executable executable used to generate descriptor 130 * @return MethodDescriptor instance 131 */ 132 public static MethodDescriptor anyMatchDescriptor(Executable executable) { 133 MethodDescriptor md = new MethodDescriptor(executable); 134 Combination<PatternType> patterns = new Combination<>(PatternType.ANY, 135 PatternType.ANY, PatternType.ANY); 136 md.aClass.setSeparator(Separator.SLASH); 137 md.aMethod.setSeparator(Separator.DOT); 138 md.aSignature.setSeparator(Separator.NONE); 139 md.setPatterns(patterns); 140 return md; 141 } 142 143 /** 144 * Generates a list of method patterns from the pool of methods 145 * 146 * @return a list of test cases 147 */ 148 public List<MethodDescriptor> getTests() { 149 List<MethodDescriptor> list = new ArrayList<>(); 150 METHODS.forEach(pair -> list.addAll(getTests(pair.first))); 151 return list; 152 } 153 154 /** 155 * Generates all combinations of method descriptors for a given executable 156 * 157 * @param executable executable for which the different combination is built 158 * @return list of method descriptors 159 */ 160 public List<MethodDescriptor> getTests(Executable executable) { 161 List<MethodDescriptor> list = new ArrayList<>(); 162 for (Combination<PatternType> patterns : PATTERNS_LIST) { 163 for (Combination<Separator> separators : SEPARATORS_LIST) { 164 for (Function<String, String> classGen : ELEMENT_MUTATORS) { 165 for (Function<String, String> methodGen : 166 ELEMENT_MUTATORS) { 167 for (Function<String, String> signatureGen : 168 ELEMENT_MUTATORS) { 169 list.add(makeMethodDescriptor(executable, 170 patterns, separators, 171 new Combination<>(classGen, methodGen, 172 signatureGen))); 173 } 174 } 175 } 176 } 177 } 178 return list; 179 } 180 181 /** 182 * Creates method descriptor from the given executable, 183 * patterns and separators for its elements 184 */ 185 private MethodDescriptor makeMethodDescriptor( 186 Executable executable, 187 Combination<PatternType> patterns, 188 Combination<Separator> separators, 189 Combination<Function<String, String>> mutators) { 190 MethodDescriptor methodDescriptor = new MethodDescriptor(executable); 191 methodDescriptor.setSeparators(separators); 192 methodDescriptor.applyMutates(mutators); 193 methodDescriptor.setPatterns(patterns); 194 return methodDescriptor; 195 } 196 197 /** 198 * Creates a list of functions that change given string 199 */ 200 private static List<Function<String, String>> generateMutators() { 201 List<Function<String, String>> elements = new ArrayList<>(); 202 // Use the input itself 203 elements.add(input -> input); 204 // Use half of the input string 205 elements.add(input -> input.substring(input.length() / 2)); 206 // Add nonexistent element 207 elements.add(input -> "nonexistent"); 208 // Use left and right angle brackets 209 elements.add(input -> "<" + input + ">"); 210 // Embed * inside 211 elements.add(input -> embed(input, "*")); 212 // ** as a whole element 213 elements.add(input -> "**"); 214 // Embed JLS-invalid letters 215 elements.add(input -> embed(input, "@%")); 216 elements.add(input -> embed(input, "]")); 217 // Use JLS-invalid letters 218 elements.add(input -> "-"); 219 elements.add(input -> "+"); 220 elements.add(input -> ")" + input); 221 elements.add(input -> "{" + input + "}"); 222 // Add valid Java identifier start char 223 elements.add(input -> "_" + input); 224 elements.add(input -> "$" + input); 225 elements.add(input -> "0" + input); 226 227 /* TODO: uncomment this together with the fix for 8140631 228 // Unicode characters 229 elements.add(input -> embed(input, "\u0001")); 230 elements.add(input -> embed(input, "\u007F")); 231 // Combining character 232 elements.add(input -> embed(input, "\u0300")); 233 elements.add(input -> embed(input, "\u0306")); 234 // Supplementary character 235 elements.add(input -> new String(Character.toChars(0x1F64C))); 236 */ 237 return elements; 238 } 239 240 /** 241 * Embeds one string inside another one 242 * 243 * @param target target source string 244 * @param element string to be embedded into target string 245 * @return result string 246 */ 247 private static String embed(String target, String element) { 248 int mid = target.length() / 2; 249 String begin = target.substring(0, mid); 250 String end = target.substring(mid); 251 return begin + element + end; 252 } 253 254 /** 255 * Generates triples from the given enum sets 256 * for each of the method elements 257 * 258 * @param classSet set of allowed elements for class 259 * @param methodSet set of allowed elements for method 260 * @param signSet set of allowed elements for signature 261 * @param <E> type of generated triples 262 * @return list of triples 263 */ 264 private static <E extends Enum<E>> List<Combination<E>> generate( 265 EnumSet<E> classSet, EnumSet<E> methodSet, EnumSet<E> signSet) { 266 List<Combination<E>> list = new ArrayList<>(); 267 classSet.forEach(clsElement -> 268 methodSet.forEach(methodElement -> 269 signSet.forEach(signElement -> 270 list.add(new Combination<>(clsElement, methodElement, 271 signElement)) 272 ) 273 ) 274 ); 275 return list; 276 } 277 278 private static class Combination<T> extends Triple<T, T, T> { 279 public Combination(T first, T second, T third) { 280 super(first, second, third); 281 } 282 } 283 }