<commit_before>/*
 * Copyright (c) 2000
 *      <NAME>.  All rights reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * I'd appreciate comments/suggestions on the code <EMAIL>
 */
package net.mtu.eggplant.dbc;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.Stack;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/*
  Things to keep track of:
  methods: pre/post
  classes: methods, invariants

  This to keep track of from class to class:
  interfaces: pre/post, methods, invariant

  I figure I can just write a method called jps__checkPre<methodName>(same
  signature) and jps__checkPost<methodName>(same signature) to get pre and
  post conditions and then just use introspection to call the super method if
  it exists.  Need to explicitly code all interface pre/post/invariant methods
  into all classes that implement an interface.


  DataStructures to be maintained:
    Set of all classes parsed, so we don't parse one twice
    
    Map of files: HashMap (File, SortedSet)
      classes associated with those files?
      CodeFragments associated with those files
    Map of classes:
      Key = full classname
      Value = AssertClass (contains AssertMethods)
    Map of interfaces:
      Key = full interface name
      Value = AssertClass (contains AssertMethods)

    AssertClass:
      Set of Methods in this class
      Set of invariants (Set -> AssertToken)
      
    AssertMethod:
      Set of preconditions, in order that they appear in the code (Set -> AssertToken)
      Entrance point (line, column)
      Set of exit points (Set->(line, column))
      Set of post conditions, order matters (Set -> AssertToken)
      Return type (String)
      Static or not (boolean)
      
  At end of method build CodeFragments for all pre, post, invariants and
  associate them with the current file being processed at the correct lines.
  Also put the checkPost and checkPre methods on the end of the class, right
  after the '}'

  Associate asserts with the current file as they appear

  At the end of a class create a CodeFragment that contains the checkInvariant
  method and associate it with the current file, put it at '}', get this from
  the parser token.
  

*/

/**
 * Class that keeps track of all classes and interfaces parsed in this run.
 * This is the place where most of the work for instrumentation gets done.
 * All lookups are done here.
 * 
 * @version $Revision: 1.10 $
 */
public class Symtab {

  private static final Log LOG = LogFactory.getLog(JonsAssert.class);
  
  /**
     @pre (config != null)
  **/
  public Symtab(final Configuration config) {
    _classStack = new Stack();
    _currentClass = null;
    _currentFile = null;
    _fileStack = new Stack();
    _currentPackageName = "";
    _allPackages = new HashMap();
    _allFiles = new HashSet();
    _methodStack = new Stack();
    _currentMethod = null;
    _config = config;
  }

  private Configuration _config;
  /**
     @return the configuration object used with this symbol table.
  **/
  public final Configuration getConfiguration() {
    return _config;
  }
  
  private String _currentPackageName;
  /**
     set the package the the next class(es) belong to
  **/
  public final void setCurrentPackageName(final String packageName) {
    if(_allPackages.get(packageName) == null) {
      _allPackages.put(packageName, new HashMap());
    }
    _currentPackageName = packageName;
  }

  /**
     @return the package that we're currently defining classes for
  **/
  public final String getCurrentPackageName() {
    return _currentPackageName;
  }
  
  private InstrumentedFile _currentFile;

  public final InstrumentedFile getCurrentFile() {
    return _currentFile;
  }

  /**
     Start a file.  Sets this file as the current one and saves the state of
     the current file being processed, if there is one, nothing happens if
     this file has already been seen.
     
     @return false if the file has already been seen.
  **/
  public boolean startFile(final File f) {
    if(_allFiles.contains(f)) {
      return false;
    }

    //Keep track of the state
    if(_currentFile != null) {
      _fileStack.push(new FileState(_currentFile, _imports, _starImports));
    }

    
    final InstrumentedFile ifile = new InstrumentedFile(f);
    ifile.getFragments().add(TAGLINE_FRAGMENT);
    
    _allFiles.add(f);
    _currentFile = ifile;
    _imports = new HashMap(50);
    _starImports = new HashSet(50);
    
    return true;
  }

  /**
   * Just resets the internal pointers to files to be the last file we pushed
   * on the file stack, or null if no other files are being processed.
   */
  public void finishFile(final boolean writeFile) {
    if(writeFile) {
      instrument(_currentFile);
    }

    if(!_fileStack.isEmpty()) {
      final FileState fs = (FileState)_fileStack.pop();
      _currentFile = fs.getFile();
      _imports = fs.getImports();
      _starImports = fs.getStarImports();
    } else {
      _currentFile = null;
      _imports = null;
      _starImports= null;
    }
  }
  
