Fix nasty bug #706. See trac.
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / CompilationResult.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler;
12
13 /**
14  * A compilation result consists of all information returned by the compiler for
15  * a single compiled compilation source unit. This includes:
16  * <ul>
17  * <li> the compilation unit that was compiled
18  * <li> for each type produced by compiling the compilation unit, its binary and
19  * optionally its principal structure
20  * <li> any problems (errors or warnings) produced
21  * <li> dependency info
22  * </ul>
23  * 
24  * The principle structure and binary may be null if the compiler could not
25  * produce them. If neither could be produced, there is no corresponding entry
26  * for the type.
27  * 
28  * The dependency info includes type references such as supertypes, field types,
29  * method parameter and return types, local variable types, types of
30  * intermediate expressions, etc. It also includes the namespaces (packages) in
31  * which names were looked up. It does <em>not</em> include finer grained
32  * dependencies such as information about specific fields and methods which were
33  * referenced, but does contain their declaring types and any other types used
34  * to locate such fields or methods.
35  */
36
37 // import java.util.Enumeration;
38 import java.util.Hashtable;
39 import java.util.Map;
40
41 import net.sourceforge.phpdt.core.compiler.IProblem;
42 import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit;
43 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
44
45 public class CompilationResult {
46
47         public IProblem problems[];
48
49         public IProblem tasks[];
50
51         public int problemCount;
52
53         public int taskCount;
54
55         public ICompilationUnit compilationUnit;
56
57         private Map problemsMap;
58
59         private Map firstErrorsMap;
60
61         private int maxProblemPerUnit;
62
63         public char[][][] qualifiedReferences;
64
65         public char[][] simpleNameReferences;
66
67         public int lineSeparatorPositions[];
68
69         // public Hashtable compiledTypes = new Hashtable(11);
70         public int unitIndex, totalUnitsKnown;
71
72         public boolean hasBeenAccepted = false;
73
74         public char[] fileName;
75
76         public CompilationResult(char[] fileName, int unitIndex,
77                         int totalUnitsKnown, int maxProblemPerUnit) {
78
79                 this.fileName = fileName;
80                 this.unitIndex = unitIndex;
81                 this.totalUnitsKnown = totalUnitsKnown;
82                 this.maxProblemPerUnit = maxProblemPerUnit;
83         }
84
85         public CompilationResult(ICompilationUnit compilationUnit, int unitIndex,
86                         int totalUnitsKnown, int maxProblemPerUnit) {
87
88                 this.fileName = compilationUnit.getFileName();
89                 this.compilationUnit = compilationUnit;
90                 this.unitIndex = unitIndex;
91                 this.totalUnitsKnown = totalUnitsKnown;
92                 this.maxProblemPerUnit = maxProblemPerUnit;
93         }
94
95         private int computePriority(IProblem problem) {
96
97                 final int P_STATIC = 1000;
98                 final int P_OUTSIDE_METHOD = 4000;
99                 final int P_FIRST_ERROR = 2000;
100                 final int P_ERROR = 10000;
101
102                 int priority = 1000 - problem.getSourceLineNumber(); // early
103                                                                                                                                 // problems
104                                                                                                                                 // first
105                 if (priority < 0)
106                         priority = 0;
107                 if (problem.isError()) {
108                         priority += P_ERROR;
109                 }
110                 ReferenceContext context = problemsMap == null ? null
111                                 : (ReferenceContext) problemsMap.get(problem);
112                 if (context != null) {
113                         // if (context instanceof AbstractMethodDeclaration){
114                         // AbstractMethodDeclaration method = (AbstractMethodDeclaration)
115                         // context;
116                         // if (method.isStatic()) {
117                         // priority += P_STATIC;
118                         // }
119                         // } else {
120                         priority += P_OUTSIDE_METHOD;
121                         // }
122                 } else {
123                         priority += P_OUTSIDE_METHOD;
124                 }
125                 if (firstErrorsMap.containsKey(problem)) {
126                         priority += P_FIRST_ERROR;
127                 }
128                 return priority;
129         }
130
131         public IProblem[] getAllProblems() {
132                 IProblem[] problems = this.getProblems();
133                 int problemCount = problems != null ? problems.length : 0;
134                 IProblem[] tasks = this.getTasks();
135                 int taskCount = tasks != null ? tasks.length : 0;
136                 if (taskCount == 0) {
137                         return problems;
138                 }
139                 if (problemCount == 0) {
140                         return tasks;
141                 }
142
143                 int totalNumberOfProblem = problemCount + taskCount;
144                 IProblem[] allProblems = new IProblem[totalNumberOfProblem];
145                 int allProblemIndex = 0;
146                 int taskIndex = 0;
147                 int problemIndex = 0;
148                 while (taskIndex + problemIndex < totalNumberOfProblem) {
149                         IProblem nextTask = null;
150                         IProblem nextProblem = null;
151                         if (taskIndex < taskCount) {
152                                 nextTask = tasks[taskIndex];
153                         }
154                         if (problemIndex < problemCount) {
155                                 nextProblem = problems[problemIndex];
156                         }
157                         // select the next problem
158                         IProblem currentProblem = null;
159                         if (nextProblem != null) {
160                                 if (nextTask != null) {
161                                         if (nextProblem.getSourceStart() < nextTask
162                                                         .getSourceStart()) {
163                                                 currentProblem = nextProblem;
164                                                 problemIndex++;
165                                         } else {
166                                                 currentProblem = nextTask;
167                                                 taskIndex++;
168                                         }
169                                 } else {
170                                         currentProblem = nextProblem;
171                                         problemIndex++;
172                                 }
173                         } else {
174                                 if (nextTask != null) {
175                                         currentProblem = nextTask;
176                                         taskIndex++;
177                                 }
178                         }
179                         allProblems[allProblemIndex++] = currentProblem;
180                 }
181                 return allProblems;
182         }
183
184         // public ClassFile[] getClassFiles() {
185         // Enumeration enum = compiledTypes.elements();
186         // ClassFile[] classFiles = new ClassFile[compiledTypes.size()];
187         // int index = 0;
188         // while (enum.hasMoreElements()){
189         // classFiles[index++] = (ClassFile)enum.nextElement();
190         // }
191         // return classFiles;
192         // }
193
194         /**
195          * Answer the initial compilation unit corresponding to the present
196          * compilation result
197          */
198         public ICompilationUnit getCompilationUnit() {
199                 return compilationUnit;
200         }
201
202         /**
203          * Answer the initial file name
204          */
205         public char[] getFileName() {
206                 return fileName;
207         }
208
209         /**
210          * Answer the errors encountered during compilation.
211          */
212         public IProblem[] getErrors() {
213
214                 IProblem[] problems = getProblems();
215                 int errorCount = 0;
216                 for (int i = 0; i < this.problemCount; i++) {
217                         if (problems[i].isError())
218                                 errorCount++;
219                 }
220                 if (errorCount == this.problemCount)
221                         return problems;
222                 IProblem[] errors = new IProblem[errorCount];
223                 int index = 0;
224                 for (int i = 0; i < this.problemCount; i++) {
225                         if (problems[i].isError())
226                                 errors[index++] = problems[i];
227                 }
228                 return errors;
229         }
230
231         /**
232          * Answer the problems (errors and warnings) encountered during compilation.
233          * 
234          * This is not a compiler internal API - it has side-effects ! It is
235          * intended to be used only once all problems have been detected, and makes
236          * sure the problems slot as the exact size of the number of problems.
237          */
238         public IProblem[] getProblems() {
239
240                 // Re-adjust the size of the problems if necessary.
241                 if (problems != null) {
242
243                         if (this.problemCount != problems.length) {
244                                 System.arraycopy(problems, 0,
245                                                 (problems = new IProblem[problemCount]), 0,
246                                                 problemCount);
247                         }
248
249                         if (this.maxProblemPerUnit > 0
250                                         && this.problemCount > this.maxProblemPerUnit) {
251                                 quickPrioritize(problems, 0, problemCount - 1);
252                                 this.problemCount = this.maxProblemPerUnit;
253                                 System.arraycopy(problems, 0,
254                                                 (problems = new IProblem[problemCount]), 0,
255                                                 problemCount);
256                         }
257
258                         // Sort problems per source positions.
259                         quickSort(problems, 0, problems.length - 1);
260                 }
261                 return problems;
262         }
263
264         /**
265          * Answer the tasks (TO-DO, ...) encountered during compilation.
266          * 
267          * This is not a compiler internal API - it has side-effects ! It is
268          * intended to be used only once all problems have been detected, and makes
269          * sure the problems slot as the exact size of the number of problems.
270          */
271         public IProblem[] getTasks() {
272
273                 // Re-adjust the size of the tasks if necessary.
274                 if (this.tasks != null) {
275
276                         if (this.taskCount != this.tasks.length) {
277                                 System.arraycopy(this.tasks, 0,
278                                                 (this.tasks = new IProblem[this.taskCount]), 0,
279                                                 this.taskCount);
280                         }
281                         quickSort(tasks, 0, tasks.length - 1);
282                 }
283                 return this.tasks;
284         }
285
286         public boolean hasErrors() {
287
288                 if (problems != null)
289                         for (int i = 0; i < problemCount; i++) {
290                                 if (problems[i].isError())
291                                         return true;
292                         }
293                 return false;
294         }
295
296         public boolean hasProblems() {
297
298                 return problemCount != 0;
299         }
300
301         public boolean hasSyntaxError() {
302
303                 if (problems != null)
304                         for (int i = 0; i < problemCount; i++) {
305                                 IProblem problem = problems[i];
306                                 if ((problem.getID() & IProblem.Syntax) != 0
307                                                 && problem.isError())
308                                         return true;
309                         }
310                 return false;
311         }
312
313         public boolean hasTasks() {
314                 return this.taskCount != 0;
315         }
316
317         public boolean hasWarnings() {
318
319                 if (problems != null)
320                         for (int i = 0; i < problemCount; i++) {
321                                 if (problems[i].isWarning())
322                                         return true;
323                         }
324                 return false;
325         }
326
327         private static void quickSort(IProblem[] list, int left, int right) {
328
329                 if (left >= right)
330                         return;
331
332                 // sort the problems by their source start position... starting with 0
333                 int original_left = left;
334                 int original_right = right;
335                 int mid = list[(left + right) / 2].getSourceStart();
336                 do {
337                         while (list[left].getSourceStart() < mid)
338                                 left++;
339                         while (mid < list[right].getSourceStart())
340                                 right--;
341                         if (left <= right) {
342                                 IProblem tmp = list[left];
343                                 list[left] = list[right];
344                                 list[right] = tmp;
345                                 left++;
346                                 right--;
347                         }
348                 } while (left <= right);
349                 if (original_left < right)
350                         quickSort(list, original_left, right);
351                 if (left < original_right)
352                         quickSort(list, left, original_right);
353         }
354
355         private void quickPrioritize(IProblem[] list, int left, int right) {
356
357                 if (left >= right)
358                         return;
359
360                 // sort the problems by their priority... starting with the highest
361                 // priority
362                 int original_left = left;
363                 int original_right = right;
364                 int mid = computePriority(list[(left + right) / 2]);
365                 do {
366                         while (computePriority(list[right]) < mid)
367                                 right--;
368                         while (mid < computePriority(list[left]))
369                                 left++;
370                         if (left <= right) {
371                                 IProblem tmp = list[left];
372                                 list[left] = list[right];
373                                 list[right] = tmp;
374                                 left++;
375                                 right--;
376                         }
377                 } while (left <= right);
378                 if (original_left < right)
379                         quickPrioritize(list, original_left, right);
380                 if (left < original_right)
381                         quickPrioritize(list, left, original_right);
382         }
383
384         /**
385          * For now, remember the compiled type using its compound name.
386          */
387         // public void record(char[] typeName, ClassFile classFile) {
388         //
389         // compiledTypes.put(typeName, classFile);
390         // }
391         public void record(IProblem newProblem, ReferenceContext referenceContext) {
392
393                 if (newProblem.getID() == IProblem.Task) {
394                         recordTask(newProblem);
395                         return;
396                 }
397                 if (problemCount == 0) {
398                         problems = new IProblem[5];
399                 } else if (problemCount == problems.length) {
400                         System.arraycopy(problems, 0,
401                                         (problems = new IProblem[problemCount * 2]), 0,
402                                         problemCount);
403                 }
404                 problems[problemCount++] = newProblem;
405                 if (referenceContext != null) {
406                         if (problemsMap == null)
407                                 problemsMap = new Hashtable(5);
408                         if (firstErrorsMap == null)
409                                 firstErrorsMap = new Hashtable(5);
410                         if (newProblem.isError() && !referenceContext.hasErrors())
411                                 firstErrorsMap.put(newProblem, newProblem);
412                         problemsMap.put(newProblem, referenceContext);
413                 }
414         }
415
416         private void recordTask(IProblem newProblem) {
417                 if (this.taskCount == 0) {
418                         this.tasks = new IProblem[5];
419                 } else if (this.taskCount == this.tasks.length) {
420                         System.arraycopy(this.tasks, 0,
421                                         (this.tasks = new IProblem[this.taskCount * 2]), 0,
422                                         this.taskCount);
423                 }
424                 this.tasks[this.taskCount++] = newProblem;
425         }
426
427         public CompilationResult tagAsAccepted() {
428
429                 this.hasBeenAccepted = true;
430                 this.problemsMap = null; // flush
431                 return this;
432         }
433
434         public String toString() {
435
436                 StringBuffer buffer = new StringBuffer();
437                 if (this.fileName != null) {
438                         buffer.append("Filename : ").append(this.fileName).append('\n'); //$NON-NLS-1$
439                 }
440                 // if (this.compiledTypes != null){
441                 // buffer.append("COMPILED type(s) \n"); //$NON-NLS-1$
442                 // Enumeration typeNames = this.compiledTypes.keys();
443                 // while (typeNames.hasMoreElements()) {
444                 // char[] typeName = (char[]) typeNames.nextElement();
445                 // buffer.append("\t - ").append(typeName).append('\n'); //$NON-NLS-1$
446                 //                              
447                 // }
448                 // } else {
449                 // buffer.append("No COMPILED type\n"); //$NON-NLS-1$
450                 // }
451                 if (problems != null) {
452                         buffer.append(this.problemCount).append(" PROBLEM(s) detected \n"); //$NON-NLS-1$//$NON-NLS-2$
453                         for (int i = 0; i < this.problemCount; i++) {
454                                 buffer.append("\t - ").append(this.problems[i]).append('\n'); //$NON-NLS-1$
455                         }
456                 } else {
457                         buffer.append("No PROBLEM\n"); //$NON-NLS-1$
458                 }
459                 return buffer.toString();
460         }
461 }