/*
* fb-contrib - Auxiliary detectors for Java programs
* Copyright (C) 2005-2017 Dave Brosius
*
* 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 com.mebigfatguy.fbcontrib.detect;
import java.util.Set;
import org.apache.bcel.classfile.Constant;
import org.apache.bcel.classfile.ConstantClass;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.JavaClass;
import com.mebigfatguy.fbcontrib.utils.BugType;
import com.mebigfatguy.fbcontrib.utils.ToString;
import com.mebigfatguy.fbcontrib.utils.UnmodifiableSet;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.Detector;
import edu.umd.cs.findbugs.ba.ClassContext;
/**
* looks for classes that use objects from com.sun.xxx packages. As these are internal to sun and subject to change, this should not be done.
*/
public class IncorrectInternalClassUse implements Detector {
private static final Set<String> internalPackages = UnmodifiableSet.create(
// @formatter:off
"com/apple/eawt/",
"com/sun/org/apache/xml/internal/",
"com/sun/net/ssl/",
"com/sun/crypto/provider/",
"com/sun/image/codec/jpeg/",
"com/sun/rowset/",
"com/sun/tools/javac/",
"sun/",
"java/awt/peer/",
"java/awt/dnd/peer/",
"jdk/nashorn/internal/",
"org/apache/commons/digester/annotations/internal",
"org/apache/xerces/",
"org/apache/xalan/",
"org/easymock/internal/",
"org/ehcache/internal",
"org/glassfish/internal",
"org/hibernate/cache/internal",
"org/mockito/internal/",
"org/relaxng/datatype/",
"org/springframework/asm/",
"org/springframework/cglib/",
"org/springframework/objenesis/",
"dagger/internal"
// @formatter:on
);
private static final Set<String> externalPackages = UnmodifiableSet.create(
// @formatter:off
"org/apache/xerces/xni/",
"org/apache/xerces/xs/",
"org/apache/xalan/extensions"
// @formatter:on
);
private final BugReporter bugReporter;
/**
* constructs a IICU detector given the reporter to report bugs on
*
* @param bugReporter
* the sync of bug reports
*/
public IncorrectInternalClassUse(BugReporter bugReporter) {
this.bugReporter = bugReporter;
}
/**
* implements the visitor to look for classes that reference com.sun.xxx, or org.apache.xerces.xxx classes by looking for class constants in the constant
* pool
*
* @param context
* the context object of the currently parsed class
*/
@Override
public void visitClassContext(ClassContext context) {
JavaClass cls = context.getJavaClass();
if (!isInternal(cls.getClassName())) {
ConstantPool pool = cls.getConstantPool();
int numItems = pool.getLength();
for (int i = 0; i < numItems; i++) {
Constant c = pool.getConstant(i);
if (c instanceof ConstantClass) {
String clsName = ((ConstantClass) c).getBytes(pool);
if (isInternal(clsName)) {
bugReporter.reportBug(
new BugInstance(this, BugType.IICU_INCORRECT_INTERNAL_CLASS_USE.name(), NORMAL_PRIORITY).addClass(cls).addString(clsName));
}
}
}
}
}
/**
* implementation stub for Detector interface
*/
@Override
public void report() {
// not used, required by the interface
}
/**
* determines if the class in question is an internal class by looking at package prefixes
*
* @param clsName
* the name of the class to check
* @return whether the class is internal
*/
private static boolean isInternal(String clsName) {
boolean internal = false;
for (String internalPackage : internalPackages) {
if (clsName.startsWith(internalPackage)) {
internal = true;
break;
}
}
if (internal) {
for (String externalPackage : externalPackages) {
if (clsName.startsWith(externalPackage)) {
internal = false;
break;
}
}
}
return internal;
}
@Override
public String toString() {
return ToString.build(this);
}
}