FieldAnnotation.java :  » Code-Analyzer » findbugs-1.3.9 » edu » umd » cs » findbugs » Java Open Source

Java Open Source » Code Analyzer » findbugs 1.3.9 
findbugs 1.3.9 » edu » umd » cs » findbugs » FieldAnnotation.java
/*
 * FindBugs - Find bugs in Java programs
 * Copyright (C) 2003-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;

import java.io.IOException;

import org.apache.bcel.Constants;
import org.apache.bcel.classfile.Field;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.FieldInstruction;
import org.apache.bcel.generic.GETFIELD;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.PUTFIELD;
import org.apache.bcel.generic.PUTSTATIC;

import edu.umd.cs.findbugs.ba.AnalysisContext;
import edu.umd.cs.findbugs.ba.SignatureConverter;
import edu.umd.cs.findbugs.ba.SourceInfoMap;
import edu.umd.cs.findbugs.ba.XField;
import edu.umd.cs.findbugs.classfile.FieldDescriptor;
import edu.umd.cs.findbugs.internalAnnotations.DottedClassName;
import edu.umd.cs.findbugs.visitclass.DismantleBytecode;
import edu.umd.cs.findbugs.visitclass.PreorderVisitor;
import edu.umd.cs.findbugs.xml.XMLAttributeList;
import edu.umd.cs.findbugs.xml.XMLOutput;

/**
 * A BugAnnotation specifying a particular field in particular class.
 *
 * @author David Hovemeyer
 * @see BugAnnotation
 */
public class FieldAnnotation extends PackageMemberAnnotation {
  private static final long serialVersionUID = 1L;

  public static final String DEFAULT_ROLE = "FIELD_DEFAULT";

  public static final String DID_YOU_MEAN_ROLE = "FIELD_DID_YOU_MEAN";
  public static final String VALUE_OF_ROLE="FIELD_VALUE_OF";
  public static final String LOADED_FROM_ROLE = VALUE_OF_ROLE;
  public static final String STORED_ROLE = "FIELD_STORED";
  public static final String INVOKED_ON_ROLE="FIELD_INVOKED_ON";
  public static final String ARGUMENT_ROLE="FIELD_ARGUMENT";

  private String fieldName;
  private String fieldSig;
  private String fieldSourceSig;
  private boolean isStatic;

  /**
   * Constructor.
   *
   * @param className the name of the class containing the field
   * @param fieldName the name of the field
   * @param fieldSig  the type signature of the field
   */
  public FieldAnnotation(@DottedClassName String className, String fieldName, String fieldSig, boolean isStatic) {
    super(className, DEFAULT_ROLE);
    if (fieldSig.indexOf(".") >= 0) {
      assert false : "signatures should not be dotted: " + fieldSig;
      fieldSig = fieldSig.replace('.','/');
    }
    this.fieldName = fieldName;
    this.fieldSig = fieldSig;
    this.isStatic = isStatic;
  }
  
  public FieldAnnotation(@DottedClassName String className, String fieldName, String fieldSig, String fieldSourceSig, boolean isStatic) {
    this(className, fieldName, fieldSig, isStatic);
    this.fieldSourceSig = fieldSourceSig;
  }
  /**
   * Constructor.
   *
   * @param className the name of the class containing the field
   * @param fieldName the name of the field
   * @param fieldSig  the type signature of the field
   * @param accessFlags accessFlags for the field
   */
  public FieldAnnotation(@DottedClassName String className, String fieldName, String fieldSig, int accessFlags) {
    this(className, fieldName, fieldSig, (accessFlags & Constants.ACC_STATIC) != 0);
  }
  /**
   * Factory method. Class name, field name, and field signatures are taken from
   * the given visitor, which is visiting the field.
   *
   * @param visitor the visitor which is visiting the field
   * @return the FieldAnnotation object
   */
  public static FieldAnnotation fromVisitedField(PreorderVisitor visitor) {
    return new FieldAnnotation(visitor.getDottedClassName(),
        visitor.getFieldName(), visitor.getFieldSig(),
        visitor.getFieldIsStatic());
  }

