1 package net.sourceforge.phpeclipse.builder;
 
   2 import java.io.BufferedInputStream;
 
   3 import java.io.BufferedReader;
 
   4 import java.io.FileNotFoundException;
 
   5 import java.io.FileReader;
 
   6 import java.io.FileWriter;
 
   7 import java.io.IOException;
 
   8 import java.io.InputStream;
 
   9 import java.util.ArrayList;
 
  10 import java.util.Collection;
 
  11 import java.util.Comparator;
 
  12 import java.util.HashMap;
 
  13 import java.util.Iterator;
 
  14 import java.util.List;
 
  16 import java.util.SortedMap;
 
  17 import java.util.StringTokenizer;
 
  18 import java.util.TreeMap;
 
  20 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
 
  21 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
 
  22 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
 
  23 import net.sourceforge.phpdt.internal.compiler.parser.SyntaxError;
 
  24 import net.sourceforge.phpdt.internal.compiler.util.Util;
 
  25 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 
  26 import net.sourceforge.phpeclipse.obfuscator.PHPIdentifier;
 
  28 import org.eclipse.core.resources.IFile;
 
  29 import org.eclipse.core.runtime.CoreException;
 
  30 import org.eclipse.core.runtime.IStatus;
 
  32  * Manages the identifer index information for a specific project
 
  35 public class IdentifierIndexManager {
 
  36   public class LineCreator implements ITerminalSymbols {
 
  37     private Scanner fScanner;
 
  39     public LineCreator() {
 
  40       fScanner = new Scanner(true, false, false, false, true, null, null);
 
  43      * Add the information of the current identifier to the line
 
  45      * @param typeOfIdentifier
 
  46      *            the type of the identifier ('c'lass, 'd'efine, 'f'unction,
 
  47      *            'm'ethod(class), 'v'ariable(class) 'g'lobal variable)
 
  51      *            Buffer for the current index line
 
  53      *            the offset of the PHPdoc comment if available
 
  55      *            the length of the PHPdoc comment if available
 
  57     private void addIdentifierInformation(char typeOfIdentifier,
 
  58         char[] identifier, StringBuffer line, int phpdocOffset, int phpdocLength) {
 
  60       line.append(typeOfIdentifier);
 
  61       line.append(identifier);
 
  62       line.append("\to"); // Offset
 
  63       line.append(fScanner.getCurrentTokenStartPosition());
 
  64       if (phpdocOffset >= 0) {
 
  65         line.append("\tp"); // phpdoc offset
 
  66         line.append(phpdocOffset);
 
  67         line.append("\tl"); // phpdoc length
 
  68         line.append(phpdocLength);
 
  72      * Get the next token from input
 
  74     private void getNextToken() {
 
  76         fToken = fScanner.getNextToken();
 
  78           int currentEndPosition = fScanner.getCurrentTokenEndPosition();
 
  79           int currentStartPosition = fScanner.getCurrentTokenStartPosition();
 
  80           System.out.print(currentStartPosition + "," + currentEndPosition
 
  82           System.out.println(fScanner.toStringAction(fToken));
 
  85       } catch (InvalidInputException e) {
 
  87 //        e.printStackTrace();
 
  89       fToken = TokenNameERROR;
 
  91     private void parseDeclarations(char[] parent, StringBuffer buf,
 
  96       int phpdocOffset = -1;
 
  97       int phpdocLength = -1;
 
  99         while (fToken != TokenNameEOF && fToken != TokenNameERROR) {
 
 101           if (fToken == TokenNameCOMMENT_PHPDOC) {
 
 102             phpdocOffset = fScanner.getCurrentTokenStartPosition();
 
 103             phpdocLength = fScanner.getCurrentTokenEndPosition()
 
 104                 - fScanner.getCurrentTokenStartPosition() + 1;
 
 106             if (fToken == TokenNameEOF || fToken == TokenNameERROR) {
 
 110           if (fToken == TokenNamevar || fToken == TokenNamepublic
 
 111               || fToken == TokenNameprotected || fToken == TokenNameprivate) {
 
 113             if (fToken == TokenNameVariable) {
 
 114               ident = fScanner.getCurrentIdentifierSource();
 
 115               classVariable = new char[ident.length - 1];
 
 116               System.arraycopy(ident, 1, classVariable, 0, ident.length - 1);
 
 117               addIdentifierInformation('v', classVariable, buf, phpdocOffset,
 
 121           } else if (fToken == TokenNamefunction) {
 
 123             if (fToken == TokenNameAND) {
 
 126             if (fToken == TokenNameIdentifier) {
 
 127               ident = fScanner.getCurrentIdentifierSource();
 
 128               if (parent != null && equalCharArrays(parent, ident)) {
 
 129                 // constructor function
 
 130                 addIdentifierInformation('k', ident, buf, phpdocOffset,
 
 133                 if (parent != null) {
 
 134                   // class method function
 
 135                   addIdentifierInformation('m', ident, buf, phpdocOffset,
 
 138                   // nested function ?!
 
 139                   addIdentifierInformation('f', ident, buf, phpdocOffset,
 
 144               parseDeclarations(null, buf, true);
 
 146           } else if (fToken == TokenNameclass) {
 
 148             if (fToken == TokenNameIdentifier) {
 
 149               ident = fScanner.getCurrentIdentifierSource();
 
 150               addIdentifierInformation('c', ident, buf, phpdocOffset,
 
 153               //skip tokens for classname, extends and others until we have
 
 155               while (fToken != TokenNameLBRACE && fToken != TokenNameEOF
 
 156                   && fToken != TokenNameERROR) {
 
 159               parseDeclarations(ident, buf, true);
 
 161           } else if (fToken == TokenNameIdentifier) {
 
 162             ident = fScanner.getCurrentIdentifierSource();
 
 164             if (ident.length==6 && 
 
 171               if (fToken == TokenNameLPAREN) {
 
 173                 if (fToken == TokenNameStringDoubleQuote) {
 
 174                   ident = fScanner.getCurrentStringLiteralSource();
 
 175                   addIdentifierInformation('d', ident, buf, phpdocOffset,
 
 181           } else if (fToken == TokenNameglobal) {
 
 183             while (fToken != TokenNameEOF && fToken != TokenNameERROR && 
 
 184                    fToken != TokenNameSEMICOLON &&
 
 185                    fToken != TokenNameLBRACE &&
 
 186                    fToken != TokenNameRBRACE ) {
 
 188               if (fToken == TokenNameVariable) {
 
 189                 ident = fScanner.getCurrentIdentifierSource();
 
 190                 addIdentifierInformation('g', ident, buf, phpdocOffset,
 
 194           } else if (fToken == TokenNameLBRACE) {
 
 197           } else if (fToken == TokenNameRBRACE) {
 
 200             if (counter == 0 && goBack) {
 
 207       } catch (SyntaxError e) {
 
 208         // TODO Auto-generated catch block
 
 212     synchronized public void parseIdentifiers(char[] charArray, StringBuffer buf) {
 
 216       int phpdocOffset = -1;
 
 217       int phpdocLength = -1;
 
 218       fScanner.setSource(charArray);
 
 219       fScanner.setPHPMode(false);
 
 220       fToken = TokenNameEOF;
 
 223         while (fToken != TokenNameEOF) { // && fToken != TokenNameERROR) {
 
 225           if (fToken == TokenNameCOMMENT_PHPDOC) {
 
 226             phpdocOffset = fScanner.getCurrentTokenStartPosition();
 
 227             phpdocLength = fScanner.getCurrentTokenEndPosition()
 
 228                 - fScanner.getCurrentTokenStartPosition() + 1;
 
 230             if (fToken == TokenNameEOF || fToken == TokenNameERROR) {
 
 234           if (fToken == TokenNamefunction) {
 
 236             if (fToken == TokenNameAND) {
 
 239             if (fToken == TokenNameIdentifier) {
 
 240               ident = fScanner.getCurrentIdentifierSource();
 
 241               addIdentifierInformation('f', ident, buf, phpdocOffset,
 
 244               parseDeclarations(null, buf, true);
 
 246           } else if (fToken == TokenNameclass) {
 
 248             if (fToken == TokenNameIdentifier) {
 
 249               ident = fScanner.getCurrentIdentifierSource();
 
 250               addIdentifierInformation('c', ident, buf, phpdocOffset,
 
 253               //skip fTokens for classname, extends and others until we have
 
 255               while (fToken != TokenNameLBRACE && fToken != TokenNameEOF
 
 256                   && fToken != TokenNameERROR) {
 
 259               parseDeclarations(ident, buf, true);
 
 261           } else if (fToken == TokenNameVariable) {
 
 263             ident = fScanner.getCurrentIdentifierSource();
 
 264             addIdentifierInformation('g', ident, buf, phpdocOffset,
 
 267           } else if (fToken == TokenNameIdentifier) {
 
 268             ident = fScanner.getCurrentIdentifierSource();
 
 270             if (ident.length==6 && 
 
 277               if (fToken == TokenNameLPAREN) {
 
 279                 if (fToken == TokenNameStringDoubleQuote) {
 
 280                   ident = fScanner.getCurrentStringLiteralSource();
 
 281                   addIdentifierInformation('d', ident, buf, phpdocOffset,
 
 291       } catch (SyntaxError e) {
 
 292         // TODO Auto-generated catch block
 
 297   class StringComparator implements Comparator {
 
 298     public int compare(Object o1, Object o2) {
 
 299       String s1 = (String) o1;
 
 300       String s2 = (String) o2;
 
 301       return s1.compareTo(s2);
 
 302       //        return s1.toUpperCase().compareTo(s2.toUpperCase());
 
 304     public boolean equals(Object o) {
 
 305       String s = (String) o;
 
 306       return compare(this, o) == 0;
 
 309   private HashMap fFileMap;
 
 310   private String fFilename;
 
 311   private TreeMap fIndentifierMap;
 
 312   public IdentifierIndexManager(String filename) {
 
 313     fFilename = filename;
 
 318    * Check if 2 char arrays are equal
 
 324   private static boolean equalCharArrays(char[] a, char[] b) {
 
 325     if (a.length != b.length) {
 
 328     for (int i = 0; i < b.length; i++) {
 
 335   public LineCreator createLineCreator() {
 
 336     return new LineCreator();
 
 339    * Add the information for a given IFile resource
 
 342   public void addFile(IFile fileToParse) {
 
 343     //    InputStream iStream;
 
 344     LineCreator lineCreator = createLineCreator();
 
 346       addInputStream(new BufferedInputStream(fileToParse.getContents()), fileToParse.getProjectRelativePath().toString(), lineCreator);
 
 347     } catch (CoreException e1) {
 
 348       // TODO Auto-generated catch block
 
 349       e1.printStackTrace();
 
 355    * @throws CoreException
 
 357   public void addInputStream(InputStream stream, String filePath, LineCreator lineCreator) throws CoreException {
 
 359       StringBuffer lineBuffer = new StringBuffer();
 
 360       lineBuffer.append(filePath);
 
 361       int lineLength = lineBuffer.length();
 
 362       lineCreator.parseIdentifiers(Util.getInputStreamAsCharArray(stream, -1,
 
 364 //      if (lineLength != lineBuffer.length()) {
 
 365       // always add the file for Open Include Action  
 
 366       addLine(lineBuffer.toString());
 
 368     }  catch (IOException e) {
 
 372         if (stream != null) {
 
 375       } catch (IOException e) {
 
 380    * Adds a line of the index file for function, class, class-method and
 
 381    * class-variable names
 
 385   private void addLine(String line) {
 
 386     StringTokenizer tokenizer;
 
 387     String phpFileName = null;
 
 389     String identifier = null;
 
 390     String classname = null;
 
 391     String offset = null;
 
 392     PHPIdentifierLocation phpIdentifier = null;
 
 393     boolean tokenExists = false;
 
 394     tokenizer = new StringTokenizer(line, "\t");
 
 395     // first token contains the filename:
 
 396     if (tokenizer.hasMoreTokens()) {
 
 397       phpFileName = tokenizer.nextToken();
 
 398       //System.out.println(token);
 
 402     // all the other tokens are identifiers:
 
 403     while (tokenizer.hasMoreTokens()) {
 
 404       token = tokenizer.nextToken();
 
 405       //System.out.println(token);
 
 406       switch (token.charAt(0)) {
 
 409           identifier = token.substring(1);
 
 410           classname = identifier;
 
 411           phpIdentifier = new PHPIdentifierLocation(identifier,
 
 412               PHPIdentifier.CLASS, phpFileName);
 
 416           identifier = token.substring(1);
 
 417           phpIdentifier = new PHPIdentifierLocation(identifier,
 
 418               PHPIdentifier.DEFINE, phpFileName);
 
 422           identifier = token.substring(1);
 
 423           phpIdentifier = new PHPIdentifierLocation(identifier,
 
 424               PHPIdentifier.FUNCTION, phpFileName);
 
 428           identifier = token.substring(1);
 
 429           phpIdentifier = new PHPIdentifierLocation(identifier,
 
 430               PHPIdentifier.GLOBAL_VARIABLE, phpFileName);
 
 433           // constructor function name
 
 434           identifier = token.substring(1);
 
 435           phpIdentifier = new PHPIdentifierLocation(identifier,
 
 436               PHPIdentifier.CONSTRUCTOR, phpFileName);
 
 439           //method inside a class
 
 440           identifier = token.substring(1);
 
 441           phpIdentifier = new PHPIdentifierLocation(identifier,
 
 442               PHPIdentifier.METHOD, phpFileName, classname);
 
 445           // variable inside a class
 
 446           identifier = token.substring(1);
 
 447           phpIdentifier = new PHPIdentifierLocation(identifier,
 
 448               PHPIdentifier.VARIABLE, phpFileName, classname);
 
 451           // offset information
 
 453           if (phpIdentifier != null) {
 
 454             offset = token.substring(1);
 
 455             phpIdentifier.setOffset(Integer.parseInt(offset));
 
 459           // PHPdoc offset information
 
 461           if (phpIdentifier != null) {
 
 462             offset = token.substring(1);
 
 463             phpIdentifier.setPHPDocOffset(Integer.parseInt(offset));
 
 467           // PHPdoc length information
 
 469           if (phpIdentifier != null) {
 
 470             offset = token.substring(1);
 
 471             phpIdentifier.setPHPDocLength(Integer.parseInt(offset));
 
 475           PHPeclipsePlugin.log(IStatus.ERROR, "Unknown token character in IdentifierIndexManager: "+token.charAt(0));
 
 477           phpIdentifier = null;
 
 480       if (identifier != null && phpIdentifier != null) {
 
 482         ArrayList list = (ArrayList) fIndentifierMap.get(identifier);
 
 484           list = new ArrayList();
 
 485           list.add(phpIdentifier);
 
 486           fIndentifierMap.put(identifier, list);
 
 488           boolean flag = false;
 
 489           for (int i = 0; i < list.size(); i++) {
 
 490             if (list.get(i).equals(phpIdentifier)) {
 
 496             list.add(phpIdentifier);
 
 501 //    if (tokenExists) {
 
 502       fFileMap.put(phpFileName, line);
 
 506    * Change the information for a given IFile resource
 
 509   public void changeFile(IFile fileToParse) {
 
 510     removeFile(fileToParse);
 
 511     addFile(fileToParse);
 
 514    * Get a list of all PHPIdentifierLocation object's associated with an
 
 520   public List getLocations(String identifier) {
 
 521     return (List) fIndentifierMap.get(identifier);
 
 524    * Initialize (i.e. clear) the current index information
 
 527   public void initialize() {
 
 528     fIndentifierMap = new TreeMap(new StringComparator());
 
 529     fFileMap = new HashMap();
 
 531   private void readFile() {
 
 532     FileReader fileReader;
 
 534       fileReader = new FileReader(fFilename);
 
 535       BufferedReader bufferedReader = new BufferedReader(fileReader);
 
 537       while (bufferedReader.ready()) {
 
 538         // all entries for one file are in a line
 
 539         // separated by tabs !
 
 540         line = bufferedReader.readLine();
 
 544     } catch (FileNotFoundException e) {
 
 546       // TODO DialogBox which asks the user if she/he likes to build new index?
 
 547     } catch (IOException e) {
 
 548       // TODO Auto-generated catch block
 
 553    * Remove the information for a given IFile resource
 
 556   public void removeFile(IFile fileToParse) {
 
 557     //    String line = (String)
 
 558     // fFileMap.get(fileToParse.getLocation().toString());
 
 559     String line = (String) fFileMap.get(fileToParse.getFullPath().toString());
 
 565    * Removes a line of the index file for function, class, class-method and
 
 566    * class-variable names
 
 570   private void removeLine(String line) {
 
 571     StringTokenizer tokenizer;
 
 572     String phpFileName = null;
 
 574     String identifier = null;
 
 575     String classname = null;
 
 576     PHPIdentifier phpIdentifier = null;
 
 577     boolean tokenExists = false;
 
 578     tokenizer = new StringTokenizer(line, "\t");
 
 579     // first token contains the filename:
 
 580     if (tokenizer.hasMoreTokens()) {
 
 581       phpFileName = tokenizer.nextToken();
 
 582       //System.out.println(token);
 
 587     // all the other tokens are identifiers:
 
 588     while (tokenizer.hasMoreTokens()) {
 
 589       token = tokenizer.nextToken();
 
 590       //System.out.println(token);
 
 591       switch (token.charAt(0)) {
 
 594           identifier = token.substring(1);
 
 595           classname = identifier;
 
 596           phpIdentifier = new PHPIdentifierLocation(identifier,
 
 597               PHPIdentifier.CLASS, phpFileName);
 
 601           identifier = token.substring(1);
 
 602           phpIdentifier = new PHPIdentifierLocation(identifier,
 
 603               PHPIdentifier.DEFINE, phpFileName);
 
 607           identifier = token.substring(1);
 
 608           phpIdentifier = new PHPIdentifierLocation(identifier,
 
 609               PHPIdentifier.FUNCTION, phpFileName);
 
 613           identifier = token.substring(1);
 
 614           phpIdentifier = new PHPIdentifierLocation(identifier,
 
 615               PHPIdentifier.GLOBAL_VARIABLE, phpFileName);
 
 618           // constructor function name
 
 619           identifier = token.substring(1);
 
 620           phpIdentifier = new PHPIdentifierLocation(identifier,
 
 621               PHPIdentifier.CONSTRUCTOR, phpFileName);
 
 624           //method inside a class
 
 625           identifier = token.substring(1);
 
 626           phpIdentifier = new PHPIdentifierLocation(identifier,
 
 627               PHPIdentifier.METHOD, phpFileName, classname);
 
 630           // offset information
 
 634           // PHPdoc offset information
 
 638           // PHPdoc length information
 
 642           // variable inside a class
 
 643           identifier = token.substring(1);
 
 644           phpIdentifier = new PHPIdentifierLocation(identifier,
 
 645               PHPIdentifier.VARIABLE, phpFileName, classname);
 
 648           PHPeclipsePlugin.log(IStatus.ERROR, "Unknown token character in IdentifierIndexManager: "+token.charAt(0));
 
 650           phpIdentifier = null;
 
 653       if (identifier != null && phpIdentifier != null) {
 
 654         ArrayList list = (ArrayList) fIndentifierMap.get(identifier);
 
 657           for (int i = 0; i < list.size(); i++) {
 
 658             if (list.get(i).equals(phpIdentifier)) {
 
 663           if (list.size() == 0) {
 
 664             fIndentifierMap.remove(identifier);
 
 669     fFileMap.remove(phpFileName);
 
 672    * Save the current index information in the projects index file
 
 675   public void writeFile() {
 
 676     FileWriter fileWriter;
 
 678       fileWriter = new FileWriter(fFilename);
 
 680       Collection collection = fFileMap.values();
 
 681       Iterator iterator = collection.iterator();
 
 682       while (iterator.hasNext()) {
 
 683         line = (String) iterator.next();
 
 684         fileWriter.write(line + '\n');
 
 687     } catch (FileNotFoundException e) {
 
 688       // ignore exception; project is deleted by user
 
 689     } catch (IOException e) {
 
 690       // TODO Auto-generated catch block
 
 699   public SortedMap getIdentifierMap() {
 
 700     return fIndentifierMap;
 
 703   synchronized public List getFileList(String filePattern) {
 
 704     Set set = fFileMap.keySet();
 
 708     Iterator iter = set.iterator();
 
 709     ArrayList list = new ArrayList();
 
 712     while(iter.hasNext()) {
 
 713       fileName = (String) iter.next();
 
 714       if ((index=fileName.indexOf(filePattern))!=-1 && fileName.length()==(index+filePattern.length())) {