1 package net.sourceforge.phpeclipse.builder;
 
   3 import java.io.BufferedInputStream;
 
   4 import java.io.BufferedReader;
 
   5 import java.io.FileNotFoundException;
 
   6 import java.io.FileReader;
 
   7 import java.io.FileWriter;
 
   8 import java.io.IOException;
 
   9 import java.io.InputStream;
 
  10 import java.util.ArrayList;
 
  11 import java.util.Collection;
 
  12 import java.util.Comparator;
 
  13 import java.util.HashMap;
 
  14 import java.util.Iterator;
 
  15 import java.util.List;
 
  17 import java.util.SortedMap;
 
  18 import java.util.StringTokenizer;
 
  19 import java.util.TreeMap;
 
  21 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
 
  22 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
 
  23 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
 
  24 import net.sourceforge.phpdt.internal.compiler.parser.SyntaxError;
 
  25 import net.sourceforge.phpdt.internal.compiler.util.Util;
 
  26 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 
  27 import net.sourceforge.phpeclipse.obfuscator.PHPIdentifier;
 
  29 import org.eclipse.core.resources.IFile;
 
  30 import org.eclipse.core.runtime.CoreException;
 
  31 import org.eclipse.core.runtime.IStatus;
 
  34  * Manages the identifer index information for a specific project
 
  37 public class IdentifierIndexManager {
 
  38   public class LineCreator implements ITerminalSymbols {
 
  39     private Scanner fScanner;
 
  43     public LineCreator() {
 
  44       fScanner = new Scanner(true, false, false, false, true, null, null, true /* taskCaseSensitive */);
 
  48      * Add the information of the current identifier to the line
 
  50      * @param typeOfIdentifier
 
  51      *          the type of the identifier ('c'lass, 'd'efine, 'f'unction, 'm'ethod(class), 'v'ariable(class) 'g'lobal variable)
 
  55      *          Buffer for the current index line
 
  57      *          the offset of the PHPdoc comment if available
 
  59      *          the length of the PHPdoc comment if available
 
  61     private void addIdentifierInformation(char typeOfIdentifier, char[] identifier, StringBuffer line, int phpdocOffset,
 
  64       line.append(typeOfIdentifier);
 
  65       line.append(identifier);
 
  66       line.append("\to"); // Offset
 
  67       line.append(fScanner.getCurrentTokenStartPosition());
 
  68       if (phpdocOffset >= 0) {
 
  69         line.append("\tp"); // phpdoc offset
 
  70         line.append(phpdocOffset);
 
  71         line.append("\tl"); // phpdoc length
 
  72         line.append(phpdocLength);
 
  76     private void addClassVariableInformation(char typeOfIdentifier, char[] identifier, StringBuffer line, int phpdocOffset,
 
  79       line.append(typeOfIdentifier);
 
  80       line.append(identifier);
 
  81       line.append("\to"); // Offset
 
  82       // we don't store the '$' in the index for class variables:
 
  83       line.append(fScanner.getCurrentTokenStartPosition() + 1);
 
  84       if (phpdocOffset >= 0) {
 
  85         line.append("\tp"); // phpdoc offset
 
  86         line.append(phpdocOffset);
 
  87         line.append("\tl"); // phpdoc length
 
  88         line.append(phpdocLength);
 
  93      * Get the next token from input
 
  95     private void getNextToken() {
 
  97         fToken = fScanner.getNextToken();
 
  99           int currentEndPosition = fScanner.getCurrentTokenEndPosition();
 
 100           int currentStartPosition = fScanner.getCurrentTokenStartPosition();
 
 101           System.out.print(currentStartPosition + "," + currentEndPosition + ": ");
 
 102           System.out.println(fScanner.toStringAction(fToken));
 
 105       } catch (InvalidInputException e) {
 
 107         //        e.printStackTrace();
 
 109       fToken = TokenNameERROR;
 
 112     private void parseDeclarations(char[] parent, StringBuffer buf, boolean goBack) {
 
 114       char[] classVariable;
 
 116       boolean hasModifiers = false;
 
 117       int phpdocOffset = -1;
 
 118       int phpdocLength = -1;
 
 120         while (fToken != TokenNameEOF && fToken != TokenNameERROR) {
 
 122           hasModifiers = false;
 
 123           if (fToken == TokenNameCOMMENT_PHPDOC) {
 
 124             phpdocOffset = fScanner.getCurrentTokenStartPosition();
 
 125             phpdocLength = fScanner.getCurrentTokenEndPosition() - fScanner.getCurrentTokenStartPosition() + 1;
 
 127             while (fToken == TokenNamestatic || fToken == TokenNamefinal || fToken == TokenNamepublic
 
 128                 || fToken == TokenNameprotected || fToken == TokenNameprivate || fToken == TokenNameabstract) {
 
 132             if (fToken == TokenNameEOF || fToken == TokenNameERROR) {
 
 136           if (fToken == TokenNamefunction) {
 
 138             if (fToken == TokenNameAND) {
 
 141             if (fToken == TokenNameIdentifier) {
 
 142               ident = fScanner.getCurrentIdentifierSource();
 
 143               if (parent != null && equalCharArrays(parent, ident)) {
 
 144                 // constructor function
 
 145                 addIdentifierInformation('k', ident, buf, phpdocOffset, phpdocLength);
 
 147                 if (parent != null) {
 
 148                   // class method function
 
 149                   addIdentifierInformation('m', ident, buf, phpdocOffset, phpdocLength);
 
 151                   // nested function ?!
 
 152                   addIdentifierInformation('f', ident, buf, phpdocOffset, phpdocLength);
 
 156               parseDeclarations(null, buf, true);
 
 158           } else if (fToken == TokenNameclass || fToken == TokenNameinterface) {
 
 160             if (fToken == TokenNameIdentifier) {
 
 161               ident = fScanner.getCurrentIdentifierSource();
 
 162               addIdentifierInformation('c', ident, buf, phpdocOffset, phpdocLength);
 
 164               //skip tokens for classname, extends and others until we have
 
 166               while (fToken != TokenNameLBRACE && fToken != TokenNameEOF && fToken != TokenNameERROR) {
 
 169               parseDeclarations(ident, buf, true);
 
 171           } else if (fToken == TokenNamevar || hasModifiers || fToken == TokenNamestatic || fToken == TokenNamefinal
 
 172               || fToken == TokenNamepublic || fToken == TokenNameprotected || fToken == TokenNameprivate) {
 
 173             while (fToken == TokenNamevar || fToken == TokenNamestatic || fToken == TokenNamefinal || fToken == TokenNamepublic
 
 174                 || fToken == TokenNameprotected || fToken == TokenNameprivate) {
 
 177             while (fToken == TokenNameVariable) {
 
 178               ident = fScanner.getCurrentIdentifierSource();
 
 179               classVariable = new char[ident.length - 1];
 
 180               System.arraycopy(ident, 1, classVariable, 0, ident.length - 1);
 
 181               addClassVariableInformation('v', classVariable, buf, phpdocOffset, phpdocLength);
 
 183               if (fToken == TokenNameCOMMA) {
 
 187           } else if (!hasModifiers && fToken == TokenNameIdentifier) {
 
 188             ident = fScanner.getCurrentIdentifierSource();
 
 190             if (ident.length == 6 && ident[0] == 'd' && ident[1] == 'e' && ident[2] == 'f' && ident[3] == 'i' && ident[4] == 'n'
 
 191                 && ident[5] == 'e') {
 
 192               if (fToken == TokenNameLPAREN) {
 
 194                 if (fToken == TokenNameStringDoubleQuote) {
 
 195                   ident = fScanner.getCurrentStringLiteralSource();
 
 196                   addIdentifierInformation('d', ident, buf, phpdocOffset, phpdocLength);
 
 198                 } else if (fToken == TokenNameStringSingleQuote) {
 
 199                   ident = fScanner.getCurrentStringLiteralSource();
 
 200                   addIdentifierInformation('d', ident, buf, phpdocOffset, phpdocLength);
 
 205           } else if (fToken == TokenNameglobal) {
 
 207             while (fToken != TokenNameEOF && fToken != TokenNameERROR && fToken != TokenNameSEMICOLON && fToken != TokenNameLBRACE
 
 208                 && fToken != TokenNameRBRACE) {
 
 210               if (fToken == TokenNameVariable) {
 
 211                 ident = fScanner.getCurrentIdentifierSource();
 
 212                 addIdentifierInformation('g', ident, buf, phpdocOffset, phpdocLength);
 
 215           } else if (fToken == TokenNameLBRACE) {
 
 218           } else if (fToken == TokenNameRBRACE) {
 
 221             if (counter == 0 && goBack) {
 
 228       } catch (SyntaxError e) {
 
 229         // TODO Auto-generated catch block
 
 234     synchronized public void parseIdentifiers(char[] charArray, StringBuffer buf) {
 
 238       boolean hasModifiers = false;
 
 239       int phpdocOffset = -1;
 
 240       int phpdocLength = -1;
 
 241       fScanner.setSource(charArray);
 
 242       fScanner.setPHPMode(false);
 
 243       fToken = TokenNameEOF;
 
 246         while (fToken != TokenNameEOF) { // && fToken != TokenNameERROR) {
 
 248           hasModifiers = false;
 
 249           if (fToken == TokenNameCOMMENT_PHPDOC) {
 
 250             phpdocOffset = fScanner.getCurrentTokenStartPosition();
 
 251             phpdocLength = fScanner.getCurrentTokenEndPosition() - fScanner.getCurrentTokenStartPosition() + 1;
 
 253             while (fToken == TokenNamestatic || fToken == TokenNamefinal || fToken == TokenNamepublic
 
 254                 || fToken == TokenNameprotected || fToken == TokenNameprivate || fToken == TokenNameabstract) {
 
 258             if (fToken == TokenNameEOF || fToken == TokenNameERROR) {
 
 262           if (fToken == TokenNamefunction) {
 
 264             if (fToken == TokenNameAND) {
 
 267             if (fToken == TokenNameIdentifier) {
 
 268               ident = fScanner.getCurrentIdentifierSource();
 
 269               addIdentifierInformation('f', ident, buf, phpdocOffset, phpdocLength);
 
 271               parseDeclarations(null, buf, true);
 
 273           } else if (fToken == TokenNameclass || fToken == TokenNameinterface) {
 
 275             if (fToken == TokenNameIdentifier) {
 
 276               ident = fScanner.getCurrentIdentifierSource();
 
 277               addIdentifierInformation('c', ident, buf, phpdocOffset, phpdocLength);
 
 279               //skip fTokens for classname, extends and others until we have
 
 281               while (fToken != TokenNameLBRACE && fToken != TokenNameEOF && fToken != TokenNameERROR) {
 
 284               parseDeclarations(ident, buf, true);
 
 286           } else if (fToken == TokenNameVariable) {
 
 288             ident = fScanner.getCurrentIdentifierSource();
 
 289             addIdentifierInformation('g', ident, buf, phpdocOffset, phpdocLength);
 
 291           } else if (!hasModifiers && fToken == TokenNameIdentifier) {
 
 292             ident = fScanner.getCurrentIdentifierSource();
 
 294             if (ident.length == 6 && ident[0] == 'd' && ident[1] == 'e' && ident[2] == 'f' && ident[3] == 'i' && ident[4] == 'n'
 
 295                 && ident[5] == 'e') {
 
 296               if (fToken == TokenNameLPAREN) {
 
 298                 if (fToken == TokenNameStringDoubleQuote) {
 
 299                   ident = fScanner.getCurrentStringLiteralSource();
 
 300                   addIdentifierInformation('d', ident, buf, phpdocOffset, phpdocLength);
 
 302                 } else if (fToken == TokenNameStringSingleQuote) {
 
 303                   ident = fScanner.getCurrentStringLiteralSource();
 
 304                   addIdentifierInformation('d', ident, buf, phpdocOffset, phpdocLength);
 
 313       } catch (SyntaxError e) {
 
 314         // TODO Auto-generated catch block
 
 320   class StringComparator implements Comparator {
 
 321     public int compare(Object o1, Object o2) {
 
 322       String s1 = (String) o1;
 
 323       String s2 = (String) o2;
 
 324       return s1.compareTo(s2);
 
 325       //        return s1.toUpperCase().compareTo(s2.toUpperCase());
 
 328     public boolean equals(Object o) {
 
 329       String s = (String) o;
 
 330       return compare(this, o) == 0;
 
 334   private HashMap fFileMap;
 
 336   private String fFilename;
 
 338   private TreeMap fIndentifierMap;
 
 340   public IdentifierIndexManager(String filename) {
 
 341     fFilename = filename;
 
 347    * Check if 2 char arrays are equal
 
 353   private static boolean equalCharArrays(char[] a, char[] b) {
 
 354     if (a.length != b.length) {
 
 357     for (int i = 0; i < b.length; i++) {
 
 365   public LineCreator createLineCreator() {
 
 366     return new LineCreator();
 
 370    * Add the information for a given IFile resource
 
 373   public void addFile(IFile fileToParse) {
 
 374     //    InputStream iStream;
 
 375     LineCreator lineCreator = createLineCreator();
 
 377       addInputStream(new BufferedInputStream(fileToParse.getContents()), fileToParse.getProjectRelativePath().toString(),
 
 379     } catch (CoreException e1) {
 
 380       // TODO Auto-generated catch block
 
 381       e1.printStackTrace();
 
 388    * @throws CoreException
 
 390   public void addInputStream(InputStream stream, String filePath, LineCreator lineCreator) throws CoreException {
 
 392       StringBuffer lineBuffer = new StringBuffer();
 
 393       lineBuffer.append(filePath);
 
 394       int lineLength = lineBuffer.length();
 
 395       lineCreator.parseIdentifiers(Util.getInputStreamAsCharArray(stream, -1, null), lineBuffer);
 
 396       //      if (lineLength != lineBuffer.length()) {
 
 397       // always add the file for Open Include Action
 
 398       addLine(lineBuffer.toString());
 
 400     } catch (IOException e) {
 
 404         if (stream != null) {
 
 407       } catch (IOException e) {
 
 413    * Adds a line of the index file for function, class, class-method and class-variable names
 
 417   private void addLine(String line) {
 
 418     StringTokenizer tokenizer;
 
 419     String phpFileName = null;
 
 421     String identifier = null;
 
 422     String classname = null;
 
 423     String offset = null;
 
 424     PHPIdentifierLocation phpIdentifier = null;
 
 425     boolean tokenExists = false;
 
 426     tokenizer = new StringTokenizer(line, "\t");
 
 427     // first token contains the filename:
 
 429       if (tokenizer.hasMoreTokens()) {
 
 430         phpFileName = tokenizer.nextToken();
 
 431         //System.out.println(token);
 
 435       // all the other tokens are identifiers:
 
 436       while (tokenizer.hasMoreTokens()) {
 
 437         token = tokenizer.nextToken();
 
 438         //System.out.println(token);
 
 439         switch (token.charAt(0)) {
 
 442           identifier = token.substring(1);
 
 443           classname = identifier;
 
 444           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CLASS, phpFileName);
 
 448           identifier = token.substring(1);
 
 449           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.DEFINE, phpFileName);
 
 453           identifier = token.substring(1);
 
 454           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.FUNCTION, phpFileName);
 
 458           identifier = token.substring(1);
 
 459           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.GLOBAL_VARIABLE, phpFileName);
 
 462           // constructor function name
 
 463           identifier = token.substring(1);
 
 464           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CONSTRUCTOR, phpFileName);
 
 467           //method inside a class
 
 468           identifier = token.substring(1);
 
 469           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.METHOD, phpFileName, classname);
 
 472           // variable inside a class
 
 473           identifier = token.substring(1);
 
 474           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.VARIABLE, phpFileName, classname);
 
 477           // offset information
 
 479           if (phpIdentifier != null) {
 
 480             offset = token.substring(1);
 
 481             phpIdentifier.setOffset(Integer.parseInt(offset));
 
 485           // PHPdoc offset information
 
 487           if (phpIdentifier != null) {
 
 488             offset = token.substring(1);
 
 489             phpIdentifier.setPHPDocOffset(Integer.parseInt(offset));
 
 493           // PHPdoc length information
 
 495           if (phpIdentifier != null) {
 
 496             offset = token.substring(1);
 
 497             phpIdentifier.setPHPDocLength(Integer.parseInt(offset));
 
 501           PHPeclipsePlugin.log(IStatus.ERROR, "Unknown token character in IdentifierIndexManager: " + token.charAt(0));
 
 503           phpIdentifier = null;
 
 506         if (identifier != null && phpIdentifier != null) {
 
 508           ArrayList list = (ArrayList) fIndentifierMap.get(identifier);
 
 510             list = new ArrayList();
 
 511             list.add(phpIdentifier);
 
 512             fIndentifierMap.put(identifier, list);
 
 514             boolean flag = false;
 
 515             for (int i = 0; i < list.size(); i++) {
 
 516               if (list.get(i).equals(phpIdentifier)) {
 
 522               list.add(phpIdentifier);
 
 527       fFileMap.put(phpFileName, line);
 
 528     } catch (Throwable e) {
 
 529       // write to workspace/.metadata/.log file
 
 530       PHPeclipsePlugin.log(e);
 
 532     //    if (tokenExists) {
 
 538    * Change the information for a given IFile resource
 
 541   public void changeFile(IFile fileToParse) {
 
 542     removeFile(fileToParse);
 
 543     addFile(fileToParse);
 
 547    * Get a list of all PHPIdentifierLocation object's associated with an identifier
 
 552   public List getLocations(String identifier) {
 
 553     return (List) fIndentifierMap.get(identifier);
 
 557    * Initialize (i.e. clear) the current index information
 
 560   public void initialize() {
 
 561     fIndentifierMap = new TreeMap(new StringComparator());
 
 562     fFileMap = new HashMap();
 
 565   private void readFile() {
 
 566     FileReader fileReader;
 
 568       fileReader = new FileReader(fFilename);
 
 569       BufferedReader bufferedReader = new BufferedReader(fileReader);
 
 571       while (bufferedReader.ready()) {
 
 572         // all entries for one file are in a line
 
 573         // separated by tabs !
 
 574         line = bufferedReader.readLine();
 
 578     } catch (FileNotFoundException e) {
 
 580       // TODO DialogBox which asks the user if she/he likes to build new index?
 
 581     } catch (IOException e) {
 
 582       // TODO Auto-generated catch block
 
 588    * Remove the information for a given IFile resource
 
 591   public void removeFile(IFile fileToParse) {
 
 592     //    String line = (String)
 
 593     // fFileMap.get(fileToParse.getLocation().toString());
 
 594     String line = (String) fFileMap.get(fileToParse.getProjectRelativePath().toString());
 
 601    * Removes a line of the index file for function, class, class-method and class-variable names
 
 605   private void removeLine(String line) {
 
 606     StringTokenizer tokenizer;
 
 607     String phpFileName = null;
 
 609     String identifier = null;
 
 610     String classname = null;
 
 611     PHPIdentifier phpIdentifier = null;
 
 612     boolean tokenExists = false;
 
 613     tokenizer = new StringTokenizer(line, "\t");
 
 614     // first token contains the filename:
 
 615     if (tokenizer.hasMoreTokens()) {
 
 616       phpFileName = tokenizer.nextToken();
 
 617       //System.out.println(token);
 
 622     // all the other tokens are identifiers:
 
 623     while (tokenizer.hasMoreTokens()) {
 
 624       token = tokenizer.nextToken();
 
 625       //System.out.println(token);
 
 626       switch (token.charAt(0)) {
 
 629         identifier = token.substring(1);
 
 630         classname = identifier;
 
 631         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CLASS, phpFileName);
 
 635         identifier = token.substring(1);
 
 636         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.DEFINE, phpFileName);
 
 640         identifier = token.substring(1);
 
 641         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.FUNCTION, phpFileName);
 
 645         identifier = token.substring(1);
 
 646         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.GLOBAL_VARIABLE, phpFileName);
 
 649         // constructor function name
 
 650         identifier = token.substring(1);
 
 651         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CONSTRUCTOR, phpFileName);
 
 654         //method inside a class
 
 655         identifier = token.substring(1);
 
 656         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.METHOD, phpFileName, classname);
 
 659         // offset information
 
 663         // PHPdoc offset information
 
 667         // PHPdoc length information
 
 671         // variable inside a class
 
 672         identifier = token.substring(1);
 
 673         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.VARIABLE, phpFileName, classname);
 
 676         PHPeclipsePlugin.log(IStatus.ERROR, "Unknown token character in IdentifierIndexManager: " + token.charAt(0));
 
 678         phpIdentifier = null;
 
 681       if (identifier != null && phpIdentifier != null) {
 
 682         ArrayList list = (ArrayList) fIndentifierMap.get(identifier);
 
 685           for (int i = 0; i < list.size(); i++) {
 
 686             if (list.get(i).equals(phpIdentifier)) {
 
 691           if (list.size() == 0) {
 
 692             fIndentifierMap.remove(identifier);
 
 697     fFileMap.remove(phpFileName);
 
 701    * Save the current index information in the projects index file
 
 704   public void writeFile() {
 
 705     FileWriter fileWriter;
 
 707       fileWriter = new FileWriter(fFilename);
 
 709       Collection collection = fFileMap.values();
 
 710       Iterator iterator = collection.iterator();
 
 711       while (iterator.hasNext()) {
 
 712         line = (String) iterator.next();
 
 713         fileWriter.write(line + '\n');
 
 716     } catch (FileNotFoundException e) {
 
 717       // ignore exception; project is deleted by user
 
 718     } catch (IOException e) {
 
 719       // TODO Auto-generated catch block
 
 729   public SortedMap getIdentifierMap() {
 
 730     return fIndentifierMap;
 
 733   synchronized public List getFileList(String filePattern) {
 
 734     Set set = fFileMap.keySet();
 
 738     Iterator iter = set.iterator();
 
 739     ArrayList list = new ArrayList();
 
 742     while (iter.hasNext()) {
 
 743       fileName = (String) iter.next();
 
 744       if ((index = fileName.indexOf(filePattern)) != -1 && fileName.length() == (index + filePattern.length())) {