Logo Search packages:      
Sourcecode: jlint version File versions

class_desc.cc

#include "class_desc.hh"

class_desc::class_desc(utf_string const& str) 
  : name(str), source_file(str+".java", true) 
{ 
  fields = NULL;
  methods = NULL;
  n_bases = 0;
  attr = cl_system;
  class_vertex = new graph_vertex(this);
  metaclass_vertex = new graph_vertex(this);
  next = chain;
  chain = this;
}

class_desc* class_desc::get(utf_string const& str)
{
  unsigned h = str.hash() % class_hash_table_size;
  class_desc* cls;
  for (cls = hash_table[h]; cls != NULL; cls = cls->collision_chain) { 
    if (str == cls->name) { 
      return cls;
    }
  }
  cls = new class_desc(str);
  cls->collision_chain = hash_table[h];
  hash_table[h] = cls;
  n_classes += 1;
  return cls;
}

method_desc* class_desc::get_method(utf_string const& mth_name,
                                    utf_string const& mth_desc) 
{ 
  for (method_desc* method = methods; method != NULL; method = method->next){
    if (method->name == mth_name && method->desc == mth_desc) {
      return method;
    }
  }
  return methods = new method_desc(mth_name, mth_desc, this, methods);
}

field_desc* class_desc::get_field(utf_string const& field_name)
{ 
  for (field_desc* field = fields; field != NULL; field = field->next) { 
    if (field->name == field_name) return field;
  }
  return fields = new field_desc(field_name, this, fields);
}

bool class_desc::isa(const char* cls_name)
{
  for (class_desc* cls = this; cls->n_bases != 0; cls = *cls->bases) { 
    if (cls->name == cls_name) return true;
  }
  return false;
}

bool class_desc::isa(class_desc* base_class)
{
  for (class_desc* cls = this; cls->n_bases != 0; cls = *cls->bases) { 
    if (cls == base_class) return true;
  }
  return false;
}

bool class_desc::implements(const char* interface_name)
{
  if (name == interface_name) { 
    return true;
  }
  for (int i = n_bases; --i >= 0;) { 
    if (bases[i]->implements(interface_name)) {  
      return true;
    }
  }
  return false;    
}

bool class_desc::in_relationship_with(class_desc* cls)
{
  return isa(cls) || cls->isa(this);
}

void class_desc::check_inheritance(class_desc* derived)
{
  for (field_desc* bf = fields; bf != NULL; bf = bf->next) {
    for (field_desc* df = derived->fields; df != NULL; df = df->next) {
      if (bf->name == df->name) { 
        message_at(msg_field_redefined, derived->source_file, 0, 
                   &bf->name, derived, this);
        break;
      }
    }
  }
  for (method_desc* bm = methods; bm != NULL; bm = bm->next) { 
    if (bm->is_special_method() || (bm->attr & method_desc::m_static)) { 
      continue;
    }
    bool overridden = false;
    method_desc* match = NULL;
    for (method_desc* dm=derived->methods; dm != NULL; dm=dm->next) {
      if (bm->name == dm->name) { 
        match = dm;
        if (bm->desc == dm->desc) { 
          overridden = true;
          if (!(dm->attr & method_desc::m_override)) { 
            bm->overridden = 
              new overridden_method(dm, bm->overridden);
            if ((bm->attr & method_desc::m_synchronized) &&
                !(dm->attr & method_desc::m_synchronized))
              {
                message_at(msg_nosync, derived->source_file, 
                           dm->first_line, bm, derived);
              }
            if (!(attr & cl_interface)) { 
              dm->attr |= method_desc::m_override;
            }
          }
          break;
        }
      }    
    }
    if (match != NULL && !overridden) { 
      message_at(msg_not_overridden, derived->source_file, 
                 match->first_line, bm, derived);
    }
  }
  for (int n = 0; n < n_bases; n++) { 
    bases[n]->check_inheritance(derived);
  }
}

void class_desc::calculate_attributes()
{
  for (method_desc* method = methods; method != NULL; method = method->next){
    method->calculate_attributes();
  }
}

void class_desc::build_concurrent_closure()
{
  for (method_desc* method = methods; method != NULL; method = method->next){
    method->build_concurrent_closure();
  }
}

void class_desc::verify()
{
  for (method_desc* method = methods; method != NULL; method=method->next) {
    method->check_synchronization();
    method->check_invocations();
  }
}

void class_desc::build_class_info()
{
  for (int i = 0; i < n_bases; i++) { 
    bases[i]->check_inheritance(this);
  }
  for (method_desc* method = methods; method != NULL; method = method->next){
    method->find_access_dependencies();
  }
  bool overriden_equals = false;
  bool overriden_hashcode = false;
  method_desc* equals_hashcode_match = NULL;
  for (method_desc* bm = methods; bm != NULL; bm = bm->next) { 
    if (bm->name == "equals") {
      overriden_equals = true;
      equals_hashcode_match = bm;
    } else if (bm->name == "hashCode") {
      overriden_hashcode = true;
      equals_hashcode_match = bm;
    }
  }
  if (overriden_equals != overriden_hashcode) {
    if (overriden_equals) {
      message_at(msg_hashcode_not_overridden, source_file, 
                 equals_hashcode_match->first_line);
    } else {
      message_at(msg_equals_not_overridden, source_file, 
                 equals_hashcode_match->first_line);
    }
  }
}

void class_desc::build_call_graph()
{
  for (method_desc* method = methods; method != NULL; method = method->next){
    method->build_call_graph();
  }
}

void class_desc::global_analysis()
{
  class_desc* cls;

  //
  // Set attributes which depends on inheritance hierarchy. 
  //
  for (cls = chain; cls != NULL; cls = cls->next) { 
    cls->calculate_attributes();
  } 

  //
  // Set m_concurrent attribute for all synchronized methods and methods
  // called from them. Detect invocation of wait() method with multiple
  // monitors locked.
  //
  for (cls = chain; cls != NULL; cls = cls->next) { 
    cls->build_concurrent_closure();
  } 
    
  for (cls = chain; cls != NULL; cls = cls->next) { 
    cls->build_class_info();
  }
    
  for (cls = chain; cls != NULL; cls = cls->next) { 
    cls->build_call_graph();
  }
    
  //
  // Check non-synchrnized access to variables by concurrent methods
  // (race condition) and detect unchecked accessed to formal parameters
  // of method which can be passed "null" value in some invocation of 
  // this method
  //
  for (cls = chain; cls != NULL; cls = cls->next) { 
    cls->verify();
  }
    
  //
  // Explore class dependency grpah to detect possible sources of 
  // deadlocks
  //
  graph_vertex::verify();
}

Generated by  Doxygen 1.6.0   Back to index