gt:             FastStringBuffer fastStringBuffer = (FastStringBuffer) doc;
context: /**
   * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
   * Licensed under the terms of the Eclipse Public License (EPL).
   * Please see the license.txt included with this distribution for details.
   * Any modifications to this file must keep this entire header intact.
   */
  /*
   * Created on 07/09/2005
   */
  package com.python.pydev.analysis.additionalinfo;
  
  import java.io.BufferedInputStream;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.ObjectInputStream;
  import java.io.OutputStreamWriter;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Map.Entry;
  import java.util.Set;
  import java.util.SortedMap;
  
  import org.eclipse.core.runtime.IProgressMonitor;
  import org.eclipse.jface.text.IDocument;
  import org.python.pydev.core.FileUtilsFileBuffer;
  import org.python.pydev.core.FullRepIterable;
  import org.python.pydev.core.MisconfigurationException;
  import org.python.pydev.core.ModulesKey;
  import org.python.pydev.core.ModulesKeyForZip;
  import org.python.pydev.core.ObjectsPool;
  import org.python.pydev.core.Tuple3;
  import org.python.pydev.core.docutils.StringUtils;
  import org.python.pydev.core.log.Log;
  import org.python.pydev.core.structure.FastStack;
  import org.python.pydev.editor.codecompletion.revisited.PyPublicTreeMap;
  import org.python.pydev.logging.DebugSettings;
  import org.python.pydev.parser.fastparser.FastDefinitionsParser;
  import org.python.pydev.parser.jython.SimpleNode;
  import org.python.pydev.parser.jython.ast.ClassDef;
  import org.python.pydev.parser.jython.ast.FunctionDef;
  import org.python.pydev.parser.jython.ast.NameTok;
  import org.python.pydev.parser.visitors.NodeUtils;
  import org.python.pydev.parser.visitors.scope.ASTEntry;
  import org.python.pydev.parser.visitors.scope.DefinitionsASTIteratorVisitor;
  
  import com.aptana.shared_core.string.FastStringBuffer;
  import com.aptana.shared_core.structure.Tuple;
  
  /**
   * This class contains additional information on an interpreter, so that we are able to make code-completion in
   * a context-insensitive way (and make additionally auto-import).
   * 
   * The information that is needed for that is the following:
   * 
   * - Classes that are available in the global context
   * - Methods that are available in the global context
   * 
   * We must access this information very fast, so the underlying structure has to take that into consideration.
   * 
   * It should not 'eat' too much memory because it should be all in memory at all times
   * 
   * It should also be easy to query it. 
   *      Some query situations include: 
   *          - which classes have the method xxx and yyy?
   *          - which methods and classes start with xxx?
   *          - is there any class or method with the name xxx?
   *      
   * The information must be persisted for reuse (and persisting and restoring it should be fast).
   * 
   * We need to store information for any interpreter, be it python, jython...
   * 
   * For creating and keeping this information up-to-date, we have to know when:
   * - the interpreter used changes (the InterpreterInfo should be passed after the change)
   * - some file changes (pydev_builder)
   * 
   * @author Fabio
   */
  public abstract class AbstractAdditionalTokensInfo {
  
      /**
       * this is the number of initials that is used for indexing
       */
      public static final int NUMBER_OF_INITIALS_TO_INDEX = 3;
  
      /**
       * Do you want to debug this class?
       */
      private static final boolean DEBUG_ADDITIONAL_INFO = false;
  
      /**
       * Defines that some operation should be done on top level tokens
       */
      public final static int TOP_LEVEL = 1;
  
      /**
       * Defines that some operation should be done on inner level tokens
       */
      public final static int INNER = 2;
  
      /**
       * indexes used so that we can access the information faster - it is ordered through a tree map, and should be
       * very fast to access given its initials.
       * 
       * It contains only top/level information for a module
       * 
       * This map is persisted.
       */
      protected SortedMap<String, Set<IInfo>> topLevelInitialsToInfo = new PyPublicTreeMap<String, Set<IInfo>>();
  
      /**
       * indexes so that we can get 'inner information' from classes, such as methods or inner classes from a class 
       */
      protected SortedMap<String, Set<IInfo>> innerInitialsToInfo = new PyPublicTreeMap<String, Set<IInfo>>();
  
      /**
       * Should be used before re-creating the info, so that we have enough memory. 
       */
      public void clearAllInfo() {
          synchronized (lock) {
              if (topLevelInitialsToInfo != null) {
                  topLevelInitialsToInfo.clear();
              }
              if (innerInitialsToInfo != null) {
                  innerInitialsToInfo.clear();
              }
          }
      }
  
      protected Object lock = new Object();
  
      /**
       * The filter interface
       */
      public interface Filter {
          boolean doCompare(String lowerCaseQual, IInfo info);
  
          boolean doCompare(String lowerCaseQual, String infoName);
      }
  
      /**
       * A filter that checks if tokens are equal
       */
      private final Filter equalsFilter = new Filter() {
          public boolean doCompare(String qualifier, IInfo info) {
              return info.getName().equals(qualifier);
          }
  
          public boolean doCompare(String qualifier, String infoName) {
              return infoName.equals(qualifier);
          }
      };
  
      /**
       * A filter that checks if the tokens starts with a qualifier
       */
      private final Filter startingWithFilter = new Filter() {
  
          public boolean doCompare(String lowerCaseQual, IInfo info) {
              return doCompare(lowerCaseQual, info.getName());
          }
  
          public boolean doCompare(String qualifier, String infoName) {
              return infoName.toLowerCase().startsWith(qualifier);
          }
  
      };
  
      /**
       * 2: because we've removed some info (the hash is no longer saved)
       * 3: Changed from string-> list to string->set
       */
      protected static final int version = 3;
  
      public AbstractAdditionalTokensInfo() {
      }
  
      /**
       * That's the function actually used to add some info
       * 
       * @param info information to be added
       */
      protected void add(IInfo info, int doOn) {
          synchronized (lock) {
              String name = info.getName();
              String initials = getInitials(name);
              SortedMap<String, Set<IInfo>> initialsToInfo;
  
              if (doOn == TOP_LEVEL) {
                  if (info.getPath() != null && info.getPath().length() > 0) {
                      throw new RuntimeException(
                              "Error: the info being added is added as an 'top level' info, but has path. Info:" + info);
                  }
                  initialsToInfo = topLevelInitialsToInfo;
  
              } else if (doOn == INNER) {
                  if (info.getPath() == null || info.getPath().length() == 0) {
                      throw new RuntimeException(
                              "Error: the info being added is added as an 'inner' info, but does not have a path. Info: "
                                      + info);
                  }
                  initialsToInfo = innerInitialsToInfo;
  
              } else {
                  throw new RuntimeException("List to add is invalid: " + doOn);
              }
              Set<IInfo> listForInitials = getAndCreateListForInitials(initials, initialsToInfo);
              listForInitials.add(info);
          }
      }
  
      /**
       * @param name the name from where we want to get the initials
       * @return the initials for the name
       */
      protected String getInitials(String name) {
          if (name.length() < NUMBER_OF_INITIALS_TO_INDEX) {
              return name;
          }
          return name.substring(0, NUMBER_OF_INITIALS_TO_INDEX).toLowerCase();
      }
  
      /**
       * @param initials the initials we are looking for
       * @param initialsToInfo this is the list we should use (top level or inner)
       * @return the list of tokens with the specified initials (must be exact match)
       */
      protected Set<IInfo> getAndCreateListForInitials(String initials, SortedMap<String, Set<IInfo>> initialsToInfo) {
          Set<IInfo> lInfo = initialsToInfo.get(initials);
          if (lInfo == null) {
              lInfo = new HashSet<IInfo>();
              initialsToInfo.put(initials, lInfo);
          }
          return lInfo;
      }
  
      private IInfo addAssignTargets(ASTEntry entry, String moduleName, int doOn, String path, boolean lastIsMethod) {
          String rep = NodeUtils.getFullRepresentationString(entry.node);
          if (lastIsMethod) {
              List<String> parts = StringUtils.dotSplit(rep);
              if (parts.size() >= 2) {
                  //at least 2 parts are required
                  if (parts.get(0).equals("self")) {
                      rep = parts.get(1);
                      //no intern construct (locked in the loop that calls this method)
                      AttrInfo info = new AttrInfo(ObjectsPool.internUnsynched(rep), moduleName,
                              ObjectsPool.internUnsynched(path), false);
                      add(info, doOn);
                      return info;
                  }
              }
          } else {
              //no intern construct (locked in the loop that calls this method)
              AttrInfo info = new AttrInfo(ObjectsPool.internUnsynched(FullRepIterable.getFirstPart(rep)), moduleName,
                      ObjectsPool.internUnsynched(path), false);
              add(info, doOn);
              return info;
          }
          return null;
      }
  
      public List<IInfo> addAstInfo(ModulesKey key, boolean generateDelta) throws Exception {
          boolean isZipModule = key instanceof ModulesKeyForZip;
          ModulesKeyForZip modulesKeyForZip = null;
          if (isZipModule) {
              modulesKeyForZip = (ModulesKeyForZip) key;
          }
  
          Object doc;
          if (isZipModule) {
              doc = FileUtilsFileBuffer.getCustomReturnFromZip(modulesKeyForZip.file, modulesKeyForZip.zipModulePath, null);
  
          } else {
              doc = FileUtilsFileBuffer.getCustomReturnFromFile(key.file, true, null);
          }
  
          char[] charArray;
          int len;
          if (doc instanceof IDocument) {
              IDocument document = (IDocument) doc;
              charArray = document.get().toCharArray();
              len = charArray.length;
  
          } else if (doc instanceof FastStringBuffer) {
  