/*
* FindBugs - Find Bugs in Java programs
* Copyright (C) 2006, University of Maryland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package edu.umd.cs.findbugs.util;
import javax.annotation.meta.When;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.classfile.ClassDescriptor;
import edu.umd.cs.findbugs.classfile.DescriptorFactory;
import edu.umd.cs.findbugs.internalAnnotations.DottedClassName;
import edu.umd.cs.findbugs.internalAnnotations.SlashedClassName;
/**
* Utility methods for working with class names.
*
* @author David Hovemeyer
*/
public abstract class ClassName {
public static String toSignature(@SlashedClassName String className) {
if (className.length() == 0)
throw new IllegalArgumentException("classname can't be empty");
if (className.charAt(0) == '[' || className.endsWith(";")) return className;
return "L" + className + ";";
}
public static @CheckForNull @SlashedClassName String fromFieldSignature(String signature) {
if (signature.charAt(0) != 'L') return null;
return signature.substring(1, signature.length()-1);
}
/**
*
* @param signature bytecode notated type name
* @return for reference types: class name without bytecode characters, otherwise
* unchanged signature
*/
@Deprecated
public static String fromSignature(String signature) {
if (signature.charAt(0) == '[') {
if (signature.charAt(signature.length() - 1) == ';') {
// [Ljava.lang.String; or [[Ljava.lang.String;
int start = 1;
while (signature.charAt(start) == '[') {
start++;
}
return signature.substring(start + 1, signature.length() - 1);
} else {
// [Z
return signature; //signature.substring(start, signature.length());
}
}
return signature;
}
/**
* Convert class name to slashed format.
* If the class name is already in slashed format,
* it is returned unmodified.
*
* @param className a class name
* @return the same class name in slashed format
*/
public static @SlashedClassName String toSlashedClassName(
@SlashedClassName(when=When.UNKNOWN) String className) {
if (className.indexOf('.') >= 0) {
return DescriptorFactory.canonicalizeString(className.replace('.', '/'));
}
return className;
}
/**
* Convert class name to dotted format.
* If the class name is already in dotted format,
* it is returned unmodified.
*
* @param className a class name
* @return the same class name in dotted format
*/
public static @DottedClassName String toDottedClassName(@SlashedClassName(when=When.UNKNOWN) String className) {
if (className.indexOf('/') >= 0) {
return DescriptorFactory.canonicalizeString(className.replace('/', '.'));
}
return className;
}
/**
* extract the package name from a dotted class name.
* Package names are always in dotted format.
*
* @param className a dotted class name
* @return the name of the package containing the class
*/
public static @DottedClassName String extractPackageName(@DottedClassName String className) {
int i = className.lastIndexOf('.');
if (i < 0) return "";
return className.substring(0, i);
}
public static @DottedClassName String extractSimpleName(@DottedClassName String className) {
int i = className.lastIndexOf('.');
if (i < 0) return className;
return className.substring(i+1);
}
/**
* Return whether or not the given class name is valid.
*
* @param className a possible class name
* @return true if it's a valid class name, false otherwise
*/
public static boolean isValidClassName(String className) {
// FIXME: should use a regex
if (className.indexOf('(') >= 0) {
return false;
}
return true;
}
/**
* Does a class name appear to designate an anonymous class?
* Only the name is analyzed. No classes are loaded or looked up.
*
* @param className class name, slashed or dotted, fully qualified or unqualified
* @return true if className is the name of an anonymous class
*/
public static boolean isAnonymous(String className) {
int i = className.lastIndexOf('$');
if (i >= 0 && i + 1 < className.length()) {
return Character.isDigit(className.charAt(i + 1));
}
return false;
}
/**
* Extract a slashed classname from a JVM classname or signature.
*
* @param originalName JVM classname or signature
* @return a slashed classname
*/
public static @SlashedClassName String extractClassName(String originalName) {
String name = originalName;
if (name.charAt(0) != '[' && name.charAt(name.length() - 1) != ';')
return name;
while (name.charAt(0) == '[')
name = name.substring(1);
if (name.charAt(0) == 'L' && name.charAt(name.length() - 1) == ';')
name = name.substring(1, name.length() - 1);
if (name.charAt(0) == '[') throw new IllegalArgumentException("Bad class name: " + originalName);
return name;
}
public static String extractPackagePrefix(String packageName, int count) {
int dotsSeen = 0;
int prefixLength = 0;
while (dotsSeen < count) {
int p = packageName.indexOf('.', prefixLength);
if (p < 0)
return packageName;
prefixLength = p+1;
dotsSeen++;
}
if (prefixLength == 0)
return "";
return packageName.substring(0, prefixLength-1);
}
public static boolean matchedPrefixes(String[] classSearchStrings, @DottedClassName String className) {
String[] pp = classSearchStrings;
if (pp == null || pp.length == 0)
return true;
for (String p : pp)
if (p.length() > 0 && className.indexOf(p) >= 0)
return true;
return false;
}
}