/* * FindBugs - Find Bugs in Java programs * Copyright (C) 2003-2008 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.ba.jsr305; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import javax.annotation.meta.When; import org.apache.bcel.generic.ConstantPoolGen; import org.apache.bcel.generic.Instruction; import org.apache.bcel.generic.InvokeInstruction; import edu.umd.cs.findbugs.SystemProperties; import edu.umd.cs.findbugs.ba.AnalysisContext; import edu.umd.cs.findbugs.ba.CFG; import edu.umd.cs.findbugs.ba.Location; import edu.umd.cs.findbugs.ba.SignatureParser; import edu.umd.cs.findbugs.ba.XFactory; import edu.umd.cs.findbugs.ba.XMethod; import edu.umd.cs.findbugs.ba.ch.InheritanceGraphVisitor; import edu.umd.cs.findbugs.ba.ch.OverriddenMethodsVisitor; import edu.umd.cs.findbugs.classfile.CheckedAnalysisException; import edu.umd.cs.findbugs.classfile.Global; import edu.umd.cs.findbugs.classfile.IAnalysisCache; import edu.umd.cs.findbugs.classfile.MethodDescriptor; import edu.umd.cs.findbugs.classfile.UncheckedAnalysisException; /** * Find relevant type qualifiers needing to be checked for a given method. * * @author William Pugh */ public class Analysis { private static final boolean DEBUG = SystemProperties.getBoolean("ctq.debug.analysis"); /** * This system property enables additional work to try to detect all * *effective* type qualifiers (direct, inherited, and default) applied to * methods and called methods. * * This step uses an interprocedural call graph. */ public static final boolean FIND_EFFECTIVE_RELEVANT_QUALIFIERS = true; // SystemProperties.getBoolean("ctq.findeffective"); public static final boolean DEBUG_FIND_EFFECTIVE_RELEVANT_QUALIFIERS = FIND_EFFECTIVE_RELEVANT_QUALIFIERS && SystemProperties.getBoolean("ctq.findeffective.debug"); /** * Find relevant type qualifiers needing to be checked for a given method. * * @param methodDescriptor * a method * @return Collection of relevant type qualifiers needing to be checked * @throws CheckedAnalysisException */ public static Collection<TypeQualifierValue> getRelevantTypeQualifiers(MethodDescriptor methodDescriptor, CFG cfg) throws CheckedAnalysisException { final HashSet<TypeQualifierValue> result = new HashSet<TypeQualifierValue>(); XMethod xmethod = XFactory.createXMethod(methodDescriptor); if (FIND_EFFECTIVE_RELEVANT_QUALIFIERS) { if (DEBUG_FIND_EFFECTIVE_RELEVANT_QUALIFIERS) { System.out.println("**** Finding effective type qualifiers for " + xmethod); } // // This will take care of methods using fields annotated with // a type qualifier. // getDirectlyRelevantTypeQualifiers(xmethod, result); // For all known type qualifiers, find the effective (direct, // inherited, // or default) type qualifier annotations // on the method and all methods directly called by the method. // addEffectiveRelevantQualifiers(result, xmethod); IAnalysisCache analysisCache = Global.getAnalysisCache(); ConstantPoolGen cpg = analysisCache.getClassAnalysis(ConstantPoolGen.class, methodDescriptor.getClassDescriptor()); for (Iterator<Location> i = cfg.locationIterator(); i.hasNext();) { Location location = i.next(); Instruction ins = location.getHandle().getInstruction(); if (ins instanceof InvokeInstruction) { XMethod called = XFactory.createXMethod((InvokeInstruction) ins, cpg); addEffectiveRelevantQualifiers(result, called); } if (DEBUG_FIND_EFFECTIVE_RELEVANT_QUALIFIERS) { System.out.println("===> result: " + result); } } // // XXX: this code can go away eventually // if (!methodDescriptor.isStatic()) { // Instance method - must consider type qualifiers inherited // from superclasses InheritanceGraphVisitor visitor = new OverriddenMethodsVisitor(xmethod) { /* * (non-Javadoc) * * @see edu.umd.cs.findbugs.ba.ch.OverriddenMethodsVisitor# * visitOverriddenMethod(edu.umd.cs.findbugs.ba.XMethod) */ @Override protected boolean visitOverriddenMethod(XMethod xmethod) { getDirectlyRelevantTypeQualifiers(xmethod, result); return true; } }; try { AnalysisContext.currentAnalysisContext().getSubtypes2() .traverseSupertypes(xmethod.getClassDescriptor(), visitor); } catch (ClassNotFoundException e) { AnalysisContext.currentAnalysisContext().getLookupFailureCallback().reportMissingClass(e); return Collections.<TypeQualifierValue> emptySet(); } catch (UncheckedAnalysisException e) { AnalysisContext.currentAnalysisContext().getLookupFailureCallback() .logError("Error getting relevant type qualifiers for " + xmethod.toString(), e); return Collections.<TypeQualifierValue> emptySet(); } } } return result; } private static void addEffectiveRelevantQualifiers(HashSet<TypeQualifierValue> result, XMethod xmethod) { if (DEBUG_FIND_EFFECTIVE_RELEVANT_QUALIFIERS) { System.out.println(" Finding effective qualifiers for " + xmethod); } for (TypeQualifierValue tqv : TypeQualifierValue.getAllKnownTypeQualifiers()) { if (DEBUG_FIND_EFFECTIVE_RELEVANT_QUALIFIERS) { System.out.print(" " + tqv + "..."); } TypeQualifierAnnotation tqa; boolean add = false; tqa = TypeQualifierApplications.getEffectiveTypeQualifierAnnotation(xmethod, tqv); if (tqa != null) { add = true; } if (!add) { for (int i = 0; i < xmethod.getNumParams(); i++) { tqa = TypeQualifierApplications.getEffectiveTypeQualifierAnnotation(xmethod, i, tqv); if (tqa != null) { add = true; break; } } } if (add) { result.add(tqv); } if (DEBUG_FIND_EFFECTIVE_RELEVANT_QUALIFIERS) { System.out.println(add ? "YES" : "NO"); } } } // private static void propagateInheritedAnnotations() { // // TODO // } private static void getDirectlyRelevantTypeQualifiers(XMethod xmethod, HashSet<TypeQualifierValue> result) { result.addAll(AnalysisContext.currentAnalysisContext().getDirectlyRelevantTypeQualifiersDatabase() .getDirectlyRelevantTypeQualifiers(xmethod.getMethodDescriptor())); } /** * @param result * @param m */ public static void addKnownTypeQualifiersForParameters(HashSet<TypeQualifierValue> result, XMethod m) { int numParameters = new SignatureParser(m.getSignature()).getNumParameters(); for (int p = 0; p < numParameters; p++) { addKnownTypeQualifiers(result, TypeQualifierApplications.getApplicableApplications(m, p)); } } /** * @param result * @param applicableApplications */ public static void addKnownTypeQualifiers(HashSet<TypeQualifierValue> result, Collection<TypeQualifierAnnotation> applicableApplications) { for (TypeQualifierAnnotation t : applicableApplications) { if (t.when != When.UNKNOWN) { result.add(t.typeQualifier); } } } }