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 jdk.test.lib.Triple; 27 28 import java.lang.reflect.Executable; 29 import java.util.function.Function; 30 import java.util.regex.Pattern; 31 32 /** 33 * Method descriptor for Compiler Control commands. 34 * It represents method pattern used for matching in Compiler Control 35 * and CompileCommand option 36 */ 37 public class MethodDescriptor { 38 public final ClassType aClass; // Represents class and package 39 public final MethodType aMethod; // Represents method 40 public final SignatureType aSignature; // Represents signature 41 42 /** 43 * Constructor 44 * 45 * @param method executable to build method descriptor from 46 */ 47 public MethodDescriptor(Executable method) { 48 aClass = new ClassType(method); 49 aMethod = new MethodType(method); 50 aSignature = new SignatureType(method); 51 } 52 53 /** 54 * Sets signature separators for all elements 55 */ 56 public void setSeparators( 57 Triple<Separator, Separator, Separator> separators) { 58 aClass.setSeparator(separators.getFirst()); 59 aMethod.setSeparator(separators.getSecond()); 60 aSignature.setSeparator(separators.getThird()); 61 } 62 63 /** 64 * Sets custom strings for each element 65 */ 66 public void setStrings(Triple<String, String, String> strings) { 67 aClass.setElement(strings.getFirst()); 68 aMethod.setElement(strings.getSecond()); 69 aSignature.setElement(strings.getThird()); 70 } 71 72 /** 73 * Sets patterns for all elements 74 */ 75 public void setPatterns( 76 Triple<PatternType, PatternType, PatternType> patterns) { 77 aClass.setPattern(patterns.getFirst()); 78 aMethod.setPattern(patterns.getSecond()); 79 aSignature.setPattern(patterns.getThird()); 80 } 81 82 /** 83 * Separates elements in the MethodDescriptor 84 */ 85 public static enum Separator { 86 SLASH("/"), 87 DOT("."), 88 COMMA(","), 89 DOUBLECOLON("::"), 90 SPACE(" "), 91 NONE(""); 92 93 public final String symbol; 94 95 Separator(String symbol) { 96 this.symbol = symbol; 97 } 98 99 /** 100 * Validates method descriptor separators 101 * 102 * @param md method descriptor to validate 103 * @return true if descriptor's separators are valid 104 */ 105 public static boolean isValid(MethodDescriptor md) { 106 Separator cls = md.getClassSeparator(); 107 Separator method = md.getMethodSeparator(); 108 Separator sign = md.getSignatureSeparator(); 109 if (sign == SPACE || sign == NONE || sign == COMMA) { 110 // if it looks like java/lang/String.indexOf 111 if ((cls == SLASH || cls == NONE) 112 // allow space and comma instead of dot 113 && (method == DOT || method == SPACE 114 || method == COMMA)) { 115 return true; 116 } 117 // if it looks like java.lang.String::indexOf 118 if ((cls == DOT || cls == NONE) && method == DOUBLECOLON) { 119 return true; 120 } 121 } 122 return false; 123 } 124 } 125 126 /** 127 * Type of the pattern 128 */ 129 public static enum PatternType { 130 PREFIX, 131 ANY, 132 SUFFIX, 133 SUBSTRING, 134 EXACT 135 } 136 137 public Separator getClassSeparator() { 138 return aClass.getSeparator(); 139 } 140 141 public Separator getMethodSeparator() { 142 return aMethod.getSeparator(); 143 } 144 145 public Separator getSignatureSeparator() { 146 return aSignature.getSeparator(); 147 } 148 149 /** 150 * Gets regular expression to match methods 151 * 152 * @return string representation of the regular expression 153 */ 154 public String getRegexp() { 155 // regexp should have a . as a method separator 156 // and / as a package/class separator 157 return aClass.getRegexp().replaceAll("\\.", "/") 158 .replaceAll("/\\*", ".*") 159 + Pattern.quote(Separator.DOT.symbol) 160 + aMethod.getRegexp() + aSignature.getRegexp(); 161 } 162 163 /** 164 * Gets method descriptor string representation. 165 * This string is used as a pattern in CompilerControl and CompileCommand 166 */ 167 public String getString() { 168 return aClass.getElement() + getMethodSeparator().symbol 169 + aMethod.getElement() + getSignatureSeparator().symbol 170 + aSignature.getElement(); 171 } 172 173 /** 174 * Convert method descriptor to be regexp-compatible 175 * 176 * @return string representation of the method signature 177 */ 178 public String getCanonicalString() { 179 return aClass.getElement().replaceAll("\\.", "/") + Separator.DOT.symbol 180 + aMethod.getElement() + aSignature.getElement(); 181 } 182 183 /** 184 * Shows if this descriptor is a valid pattern for CompilerControl 185 * 186 * @return true, if descriptor is valid, false otherwise 187 */ 188 public boolean isValid() { 189 return aClass.isValid() && aMethod.isValid() && aSignature.isValid() 190 && Separator.isValid(this); 191 } 192 193 /** 194 * Sets custom string from element mutate function 195 * to the appropriate element of method descriptor 196 */ 197 public void applyMutates(Triple<Function<String, String>, 198 Function<String, String>, 199 Function<String, String>> mutators) { 200 String elementString = aClass.getElement(); 201 aClass.setElement(mutators.getFirst().apply(elementString)); 202 elementString = aMethod.getElement(); 203 aMethod.setElement(mutators.getSecond().apply(elementString)); 204 elementString = aSignature.getElement(); 205 aSignature.setElement(mutators.getThird().apply(elementString)); 206 } 207 }