  /**
   * Factory method. Class name, field name, and field signatures are taken from
   * the given visitor, which is visiting a reference to the field
   * (i.e., a getfield or getstatic instruction).
   *
   * @param visitor the visitor which is visiting the field reference
   * @return the FieldAnnotation object
   */
  public static FieldAnnotation fromReferencedField(DismantleBytecode visitor) {
    String className = visitor.getDottedClassConstantOperand();
    return new FieldAnnotation(className,
        visitor.getNameConstantOperand(),
        visitor.getSigConstantOperand(), visitor.getRefFieldIsStatic());
  }

  /**
   * Factory method. Construct from class name and BCEL Field object.
   *
   * @param className the name of the class which defines the field
   * @param field     the BCEL Field object
   * @return the FieldAnnotation
   */
  public static FieldAnnotation fromBCELField(@DottedClassName String className, Field field) {
    return new FieldAnnotation(className, field.getName(), field.getSignature(), field.isStatic());
  }
  /**
   * Factory method. Construct from class name and BCEL Field object.
   *
   * @param jClass the class which defines the field
   * @param field     the BCEL Field object
   * @return the FieldAnnotation
   */
  public static FieldAnnotation fromBCELField(JavaClass jClass, Field field) {
    return new FieldAnnotation(jClass.getClassName(), field.getName(), field.getSignature(), field.isStatic());
  }

  /**
   * Factory method.  Construct from a FieldDescriptor.
   * 
   * @param fieldDescriptor the FieldDescriptor
   * @return the FieldAnnotation
   */
  public static FieldAnnotation fromFieldDescriptor(FieldDescriptor fieldDescriptor) {
    return new FieldAnnotation(
        fieldDescriptor.getClassDescriptor().getDottedClassName(),
        fieldDescriptor.getName(),
        fieldDescriptor.getSignature(),
        fieldDescriptor.isStatic());
  }

  public static FieldAnnotation fromXField(XField fieldDescriptor) {
    return new FieldAnnotation(
        fieldDescriptor.getClassName(),
        fieldDescriptor.getName(),
        fieldDescriptor.getSignature(),
        fieldDescriptor.getSourceSignature(),
        fieldDescriptor.isStatic());
  }
  /**
   * Get the field name.
   */
  public String getFieldName() {
    return fieldName;
  }

  /**
   * Get the type signature of the field.
   */
  public String getFieldSignature() {
    return fieldSig;
  }

  /**
   * Return whether or not the field is static.
   */
  public boolean isStatic() {
    return isStatic;
  }

  /**
   * Is the given instruction a read of a field?
   *
   * @param ins the Instruction to check
   * @param cpg ConstantPoolGen of the method containing the instruction
   * @return the Field if the instruction is a read of a field, null otherwise
   */
  public static FieldAnnotation isRead(Instruction ins, ConstantPoolGen cpg) {
    if (ins instanceof GETFIELD || ins instanceof GETSTATIC) {
      FieldInstruction fins = (FieldInstruction) ins;
      String className = fins.getClassName(cpg);
      return new FieldAnnotation(className, fins.getName(cpg), fins.getSignature(cpg), fins instanceof GETSTATIC);
    } else
      return null;
  }

  /**
   * Is the instruction a write of a field?
   *
   * @param ins the Instruction to check
   * @param cpg ConstantPoolGen of the method containing the instruction
   * @return the Field if instruction is a write of a field, null otherwise
   */
  public static FieldAnnotation isWrite(Instruction ins, ConstantPoolGen cpg) {
    if (ins instanceof PUTFIELD || ins instanceof PUTSTATIC) {
      FieldInstruction fins = (FieldInstruction) ins;
      String className = fins.getClassName(cpg);
      return new FieldAnnotation(className, fins.getName(cpg), fins.getSignature(cpg), fins instanceof PUTSTATIC);
    } else
      return null;
  }

  public void accept(BugAnnotationVisitor visitor) {
    visitor.visitFieldAnnotation(this);
  }

  @Override
  protected String formatPackageMember(String key, ClassAnnotation primaryClass) {
    if (key.equals("") || key.equals("hash"))
      return className + "." + fieldName;
    else if (key.equals("givenClass")) {
      String primaryClassName = primaryClass.getClassName();
      if (className.equals(primaryClassName)) 
        return getNameInClass(primaryClass);
      else return shorten(primaryClass.getPackageName(), className) + "." + fieldName;
    }
    else if (key.equals("name"))
      return fieldName;
    else if (key.equals("fullField")) {
      SignatureConverter converter = new SignatureConverter(fieldSig);
      StringBuilder result = new StringBuilder();
      if (isStatic)
        result.append("static ");
      result.append(converter.parseNext());
      result.append(' ');
      result.append(className);
      result.append('.');
      result.append(fieldName);
      return result.toString();
    } else
      throw new IllegalArgumentException("unknown key " + key);
  }

