Changed "Open PHP Declarartion" action in the PHP editor:
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / builder / IdentifierIndexManager.java
1 package net.sourceforge.phpeclipse.builder;
2
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.HashMap;
12 import java.util.Iterator;
13 import java.util.List;
14 import java.util.StringTokenizer;
15
16 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
17 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
18 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
19 import net.sourceforge.phpdt.internal.compiler.parser.SyntaxError;
20 import net.sourceforge.phpeclipse.mover.obfuscator.PHPIdentifier;
21
22 import org.eclipse.core.resources.IFile;
23 import org.eclipse.core.runtime.CoreException;
24
25 /**
26  * Manages the identifer index information for a specific project
27  *
28  */
29 public class IdentifierIndexManager {
30
31   public class LineCreator implements ITerminalSymbols {
32
33     private Scanner fScanner;
34     private int fToken;
35
36     public LineCreator() {
37       fScanner = new Scanner(false, false);
38     }
39     /**
40      * gets the next token from input
41      */
42     private void getNextToken() {
43
44       try {
45         fToken = fScanner.getNextToken();
46         if (Scanner.DEBUG) {
47           int currentEndPosition = fScanner.getCurrentTokenEndPosition();
48           int currentStartPosition = fScanner.getCurrentTokenStartPosition();
49
50           System.out.print(currentStartPosition + "," + currentEndPosition + ": ");
51           System.out.println(fScanner.toStringAction(fToken));
52         }
53         return;
54       } catch (InvalidInputException e) {
55         // ignore errors
56       }
57       fToken = TokenNameERROR;
58     }
59
60     private void parseDeclarations(StringBuffer buf, boolean goBack) {
61       char[] ident;
62       int counter = 0;
63
64       try {
65         while (fToken != TokenNameEOF && fToken != TokenNameERROR) {
66           if (fToken == TokenNamevar) {
67             getNextToken();
68             if (fToken == TokenNameVariable) {
69               ident = fScanner.getCurrentIdentifierSource();
70               buf.append("\tv");
71               buf.append(ident);
72
73               getNextToken();
74             }
75           } else if (fToken == TokenNamefunction) {
76             getNextToken();
77             if (fToken == TokenNameAND) {
78               getNextToken();
79             }
80             if (fToken == TokenNameIdentifier) {
81               ident = fScanner.getCurrentIdentifierSource();
82               buf.append("\tm");
83               buf.append(ident);
84               getNextToken();
85               parseDeclarations(buf, true);
86             }
87           } else if (fToken == TokenNameclass) {
88             getNextToken();
89             if (fToken == TokenNameIdentifier) {
90               ident = fScanner.getCurrentIdentifierSource();
91               buf.append("\tc");
92               buf.append(ident);
93               getNextToken();
94
95               //skip tokens for classname, extends and others until we have the opening '{'
96               while (fToken != TokenNameLBRACE && fToken != TokenNameEOF && fToken != TokenNameERROR) {
97                 getNextToken();
98               }
99               parseDeclarations(buf, true);
100             }
101           } else if (fToken == TokenNamedefine) {
102             getNextToken();
103             if (fToken == TokenNameLPAREN) {
104               getNextToken();
105               if (fToken == TokenNameStringLiteral) {
106                 ident = fScanner.getCurrentStringLiteralSource();
107                 buf.append("\td");
108                 buf.append(ident);
109                 getNextToken();
110               }
111             }
112           } else if ((fToken == TokenNameLBRACE) || (fToken == TokenNameDOLLAR_LBRACE)) {
113             getNextToken();
114             counter++;
115           } else if (fToken == TokenNameRBRACE) {
116             getNextToken();
117             --counter;
118             if (counter == 0 && goBack) {
119               return;
120             }
121           } else {
122             getNextToken();
123           }
124         }
125       } catch (SyntaxError e) {
126         // TODO Auto-generated catch block
127         e.printStackTrace();
128       }
129     }
130
131     public void parseIdentifiers(char[] charArray, StringBuffer buf) {
132       char[] ident;
133       String identifier;
134       int counter = 0;
135
136       fScanner.setSource(charArray);
137       fScanner.setPHPMode(false);
138       fToken = TokenNameEOF;
139       getNextToken();
140
141       try {
142         while (fToken != TokenNameEOF && fToken != TokenNameERROR) {
143           if (fToken == TokenNamefunction) {
144             getNextToken();
145             if (fToken == TokenNameAND) {
146               getNextToken();
147             }
148             if (fToken == TokenNameIdentifier) {
149               ident = fScanner.getCurrentIdentifierSource();
150               buf.append("\tf");
151               buf.append(ident);
152               getNextToken();
153               parseDeclarations(buf, true);
154             }
155           } else if (fToken == TokenNameclass) {
156             getNextToken();
157             if (fToken == TokenNameIdentifier) {
158               ident = fScanner.getCurrentIdentifierSource();
159               buf.append("\tc");
160               buf.append(ident);
161               getNextToken();
162
163               //skip fTokens for classname, extends and others until we have the opening '{'
164               while (fToken != TokenNameLBRACE && fToken != TokenNameEOF && fToken != TokenNameERROR) {
165                 getNextToken();
166               }
167
168               parseDeclarations(buf, true);
169
170             }
171           } else if (fToken == TokenNamedefine) {
172             getNextToken();
173             if (fToken == TokenNameLPAREN) {
174               getNextToken();
175               if (fToken == TokenNameStringLiteral) {
176                 ident = fScanner.getCurrentStringLiteralSource();
177                 buf.append("\td");
178                 buf.append(ident);
179                 getNextToken();
180               }
181             }
182           } else {
183             getNextToken();
184           }
185         }
186       } catch (SyntaxError e) {
187         // TODO Auto-generated catch block
188         e.printStackTrace();
189       }
190     }
191   }
192
193   private HashMap fFileMap;
194   private String fFilename;
195   private HashMap fIndentifierMap;
196
197   public IdentifierIndexManager(String filename) {
198     fFilename = filename;
199     initialize();
200     readFile();
201   }
202
203   /**
204    * Add the information for a given IFile resource
205    *
206    */
207   public void addFile(IFile fileToParse) {
208     InputStream iStream;
209     LineCreator lineCreator = new LineCreator();
210     try {
211       iStream = fileToParse.getContents();
212
213       StringBuffer buf = new StringBuffer();
214       int c0;
215       try {
216         while ((c0 = iStream.read()) != (-1)) {
217           buf.append((char) c0);
218         }
219       } catch (IOException e) {
220         return;
221       }
222
223       StringBuffer lineBuffer = new StringBuffer();
224       //      lineBuffer.append(fileToParse.getLocation().toString());
225       lineBuffer.append(fileToParse.getFullPath().toString());
226       int lineLength = lineBuffer.length();
227       lineCreator.parseIdentifiers(buf.toString().toCharArray(), lineBuffer);
228       if (lineLength != lineBuffer.length()) {
229         addLine(lineBuffer.toString());
230       }
231     } catch (CoreException e1) {
232       // TODO Auto-generated catch block
233       e1.printStackTrace();
234     }
235   }
236
237   /**
238    * Adds a line of the index file for function, class, class-method and class-variable names
239    * 
240    * @param line
241    */
242   private void addLine(String line) {
243     StringTokenizer tokenizer;
244     String phpFileName = null;
245     String token;
246     String identifier = null;
247     String classname = null;
248     PHPIdentifier phpIdentifier = null;
249     boolean tokenExists = false;
250
251     tokenizer = new StringTokenizer(line, "\t");
252     // first token contains the filename:
253     if (tokenizer.hasMoreTokens()) {
254       phpFileName = tokenizer.nextToken();
255       //System.out.println(token);
256     } else {
257       return;
258     }
259     // all the other tokens are identifiers:
260     while (tokenizer.hasMoreTokens()) {
261       token = tokenizer.nextToken();
262       //System.out.println(token);
263       switch (token.charAt(0)) {
264         case 'c' : // class name
265           identifier = token.substring(1);
266           classname = identifier;
267           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CLASS, phpFileName);
268           break;
269         case 'd' : // define
270           identifier = token.substring(1);
271           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.DEFINE, phpFileName);
272           break;
273         case 'f' : // function name
274           identifier = token.substring(1);
275           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.FUNCTION, phpFileName);
276           break;
277         case 'm' : //method inside a class
278           identifier = token.substring(1);
279           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.METHOD, phpFileName, classname);
280           break;
281         case 'v' : // variable inside a class
282           identifier = token.substring(1);
283           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.VARIABLE, phpFileName, classname);
284           break;
285         default :
286           identifier = null;
287           phpIdentifier = null;
288           classname = null;
289       }
290       if (identifier != null && phpIdentifier != null) {
291         tokenExists = true;
292         ArrayList list = (ArrayList) fIndentifierMap.get(identifier);
293         if (list == null) {
294           list = new ArrayList();
295           list.add(phpIdentifier);
296           fIndentifierMap.put(identifier, list);
297         } else {
298           boolean flag = false;
299           for (int i = 0; i < list.size(); i++) {
300             if (list.get(i).equals(phpIdentifier)) {
301               flag = true;
302               break;
303             }
304           }
305           if (flag == false) {
306             list.add(phpIdentifier);
307           }
308         }
309       }
310     }
311     if (tokenExists) {
312       fFileMap.put(phpFileName, line);
313     }
314   }
315
316   /**
317    * Change the information for a given IFile resource
318    *
319    */
320   public void changeFile(IFile fileToParse) {
321     removeFile(fileToParse);
322     addFile(fileToParse);
323   }
324
325   /**
326    * Get a list of all PHPIdentifierLocation object's associated with an identifier
327    * 
328    * @param identifier
329    * @return
330    */
331   public List getLocations(String identifier) {
332     return (List) fIndentifierMap.get(identifier);
333   }
334
335   /**
336    * Initialize (i.e. clear) the current index information
337    *
338    */
339   public void initialize() {
340     fIndentifierMap = new HashMap();
341     fFileMap = new HashMap();
342   }
343
344   private void readFile() {
345
346     FileReader fileReader;
347     try {
348       fileReader = new FileReader(fFilename);
349
350       BufferedReader bufferedReader = new BufferedReader(fileReader);
351
352       String line;
353       while (bufferedReader.ready()) {
354         // all entries for one file are in a line
355         // separated by tabs !
356         line = bufferedReader.readLine();
357         addLine(line);
358       }
359
360       fileReader.close();
361     } catch (FileNotFoundException e) {
362       // ignore this
363       // TODO DialogBox which asks the user if she/he likes to build new index?
364     } catch (IOException e) {
365       // TODO Auto-generated catch block
366       e.printStackTrace();
367     }
368
369   }
370
371   /**
372    * Remove the information for a given IFile resource
373    *
374    */
375   public void removeFile(IFile fileToParse) {
376     //    String line = (String) fFileMap.get(fileToParse.getLocation().toString());
377     String line = (String) fFileMap.get(fileToParse.getFullPath().toString());
378     if (line != null) {
379       removeLine(line);
380     }
381   }
382
383   /**
384    * Removes a line of the index file for function, class, class-method and class-variable names
385    * 
386    * @param line
387    */
388   private void removeLine(String line) {
389     StringTokenizer tokenizer;
390     String phpFileName = null;
391     String token;
392     String identifier = null;
393     String classname = null;
394     PHPIdentifier phpIdentifier = null;
395     boolean tokenExists = false;
396
397     tokenizer = new StringTokenizer(line, "\t");
398     // first token contains the filename:
399     if (tokenizer.hasMoreTokens()) {
400       phpFileName = tokenizer.nextToken();
401       //System.out.println(token);
402     } else {
403       return;
404     }
405     // all the other tokens are identifiers:
406     while (tokenizer.hasMoreTokens()) {
407       token = tokenizer.nextToken();
408       //System.out.println(token);
409       switch (token.charAt(0)) {
410         case 'c' : // class name
411           identifier = token.substring(1);
412           classname = identifier;
413           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CLASS, phpFileName);
414           break;
415         case 'd' : // define
416           identifier = token.substring(1);
417           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.DEFINE, phpFileName);
418           break;
419         case 'f' : // function name
420           identifier = token.substring(1);
421           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.FUNCTION, phpFileName);
422           break;
423         case 'm' : //method inside a class
424           identifier = token.substring(1);
425           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.METHOD, phpFileName, classname);
426           break;
427         case 'v' : // variable inside a class
428           identifier = token.substring(1);
429           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.VARIABLE, phpFileName, classname);
430           break;
431         default :
432           identifier = null;
433           phpIdentifier = null;
434           classname = null;
435       }
436       if (identifier != null && phpIdentifier != null) {
437         ArrayList list = (ArrayList) fIndentifierMap.get(identifier);
438         if (list == null) {
439         } else {
440           for (int i = 0; i < list.size(); i++) {
441             if (list.get(i).equals(phpIdentifier)) {
442               list.remove(i);
443               break;
444             }
445           }
446           if (list.size() == 0) {
447             fIndentifierMap.remove(identifier);
448           }
449         }
450       }
451     }
452     fFileMap.remove(phpFileName);
453   }
454
455   /**
456    * Save the current index information in the projects index file
457    *
458    */
459   public void writeFile() {
460     FileWriter fileWriter;
461     try {
462       fileWriter = new FileWriter(fFilename);
463       String line;
464       Collection collection = fFileMap.values();
465       Iterator iterator = collection.iterator();
466       while (iterator.hasNext()) {
467         line = (String) iterator.next();
468         fileWriter.write(line + '\n');
469       }
470       fileWriter.close();
471     } catch (IOException e) {
472       // TODO Auto-generated catch block
473       e.printStackTrace();
474     }
475   }
476 }