1) Fixed issue #764: Ignore strings when looking for single line comments.
[phpeclipse.git] / net.sourceforge.phpeclipse.ui / src / net / sourceforge / phpeclipse / builder / IdentifierIndexManager.java
1 package net.sourceforge.phpeclipse.builder;
2
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;
16 import java.util.Set;
17 import java.util.SortedMap;
18 import java.util.StringTokenizer;
19 import java.util.TreeMap;
20
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;
28
29 import org.eclipse.core.resources.IFile;
30 import org.eclipse.core.runtime.CoreException;
31 import org.eclipse.core.runtime.IStatus;
32
33 /**
34  * Manages the identifer index information for a specific project
35  * 
36  */
37 public class IdentifierIndexManager {
38         public class LineCreator implements ITerminalSymbols {
39                 private Scanner fScanner;
40
41                 private int fToken;
42
43                 public LineCreator() {
44                         fScanner = new Scanner(true, false, false, false, true, null, null,
45                                         true /* taskCaseSensitive */);
46                 }
47
48                 /**
49                  * Add the information of the current identifier to the line
50                  * 
51                  * @param typeOfIdentifier
52                  *            the type of the identifier ('c'lass, 'd'efine, 'f'unction,
53                  *            'm'ethod(class), 'v'ariable(class) 'g'lobal variable)
54                  * @param identifier
55                  *            current identifier
56                  * @param line
57                  *            Buffer for the current index line
58                  */
59                 private void addIdentifierInformation(char typeOfIdentifier,
60                                 char[] identifier, StringBuffer line) {
61                         line.append('\t');
62                         line.append(typeOfIdentifier);
63                         line.append(identifier);
64                 }
65
66                 /**
67                  * Add the information of the current identifier to the line
68                  * 
69                  * @param typeOfIdentifier
70                  *            the type of the identifier ('c'lass, 'd'efine, 'f'unction,
71                  *            'm'ethod(class), 'v'ariable(class) 'g'lobal variable)
72                  * @param identifier
73                  *            current identifier
74                  * @param line
75                  *            Buffer for the current index line
76                  * @param phpdocOffset
77                  *            the offset of the PHPdoc comment if available
78                  * @param phpdocLength
79                  *            the length of the PHPdoc comment if available
80                  */
81                 private void addIdentifierInformation(char typeOfIdentifier,
82                                 char[] identifier, StringBuffer line, int phpdocOffset,
83                                 int phpdocLength) {
84                         line.append('\t');
85                         line.append(typeOfIdentifier);
86                         line.append(identifier);
87                         line.append("\to"); // Offset
88                         line.append(fScanner.getCurrentTokenStartPosition());
89                         if (phpdocOffset >= 0) {
90                                 line.append("\tp"); // phpdoc offset
91                                 line.append(phpdocOffset);
92                                 line.append("\tl"); // phpdoc length
93                                 line.append(phpdocLength);
94                         }
95                 }
96
97                 private void addClassVariableInformation(char typeOfIdentifier,
98                                 char[] identifier, StringBuffer line, int phpdocOffset,
99                                 int phpdocLength) {
100                         line.append('\t');
101                         line.append(typeOfIdentifier);
102                         line.append(identifier);
103                         line.append("\to"); // Offset
104                         // we don't store the '$' in the index for class variables:
105                         line.append(fScanner.getCurrentTokenStartPosition() + 1);
106                         if (phpdocOffset >= 0) {
107                                 line.append("\tp"); // phpdoc offset
108                                 line.append(phpdocOffset);
109                                 line.append("\tl"); // phpdoc length
110                                 line.append(phpdocLength);
111                         }
112                 }
113
114                 /**
115                  * Get the next token from input
116                  */
117                 private void getNextToken() throws InvalidInputException {
118                         // try {
119                         fToken = fScanner.getNextToken();
120                         if (Scanner.DEBUG) {
121                                 int currentEndPosition = fScanner.getCurrentTokenEndPosition();
122                                 int currentStartPosition = fScanner
123                                                 .getCurrentTokenStartPosition();
124                                 System.out.print(currentStartPosition + ","
125                                                 + currentEndPosition + ": ");
126                                 System.out.println(fScanner.toStringAction(fToken));
127                         }
128                         return;
129                 }
130
131                 private void skipComments()
132                 {
133                         try {
134                                 getNextToken();
135                                 while (fToken == TokenNameCOMMENT_BLOCK  || fToken == TokenNameCOMMENT_PHPDOC) {
136                                                 getNextToken();
137                                 }
138                         } catch (InvalidInputException e1) {
139                                 // TODO Auto-generated catch block
140                                 e1.printStackTrace();
141                         }
142                 }
143                 
144                 private void parseDeclarations(char[] parent, StringBuffer buf,
145                                 boolean goBack) {
146                         char[] ident;
147                         char[] classVariable;
148                         int counter = 0;
149                         boolean hasModifiers = false;
150                         int phpdocOffset = -1;
151                         int phpdocLength = -1;
152                         try {
153                                 while (fToken != TokenNameEOF && fToken != TokenNameERROR) {
154                                         phpdocOffset = -1;
155                                         hasModifiers = false;
156                                         if (fToken == TokenNameCOMMENT_PHPDOC) {
157                                                 phpdocOffset = fScanner.getCurrentTokenStartPosition();
158                                                 phpdocLength = fScanner.getCurrentTokenEndPosition()
159                                                                 - fScanner.getCurrentTokenStartPosition() + 1;
160                                                 getNextToken();
161                                                 while (fToken == TokenNamestatic
162                                                                 || fToken == TokenNamefinal
163                                                                 || fToken == TokenNamepublic
164                                                                 || fToken == TokenNameprotected
165                                                                 || fToken == TokenNameprivate
166                                                                 || fToken == TokenNameabstract) {
167                                                         hasModifiers = true;
168                                                         getNextToken();
169                                                 }
170                                                 if (fToken == TokenNameEOF || fToken == TokenNameERROR) {
171                                                         break;
172                                                 }
173                                         }
174                                         if (fToken == TokenNamefunction) {
175                                                 skipComments();
176                                                 if (fToken == TokenNameAND) {
177                                                         getNextToken();
178                                                 }
179                                                 if (fToken == TokenNameIdentifier) {
180                                                         ident = fScanner.getCurrentIdentifierSource();
181                                                         if (parent != null
182                                                                         && equalCharArrays(parent, ident)) {
183                                                                 // constructor function
184                                                                 addIdentifierInformation('k', ident, buf,
185                                                                                 phpdocOffset, phpdocLength);
186                                                         } else {
187                                                                 if (parent != null) {
188                                                                         // class method function
189                                                                         addIdentifierInformation('m', ident, buf,
190                                                                                         phpdocOffset, phpdocLength);
191                                                                 } else {
192                                                                         // nested function ?!
193                                                                         addIdentifierInformation('f', ident, buf,
194                                                                                         phpdocOffset, phpdocLength);
195                                                                 }
196                                                         }
197                                                         skipComments();
198                                                         parseDeclarations(null, buf, true);
199                                                 }
200                                         } else if (fToken == TokenNameclass
201                                                         || fToken == TokenNameinterface) {
202                                                 skipComments();
203                                                 if (fToken == TokenNameIdentifier) {
204                                                         ident = fScanner.getCurrentIdentifierSource();
205                                                         addIdentifierInformation('c', ident, buf,
206                                                                         phpdocOffset, phpdocLength);
207                                                         skipComments();
208                                                         if (fToken == TokenNameextends) {
209                                                                 skipComments();
210                                                                 while (fToken == TokenNameIdentifier) {
211                                                                         ident = fScanner
212                                                                                         .getCurrentIdentifierSource();
213                                                                         // extends ident
214                                                                         addIdentifierInformation('e', ident, buf);
215                                                                         skipComments();
216                                                                 if (fToken == TokenNameCOMMA) {
217                                                                         skipComments();
218                                                                         }
219                                                                 }
220                                                         }
221                                                         if (fToken == TokenNameimplements) {
222                                                                 skipComments();
223                                                                 while (fToken == TokenNameIdentifier) {
224                                                                         ident = fScanner
225                                                                                         .getCurrentIdentifierSource();
226                                                                         // implements ident
227                                                                         addIdentifierInformation('e', ident, buf);
228                                                                         skipComments();
229                                                                         if (fToken == TokenNameCOMMA) {
230                                                                                 skipComments();
231 //                                                                              getNextToken();
232                                                                         }
233                                                                 }
234                                                         }
235                                                         // skip tokens for classname, extends and others
236                                                         // until we have
237                                                         // the opening '{'
238                                                         while (fToken != TokenNameLBRACE
239                                                                         && fToken != TokenNameEOF
240                                                                         && fToken != TokenNameERROR) {
241                                                                 getNextToken();
242                                                         }
243                                                         parseDeclarations(ident, buf, true);
244                                                 }
245                                         } else if (fToken == TokenNamevar || hasModifiers
246                                                         || fToken == TokenNamestatic
247                                                         || fToken == TokenNamefinal
248                                                         || fToken == TokenNamepublic
249                                                         || fToken == TokenNameprotected
250                                                         || fToken == TokenNameprivate) {
251                                                 while (fToken == TokenNamevar
252                                                                 || fToken == TokenNamestatic
253                                                                 || fToken == TokenNamefinal
254                                                                 || fToken == TokenNamepublic
255                                                                 || fToken == TokenNameprotected
256                                                                 || fToken == TokenNameprivate) {
257                                                         skipComments();
258                                                 }
259                                                 while (fToken == TokenNameVariable) {
260                                                         ident = fScanner.getCurrentIdentifierSource();
261                                                         classVariable = new char[ident.length - 1];
262                                                         System.arraycopy(ident, 1, classVariable, 0,
263                                                                         ident.length - 1);
264                                                         addClassVariableInformation('v', classVariable,
265                                                                         buf, phpdocOffset, phpdocLength);
266                                                         skipComments();
267                                                         if (fToken == TokenNameCOMMA) {
268                                                                 skipComments();
269                                                         }
270                                                 }
271                                         } else if (!hasModifiers && fToken == TokenNameIdentifier) {
272                                                 ident = fScanner.getCurrentIdentifierSource();
273                                                 getNextToken();
274                                                 if (ident.length == 6 && ident[0] == 'd'
275                                                                 && ident[1] == 'e' && ident[2] == 'f'
276                                                                 && ident[3] == 'i' && ident[4] == 'n'
277                                                                 && ident[5] == 'e') {
278                                                         if (fToken == TokenNameLPAREN) {
279                                                                 getNextToken();
280                                                                 if (fToken == TokenNameStringDoubleQuote) {
281                                                                         ident = fScanner
282                                                                                         .getCurrentStringLiteralSource();
283                                                                         addIdentifierInformation('d', ident, buf,
284                                                                                         phpdocOffset, phpdocLength);
285                                                                         getNextToken();
286                                                                 } else if (fToken == TokenNameStringSingleQuote) {
287                                                                         ident = fScanner
288                                                                                         .getCurrentStringLiteralSource();
289                                                                         addIdentifierInformation('d', ident, buf,
290                                                                                         phpdocOffset, phpdocLength);
291                                                                         getNextToken();
292                                                                 }
293                                                         }
294                                                 }
295                                         } else if (fToken == TokenNameglobal) {
296                                                 // global variable
297                                                 while (fToken != TokenNameEOF
298                                                                 && fToken != TokenNameERROR
299                                                                 && fToken != TokenNameSEMICOLON
300                                                                 && fToken != TokenNameLBRACE
301                                                                 && fToken != TokenNameRBRACE) {
302                                                         getNextToken();
303                                                         if (fToken == TokenNameVariable) {
304                                                                 ident = fScanner.getCurrentIdentifierSource();
305                                                                 addIdentifierInformation('g', ident, buf,
306                                                                                 phpdocOffset, phpdocLength);
307                                                         }
308                                                 }
309                                         } else if (fToken == TokenNameLBRACE) {
310                                                 getNextToken();
311                                                 counter++;
312                                         } else if (fToken == TokenNameRBRACE) {
313                                                 getNextToken();
314                                                 --counter;
315                                                 if (counter == 0 && goBack) {
316                                                         return;
317                                                 }
318                                         } else {
319                                                 getNextToken();
320                                         }
321                                 }
322                         } catch (InvalidInputException e) {
323                                 // ignore errors
324                         } catch (SyntaxError e) {
325                                 // TODO Auto-generated catch block
326                                 e.printStackTrace();
327                         }
328                 }
329
330                 synchronized public void parseIdentifiers(char[] charArray,
331                                 StringBuffer buf) {
332                         char[] ident;
333                         String identifier;
334                         boolean hasModifiers = false;
335                         int phpdocOffset = -1;
336                         int phpdocLength = -1;
337                         fScanner.setSource(charArray);
338                         fScanner.setPHPMode(false);
339                         fToken = TokenNameEOF;
340                         try {
341                                 getNextToken();
342                                 while (fToken != TokenNameEOF) { // && fToken !=
343                                         // TokenNameERROR) {
344                                         phpdocOffset = -1;
345                                         hasModifiers = false;
346                                         switch (fToken) {
347                                         case TokenNameCOMMENT_PHPDOC:
348                                                 phpdocOffset = fScanner.getCurrentTokenStartPosition();
349                                                 phpdocLength = fScanner.getCurrentTokenEndPosition()
350                                                                 - fScanner.getCurrentTokenStartPosition() + 1;
351                                                 getNextToken();
352                                                 while (fToken == TokenNamestatic
353                                                                 || fToken == TokenNamefinal
354                                                                 || fToken == TokenNamepublic
355                                                                 || fToken == TokenNameprotected
356                                                                 || fToken == TokenNameprivate
357                                                                 || fToken == TokenNameabstract) {
358                                                         hasModifiers = true;
359                                                         getNextToken();
360                                                 }
361                                                 if (fToken == TokenNameEOF || fToken == TokenNameERROR) {
362                                                         break;
363                                                 }
364                                                 break;
365                                                 
366                                         case TokenNamefunction:
367                                                 skipComments();
368                                                 if (fToken == TokenNameAND) {
369                                                         getNextToken();
370                                                 }
371                                                 if (fToken == TokenNameIdentifier) {
372                                                         ident = fScanner.getCurrentIdentifierSource();
373                                                         addIdentifierInformation('f', ident, buf,
374                                                                         phpdocOffset, phpdocLength);
375                                                         skipComments();
376                                                         if (fToken == TokenNameLPAREN) {
377                                                                 skipComments();
378                                                                 do {
379                                                                         if (fToken == TokenNameVariable) {
380                                                                                 ident = fScanner.getCurrentIdentifierSource();
381                                                                                 addIdentifierInformation('v', ident, buf,
382                                                                                                 phpdocOffset, phpdocLength);
383                                                                                 skipComments();
384                                                                                 if (fToken == TokenNameCOMMA) {
385                                                                                         skipComments();
386                                                                                 }
387                                                                         }       
388                                                                 } while (fToken != TokenNameRPAREN );
389                                                         }
390                                                         parseDeclarations(null, buf, true);
391                                                 }
392                                                 break;
393                                                 
394                                         case TokenNameclass:
395                                         case TokenNameinterface:
396                                                 skipComments();
397                                                 if (fToken == TokenNameIdentifier) {
398                                                         ident = fScanner.getCurrentIdentifierSource();
399                                                         addIdentifierInformation('c', ident, buf,
400                                                                         phpdocOffset, phpdocLength);
401                                                         skipComments();
402                                                         if (fToken == TokenNameextends) {
403                                                                 skipComments();
404                                                                 while (fToken == TokenNameIdentifier) {
405                                                                         ident = fScanner
406                                                                                         .getCurrentIdentifierSource();
407                                                                         // extends ident
408                                                                         addIdentifierInformation('e', ident, buf);
409                                                                         skipComments();
410                                                                         if (fToken == TokenNameCOMMA) {
411                                                                                 skipComments();
412                                                                         }
413                                                                 }
414                                                         }
415                                                         if (fToken == TokenNameimplements) {
416                                                                 skipComments();
417                                                                 while (fToken == TokenNameIdentifier) {
418                                                                         ident = fScanner
419                                                                                         .getCurrentIdentifierSource();
420                                                                         // implements ident
421                                                                         addIdentifierInformation('e', ident, buf);
422                                                                         skipComments();
423                                                                         if (fToken == TokenNameCOMMA) {
424                                                                                 skipComments();
425                                                                         }
426                                                                 }
427                                                         }
428                                                         // skip fTokens for classname, extends and others
429                                                         // until we have
430                                                         // the opening '{'
431                                                         while (fToken != TokenNameLBRACE
432                                                                         && fToken != TokenNameEOF
433                                                                         && fToken != TokenNameERROR) {
434                                                                 getNextToken();
435                                                         }
436                                                         parseDeclarations(ident, buf, true);
437                                                 }
438                                                 break;
439
440                                         case TokenNameVariable:
441                                                 // global variable
442                                                 ident = fScanner.getCurrentIdentifierSource();
443                                                 addIdentifierInformation('g', ident, buf, phpdocOffset,
444                                                                 phpdocLength);
445                                                 getNextToken();
446                                                 break;
447
448                                         default:
449                                                 getNextToken();
450                                         }
451                                         
452                                 }
453                         } catch (InvalidInputException e) {
454                                 // ignore errors
455                         } catch (SyntaxError e) {
456                                 // TODO Auto-generated catch block
457                                 e.printStackTrace();
458                         }
459                 }
460         }
461                 
462         class StringComparator implements Comparator {
463                 public int compare(Object o1, Object o2) {
464                         String s1 = (String) o1;
465                         String s2 = (String) o2;
466                         return s1.compareTo(s2);
467                         // return s1.toUpperCase().compareTo(s2.toUpperCase());
468                 }
469
470                 public boolean equals(Object o) {
471                         //String s = (String) o;
472                         return compare(this, o) == 0;
473                 }
474         }
475
476         private HashMap fFileMap;
477
478         private String fFilename;
479
480         private TreeMap fIndentifierMap;
481
482         public IdentifierIndexManager(String filename) {
483                 fFilename = filename;
484                 initialize();
485                 readFile();
486         }
487
488         /**
489          * Check if 2 char arrays are equal
490          * 
491          * @param a
492          * @param b
493          * @return
494          */
495         private static boolean equalCharArrays(char[] a, char[] b) {
496                 if (a.length != b.length) {
497                         return false;
498                 }
499                 for (int i = 0; i < b.length; i++) {
500                         if (a[i] != b[i]) {
501                                 return false;
502                         }
503                 }
504                 return true;
505         }
506
507         public LineCreator createLineCreator() {
508                 return new LineCreator();
509         }
510
511         /**
512          * Add the information for a given IFile resource
513          * 
514          */
515         public void addFile(IFile fileToParse) {
516                 LineCreator lineCreator = createLineCreator();
517                 try {
518                         addInputStream(new BufferedInputStream(fileToParse.getContents()),
519                                         fileToParse.getProjectRelativePath().toString(),
520                                         lineCreator, fileToParse.getCharset());
521                 } catch (CoreException e1) {
522                         // TODO Auto-generated catch block
523                         e1.printStackTrace();
524                 }
525         }
526
527         /**
528          * @param fileToParse
529          * @param lineCreator
530          * @throws CoreException
531          */
532         public void addInputStream(InputStream stream, String filePath,
533                         LineCreator lineCreator, String charset) throws CoreException {
534                 try {
535                         StringBuffer lineBuffer = new StringBuffer();
536                         lineBuffer.append(filePath);
537                         lineCreator.parseIdentifiers(Util.getInputStreamAsCharArray(stream,
538                                         -1, charset), lineBuffer);
539                         addLine(lineBuffer.toString());
540                 } catch (IOException e) {
541                         e.printStackTrace();
542                 } finally {
543                         try {
544                                 if (stream != null) {
545                                         stream.close();
546                                 }
547                         } catch (IOException e) {
548                                 // do nothing
549                         }
550                 }
551         }
552
553         /**
554          * Adds a line of the index file for function, class, class-method and
555          * class-variable names
556          * 
557          * @param line
558          */
559         private void addLine(String line) {
560                 addLine(fIndentifierMap, fFileMap, line, null);
561         }
562
563         public TreeMap getIdentifiers(IFile file) {
564                 TreeMap treeMap = new TreeMap(new StringComparator());
565                 addIdentifiers(treeMap, file);
566                 return treeMap;
567         }
568
569         public TreeMap getIdentifiers(String startClazz) {
570                 TreeMap treeMap = new TreeMap(new StringComparator());
571                 addIdentifiers(treeMap, startClazz);
572                 return treeMap;
573         }
574
575         public void addIdentifiers(TreeMap treeMap, IFile file) {
576                 String line = (String) fFileMap.get(file.getProjectRelativePath()
577                                 .toString());
578                 if (line != null) {
579                         //PHPIdentifierLocation ident;
580                         ArrayList allClassNames = new ArrayList();
581                         addLine(treeMap, null, line, allClassNames);
582                         int i = 0;
583                         while (i < allClassNames.size()) {
584                                 String clazz = (String) allClassNames.get(i++);
585                                 addClassName(treeMap, clazz, allClassNames);
586                         }
587                 }
588         }
589
590         public void addIdentifiers(TreeMap treeMap, String startClazz) {
591                 //PHPIdentifierLocation ident;
592                 ArrayList allClassNames = new ArrayList();
593                 addClassName(treeMap, startClazz, allClassNames);
594                 int i = 0;
595                 while (i < allClassNames.size()) {
596                         String clazz = (String) allClassNames.get(i++);
597                         addClassName(treeMap, clazz, allClassNames);
598                 }
599         }
600
601         /**
602          * @param treeMap
603          * @param clazz
604          * @param allClassNames
605          */
606         private boolean addClassName(TreeMap treeMap, String clazz,
607                         List allClassNames) {
608                 String line;
609                 PHPIdentifierLocation ident;
610                 List list = getLocations(clazz);
611                 if (list == null) {
612                         return false;
613                 }
614                 boolean result = false;
615                 for (int i = 0; i < list.size(); i++) {
616                         ident = (PHPIdentifierLocation) list.get(i);
617                         if (ident.isClass()) {
618                                 line = (String) fFileMap.get(ident.getFilename());
619                                 addLine(treeMap, null, line, allClassNames);
620                                 result = true;
621                         }
622                 }
623                 return result;
624         }
625
626         /**
627          * Adds a line of the index file for function, class, class-method and
628          * class-variable names
629          * 
630          * @param line
631          */
632         public void addLine(TreeMap treeMap, HashMap fileMap, String line,
633                         List allClassNames) {
634                 StringTokenizer tokenizer;
635                 String phpFileName = null;
636                 String token;
637                 String identifier = null;
638                 String classname = null;
639                 String offset = null;
640                 PHPIdentifierLocation phpIdentifier = null;
641                 boolean tokenExists = false;
642                 tokenizer = new StringTokenizer(line, "\t");
643                 // first token contains the filename:
644                 try {
645                         if (tokenizer.hasMoreTokens()) {
646                                 phpFileName = tokenizer.nextToken();
647                                 // System.out.println(token);
648                         } else {
649                                 return;
650                         }
651                         // all the other tokens are identifiers:
652                         while (tokenizer.hasMoreTokens()) {
653                                 token = tokenizer.nextToken();
654                                 // System.out.println(token);
655                                 switch (token.charAt(0)) {
656                                 case 'c':
657                                         // class name
658                                         identifier = token.substring(1);
659                                         classname = identifier;
660                                         phpIdentifier = new PHPIdentifierLocation(identifier,
661                                                         PHPIdentifier.CLASS, phpFileName);
662                                         break;
663                                 case 'd':
664                                         // define
665                                         identifier = token.substring(1);
666                                         phpIdentifier = new PHPIdentifierLocation(identifier,
667                                                         PHPIdentifier.DEFINE, phpFileName);
668                                         break;
669                                 case 'e':
670                                         // extends <class name>
671                                         // not in map
672                                         identifier = null;
673                                         phpIdentifier = null;
674                                         if (allClassNames != null) {
675                                                 String extName = token.substring(1);
676                                                 if (!allClassNames.contains(extName)) {
677                                                         allClassNames.add(extName);
678                                                 }
679                                         }
680                                         break;
681                                 case 'f':
682                                         // function name
683                                         identifier = token.substring(1);
684                                         phpIdentifier = new PHPIdentifierLocation(identifier,
685                                                         PHPIdentifier.FUNCTION, phpFileName);
686                                         break;
687                                 case 'g':
688                                         // global variable
689                                         identifier = token.substring(1);
690                                         phpIdentifier = new PHPIdentifierLocation(identifier,
691                                                         PHPIdentifier.GLOBAL_VARIABLE, phpFileName);
692                                         break;
693                                 case 'i':
694                                         // implements <class name>
695                                         // not in map
696                                         identifier = null;
697                                         phpIdentifier = null;
698                                         if (allClassNames != null) {
699                                                 String implName = token.substring(1);
700                                                 if (!allClassNames.contains(implName)) {
701                                                         allClassNames.add(implName);
702                                                 }
703                                         }
704                                         break;
705                                 case 'k':
706                                         // constructor function name
707                                         identifier = token.substring(1);
708                                         phpIdentifier = new PHPIdentifierLocation(identifier,
709                                                         PHPIdentifier.CONSTRUCTOR, phpFileName);
710                                         break;
711                                 case 'm':
712                                         // method inside a class
713                                         identifier = token.substring(1);
714                                         phpIdentifier = new PHPIdentifierLocation(identifier,
715                                                         PHPIdentifier.METHOD, phpFileName, classname);
716                                         break;
717                                 case 'v':
718                                         // variable inside a class
719                                         identifier = token.substring(1);
720                                         phpIdentifier = new PHPIdentifierLocation(identifier,
721                                                         PHPIdentifier.VARIABLE, phpFileName, classname);
722                                         break;
723                                 case 'o':
724                                         // offset information
725                                         identifier = null;
726                                         if (phpIdentifier != null) {
727                                                 offset = token.substring(1);
728                                                 phpIdentifier.setOffset(Integer.parseInt(offset));
729                                         }
730                                         break;
731                                 case 'p':
732                                         // PHPdoc offset information
733                                         identifier = null;
734                                         if (phpIdentifier != null) {
735                                                 offset = token.substring(1);
736                                                 phpIdentifier.setPHPDocOffset(Integer.parseInt(offset));
737                                         }
738                                         break;
739                                 case 'l':
740                                         // PHPdoc length information
741                                         identifier = null;
742                                         if (phpIdentifier != null) {
743                                                 offset = token.substring(1);
744                                                 phpIdentifier.setPHPDocLength(Integer.parseInt(offset));
745                                         }
746                                         break;
747                                 default:
748                                         PHPeclipsePlugin.log(IStatus.ERROR,
749                                                         "Unknown token character in IdentifierIndexManager: "
750                                                                         + token.charAt(0));
751                                         identifier = null;
752                                         phpIdentifier = null;
753                                         classname = null;
754                                 }
755                                 if (identifier != null && phpIdentifier != null) {
756                                         tokenExists = true;
757                                         ArrayList list = (ArrayList) treeMap.get(identifier);
758                                         if (list == null) {
759                                                 list = new ArrayList();
760                                                 list.add(phpIdentifier);
761                                                 treeMap.put(identifier, list);
762                                         } else {
763                                                 boolean flag = false;
764                                                 for (int i = 0; i < list.size(); i++) {
765                                                         if (list.get(i).equals(phpIdentifier)) {
766                                                                 flag = true;
767                                                                 break;
768                                                         }
769                                                 }
770                                                 if (flag == false) {
771                                                         list.add(phpIdentifier);
772                                                 }
773                                         }
774                                 }
775                         }
776                         if (fileMap != null) {
777                                 fileMap.put(phpFileName, line);
778                         }
779                 } catch (Throwable e) {
780                         // write to workspace/.metadata/.log file
781                         PHPeclipsePlugin.log(e);
782                 }
783                 // if (tokenExists) {
784
785                 // }
786         }
787
788         /**
789          * Change the information for a given IFile resource
790          * 
791          */
792         public void changeFile(IFile fileToParse) {
793                 removeFile(fileToParse);
794                 addFile(fileToParse);
795         }
796
797         /**
798          * Get a list of all PHPIdentifierLocation object's associated with an
799          * identifier
800          * 
801          * @param identifier
802          * @return
803          */
804         public List getLocations(String identifier) {
805                 List list = (List) fIndentifierMap.get(identifier);
806                 if (list != null) {
807                         return list;
808                 }
809                 return new ArrayList();
810         }
811
812         /**
813          * Initialize (i.e. clear) the current index information
814          * 
815          */
816         public void initialize() {
817                 fIndentifierMap = new TreeMap(new StringComparator());
818                 fFileMap = new HashMap();
819         }
820
821         private void readFile() {
822                 FileReader fileReader;
823                 try {
824                         fileReader = new FileReader(fFilename);
825                         BufferedReader bufferedReader = new BufferedReader(fileReader);
826                         String line;
827                         while (bufferedReader.ready()) {
828                                 // all entries for one file are in a line
829                                 // separated by tabs !
830                                 line = bufferedReader.readLine();
831                                 addLine(line);
832                         }
833                         fileReader.close();
834                 } catch (FileNotFoundException e) {
835                         // ignore this
836                         // TODO DialogBox which asks the user if she/he likes to build new
837                         // index?
838                 } catch (IOException e) {
839                         // TODO Auto-generated catch block
840                         e.printStackTrace();
841                 }
842         }
843
844         /**
845          * Remove the information for a given IFile resource
846          * 
847          */
848         public void removeFile(IFile fileToParse) {
849                 // String line = (String)
850                 // fFileMap.get(fileToParse.getLocation().toString());
851                 String line = (String) fFileMap.get(fileToParse
852                                 .getProjectRelativePath().toString());
853                 if (line != null) {
854                         removeLine(line);
855                 }
856         }
857
858         /**
859          * Removes a line of the index file for function, class, class-method and
860          * class-variable names
861          * 
862          * @param line
863          */
864         private void removeLine(String line) {
865                 StringTokenizer tokenizer;
866                 String phpFileName = null;
867                 String token;
868                 String identifier = null;
869                 String classname = null;
870                 PHPIdentifier phpIdentifier = null;
871                 boolean tokenExists = false;
872                 tokenizer = new StringTokenizer(line, "\t");
873                 // first token contains the filename:
874                 if (tokenizer.hasMoreTokens()) {
875                         phpFileName = tokenizer.nextToken();
876                         // System.out.println(token);
877                 } else {
878                         return;
879                 }
880                 int offset = -1;
881                 // all the other tokens are identifiers:
882                 while (tokenizer.hasMoreTokens()) {
883                         token = tokenizer.nextToken();
884                         // System.out.println(token);
885                         switch (token.charAt(0)) {
886                         case 'c':
887                                 // class name
888                                 identifier = token.substring(1);
889                                 classname = identifier;
890                                 phpIdentifier = new PHPIdentifierLocation(identifier,
891                                                 PHPIdentifier.CLASS, phpFileName);
892                                 break;
893                         case 'd':
894                                 // define
895                                 identifier = token.substring(1);
896                                 phpIdentifier = new PHPIdentifierLocation(identifier,
897                                                 PHPIdentifier.DEFINE, phpFileName);
898                                 break;
899                         case 'e':
900                                 // extends <class name>
901                                 identifier = null;
902                                 phpIdentifier = null;
903                                 break;
904                         case 'f':
905                                 // function name
906                                 identifier = token.substring(1);
907                                 phpIdentifier = new PHPIdentifierLocation(identifier,
908                                                 PHPIdentifier.FUNCTION, phpFileName);
909                                 break;
910                         case 'g':
911                                 // global variable
912                                 identifier = token.substring(1);
913                                 phpIdentifier = new PHPIdentifierLocation(identifier,
914                                                 PHPIdentifier.GLOBAL_VARIABLE, phpFileName);
915                                 break;
916                         case 'i':
917                                 // implements <class name>
918                                 identifier = null;
919                                 phpIdentifier = null;
920                                 break;
921                         case 'k':
922                                 // constructor function name
923                                 identifier = token.substring(1);
924                                 phpIdentifier = new PHPIdentifierLocation(identifier,
925                                                 PHPIdentifier.CONSTRUCTOR, phpFileName);
926                                 break;
927                         case 'm':
928                                 // method inside a class
929                                 identifier = token.substring(1);
930                                 phpIdentifier = new PHPIdentifierLocation(identifier,
931                                                 PHPIdentifier.METHOD, phpFileName, classname);
932                                 break;
933                         case 'o':
934                                 // offset information
935                                 identifier = null;
936                                 break;
937                         case 'p':
938                                 // PHPdoc offset information
939                                 identifier = null;
940                                 break;
941                         case 'l':
942                                 // PHPdoc length information
943                                 identifier = null;
944                                 break;
945                         case 'v':
946                                 // variable inside a class
947                                 identifier = token.substring(1);
948                                 phpIdentifier = new PHPIdentifierLocation(identifier,
949                                                 PHPIdentifier.VARIABLE, phpFileName, classname);
950                                 break;
951                         default:
952                                 PHPeclipsePlugin.log(IStatus.ERROR,
953                                                 "Unknown token character in IdentifierIndexManager: "
954                                                                 + token.charAt(0));
955                                 identifier = null;
956                                 phpIdentifier = null;
957                                 classname = null;
958                         }
959                         if (identifier != null && phpIdentifier != null) {
960                                 ArrayList list = (ArrayList) fIndentifierMap.get(identifier);
961                                 if (list == null) {
962                                 } else {
963                                         for (int i = 0; i < list.size(); i++) {
964                                                 if (list.get(i).equals(phpIdentifier)) {
965                                                         list.remove(i);
966                                                         break;
967                                                 }
968                                         }
969                                         if (list.size() == 0) {
970                                                 fIndentifierMap.remove(identifier);
971                                         }
972                                 }
973                         }
974                 }
975                 fFileMap.remove(phpFileName);
976         }
977
978         /**
979          * Save the current index information in the projects index file
980          * 
981          */
982         public void writeFile() {
983                 FileWriter fileWriter;
984                 try {
985                         fileWriter = new FileWriter(fFilename);
986                         String line;
987                         Collection collection = fFileMap.values();
988                         Iterator iterator = collection.iterator();
989                         while (iterator.hasNext()) {
990                                 line = (String) iterator.next();
991                                 fileWriter.write(line + '\n');
992                         }
993                         fileWriter.close();
994                 } catch (FileNotFoundException e) {
995                         // ignore exception; project is deleted by user
996                 } catch (IOException e) {
997                         // TODO Auto-generated catch block
998                         e.printStackTrace();
999                 }
1000         }
1001
1002         /**
1003          * @param fromKey
1004          * @param toKey
1005          * @return
1006          */
1007         public SortedMap getIdentifierMap() {
1008                 return fIndentifierMap;
1009         }
1010
1011         synchronized public List getFileList(String filePattern) {
1012                 Set set = fFileMap.keySet();
1013                 if (set.isEmpty()) {
1014                         return null;
1015                 }
1016                 Iterator iter = set.iterator();
1017                 ArrayList list = new ArrayList();
1018                 String fileName;
1019                 int index;
1020                 while (iter.hasNext()) {
1021                         fileName = (String) iter.next();
1022                         if ((index = fileName.indexOf(filePattern)) != -1
1023                                         && fileName.length() == (index + filePattern.length())) {
1024                                 list.add(fileName);
1025                         }
1026                 }
1027                 return list;
1028         }
1029 }