b89c2796373a1319e19114513779b200459dc38f
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / CompilationUnitProblemFinder.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;
12
13 import java.util.Locale;
14 import java.util.Map;
15
16 import net.sourceforge.phpdt.core.ICompilationUnit;
17 import net.sourceforge.phpdt.core.IJavaElement;
18 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
19 import net.sourceforge.phpdt.core.IJavaProject;
20 import net.sourceforge.phpdt.core.IPackageFragment;
21 import net.sourceforge.phpdt.core.IProblemRequestor;
22 import net.sourceforge.phpdt.core.JavaCore;
23 import net.sourceforge.phpdt.core.JavaModelException;
24 import net.sourceforge.phpdt.core.WorkingCopyOwner;
25 import net.sourceforge.phpdt.core.compiler.CharOperation;
26 import net.sourceforge.phpdt.core.compiler.IProblem;
27 import net.sourceforge.phpdt.internal.compiler.CompilationResult;
28 import net.sourceforge.phpdt.internal.compiler.Compiler;
29 import net.sourceforge.phpdt.internal.compiler.DefaultErrorHandlingPolicies;
30 import net.sourceforge.phpdt.internal.compiler.ICompilerRequestor;
31 import net.sourceforge.phpdt.internal.compiler.IErrorHandlingPolicy;
32 import net.sourceforge.phpdt.internal.compiler.IProblemFactory;
33 import net.sourceforge.phpdt.internal.compiler.env.INameEnvironment;
34 import net.sourceforge.phpdt.internal.compiler.env.ISourceType;
35 import net.sourceforge.phpdt.internal.compiler.lookup.PackageBinding;
36 import net.sourceforge.phpdt.internal.compiler.parser.SourceTypeConverter;
37 import net.sourceforge.phpdt.internal.compiler.parser.UnitParser;
38 import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation;
39 import net.sourceforge.phpdt.internal.compiler.problem.DefaultProblemFactory;
40 import net.sourceforge.phpdt.internal.core.util.Util;
41 import net.sourceforge.phpeclipse.internal.compiler.ast.CompilationUnitDeclaration;
42
43 import org.eclipse.core.runtime.IProgressMonitor;
44 import net.sourceforge.phpdt.internal.core.JavaModelManager;
45
46 /**
47  * Responsible for resolving types inside a compilation unit being reconciled,
48  * reporting the discovered problems to a given IProblemRequestor.
49  */
50 public class CompilationUnitProblemFinder extends Compiler {
51
52         /**
53          * Answer a new CompilationUnitVisitor using the given name environment and compiler options.
54          * The environment and options will be in effect for the lifetime of the compiler.
55          * When the compiler is run, compilation results are sent to the given requestor.
56          *
57          *  @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment
58          *      Environment used by the compiler in order to resolve type and package
59          *      names. The name environment implements the actual connection of the compiler
60          *      to the outside world (e.g. in batch mode the name environment is performing
61          *      pure file accesses, reuse previous build state or connection to repositories).
62          *      Note: the name environment is responsible for implementing the actual classpath
63          *            rules.
64          *
65          *  @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy
66          *      Configurable part for problem handling, allowing the compiler client to
67          *      specify the rules for handling problems (stop on first error or accumulate
68          *      them all) and at the same time perform some actions such as opening a dialog
69          *      in UI when compiling interactively.
70          *      @see org.eclipse.jdt.internal.compiler.api.problem.DefaultErrorHandlingPolicies
71          * 
72          *      @param settings The settings to use for the resolution.
73          *      
74          *  @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor
75          *      Component which will receive and persist all compilation results and is intended
76          *      to consume them as they are produced. Typically, in a batch compiler, it is 
77          *      responsible for writing out the actual .class files to the file system.
78          *      @see org.eclipse.jdt.internal.compiler.api.CompilationResult
79          *
80          *  @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory
81          *      Factory used inside the compiler to create problem descriptors. It allows the
82          *      compiler client to supply its own representation of compilation problems in
83          *      order to avoid object conversions. Note that the factory is not supposed
84          *      to accumulate the created problems, the compiler will gather them all and hand
85          *      them back as part of the compilation unit result.
86          */
87         protected CompilationUnitProblemFinder(
88                 INameEnvironment environment,
89                 IErrorHandlingPolicy policy,
90                 Map settings,
91                 ICompilerRequestor requestor,
92                 IProblemFactory problemFactory) {
93
94                 super(environment, policy, settings, requestor, problemFactory, true);
95         }
96
97         /**
98          * Add additional source types
99          */
100         public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding) {
101                 // ensure to jump back to toplevel type for first one (could be a member)
102 //              while (sourceTypes[0].getEnclosingType() != null)
103 //                      sourceTypes[0] = sourceTypes[0].getEnclosingType();
104
105                 CompilationResult result =
106                         new CompilationResult(sourceTypes[0].getFileName(), 1, 1, 10); //this.options.maxProblemsPerUnit);
107
108                 // need to hold onto this
109                 CompilationUnitDeclaration unit =
110                         SourceTypeConverter.buildCompilationUnit(
111                                 sourceTypes,//sourceTypes[0] is always toplevel here
112                                 true, // need field and methods
113                                 true, // need member types
114                                 true, // need field initialization
115                                 lookupEnvironment.problemReporter,
116                                 result);
117
118                 if (unit != null) {
119                         this.lookupEnvironment.buildTypeBindings(unit);
120                         this.lookupEnvironment.completeTypeBindings(unit, true);
121                 }
122         }
123
124         /*
125          *  Low-level API performing the actual compilation
126          */
127         protected static IErrorHandlingPolicy getHandlingPolicy() {
128                 return DefaultErrorHandlingPolicies.proceedWithAllProblems();
129         }
130
131         protected static INameEnvironment getNameEnvironment(ICompilationUnit sourceUnit)
132                 throws JavaModelException {
133                 return (SearchableEnvironment) ((JavaProject) sourceUnit.getJavaProject())
134                         .getSearchableNameEnvironment();
135         }
136
137         /*
138          * Answer the component to which will be handed back compilation results from the compiler
139          */
140         protected static ICompilerRequestor getRequestor() {
141                 return new ICompilerRequestor() {
142                         public void acceptResult(CompilationResult compilationResult) {
143                         }
144                 };
145         }
146
147         protected static IProblemFactory getProblemFactory(
148                 final char[] fileName, 
149                 final IProblemRequestor problemRequestor,
150                 final IProgressMonitor monitor) {
151
152                 return new DefaultProblemFactory(Locale.getDefault()) {
153                         public IProblem createProblem(
154                                 char[] originatingFileName,
155                                 int problemId,
156                                 String[] problemArguments,
157                                 String[] messageArguments,
158                                 int severity,
159                                 int startPosition,
160                                 int endPosition,
161                                 int lineNumber) {
162
163                                 if (monitor != null && monitor.isCanceled()){
164                                         throw new AbortCompilation(true, null); // silent abort
165                                 }
166                                 
167                                 IProblem problem =
168                                         super.createProblem(
169                                                 originatingFileName,
170                                                 problemId,
171                                                 problemArguments,
172                                                 messageArguments,
173                                                 severity,
174                                                 startPosition,
175                                                 endPosition,
176                                                 lineNumber);
177                                 // only report local problems
178                                 if (CharOperation.equals(originatingFileName, fileName)){
179                                         if (JavaModelManager.VERBOSE){
180                                                 System.out.println("PROBLEM FOUND while reconciling : "+problem.getMessage());//$NON-NLS-1$
181                                         }
182                                         problemRequestor.acceptProblem(problem);
183                                 }
184                                 if (monitor != null && monitor.isCanceled()){
185                                         throw new AbortCompilation(true, null); // silent abort
186                                 }
187
188                                 return problem;
189                         }
190                 };
191         }
192
193         public static CompilationUnitDeclaration process(
194                         CompilationUnitDeclaration unit,
195                         ICompilationUnit unitElement, 
196                         char[] contents,
197                         UnitParser parser,
198                         WorkingCopyOwner workingCopyOwner,
199                         IProblemRequestor problemRequestor,
200                         IProblemFactory problemFactory,
201                         boolean cleanupCU,
202                         IProgressMonitor monitor)
203                         throws JavaModelException {
204
205                         char[] fileName = unitElement.getElementName().toCharArray();
206                         
207                         JavaProject project = (JavaProject) unitElement.getJavaProject();
208                         CompilationUnitProblemFinder problemFinder =
209                                 new CompilationUnitProblemFinder(
210                                         project.newSearchableNameEnvironment(workingCopyOwner),
211                                         getHandlingPolicy(),
212                                         project.getOptions(true),
213                                         getRequestor(),
214                                         problemFactory);
215                         if (parser != null) {
216                                 problemFinder.parser = parser;
217                         }
218
219                         try {
220                                 
221                                 IPackageFragment packageFragment = (IPackageFragment)unitElement.getAncestor(IJavaElement.PACKAGE_FRAGMENT);
222                                 char[][] expectedPackageName = null;
223                                 if (packageFragment != null){
224                                         expectedPackageName = CharOperation.splitOn('.', packageFragment.getElementName().toCharArray());
225                                 }
226                                 if (unit == null) {
227                                         unit = problemFinder.resolve(
228                                                 new BasicCompilationUnit(
229                                                         contents,
230                                                         expectedPackageName,
231                                                         new String(fileName),
232                                                         unitElement),
233                                                 true, // verify methods
234                                                 true); //, // analyze code
235                                                 //true); // generate code
236                                 } else {
237                                         problemFinder.resolve(
238                                                 unit,
239                                                 null, // no need for source
240                                                 true, // verify methods
241                                                 true); //, // analyze code
242                                         //      true); // generate code
243                                 }
244                                 reportProblems(unit, problemRequestor, monitor);
245                                 return unit;
246                         } catch(RuntimeException e) { 
247                                 // avoid breaking other tools due to internal compiler failure (40334)
248                                 Util.log(e, "Exception occurred during problem detection: "); //$NON-NLS-1$ 
249                                 throw new JavaModelException(e, IJavaModelStatusConstants.COMPILER_FAILURE);
250                         } finally {
251                                 if (cleanupCU && unit != null) {
252                                         unit.cleanUp();
253                                 }
254                                 problemFinder.lookupEnvironment.reset();                        
255                         }
256                 }
257         public static CompilationUnitDeclaration process(
258                         ICompilationUnit unitElement, 
259                         char[] contents,
260                         WorkingCopyOwner workingCopyOwner,
261                         IProblemRequestor problemRequestor,
262                         boolean cleanupCU,
263                         IProgressMonitor monitor)
264                         throws JavaModelException {
265                                 
266                         return process(null/*no CompilationUnitDeclaration*/, unitElement, contents, null/*use default Parser*/, workingCopyOwner, problemRequestor, new DefaultProblemFactory(), cleanupCU, monitor);
267                 }
268         public static CompilationUnitDeclaration process(
269                 ICompilationUnit unitElement, 
270                 IProblemRequestor problemRequestor,
271                 IProgressMonitor monitor)
272                 throws JavaModelException {
273
274                 char[] fileName = unitElement.getElementName().toCharArray();
275                 
276                 IJavaProject project = unitElement.getJavaProject();
277                 CompilationUnitProblemFinder problemFinder =
278                         new CompilationUnitProblemFinder(
279                                 getNameEnvironment(unitElement),
280                                 getHandlingPolicy(),
281                                 project.getOptions(true),
282                                 getRequestor(),
283                                 getProblemFactory(fileName, problemRequestor, monitor));
284
285                 CompilationUnitDeclaration unit = null;
286                 try {
287                         String encoding = project.getOption(JavaCore.CORE_ENCODING, true);
288                         
289                         IPackageFragment packageFragment = (IPackageFragment)unitElement.getAncestor(IJavaElement.PACKAGE_FRAGMENT);
290                         char[][] expectedPackageName = null;
291                         if (packageFragment != null){
292                                 expectedPackageName = CharOperation.splitOn('.', packageFragment.getElementName().toCharArray());
293                         }
294                         unit = problemFinder.resolve(
295                                         new BasicCompilationUnit(
296                                                 unitElement.getSource().toCharArray(),
297                                                 expectedPackageName,
298                                                 new String(fileName),
299                                                 encoding),
300                                         true, // verify methods
301                                         true); // analyze code
302 //                                      true); // generate code
303                         return unit;
304                 } finally {
305                         if (unit != null) {
306                                 unit.cleanUp();
307                         }
308                         problemFinder.lookupEnvironment.reset();                        
309                 }
310         }
311         private static void reportProblems(CompilationUnitDeclaration unit, IProblemRequestor problemRequestor, IProgressMonitor monitor) {
312                 CompilationResult unitResult = unit.compilationResult;
313                 IProblem[] problems = unitResult.getAllProblems();
314                 for (int i = 0, problemLength = problems == null ? 0 : problems.length; i < problemLength; i++) {
315                         if (JavaModelManager.VERBOSE){
316                                 System.out.println("PROBLEM FOUND while reconciling : "+problems[i].getMessage());//$NON-NLS-1$
317                         }
318                         if (monitor != null && monitor.isCanceled()) break;
319                         problemRequestor.acceptProblem(problems[i]);                            
320                 }
321         }
322 }       
323