/*
* FindBugs - Find bugs in Java programs
* Copyright (C) 2005, 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.detect;
import java.util.regex.Pattern;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Signature;
import edu.umd.cs.findbugs.BugAccumulator;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.OpcodeStack;
import edu.umd.cs.findbugs.bcel.OpcodeStackDetector;
/**
* equals and hashCode are blocking methods on URL's. Warn about invoking equals
* or hashCode on them, or defining Set or Maps with them as keys.
*/
public class URLProblems extends OpcodeStackDetector {
final static String[] BAD_SIGNATURES = { "Hashtable<Ljava/net/URL", "Map<Ljava/net/URL", "Set<Ljava/net/URL" };
final private BugReporter bugReporter;
final private BugAccumulator accumulator;
public URLProblems(BugReporter bugReporter) {
this.bugReporter = bugReporter;
this.accumulator = new BugAccumulator(bugReporter);
}
@Override
public void visitAfter(JavaClass obj) {
accumulator.reportAccumulatedBugs();
}
@Override
public void visit(Signature obj) {
String sig = obj.getSignature();
for (String s : BAD_SIGNATURES)
if (sig.indexOf(s) >= 0) {
if (visitingField())
bugReporter.reportBug(new BugInstance(this, "DMI_COLLECTION_OF_URLS", HIGH_PRIORITY).addClass(this)
.addVisitedField(this));
else if (visitingMethod())
bugReporter.reportBug(new BugInstance(this, "DMI_COLLECTION_OF_URLS", HIGH_PRIORITY).addClassAndMethod(this));
else
bugReporter.reportBug(new BugInstance(this, "DMI_COLLECTION_OF_URLS", HIGH_PRIORITY).addClass(this).addClass(
this));
}
}
void check(String className, Pattern name, int target, int url) {
if (!name.matcher(getNameConstantOperand()).matches())
return;
if (stack.getStackDepth() <= target)
return;
OpcodeStack.Item targetItem = stack.getStackItem(target);
OpcodeStack.Item urlItem = stack.getStackItem(url);
if (!urlItem.getSignature().equals("Ljava/net/URL;"))
return;
if (!targetItem.getSignature().equals(className))
return;
accumulator.accumulateBug(new BugInstance(this, "DMI_COLLECTION_OF_URLS", HIGH_PRIORITY).addClassAndMethod(this)
.addCalledMethod(this), this);
}
@Override
public void sawOpcode(int seen) {
// System.out.println(getPC() + " " + OPCODE_NAMES[seen] + " " + stack);
if (seen == INVOKEVIRTUAL || seen == INVOKEINTERFACE) {
check("Ljava/util/HashSet;", Pattern.compile("add|remove|contains"), 1, 0);
check("Ljava/util/HashMap;", Pattern.compile("remove|containsKey|get"), 1, 0);
check("Ljava/util/HashMap;", Pattern.compile("put"), 2, 1);
}
if (seen == INVOKEVIRTUAL && getClassConstantOperand().equals("java/net/URL")) {
if (getNameConstantOperand().equals("equals") && getSigConstantOperand().equals("(Ljava/lang/Object;)Z")
|| getNameConstantOperand().equals("hashCode") && getSigConstantOperand().equals("()I")) {
accumulator.accumulateBug(
new BugInstance(this, "DMI_BLOCKING_METHODS_ON_URL", HIGH_PRIORITY).addClassAndMethod(this)
.addCalledMethod(this), this);
}
}
}
}