First test
[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 java.util.Enumeration;
35 import java.util.HashSet;
36 import java.util.Hashtable;
37 import java.util.Map;
38
39 import net.sourceforge.phpdt.core.compiler.IProblem;
40 import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration;
41 import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit;
42 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
43
44 public class CompilationResult {
45         
46         public IProblem problems[];
47         public int problemCount;
48         public ICompilationUnit compilationUnit;
49         private Map problemsMap;
50         private Map firstErrorsMap;
51         private HashSet duplicateProblems;
52         private int maxProblemPerUnit;
53         public char[][][] qualifiedReferences;
54         public char[][] simpleNameReferences;
55
56         public int lineSeparatorPositions[];
57         public Hashtable compiledTypes = new Hashtable(11);
58         public int unitIndex, totalUnitsKnown;
59         public boolean hasBeenAccepted = false;
60         public char[] fileName;
61         
62 public CompilationResult(
63         char[] fileName,
64         int unitIndex, 
65         int totalUnitsKnown,
66         int maxProblemPerUnit){
67
68         this.fileName = fileName;
69         this.unitIndex = unitIndex;
70         this.totalUnitsKnown = totalUnitsKnown;
71         this.maxProblemPerUnit = maxProblemPerUnit;
72
73 }
74
75 public CompilationResult(
76         ICompilationUnit compilationUnit,
77         int unitIndex, 
78         int totalUnitsKnown,
79         int maxProblemPerUnit){
80
81         this.fileName = compilationUnit.getFileName();
82         this.compilationUnit = compilationUnit;
83         this.unitIndex = unitIndex;
84         this.totalUnitsKnown = totalUnitsKnown;
85         this.maxProblemPerUnit = maxProblemPerUnit;
86
87 }
88 private int computePriority(IProblem problem){
89
90         final int P_STATIC = 1000;
91         final int P_OUTSIDE_METHOD = 4000;
92         final int P_FIRST_ERROR = 2000;
93         final int P_ERROR = 10000;
94         
95         int priority = 1000 - problem.getSourceLineNumber(); // early problems first
96         if (priority < 0) priority = 0;
97         if (problem.isError()){
98                 priority += P_ERROR;
99         }
100         ReferenceContext context = problemsMap == null ? null : (ReferenceContext) problemsMap.get(problem);
101         if (context != null){
102                 if (context instanceof AbstractMethodDeclaration){
103                         AbstractMethodDeclaration method = (AbstractMethodDeclaration) context;
104                         if (method.isStatic()) {
105                                 priority += P_STATIC;
106                         }
107                 } else {
108                 priority += P_OUTSIDE_METHOD;
109                 }
110         } else {
111                 priority += P_OUTSIDE_METHOD;
112         }
113         if (firstErrorsMap.containsKey(problem)){
114                 priority += P_FIRST_ERROR;
115         }
116         return priority;
117 }
118 public ClassFile[] getClassFiles() {
119         Enumeration enum = compiledTypes.elements();
120         ClassFile[] classFiles = new ClassFile[compiledTypes.size()];
121         int index = 0;
122         while (enum.hasMoreElements()){
123                 classFiles[index++] = (ClassFile)enum.nextElement();
124         }
125         return classFiles;      
126 }
127 /**
128  * Answer the initial compilation unit corresponding to the present compilation result
129  */
130 public ICompilationUnit getCompilationUnit(){
131         return compilationUnit;
132 }
133 /**
134  * Answer the initial file name
135  */
136 public char[] getFileName(){
137         return fileName;
138 }
139 /**
140  * Answer the problems (errors and warnings) encountered during compilation.
141  *
142  * This is not a compiler internal API - it has side-effects !
143  * It is intended to be used only once all problems have been detected,
144  * and makes sure the problems slot as the exact size of the number of
145  * problems.
146  */
147 public IProblem[] getProblems() {
148         
149         // Re-adjust the size of the problems if necessary.
150         if (problems != null) {
151
152                 if (this.problemCount != problems.length) {
153                         System.arraycopy(problems, 0, (problems = new IProblem[problemCount]), 0, problemCount);
154                 }
155
156                 if (this.maxProblemPerUnit > 0 && this.problemCount > this.maxProblemPerUnit){
157                         quickPrioritize(problems, 0, problemCount - 1);
158                         this.problemCount = this.maxProblemPerUnit;
159                         System.arraycopy(problems, 0, (problems = new IProblem[problemCount]), 0, problemCount);
160                 }
161
162                 // Sort problems per source positions.
163                 quicksort(problems, 0, problems.length-1);
164         }
165         return problems;
166 }
167
168 public boolean hasErrors() {
169         if (problems != null)
170                 for (int i = 0; i < problemCount; i++) {
171                         if (problems[i].isError())
172                                 return true;
173                 }
174         return false;
175 }
176 public boolean hasProblems() {
177         return problemCount != 0;
178 }
179 public boolean hasWarnings() {
180         if (problems != null)
181                 for (int i = 0; i < problemCount; i++) {
182                         if (problems[i].isWarning())
183                                 return true;
184                 }
185         return false;
186 }
187
188 private static void quicksort(IProblem arr[], int left, int right) {
189         int i, last, pos;
190
191         if (left >= right) {
192                 /* do nothing if array contains fewer than two */
193                 return;
194                 /* two elements */
195         }
196
197         swap(arr, left, (left + right) / 2);
198         last = left;
199         pos = arr[left].getSourceStart();
200
201         for (i = left + 1; i <= right; i++) {
202                 if (arr[i].getSourceStart() < pos) {
203                         swap(arr, ++last, i);
204                 }
205         }
206
207         swap(arr, left, last);
208         quicksort(arr, left, last - 1);
209         quicksort(arr, last + 1, right);
210 }
211
212 private void quickPrioritize(IProblem arr[], int left, int right) {
213         int i, last, prio;
214
215         if (left >= right) {
216                 /* do nothing if array contains fewer than two */
217                 return;
218                 /* two elements */
219         }
220
221         swap(arr, left, (left + right) / 2);
222         last = left;
223         prio = computePriority(arr[left]);
224
225         for (i = left + 1; i <= right; i++) {
226                 if (computePriority(arr[i]) > prio) {
227                         swap(arr, ++last, i);
228                 }
229         }
230
231         swap(arr, left, last);
232         quickPrioritize(arr, left, last - 1);
233         quickPrioritize(arr, last + 1, right);
234 }
235
236 /**
237  * For now, remember the compiled type using its compound name.
238  */
239 public void record(char[] typeName, ClassFile classFile) {
240         compiledTypes.put(typeName, classFile);
241 }
242 public void record(IProblem newProblem, ReferenceContext referenceContext) {
243         if (problemCount == 0) {
244                 problems = new IProblem[5];
245         } else {
246                 if (problemCount == problems.length)
247                         System.arraycopy(problems, 0, (problems = new IProblem[problemCount * 2]), 0, problemCount);
248         };
249         problems[problemCount++] = newProblem;
250         if (referenceContext != null){
251                 if (problemsMap == null) problemsMap = new Hashtable(5);
252                 if (firstErrorsMap == null) firstErrorsMap = new Hashtable(5);
253                 if (newProblem.isError() && !referenceContext.hasErrors()) firstErrorsMap.put(newProblem, newProblem);
254                 problemsMap.put(newProblem, referenceContext);
255         }
256 }
257 private static void swap(IProblem arr[], int i, int j) {
258         IProblem tmp;
259         tmp = arr[i];
260         arr[i] = arr[j];
261         arr[j] = tmp;
262 }
263 CompilationResult tagAsAccepted(){
264         this.hasBeenAccepted = true;
265         this.problemsMap = null; // flush
266         return this;
267 }
268
269 public String toString(){
270         StringBuffer buffer = new StringBuffer();
271         if (this.fileName != null){
272                 buffer.append("Filename : ").append(this.fileName).append('\n'); //$NON-NLS-1$
273         }
274         if (this.compiledTypes != null){
275                 buffer.append("COMPILED type(s) \n");  //$NON-NLS-1$
276                 Enumeration typeNames = this.compiledTypes.keys();
277                 while (typeNames.hasMoreElements()) {
278                         char[] typeName = (char[]) typeNames.nextElement();
279                         buffer.append("\t - ").append(typeName).append('\n');   //$NON-NLS-1$
280                         
281                 }
282         } else {
283                 buffer.append("No COMPILED type\n");  //$NON-NLS-1$
284         }
285         if (problems != null){
286                 buffer.append(this.problemCount).append(" PROBLEM(s) detected \n"); //$NON-NLS-1$//$NON-NLS-2$
287                 for (int i = 0; i < this.problemCount; i++){
288                         buffer.append("\t - ").append(this.problems[i]).append('\n'); //$NON-NLS-1$
289                 }
290         } else {
291                 buffer.append("No PROBLEM\n"); //$NON-NLS-1$
292         } 
293         return buffer.toString();
294 }
295 }