  /**
   * @param primaryClass
   * @return
   */
  private String getNameInClass(ClassAnnotation primaryClass) {
    if (primaryClass == null)
      return   className + "." + fieldName;
    String givenPackageName = primaryClass.getPackageName();
    String thisPackageName = this.getPackageName();
    if (thisPackageName.equals(givenPackageName))
      if (thisPackageName.length() == 0) return fieldName;
      else return className.substring(thisPackageName.length() + 1) +"." + fieldName;
    return   className + "." + fieldName;
  }

  @Override
  public int hashCode() {
    return className.hashCode() + fieldName.hashCode() + fieldSig.hashCode();
  }

  @Override
  public boolean equals(Object o) {
    if (!(o instanceof FieldAnnotation))
      return false;
    FieldAnnotation other = (FieldAnnotation) o;
    return className.equals(other.className)
        && fieldName.equals(other.fieldName)
        && fieldSig.equals(other.fieldSig)
        && isStatic == other.isStatic;
  }

  public int compareTo(BugAnnotation o) {
    if (!(o instanceof FieldAnnotation)) // BugAnnotations must be Comparable with any type of BugAnnotation
      return this.getClass().getName().compareTo(o.getClass().getName());
    FieldAnnotation other = (FieldAnnotation) o;
    int cmp;
    cmp = className.compareTo(other.className);
    if (cmp != 0)
      return cmp;
    cmp = fieldName.compareTo(other.fieldName);
    if (cmp != 0)
      return cmp;
    return fieldSig.compareTo(other.fieldSig);
  }

  /* (non-Javadoc)
   * @see edu.umd.cs.findbugs.PackageMemberAnnotation#getSourceLines()
   */
  @Override
  public SourceLineAnnotation getSourceLines() {
    if (sourceLines == null) {
      // Create source line annotation for field on demand
      AnalysisContext currentAnalysisContext = AnalysisContext.currentAnalysisContext();
      if (currentAnalysisContext == null)
        sourceLines = new SourceLineAnnotation(className, sourceFileName, -1, -1, -1, -1);
      else {
      SourceInfoMap.SourceLineRange fieldLine = currentAnalysisContext
        .getSourceInfoMap()
        .getFieldLine(className, fieldName);
      if (fieldLine == null)   sourceLines = new SourceLineAnnotation(
          className, sourceFileName, -1, -1, -1, -1);
      else sourceLines = new SourceLineAnnotation(
          className, sourceFileName, fieldLine.getStart(), fieldLine.getEnd(), -1, -1);
      }
    }
    return sourceLines;
  }

  /* ----------------------------------------------------------------------
   * XML Conversion support
   * ---------------------------------------------------------------------- */

  private static final String ELEMENT_NAME = "Field";

  public void writeXML(XMLOutput xmlOutput) throws IOException {
    writeXML(xmlOutput, false, false);
  }

  public void writeXML(XMLOutput xmlOutput, boolean addMessages, boolean isPrimary) throws IOException {
    XMLAttributeList attributeList = new XMLAttributeList()
      .addAttribute("classname", getClassName())
      .addAttribute("name", getFieldName())
      .addAttribute("signature", getFieldSignature());
    if (fieldSourceSig != null)
      attributeList.addAttribute("sourceSignature", fieldSourceSig);
    attributeList.addAttribute("isStatic", String.valueOf(isStatic()));
    if (isPrimary) attributeList.addAttribute("primary", "true");


    String role = getDescription();
    if (!role.equals(DEFAULT_ROLE))
      attributeList.addAttribute("role", role);

    xmlOutput.openTag(ELEMENT_NAME, attributeList);
    getSourceLines().writeXML(xmlOutput, addMessages, false);
    if (addMessages) {
      xmlOutput.openTag(BugAnnotation.MESSAGE_TAG);
      xmlOutput.writeText(this.toString());
      xmlOutput.closeTag(BugAnnotation.MESSAGE_TAG);
    }
    xmlOutput.closeTag(ELEMENT_NAME);
  }
}

// vim:ts=4
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.