  /**
     Push a class onto the stack of classes to handle inner classes.  By the
     time this method has been called all of the imports have been seen as
     well as the superclass and the implemented/extended interfaces.

     @param name the name of the class, can be null in the case of anonomous
     classes
     @param invariants the invariants for this class, ordered as they appear
     in the source file
     
     @pre (invariants != null)
  **/
  public void startClass(final String name,
                         final List invariants,
                         final boolean isInterface,
                         final boolean isAnonymous,
                         final String superclass) {
    //[jpschewe:20001017.2330CST] Note this list should be read in from the parser
    final List interfaces = new LinkedList();
    
    AssertClass enclosingClass = _currentClass;
    if(_currentClass != null) {
      _classStack.push(_currentClass);
    }

    if(enclosingClass != null) {
      while(enclosingClass != null && enclosingClass.isAnonymous()) {
        enclosingClass = enclosingClass.getEnclosingClass();
      }
    }
    String className = name;
    if(isAnonymous) {
      className = enclosingClass.createAnonymousClassName();
    }
    _currentClass = new AssertClass(className, getCurrentPackageName(), isInterface, enclosingClass, isAnonymous, superclass, interfaces, _imports, _starImports);
    _currentClass.setInvariants(invariants);
    
    //System.out.println("in Symtab.startClass " + _currentClass);
    
    // add to the current package
    HashMap h = (HashMap)_allPackages.get(getCurrentPackageName());
    if(h == null) {
      _allPackages.put(getCurrentPackageName(), new HashMap());
      h = (HashMap)_allPackages.get(getCurrentPackageName());
    }
    h.put(className, getCurrentClass());

    // associate it with a file too
    //Set v = (Set)_allFiles.get(getCurrentFile());
    //v.addElement(getCurrentClass());    
  }

  /**
     Take all of the assertion methods that have been cached up and dump them
     out with this class.  This should dump out pre and post methods for each
     method defined as well as a checkInvariants method.

     @param cp the point that represents the closing curly brace of the class,
     the checkInvariant method will be inserted here.

     @pre (cp != null)
  **/
  public void finishClass(final CodePoint cp) {
    //Uniquify constructors
    AssertTools.setUniqueParams(_currentClass);
    
    final boolean extendsObject = AssertTools.extendsObject(_currentClass);
    //add the invariant method, not on interfaces though
    if(!_currentClass.isInterface() && !(extendsObject && _currentClass.getInvariants().isEmpty())) {
      final String code = CodeGenerator.generateInvariantMethod(_currentClass);
      final CodeFragment cf = new CodeFragment(cp, code, CodeFragmentType.INVARIANT);
      _currentFile.getFragments().add(cf);
    }
    
    _currentFile.getClasses().addElement(_currentClass);
    
    if(!_classStack.isEmpty()) {
      _currentClass = (AssertClass)_classStack.pop();
    } else {
      _currentClass = null;
    }
  }

  /**
     Accessor for the currnet class being instrumented.

     @return the current class being parsed, may return null
  **/
  public final AssertClass getCurrentClass() {
    return _currentClass;
  }

