697445965754b1f59e18a3bf8498f03933aeaeb2
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / CompilationResult.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.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 optionally its principal structure
19  * <li> any problems (errors or warnings) produced
20  * <li> dependency info
21  * </ul>
22  *
23  * The principle structure and binary may be null if the compiler could not produce them.
24  * If neither could be produced, there is no corresponding entry for the type.
25  *
26  * The dependency info includes type references such as supertypes, field types, method
27  * parameter and return types, local variable types, types of intermediate expressions, etc.
28  * It also includes the namespaces (packages) in which names were looked up.
29  * It does <em>not</em> include finer grained dependencies such as information about
30  * specific fields and methods which were referenced, but does contain their 
31  * declaring types and any other types used to locate such fields or methods.
32  */
33
34 import net.sourceforge.phpdt.core.compiler.*;
35 import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration;
36 import net.sourceforge.phpdt.internal.compiler.env.*;
37 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
38
39 import java.util.*;
40
41 public class CompilationResult {
42         
43         public IProblem problems[];
44         public int problemCount;
45         public ICompilationUnit compilationUnit;
46         private Map problemsMap;
47         private Map firstErrorsMap;
48         private HashSet duplicateProblems;
49         private int maxProblemPerUnit;
50         public char[][][] qualifiedReferences;
51         public char[][] simpleNameReferences;
52
53         public int lineSeparatorPositions[];
54         public Hashtable compiledTypes = new Hashtable(11);
55         public int unitIndex, totalUnitsKnown;
56         public boolean hasBeenAccepted = false;
57         public char[] fileName;
58         
59 public CompilationResult(
60         char[] fileName,
61         int unitIndex, 
62         int totalUnitsKnown,
63         int maxProblemPerUnit){
64
65         this.fileName = fileName;
66         this.unitIndex = unitIndex;
67         this.totalUnitsKnown = totalUnitsKnown;
68         this.maxProblemPerUnit = maxProblemPerUnit;
69
70 }
71
72 public CompilationResult(
73         ICompilationUnit compilationUnit,
74         int unitIndex, 
75         int totalUnitsKnown,
76         int maxProblemPerUnit){
77
78         this.fileName = compilationUnit.getFileName();
79         this.compilationUnit = compilationUnit;
80         this.unitIndex = unitIndex;
81         this.totalUnitsKnown = totalUnitsKnown;
82         this.maxProblemPerUnit = maxProblemPerUnit;
83
84 }
85 private int computePriority(IProblem problem){
86
87         final int P_STATIC = 1000;
88         final int P_OUTSIDE_METHOD = 4000;
89         final int P_FIRST_ERROR = 2000;
90         final int P_ERROR = 10000;
91         
92         int priority = 1000 - problem.getSourceLineNumber(); // early problems first
93         if (priority < 0) priority = 0;
94         if (problem.isError()){
95                 priority += P_ERROR;
96         }
97         ReferenceContext context = problemsMap == null ? null : (ReferenceContext) problemsMap.get(problem);
98         if (context != null){
99                 if (context instanceof AbstractMethodDeclaration){
100                         AbstractMethodDeclaration method = (AbstractMethodDeclaration) context;
101                         if (method.isStatic()) {
102                                 priority += P_STATIC;
103                         }
104                 } else {
105                 priority += P_OUTSIDE_METHOD;
106                 }
107         } else {
108                 priority += P_OUTSIDE_METHOD;
109         }
110         if (firstErrorsMap.containsKey(problem)){
111                 priority += P_FIRST_ERROR;
112         }
113         return priority;
114 }
115 public ClassFile[] getClassFiles() {
116         Enumeration enum = compiledTypes.elements();
117         ClassFile[] classFiles = new ClassFile[compiledTypes.size()];
118         int index = 0;
119         while (enum.hasMoreElements()){
120                 classFiles[index++] = (ClassFile)enum.nextElement();
121         }
122         return classFiles;      
123 }
124 /**
125  * Answer the initial compilation unit corresponding to the present compilation result
126  */
127 public ICompilationUnit getCompilationUnit(){
128         return compilationUnit;
129 }
130 /**
131  * Answer the initial file name
132  */
133 public char[] getFileName(){
134         return fileName;
135 }
136 /**
137  * Answer the problems (errors and warnings) encountered during compilation.
138  *
139  * This is not a compiler internal API - it has side-effects !
140  * It is intended to be used only once all problems have been detected,
141  * and makes sure the problems slot as the exact size of the number of
142  * problems.
143  */
144 public IProblem[] getProblems() {
145         
146         // Re-adjust the size of the problems if necessary.
147         if (problems != null) {
148
149                 if (this.problemCount != problems.length) {
150                         System.arraycopy(problems, 0, (problems = new IProblem[problemCount]), 0, problemCount);
151                 }
152
153                 if (this.maxProblemPerUnit > 0 && this.problemCount > this.maxProblemPerUnit){
154                         quickPrioritize(problems, 0, problemCount - 1);
155                         this.problemCount = this.maxProblemPerUnit;
156                         System.arraycopy(problems, 0, (problems = new IProblem[problemCount]), 0, problemCount);
157                 }
158
159                 // Sort problems per source positions.
160                 quicksort(problems, 0, problems.length-1);
161         }
162         return problems;
163 }
164
165 public boolean hasErrors() {
166         if (problems != null)
167                 for (int i = 0; i < problemCount; i++) {
168                         if (problems[i].isError())
169                                 return true;
170                 }
171         return false;
172 }
173 public boolean hasProblems() {
174         return problemCount != 0;
175 }
176 public boolean hasWarnings() {
177         if (problems != null)
178                 for (int i = 0; i < problemCount; i++) {
179                         if (problems[i].isWarning())
180                                 return true;
181                 }
182         return false;
183 }
184
185 private static void quicksort(IProblem arr[], int left, int right) {
186         int i, last, pos;
187
188         if (left >= right) {
189                 /* do nothing if array contains fewer than two */
190                 return;
191                 /* two elements */
192         }
193
194         swap(arr, left, (left + right) / 2);
195         last = left;
196         pos = arr[left].getSourceStart();
197
198         for (i = left + 1; i <= right; i++) {
199                 if (arr[i].getSourceStart() < pos) {
200                         swap(arr, ++last, i);
201                 }
202         }
203
204         swap(arr, left, last);
205         quicksort(arr, left, last - 1);
206         quicksort(arr, last + 1, right);
207 }
208
209 private void quickPrioritize(IProblem arr[], int left, int right) {
210         int i, last, prio;
211
212         if (left >= right) {
213                 /* do nothing if array contains fewer than two */
214                 return;
215                 /* two elements */
216         }
217
218         swap(arr, left, (left + right) / 2);
219         last = left;
220         prio = computePriority(arr[left]);
221
222         for (i = left + 1; i <= right; i++) {
223                 if (computePriority(arr[i]) > prio) {
224                         swap(arr, ++last, i);
225                 }
226         }
227
228         swap(arr, left, last);
229         quickPrioritize(arr, left, last - 1);
230         quickPrioritize(arr, last + 1, right);
231 }
232
233 /**
234  * For now, remember the compiled type using its compound name.
235  */
236 public void record(char[] typeName, ClassFile classFile) {
237         compiledTypes.put(typeName, classFile);
238 }
239 public void record(IProblem newProblem, ReferenceContext referenceContext) {
240         if (problemCount == 0) {
241                 problems = new IProblem[5];
242         } else {
243                 if (problemCount == problems.length)
244                         System.arraycopy(problems, 0, (problems = new IProblem[problemCount * 2]), 0, problemCount);
245         };
246         problems[problemCount++] = newProblem;
247         if (referenceContext != null){
248                 if (problemsMap == null) problemsMap = new Hashtable(5);
249                 if (firstErrorsMap == null) firstErrorsMap = new Hashtable(5);
250                 if (newProblem.isError() && !referenceContext.hasErrors()) firstErrorsMap.put(newProblem, newProblem);
251                 problemsMap.put(newProblem, referenceContext);
252         }
253 }
254 private static void swap(IProblem arr[], int i, int j) {
255         IProblem tmp;
256         tmp = arr[i];
257         arr[i] = arr[j];
258         arr[j] = tmp;
259 }
260 CompilationResult tagAsAccepted(){
261         this.hasBeenAccepted = true;
262         this.problemsMap = null; // flush
263         return this;
264 }
265
266 public String toString(){
267         StringBuffer buffer = new StringBuffer();
268         if (this.fileName != null){
269                 buffer.append("Filename : ").append(this.fileName).append('\n'); //$NON-NLS-1$
270         }
271         if (this.compiledTypes != null){
272                 buffer.append("COMPILED type(s) \n");  //$NON-NLS-1$
273                 Enumeration typeNames = this.compiledTypes.keys();
274                 while (typeNames.hasMoreElements()) {
275                         char[] typeName = (char[]) typeNames.nextElement();
276                         buffer.append("\t - ").append(typeName).append('\n');   //$NON-NLS-1$
277                         
278                 }
279         } else {
280                 buffer.append("No COMPILED type\n");  //$NON-NLS-1$
281         }
282         if (problems != null){
283                 buffer.append(this.problemCount).append(" PROBLEM(s) detected \n"); //$NON-NLS-1$//$NON-NLS-2$
284                 for (int i = 0; i < this.problemCount; i++){
285                         buffer.append("\t - ").append(this.problems[i]).append('\n'); //$NON-NLS-1$
286                 }
287         } else {
288                 buffer.append("No PROBLEM\n"); //$NON-NLS-1$
289         } 
290         return buffer.toString();
291 }
292 }