blob: 30c9a4d78bbaaca912738135bd9bccef0dfac0ad [file] [log] [blame]
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package compiler.compilercontrol.share.method;
import jdk.test.lib.util.Triple;
import java.lang.reflect.Executable;
import java.util.function.Function;
import java.util.regex.Pattern;
/**
* Method descriptor for Compiler Control commands.
* It represents method pattern used for matching in Compiler Control
* and CompileCommand option
*/
public class MethodDescriptor {
public final ClassType aClass; // Represents class and package
public final MethodType aMethod; // Represents method
public final SignatureType aSignature; // Represents signature
/**
* Constructor
*
* @param method executable to build method descriptor from
*/
public MethodDescriptor(Executable method) {
aClass = new ClassType(method);
aMethod = new MethodType(method);
aSignature = new SignatureType(method);
}
/**
* Sets signature separators for all elements
*/
public void setSeparators(
Triple<Separator, Separator, Separator> separators) {
aClass.setSeparator(separators.getFirst());
aMethod.setSeparator(separators.getSecond());
aSignature.setSeparator(separators.getThird());
}
/**
* Sets custom strings for each element
*/
public void setStrings(Triple<String, String, String> strings) {
aClass.setElement(strings.getFirst());
aMethod.setElement(strings.getSecond());
aSignature.setElement(strings.getThird());
}
/**
* Sets patterns for all elements
*/
public void setPatterns(
Triple<PatternType, PatternType, PatternType> patterns) {
aClass.setPattern(patterns.getFirst());
aMethod.setPattern(patterns.getSecond());
aSignature.setPattern(patterns.getThird());
}
/**
* Separates elements in the MethodDescriptor
*/
public static enum Separator {
SLASH("/"),
DOT("."),
COMMA(","),
DOUBLECOLON("::"),
SPACE(" "),
NONE("");
public final String symbol;
Separator(String symbol) {
this.symbol = symbol;
}
/**
* Validates method descriptor separators
*
* @param md method descriptor to validate
* @return true if descriptor's separators are valid
*/
public static boolean isValid(MethodDescriptor md) {
Separator cls = md.getClassSeparator();
Separator method = md.getMethodSeparator();
Separator sign = md.getSignatureSeparator();
if (sign == SPACE || sign == NONE || sign == COMMA) {
// if it looks like java/lang/String.indexOf
if ((cls == SLASH || cls == NONE)
// allow space and comma instead of dot
&& (method == DOT || method == SPACE
|| method == COMMA)) {
return true;
}
// if it looks like java.lang.String::indexOf
if ((cls == DOT || cls == NONE) && method == DOUBLECOLON) {
return true;
}
}
return false;
}
}
/**
* Type of the pattern
*/
public static enum PatternType {
PREFIX,
ANY,
SUFFIX,
SUBSTRING,
EXACT
}
public Separator getClassSeparator() {
return aClass.getSeparator();
}
public Separator getMethodSeparator() {
return aMethod.getSeparator();
}
public Separator getSignatureSeparator() {
return aSignature.getSeparator();
}
/**
* Gets regular expression to match methods
*
* @return string representation of the regular expression
*/
public String getRegexp() {
// regexp should have a . as a method separator
// and / as a package/class separator
return aClass.getRegexp().replaceAll("\\.", "/")
.replaceAll("/\\*", ".*")
+ Pattern.quote(Separator.DOT.symbol)
+ aMethod.getRegexp() + aSignature.getRegexp();
}
/**
* Gets method descriptor string representation.
* This string is used as a pattern in CompilerControl and CompileCommand
*/
public String getString() {
return aClass.getElement() + getMethodSeparator().symbol
+ aMethod.getElement() + getSignatureSeparator().symbol
+ aSignature.getElement();
}
/**
* Convert method descriptor to be regexp-compatible
*
* @return string representation of the method signature
*/
public String getCanonicalString() {
return aClass.getElement().replaceAll("\\.", "/") + Separator.DOT.symbol
+ aMethod.getElement() + aSignature.getElement();
}
/**
* Shows if this descriptor is a valid pattern for CompilerControl
*
* @return true, if descriptor is valid, false otherwise
*/
public boolean isValid() {
return aClass.isValid() && aMethod.isValid() && aSignature.isValid()
&& Separator.isValid(this);
}
/**
* Sets custom string from element mutate function
* to the appropriate element of method descriptor
*/
public void applyMutates(Triple<Function<String, String>,
Function<String, String>,
Function<String, String>> mutators) {
String elementString = aClass.getElement();
aClass.setElement(mutators.getFirst().apply(elementString));
elementString = aMethod.getElement();
aMethod.setElement(mutators.getSecond().apply(elementString));
elementString = aSignature.getElement();
aSignature.setElement(mutators.getThird().apply(elementString));
}
}