  /**
     instrument a file we've parsed.
  **/
  public void instrument(final InstrumentedFile ifile) {
    String packageName = null;
    //Add CodeFragments from all of the classes that are in ifile
    final Iterator classIter = ifile.getClasses().iterator();
    while(classIter.hasNext()) {
      final AssertClass aClass = (AssertClass)classIter.next();
      packageName = aClass.getPackage();
      addClassInstrumentation(ifile, aClass);
    }
    //dump out the fragments and instrument the file
    try {
      final LineNumberReader reader = new LineNumberReader(new FileReader(ifile.getFile()));
      final String ifilename = getConfiguration().getInstrumentedFilename(ifile.getFile(), packageName);
      final BufferedWriter writer = new BufferedWriter(new FileWriter(ifilename));

      // instrument lines
      final Iterator fragIter = ifile.getFragments().iterator();
      CodeFragment curFrag = null;
      if(fragIter.hasNext()) {
        //Have something to instrument
        curFrag = (CodeFragment)fragIter.next();
        String line = reader.readLine();
        while(line != null) {
          final StringBuffer buf = new StringBuffer(line);        
          int offset = 0;
          while(curFrag != null && reader.getLineNumber() == curFrag.getLocation().getLine()) {
            if(JonsAssert.getSymtab().getConfiguration().isPrettyOutput()) {
              buf.append("//DBC Line: ");
              buf.append(String.valueOf(reader.getLineNumber()));
            }
            //instrument line
            offset = curFrag.instrumentLine(offset, buf);
            if(fragIter.hasNext()) {<commit_msg>Had to turn off the printing of line numbers.<commit_after>/*
 * Copyright (c) 2000
 *      <NAME>.  All rights reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * I'd appreciate comments/suggestions on the code <EMAIL>
 */
package net.mtu.eggplant.dbc;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.Stack;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/*
  Things to keep track of:
  methods: pre/post
  classes: methods, invariants

  This to keep track of from class to class:
  interfaces: pre/post, methods, invariant

  I figure I can just write a method called jps__checkPre<methodName>(same
  signature) and jps__checkPost<methodName>(same signature) to get pre and
  post conditions and then just use introspection to call the super method if
  it exists.  Need to explicitly code all interface pre/post/invariant methods
  into all classes that implement an interface.


  DataStructures to be maintained:
    Set of all classes parsed, so we don't parse one twice
    
    Map of files: HashMap (File, SortedSet)
      classes associated with those files?
      CodeFragments associated with those files
    Map of classes:
      Key = full classname
      Value = AssertClass (contains AssertMethods)
    Map of interfaces:
      Key = full interface name
      Value = AssertClass (contains AssertMethods)

    AssertClass:
      Set of Methods in this class
      Set of invariants (Set -> AssertToken)
      
    AssertMethod:
      Set of preconditions, in order that they appear in the code (Set -> AssertToken)
      Entrance point (line, column)
      Set of exit points (Set->(line, column))
      Set of post conditions, order matters (Set -> AssertToken)
      Return type (String)
      Static or not (boolean)
      
  At end of method build CodeFragments for all pre, post, invariants and
  associate them with the current file being processed at the correct lines.
  Also put the checkPost and checkPre methods on the end of the class, right
  after the '}'

  Associate asserts with the current file as they appear

  At the end of a class create a CodeFragment that contains the checkInvariant
  method and associate it with the current file, put it at '}', get this from
  the parser token.
  

*/

/**
 * Class that keeps track of all classes and interfaces parsed in this run.
 * This is the place where most of the work for instrumentation gets done.
 * All lookups are done here.
 * 
 * @version $Revision: 1.11 $
 */
public class Symtab {

  private static final Log LOG = LogFactory.getLog(JonsAssert.class);
  
  /**
     @pre (config != null)
  **/
  public Symtab(final Configuration config) {
    _classStack = new Stack();
    _currentClass = null;
    _currentFile = null;
    _fileStack = new Stack();
    _currentPackageName = "";
    _allPackages = new HashMap();
    _allFiles = new HashSet();
    _methodStack = new Stack();
    _currentMethod = null;
    _config = config;
  }

  private Configuration _config;
  /**
     @return the configuration object used with this symbol table.
  **/
  public final Configuration getConfiguration() {
    return _config;
  }
  
  private String _currentPackageName;
  /**
     set the package the the next class(es) belong to
  **/
  public final void setCurrentPackageName(final String packageName) {
    if(_allPackages.get(packageName) == null) {
      _allPackages.put(packageName, new HashMap());
    }
    _currentPackageName = packageName;
  }

  /**
     @return the package that we're currently defining classes for
  **/
  public final String getCurrentPackageName() {
    return _currentPackageName;
  }
  
  private InstrumentedFile _currentFile;

  public final InstrumentedFile getCurrentFile() {
    return _currentFile;
  }

  /**
     Start a file.  Sets this file as the current one and saves the state of
     the current file being processed, if there is one, nothing happens if
     this file has already been seen.
     
     @return false if the file has already been seen.
  **/
  public boolean startFile(final File f) {
    if(_allFiles.contains(f)) {
      return false;
    }

    //Keep track of the state
    if(_currentFile != null) {
      _fileStack.push(new FileState(_currentFile, _imports, _starImports));
    }

    
    final InstrumentedFile ifile = new InstrumentedFile(f);
    ifile.getFragments().add(TAGLINE_FRAGMENT);
    
    _allFiles.add(f);
    _currentFile = ifile;
    _imports = new HashMap(50);
    _starImports = new HashSet(50);
    
    return true;
  }

  /**
   * Just resets the internal pointers to files to be the last file we pushed
   * on the file stack, or null if no other files are being processed.
   */
  public void finishFile(final boolean writeFile) {
    if(writeFile) {
      instrument(_currentFile);
    }

    if(!_fileStack.isEmpty()) {
      final FileState fs = (FileState)_fileStack.pop();
      _currentFile = fs.getFile();
      _imports = fs.getImports();
      _starImports = fs.getStarImports();
    } else {
      _currentFile = null;
      _imports = null;
      _starImports= null;
    }
  }
  
  /**
     Push a class onto the stack of classes to handle inner classes.  By the
     time this method has been called all of the imports have been seen as
     well as the superclass and the implemented/extended interfaces.

     @param name the name of the class, can be null in the case of anonomous
     classes
     @param invariants the invariants for this class, ordered as they appear
     in the source file
     
     @pre (invariants != null)
  **/
  public void startClass(final String name,
                         final List invariants,
                         final boolean isInterface,
                         final boolean isAnonymous,
                         final String superclass) {
    //[jpschewe:20001017.2330CST] Note this list should be read in from the parser
    final List interfaces = new LinkedList();
    
    AssertClass enclosingClass = _currentClass;
    if(_currentClass != null) {
      _classStack.push(_currentClass);
    }

    if(enclosingClass != null) {
      while(enclosingClass != null && enclosingClass.isAnonymous()) {
        enclosingClass = enclosingClass.getEnclosingClass();
      }
    }
    String className = name;
    if(isAnonymous) {
      className = enclosingClass.createAnonymousClassName();
    }
    _currentClass = new AssertClass(className, getCurrentPackageName(), isInterface, enclosingClass, isAnonymous, superclass, interfaces, _imports, _starImports);
    _currentClass.setInvariants(invariants);
    
    //System.out.println("in Symtab.startClass " + _currentClass);
    
    // add to the current package
    HashMap h = (HashMap)_allPackages.get(getCurrentPackageName());
    if(h == null) {
      _allPackages.put(getCurrentPackageName(), new HashMap());
      h = (HashMap)_allPackages.get(getCurrentPackageName());
    }
    h.put(className, getCurrentClass());

    // associate it with a file too
    //Set v = (Set)_allFiles.get(getCurrentFile());
    //v.addElement(getCurrentClass());    
  }

  /**
     Take all of the assertion methods that have been cached up and dump them
     out with this class.  This should dump out pre and post methods for each
     method defined as well as a checkInvariants method.

     @param cp the point that represents the closing curly brace of the class,
     the checkInvariant method will be inserted here.

     @pre (cp != null)
  **/
  public void finishClass(final CodePoint cp) {
    //Uniquify constructors
    AssertTools.setUniqueParams(_currentClass);
    
    final boolean extendsObject = AssertTools.extendsObject(_currentClass);
    //add the invariant method, not on interfaces though
    if(!_currentClass.isInterface() && !(extendsObject && _currentClass.getInvariants().isEmpty())) {
      final String code = CodeGenerator.generateInvariantMethod(_currentClass);
      final CodeFragment cf = new CodeFragment(cp, code, CodeFragmentType.INVARIANT);
      _currentFile.getFragments().add(cf);
    }
    
    _currentFile.getClasses().addElement(_currentClass);
    
    if(!_classStack.isEmpty()) {
      _currentClass = (AssertClass)_classStack.pop();
    } else {
      _currentClass = null;
    }
  }

  /**
     Accessor for the currnet class being instrumented.

     @return the current class being parsed, may return null
  **/
  public final AssertClass getCurrentClass() {
    return _currentClass;
  }

  /**
     instrument a file we've parsed.
  **/
  public void instrument(final InstrumentedFile ifile) {
    String packageName = null;
    //Add CodeFragments from all of the classes that are in ifile
    final Iterator classIter = ifile.getClasses().iterator();
    while(classIter.hasNext()) {
      final AssertClass aClass = (AssertClass)classIter.next();
      packageName = aClass.getPackage();
      addClassInstrumentation(ifile, aClass);
    }
    //dump out the fragments and instrument the file
    try {
      final LineNumberReader reader = new LineNumberReader(new FileReader(ifile.getFile()));
      final String ifilename = getConfiguration().getInstrumentedFilename(ifile.getFile(), packageName);
      final BufferedWriter writer = new BufferedWriter(new FileWriter(ifilename));

      // instrument lines
      final Iterator fragIter = ifile.getFragments().iterator();
      CodeFragment curFrag = null;
      if(fragIter.hasNext()) {
        //Have something to instrument
        curFrag = (CodeFragment)fragIter.next();
        String line = reader.readLine();
        while(line != null) {
          final StringBuffer buf = new StringBuffer(line);        
          //if(JonsAssert.getSymtab().getConfiguration().isPrettyOutput()) {
          //  buf.append("//DBC Line: ");
          //  buf.append(String.valueOf(reader.getLineNumber()));
          //}
            
          int offset = 0;
          while(curFrag != null && reader.getLineNumber() == curFrag.getLocation().getLine()) {
            //instrument line
            offset = curFrag.instrumentLine(offset, buf);
            if(fragIter.hasNext()) {
{'fraction_non_alphanumeric': 0.08194331289395823, 'fraction_numerical': 0.002229750010719952, 'mean_word_length': 3.0879929886064854, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5509077', 'n_tokens_mistral': 6514, 'n_tokens_neox': 6232, 'n_words': 2306}