A massive organize imports and formatting of the sources using default Eclipse code...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / builder / AbstractImageBuilder.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.core.builder;
12
13 import java.util.ArrayList;
14 import java.util.Locale;
15
16 import net.sourceforge.phpdt.core.IJavaModelMarker;
17 import net.sourceforge.phpdt.core.JavaCore;
18 import net.sourceforge.phpdt.core.JavaModelException;
19 import net.sourceforge.phpdt.core.compiler.IProblem;
20 import net.sourceforge.phpdt.internal.compiler.CompilationResult;
21 import net.sourceforge.phpdt.internal.compiler.Compiler;
22 import net.sourceforge.phpdt.internal.compiler.DefaultErrorHandlingPolicies;
23 import net.sourceforge.phpdt.internal.compiler.ICompilerRequestor;
24 import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation;
25 import net.sourceforge.phpdt.internal.compiler.problem.ProblemHandler;
26 import net.sourceforge.phpdt.internal.core.util.Util;
27
28 import org.eclipse.core.resources.IMarker;
29 import org.eclipse.core.resources.IResource;
30 import org.eclipse.core.runtime.CoreException;
31 import org.eclipse.core.runtime.IPath;
32
33 /**
34  * The abstract superclass of Java builders. Provides the building and
35  * compilation mechanism in common with the batch and incremental builders.
36  */
37 public abstract class AbstractImageBuilder implements ICompilerRequestor {
38
39         protected PHPBuilder javaBuilder;
40
41         protected State newState;
42
43         // local copies
44         protected NameEnvironment nameEnvironment;
45
46         protected ClasspathMultiDirectory[] sourceLocations;
47
48         protected BuildNotifier notifier;
49
50         protected String encoding;
51
52         protected Compiler compiler;
53
54         protected WorkQueue workQueue;
55
56         protected ArrayList problemSourceFiles;
57
58         protected boolean compiledAllAtOnce;
59
60         private boolean inCompiler;
61
62         public static int MAX_AT_ONCE = 1000;
63
64         protected AbstractImageBuilder(PHPBuilder javaBuilder) {
65                 this.javaBuilder = javaBuilder;
66                 this.newState = new State(javaBuilder);
67
68                 // local copies
69                 this.nameEnvironment = javaBuilder.nameEnvironment;
70                 this.sourceLocations = this.nameEnvironment.sourceLocations;
71                 this.notifier = javaBuilder.notifier;
72
73                 this.encoding = javaBuilder.javaProject.getOption(
74                                 JavaCore.CORE_ENCODING, true);
75                 this.compiler = newCompiler();
76                 this.workQueue = new WorkQueue();
77                 this.problemSourceFiles = new ArrayList(3);
78         }
79
80         public void acceptResult(CompilationResult result) {
81                 // In Batch mode, we write out the class files, hold onto the dependency
82                 // info
83                 // & additional types and report problems.
84
85                 // In Incremental mode, when writing out a class file we need to compare
86                 // it
87                 // against the previous file, remembering if structural changes occured.
88                 // Before reporting the new problems, we need to update the problem
89                 // count &
90                 // remove the old problems. Plus delete additional class files that no
91                 // longer exist.
92
93                 SourceFile compilationUnit = (SourceFile) result.getCompilationUnit(); // go
94                                                                                                                                                                 // directly
95                                                                                                                                                                 // back
96                                                                                                                                                                 // to
97                                                                                                                                                                 // the
98                                                                                                                                                                 // sourceFile
99                 if (!workQueue.isCompiled(compilationUnit)) {
100                         // try {
101                         workQueue.finished(compilationUnit);
102                         try {
103                                 updateProblemsFor(compilationUnit, result); // record
104                                                                                                                         // compilation
105                                                                                                                         // problems before
106                                                                                                                         // potentially
107                                                                                                                         // adding duplicate
108                                                                                                                         // errors
109                                 updateTasksFor(compilationUnit, result); // record tasks
110                         } catch (CoreException e) {
111                                 throw internalException(e);
112                         }
113
114                         // String typeLocator = compilationUnit.typeLocator();
115                         // ClassFile[] classFiles = result.getClassFiles();
116                         // int length = classFiles.length;
117                         // ArrayList duplicateTypeNames = null;
118                         // ArrayList definedTypeNames = new ArrayList(length);
119                         // for (int i = 0; i < length; i++) {
120                         // ClassFile classFile = classFiles[i];
121                         // char[][] compoundName = classFile.getCompoundName();
122                         // char[] typeName = compoundName[compoundName.length - 1];
123                         // boolean isNestedType = CharOperation.contains('$', typeName);
124                         //
125                         // // Look for a possible collision, if one exists, report an error
126                         // but do not write the class file
127                         // if (isNestedType) {
128                         // String qualifiedTypeName = new
129                         // String(classFile.outerMostEnclosingClassFile().fileName());
130                         // if (newState.isDuplicateLocator(qualifiedTypeName, typeLocator))
131                         // continue;
132                         // } else {
133                         // String qualifiedTypeName = new String(classFile.fileName()); //
134                         // the qualified type name "p1/p2/A"
135                         // if (newState.isDuplicateLocator(qualifiedTypeName, typeLocator))
136                         // {
137                         // if (duplicateTypeNames == null)
138                         // duplicateTypeNames = new ArrayList();
139                         // duplicateTypeNames.add(compoundName);
140                         // createErrorFor(compilationUnit.resource,
141                         // ProjectPrefUtil.bind("build.duplicateClassFile", new
142                         // String(typeName)));
143                         // //$NON-NLS-1$
144                         // continue;
145                         // }
146                         // newState.recordLocatorForType(qualifiedTypeName, typeLocator);
147                         // }
148                         // definedTypeNames.add(writeClassFile(classFile,
149                         // compilationUnit.sourceLocation.binaryFolder, !isNestedType));
150                         // }
151
152                         // finishedWith(typeLocator, result,
153                         // compilationUnit.getMainTypeName(), definedTypeNames,
154                         // duplicateTypeNames);
155                         notifier.compiled(compilationUnit);
156                         // } catch (CoreException e) {
157                         // Util.log(e, "JavaBuilder handling CoreException"); //$NON-NLS-1$
158                         // createErrorFor(compilationUnit.resource,
159                         // Util.bind("build.inconsistentClassFile")); //$NON-NLS-1$
160                         // }
161                 }
162         }
163
164         protected void cleanUp() {
165                 this.nameEnvironment.cleanup();
166
167                 this.javaBuilder = null;
168                 this.nameEnvironment = null;
169                 this.sourceLocations = null;
170                 this.notifier = null;
171                 this.compiler = null;
172                 this.workQueue = null;
173                 this.problemSourceFiles = null;
174         }
175
176         /*
177          * Compile the given elements, adding more elements to the work queue if
178          * they are affected by the changes.
179          */
180         protected void compile(SourceFile[] units) {
181                 int toDo = units.length;
182                 if (this.compiledAllAtOnce = toDo <= MAX_AT_ONCE) {
183                         // do them all now
184                         if (PHPBuilder.DEBUG)
185                                 for (int i = 0; i < toDo; i++)
186                                         System.out
187                                                         .println("About to compile " + units[i].typeLocator()); //$NON-NLS-1$
188                         compile(units, null);
189                 } else {
190                         int i = 0;
191                         boolean compilingFirstGroup = true;
192                         while (i < toDo) {
193                                 int doNow = toDo < MAX_AT_ONCE ? toDo : MAX_AT_ONCE;
194                                 int index = 0;
195                                 SourceFile[] toCompile = new SourceFile[doNow];
196                                 while (i < toDo && index < doNow) {
197                                         // Although it needed compiling when this method was called,
198                                         // it may have
199                                         // already been compiled when it was referenced by another
200                                         // unit.
201                                         SourceFile unit = units[i++];
202                                         if (compilingFirstGroup || workQueue.isWaiting(unit)) {
203                                                 if (PHPBuilder.DEBUG)
204                                                         System.out
205                                                                         .println("About to compile " + unit.typeLocator()); //$NON-NLS-1$
206                                                 toCompile[index++] = unit;
207                                         }
208                                 }
209                                 if (index < doNow)
210                                         System.arraycopy(toCompile, 0,
211                                                         toCompile = new SourceFile[index], 0, index);
212                                 SourceFile[] additionalUnits = new SourceFile[toDo - i];
213                                 System.arraycopy(units, i, additionalUnits, 0,
214                                                 additionalUnits.length);
215                                 compilingFirstGroup = false;
216                                 compile(toCompile, additionalUnits);
217                         }
218                 }
219         }
220
221         void compile(SourceFile[] units, SourceFile[] additionalUnits) {
222                 if (units.length == 0)
223                         return;
224                 notifier.aboutToCompile(units[0]); // just to change the message
225
226                 // extend additionalFilenames with all hierarchical problem types found
227                 // during this entire build
228                 if (!problemSourceFiles.isEmpty()) {
229                         int toAdd = problemSourceFiles.size();
230                         int length = additionalUnits == null ? 0 : additionalUnits.length;
231                         if (length == 0)
232                                 additionalUnits = new SourceFile[toAdd];
233                         else
234                                 System.arraycopy(additionalUnits, 0,
235                                                 additionalUnits = new SourceFile[length + toAdd], 0,
236                                                 length);
237                         for (int i = 0; i < toAdd; i++)
238                                 additionalUnits[length + i] = (SourceFile) problemSourceFiles
239                                                 .get(i);
240                 }
241                 String[] initialTypeNames = new String[units.length];
242                 for (int i = 0, l = units.length; i < l; i++)
243                         initialTypeNames[i] = units[i].initialTypeName;
244                 nameEnvironment.setNames(initialTypeNames, additionalUnits);
245                 notifier.checkCancel();
246                 try {
247                         inCompiler = true;
248                         compiler.compile(units);
249                 } catch (AbortCompilation ignored) {
250                         // ignore the AbortCompilcation coming from
251                         // BuildNotifier.checkCancelWithinCompiler()
252                         // the Compiler failed after the user has chose to cancel... likely
253                         // due to an OutOfMemory error
254                 } finally {
255                         inCompiler = false;
256                 }
257                 // Check for cancel immediately after a compile, because the compiler
258                 // may
259                 // have been cancelled but without propagating the correct exception
260                 notifier.checkCancel();
261         }
262
263         protected void createErrorFor(IResource resource, String message) {
264                 try {
265                         IMarker marker = resource
266                                         .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
267                         int severity = IMarker.SEVERITY_ERROR;
268                         if (message.equals(Util.bind("build.duplicateResource"))) //$NON-NLS-1$
269                                 if (JavaCore.WARNING.equals(javaBuilder.javaProject.getOption(
270                                                 JavaCore.CORE_JAVA_BUILD_DUPLICATE_RESOURCE, true)))
271                                         severity = IMarker.SEVERITY_WARNING;
272                         marker.setAttributes(new String[] { IMarker.MESSAGE,
273                                         IMarker.SEVERITY, IMarker.CHAR_START, IMarker.CHAR_END },
274                                         new Object[] { message, new Integer(severity),
275                                                         new Integer(0), new Integer(1) });
276                 } catch (CoreException e) {
277                         throw internalException(e);
278                 }
279         }
280
281         // protected void finishedWith(String sourceLocator, CompilationResult
282         // result, char[] mainTypeName) throws CoreException {//,
283         // ArrayList definedTypeNames, ArrayList duplicateTypeNames) throws
284         // CoreException {
285         // if (duplicateTypeNames == null) {
286         // newState.record(sourceLocator, result.qualifiedReferences,
287         // result.simpleNameReferences, mainTypeName, definedTypeNames);
288         // return;
289         // }
290         //
291         // char[][][] qualifiedRefs = result.qualifiedReferences;
292         // char[][] simpleRefs = result.simpleNameReferences;
293         // // for each duplicate type p1.p2.A, add the type name A (package was
294         // already added)
295         // next : for (int i = 0, l = duplicateTypeNames.size(); i < l; i++) {
296         // char[][] compoundName = (char[][]) duplicateTypeNames.get(i);
297         // char[] typeName = compoundName[compoundName.length - 1];
298         // int sLength = simpleRefs.length;
299         // for (int j = 0; j < sLength; j++)
300         // if (CharOperation.equals(simpleRefs[j], typeName))
301         // continue next;
302         // System.arraycopy(simpleRefs, 0, simpleRefs = new char[sLength + 1][], 0,
303         // sLength);
304         // simpleRefs[sLength] = typeName;
305         // }
306         // newState.record(sourceLocator, qualifiedRefs, simpleRefs, mainTypeName,
307         // definedTypeNames);
308         // }
309
310         // protected IContainer createFolder(IPath packagePath, IContainer
311         // outputFolder) throws CoreException {
312         // if (packagePath.isEmpty()) return outputFolder;
313         // IFolder folder = outputFolder.getFolder(packagePath);
314         // if (!folder.exists()) {
315         // createFolder(packagePath.removeLastSegments(1), outputFolder);
316         // folder.create(true, true, null);
317         // folder.setDerived(true);
318         // }
319         // return folder;
320         // }
321
322         protected RuntimeException internalException(CoreException t) {
323                 ImageBuilderInternalException imageBuilderException = new ImageBuilderInternalException(
324                                 t);
325                 if (inCompiler)
326                         return new AbortCompilation(true, imageBuilderException);
327                 return imageBuilderException;
328         }
329
330         protected Compiler newCompiler() {
331                 // called once when the builder is initialized... can override if needed
332                 return new Compiler(nameEnvironment, DefaultErrorHandlingPolicies
333                                 .proceedWithAllProblems(), javaBuilder.javaProject
334                                 .getOptions(true), this, ProblemFactory
335                                 .getProblemFactory(Locale.getDefault()));
336         }
337
338         protected boolean isExcludedFromProject(IPath childPath)
339                         throws JavaModelException {
340                 // answer whether the folder should be ignored when walking the project
341                 // as a source folder
342                 if (childPath.segmentCount() > 2)
343                         return false; // is a subfolder of a package
344
345                 for (int j = 0, k = sourceLocations.length; j < k; j++) {
346                         // if
347                         // (childPath.equals(sourceLocations[j].binaryFolder.getFullPath()))
348                         // return true;
349                         if (childPath.equals(sourceLocations[j].sourceFolder.getFullPath()))
350                                 return true;
351                 }
352                 // skip default output folder which may not be used by any source folder
353                 return false; // childPath.equals(javaBuilder.javaProject.getOutputLocation());
354         }
355
356         /**
357          * Creates a marker from each problem and adds it to the resource. The
358          * marker is as follows: - its type is T_PROBLEM - its plugin ID is the
359          * JavaBuilder's plugin ID - its message is the problem's message - its
360          * priority reflects the severity of the problem - its range is the
361          * problem's range - it has an extra attribute "ID" which holds the
362          * problem's id
363          */
364         protected void storeProblemsFor(SourceFile sourceFile, IProblem[] problems)
365                         throws CoreException {
366                 if (sourceFile == null || problems == null || problems.length == 0)
367                         return;
368
369                 // String missingClassFile = null;
370                 IResource resource = sourceFile.resource;
371                 for (int i = 0, l = problems.length; i < l; i++) {
372                         IProblem problem = problems[i];
373                         int id = problem.getID();
374                         switch (id) {
375                         case IProblem.IsClassPathCorrect:
376                                 // PHPBuilder.removeProblemsAndTasksFor(javaBuilder.currentProject);
377                                 // // make this the only problem for this project
378                                 // String[] args = problem.getArguments();
379                                 // missingClassFile = args[0];
380                                 break;
381                         case IProblem.SuperclassMustBeAClass:
382                         case IProblem.SuperInterfaceMustBeAnInterface:
383                         case IProblem.HierarchyCircularitySelfReference:
384                         case IProblem.HierarchyCircularity:
385                         case IProblem.HierarchyHasProblems:
386                         case IProblem.SuperclassNotFound:
387                         case IProblem.SuperclassNotVisible:
388                         case IProblem.SuperclassAmbiguous:
389                         case IProblem.SuperclassInternalNameProvided:
390                         case IProblem.SuperclassInheritedNameHidesEnclosingName:
391                         case IProblem.InterfaceNotFound:
392                         case IProblem.InterfaceNotVisible:
393                         case IProblem.InterfaceAmbiguous:
394                         case IProblem.InterfaceInternalNameProvided:
395                         case IProblem.InterfaceInheritedNameHidesEnclosingName:
396                                 // ensure that this file is always retrieved from source for the
397                                 // rest of the build
398                                 if (!problemSourceFiles.contains(sourceFile))
399                                         problemSourceFiles.add(sourceFile);
400                                 break;
401                         }
402
403                         if (id != IProblem.Task) {
404                                 IMarker marker = resource
405                                                 .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
406                                 marker
407                                                 .setAttributes(
408                                                                 new String[] { IMarker.MESSAGE,
409                                                                                 IMarker.SEVERITY, IJavaModelMarker.ID,
410                                                                                 IMarker.CHAR_START, IMarker.CHAR_END,
411                                                                                 IMarker.LINE_NUMBER,
412                                                                                 IJavaModelMarker.ARGUMENTS },
413                                                                 new Object[] {
414                                                                                 problem.getMessage(),
415                                                                                 new Integer(
416                                                                                                 problem.isError() ? IMarker.SEVERITY_ERROR
417                                                                                                                 : IMarker.SEVERITY_WARNING),
418                                                                                 new Integer(id),
419                                                                                 new Integer(problem.getSourceStart()),
420                                                                                 new Integer(problem.getSourceEnd() + 1),
421                                                                                 new Integer(problem
422                                                                                                 .getSourceLineNumber()),
423                                                                                 Util
424                                                                                                 .getProblemArgumentsForMarker(problem
425                                                                                                                 .getArguments()) });
426                         }
427
428                         /*
429                          * Do NOT want to populate the Java Model just to find the matching
430                          * Java element. Also cannot query compilation units located in
431                          * folders with invalid package names such as 'a/b.c.d/e'. //
432                          * compute a user-friendly location IJavaElement element =
433                          * JavaCore.create(resource); if (element instanceof
434                          * net.sourceforge.phpdt.core.ICompilationUnit) { // try to find a
435                          * finer grain element net.sourceforge.phpdt.core.ICompilationUnit
436                          * unit = (net.sourceforge.phpdt.core.ICompilationUnit) element;
437                          * IJavaElement fragment =
438                          * unit.getElementAt(problem.getSourceStart()); if (fragment !=
439                          * null) element = fragment; } String location = null; if (element
440                          * instanceof JavaElement) location = ((JavaElement)
441                          * element).readableName(); if (location != null)
442                          * marker.setAttribute(IMarker.LOCATION, location);
443                          */
444
445                         // if (missingClassFile != null)
446                         // throw new MissingClassFileException(missingClassFile);
447                 }
448         }
449
450         protected void storeTasksFor(SourceFile sourceFile, IProblem[] tasks)
451                         throws CoreException {
452                 if (sourceFile == null || tasks == null || tasks.length == 0)
453                         return;
454
455                 IResource resource = sourceFile.resource;
456                 for (int i = 0, l = tasks.length; i < l; i++) {
457                         IProblem task = tasks[i];
458                         if (task.getID() == IProblem.Task) {
459                                 IMarker marker = resource
460                                                 .createMarker(IJavaModelMarker.TASK_MARKER);
461                                 int priority = IMarker.PRIORITY_NORMAL;
462                                 String compilerPriority = task.getArguments()[2];
463                                 if (JavaCore.COMPILER_TASK_PRIORITY_HIGH
464                                                 .equals(compilerPriority))
465                                         priority = IMarker.PRIORITY_HIGH;
466                                 else if (JavaCore.COMPILER_TASK_PRIORITY_LOW
467                                                 .equals(compilerPriority))
468                                         priority = IMarker.PRIORITY_LOW;
469                                 marker.setAttributes(new String[] { IMarker.MESSAGE,
470                                                 IMarker.PRIORITY, IMarker.DONE, IMarker.CHAR_START,
471                                                 IMarker.CHAR_END, IMarker.LINE_NUMBER,
472                                                 IMarker.USER_EDITABLE, }, new Object[] {
473                                                 task.getMessage(), new Integer(priority),
474                                                 new Boolean(false), new Integer(task.getSourceStart()),
475                                                 new Integer(task.getSourceEnd() + 1),
476                                                 new Integer(task.getSourceLineNumber()),
477                                                 new Boolean(false), });
478                         }
479                 }
480         }
481
482         protected void updateProblemsFor(SourceFile sourceFile,
483                         CompilationResult result) throws CoreException {
484                 IProblem[] problems = result.getProblems();
485                 if (problems == null || problems.length == 0)
486                         return;
487                 // axelcl start insert - calculate line numbers
488                 if (problems != null) {
489                         for (int i = 0; i < problems.length; i++) {
490                                 if (problems[i].getSourceLineNumber() == 1) {
491                                         problems[i].setSourceLineNumber(ProblemHandler
492                                                         .searchLineNumber(result.lineSeparatorPositions,
493                                                                         problems[i].getSourceStart()));
494                                 }
495                         }
496                 }
497                 // axelcl end insert
498                 notifier.updateProblemCounts(problems);
499                 storeProblemsFor(sourceFile, problems);
500         }
501
502         protected void updateTasksFor(SourceFile sourceFile,
503                         CompilationResult result) throws CoreException {
504                 IProblem[] tasks = result.getTasks();
505                 if (tasks == null || tasks.length == 0)
506                         return;
507
508                 storeTasksFor(sourceFile, tasks);
509         }
510
511         // protected char[] writeClassFile(ClassFile classFile, IContainer
512         // outputFolder, boolean isSecondaryType) throws CoreException {
513         // String fileName = new String(classFile.fileName()); // the qualified type
514         // name "p1/p2/A"
515         // IPath filePath = new Path(fileName);
516         // IContainer container = outputFolder;
517         // if (filePath.segmentCount() > 1) {
518         // container = createFolder(filePath.removeLastSegments(1), outputFolder);
519         // filePath = new Path(filePath.lastSegment());
520         // }
521         //
522         // IFile file =
523         // container.getFile(filePath.addFileExtension(JavaBuilder.CLASS_EXTENSION));
524         // writeClassFileBytes(classFile.getBytes(), file, fileName,
525         // isSecondaryType);
526         // // answer the name of the class file as in Y or Y$M
527         // return filePath.lastSegment().toCharArray();
528         // }
529         //
530         // protected void writeClassFileBytes(byte[] bytes, IFile file, String
531         // qualifiedFileName, boolean isSecondaryType) throws
532         // CoreException {
533         // if (file.exists()) {
534         // // Deal with shared output folders... last one wins... no collision cases
535         // detected
536         // if (JavaBuilder.DEBUG)
537         // System.out.println("Writing changed class file " +
538         // file.getName());//$NON-NLS-1$
539         // file.setContents(new ByteArrayInputStream(bytes), true, false, null);
540         // if (!file.isDerived())
541         // file.setDerived(true);
542         // } else {
543         // // Default implementation just writes out the bytes for the new class
544         // file...
545         // if (JavaBuilder.DEBUG)
546         // System.out.println("Writing new class file " +
547         // file.getName());//$NON-NLS-1$
548         // file.create(new ByteArrayInputStream(bytes), IResource.FORCE, null);
549         // file.setDerived(true);
550         // }
551         // }
552 }