| 1 | /******************************************************************************* |
|---|---|
| 2 | * Copyright (c) 2000, 2022 IBM Corporation and others. |
| 3 | * |
| 4 | * This program and the accompanying materials |
| 5 | * are made available under the terms of the Eclipse Public License 2.0 |
| 6 | * which accompanies this distribution, and is available at |
| 7 | * https://www.eclipse.org/legal/epl-2.0/ |
| 8 | * |
| 9 | * SPDX-License-Identifier: EPL-2.0 |
| 10 | * |
| 11 | * Contributors: |
| 12 | * IBM Corporation - initial API and implementation |
| 13 | * Stephan Herrmann - Contribution for |
| 14 | * bug 363858 - [dom] early throwing of AbortCompilation causes NPE in CompilationUnitResolver |
| 15 | * Bug 466279 - [hovering] IAE on hover when annotation-based null analysis is enabled |
| 16 | *******************************************************************************/ |
| 17 | package org.eclipse.jdt.core.dom; |
| 18 | |
| 19 | import java.io.File; |
| 20 | import java.io.IOException; |
| 21 | import java.util.ArrayList; |
| 22 | import java.util.HashMap; |
| 23 | import java.util.Iterator; |
| 24 | import java.util.List; |
| 25 | import java.util.Map; |
| 26 | |
| 27 | import org.eclipse.core.resources.IProject; |
| 28 | import org.eclipse.core.runtime.IPath; |
| 29 | import org.eclipse.core.runtime.IProgressMonitor; |
| 30 | import org.eclipse.core.runtime.OperationCanceledException; |
| 31 | import org.eclipse.core.runtime.SubMonitor; |
| 32 | import org.eclipse.jdt.core.IClasspathEntry; |
| 33 | import org.eclipse.jdt.core.ICompilationUnit; |
| 34 | import org.eclipse.jdt.core.IJavaElement; |
| 35 | import org.eclipse.jdt.core.IJavaProject; |
| 36 | import org.eclipse.jdt.core.JavaCore; |
| 37 | import org.eclipse.jdt.core.JavaModelException; |
| 38 | import org.eclipse.jdt.core.WorkingCopyOwner; |
| 39 | import org.eclipse.jdt.core.compiler.CategorizedProblem; |
| 40 | import org.eclipse.jdt.core.compiler.CharOperation; |
| 41 | import org.eclipse.jdt.internal.compiler.CompilationResult; |
| 42 | import org.eclipse.jdt.internal.compiler.Compiler; |
| 43 | import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; |
| 44 | import org.eclipse.jdt.internal.compiler.ICompilerRequestor; |
| 45 | import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; |
| 46 | import org.eclipse.jdt.internal.compiler.IProblemFactory; |
| 47 | import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; |
| 48 | import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; |
| 49 | import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; |
| 50 | import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; |
| 51 | import org.eclipse.jdt.internal.compiler.env.AccessRestriction; |
| 52 | import org.eclipse.jdt.internal.compiler.env.INameEnvironment; |
| 53 | import org.eclipse.jdt.internal.compiler.env.ISourceType; |
| 54 | import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; |
| 55 | import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; |
| 56 | import org.eclipse.jdt.internal.compiler.lookup.Binding; |
| 57 | import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; |
| 58 | import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; |
| 59 | import org.eclipse.jdt.internal.compiler.parser.Parser; |
| 60 | import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; |
| 61 | import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; |
| 62 | import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; |
| 63 | import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; |
| 64 | import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt; |
| 65 | import org.eclipse.jdt.internal.compiler.util.Messages; |
| 66 | import org.eclipse.jdt.internal.compiler.util.Util; |
| 67 | import org.eclipse.jdt.internal.core.BinaryMember; |
| 68 | import org.eclipse.jdt.internal.core.BinaryModule; |
| 69 | import org.eclipse.jdt.internal.core.CancelableNameEnvironment; |
| 70 | import org.eclipse.jdt.internal.core.CancelableProblemFactory; |
| 71 | import org.eclipse.jdt.internal.core.ClasspathEntry; |
| 72 | import org.eclipse.jdt.internal.core.INameEnvironmentWithProgress; |
| 73 | import org.eclipse.jdt.internal.core.JavaProject; |
| 74 | import org.eclipse.jdt.internal.core.LocalVariable; |
| 75 | import org.eclipse.jdt.internal.core.NameLookup; |
| 76 | import org.eclipse.jdt.internal.core.SourceRefElement; |
| 77 | import org.eclipse.jdt.internal.core.SourceTypeElementInfo; |
| 78 | import org.eclipse.jdt.internal.core.util.BindingKeyResolver; |
| 79 | import org.eclipse.jdt.internal.core.util.CommentRecorderParser; |
| 80 | import org.eclipse.jdt.internal.core.util.DOMFinder; |
| 81 | |
| 82 | @SuppressWarnings({ "rawtypes", "unchecked" }) |
| 83 | class CompilationUnitResolver extends Compiler { |
| 84 | public static final int RESOLVE_BINDING = 0x1; |
| 85 | public static final int PARTIAL = 0x2; |
| 86 | public static final int STATEMENT_RECOVERY = 0x4; |
| 87 | public static final int IGNORE_METHOD_BODIES = 0x8; |
| 88 | public static final int BINDING_RECOVERY = 0x10; |
| 89 | public static final int INCLUDE_RUNNING_VM_BOOTCLASSPATH = 0x20; |
| 90 | |
| 91 | /* A list of int */ |
| 92 | static class IntArrayList { |
| 93 | public int[] list = new int[5]; |
| 94 | public int length = 0; |
| 95 | public void add(int i) { |
| 96 | if (this.list.length == this.length) { |
| 97 | System.arraycopy(this.list, 0, this.list = new int[this.length*2], 0, this.length); |
| 98 | } |
| 99 | this.list[this.length++] = i; |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | /* |
| 104 | * The sources that were requested. |
| 105 | * Map from file name (char[]) to org.eclipse.jdt.internal.compiler.env.ICompilationUnit. |
| 106 | */ |
| 107 | HashtableOfObject requestedSources; |
| 108 | |
| 109 | /* |
| 110 | * The binding keys that were requested. |
| 111 | * Map from file name (char[]) to BindingKey (or ArrayList if multiple keys in the same file). |
| 112 | */ |
| 113 | HashtableOfObject requestedKeys; |
| 114 | |
| 115 | DefaultBindingResolver.BindingTables bindingTables; |
| 116 | |
| 117 | boolean hasCompilationAborted; |
| 118 | CategorizedProblem abortProblem; |
| 119 | |
| 120 | private IProgressMonitor monitor; |
| 121 | |
| 122 | /** |
| 123 | * Set to <code>true</code> if the receiver was initialized using a java project name environment |
| 124 | */ |
| 125 | boolean fromJavaProject; |
| 126 | |
| 127 | /** |
| 128 | * Answer a new CompilationUnitVisitor using the given name environment and compiler options. |
| 129 | * The environment and options will be in effect for the lifetime of the compiler. |
| 130 | * When the compiler is run, compilation results are sent to the given requestor. |
| 131 | * |
| 132 | * @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment |
| 133 | * Environment used by the compiler in order to resolve type and package |
| 134 | * names. The name environment implements the actual connection of the compiler |
| 135 | * to the outside world (for example, in batch mode the name environment is performing |
| 136 | * pure file accesses, reuse previous build state or connection to repositories). |
| 137 | * Note: the name environment is responsible for implementing the actual classpath |
| 138 | * rules. |
| 139 | * |
| 140 | * @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy |
| 141 | * Configurable part for problem handling, allowing the compiler client to |
| 142 | * specify the rules for handling problems (stop on first error or accumulate |
| 143 | * them all) and at the same time perform some actions such as opening a dialog |
| 144 | * in UI when compiling interactively. |
| 145 | * @see org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies |
| 146 | * |
| 147 | * @param compilerOptions The compiler options to use for the resolution. |
| 148 | * |
| 149 | * @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor |
| 150 | * Component which will receive and persist all compilation results and is intended |
| 151 | * to consume them as they are produced. Typically, in a batch compiler, it is |
| 152 | * responsible for writing out the actual .class files to the file system. |
| 153 | * @see org.eclipse.jdt.internal.compiler.CompilationResult |
| 154 | * |
| 155 | * @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory |
| 156 | * Factory used inside the compiler to create problem descriptors. It allows the |
| 157 | * compiler client to supply its own representation of compilation problems in |
| 158 | * order to avoid object conversions. Note that the factory is not supposed |
| 159 | * to accumulate the created problems, the compiler will gather them all and hand |
| 160 | * them back as part of the compilation unit result. |
| 161 | */ |
| 162 | public CompilationUnitResolver( |
| 163 | INameEnvironment environment, |
| 164 | IErrorHandlingPolicy policy, |
| 165 | CompilerOptions compilerOptions, |
| 166 | ICompilerRequestor requestor, |
| 167 | IProblemFactory problemFactory, |
| 168 | IProgressMonitor monitor, |
| 169 | boolean fromJavaProject) { |
| 170 | |
| 171 | super(environment, policy, compilerOptions, requestor, problemFactory); |
| 172 | this.hasCompilationAborted = false; |
| 173 | this.monitor =monitor; |
| 174 | this.fromJavaProject = fromJavaProject; |
| 175 | } |
| 176 | |
| 177 | /* |
| 178 | * Add additional source types |
| 179 | */ |
| 180 | @Override |
| 181 | public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding, AccessRestriction accessRestriction) { |
| 182 | // Need to reparse the entire source of the compilation unit so as to get source positions |
| 183 | // (case of processing a source that was not known by beginToCompile (e.g. when asking to createBinding)) |
| 184 | SourceTypeElementInfo sourceType = (SourceTypeElementInfo) sourceTypes[0]; |
| 185 | accept((org.eclipse.jdt.internal.compiler.env.ICompilationUnit) sourceType.getHandle().getCompilationUnit(), accessRestriction); |
| 186 | } |
| 187 | |
| 188 | @Override |
| 189 | public synchronized void accept(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, AccessRestriction accessRestriction) { |
| 190 | super.accept(sourceUnit, accessRestriction); |
| 191 | } |
| 192 | |
| 193 | /** |
| 194 | * Add the initial set of compilation units into the loop |
| 195 | * -> build compilation unit declarations, their bindings and record their results. |
| 196 | */ |
| 197 | protected void beginToCompile(org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] sourceUnits, String[] bindingKeys) { |
| 198 | int sourceLength = sourceUnits.length; |
| 199 | int keyLength = bindingKeys.length; |
| 200 | int maxUnits = sourceLength + keyLength; |
| 201 | this.totalUnits = 0; |
| 202 | this.unitsToProcess = new CompilationUnitDeclaration[maxUnits]; |
| 203 | int index = 0; |
| 204 | |
| 205 | // walks the source units |
| 206 | this.requestedSources = new HashtableOfObject(); |
| 207 | for (int i = 0; i < sourceLength; i++) { |
| 208 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = sourceUnits[i]; |
| 209 | CompilationUnitDeclaration parsedUnit; |
| 210 | CompilationResult unitResult = |
| 211 | new CompilationResult(sourceUnit, index++, maxUnits, this.options.maxProblemsPerUnit); |
| 212 | try { |
| 213 | if (this.options.verbose) { |
| 214 | this.out.println( |
| 215 | Messages.bind(Messages.compilation_request, |
| 216 | new String[] { |
| 217 | String.valueOf(index++ + 1), |
| 218 | String.valueOf(maxUnits), |
| 219 | new String(sourceUnit.getFileName()) |
| 220 | })); |
| 221 | } |
| 222 | if (this.parser instanceof CommentRecorderParser) { |
| 223 | ((CommentRecorderParser) this.parser).resetComments(); |
| 224 | } |
| 225 | // diet parsing for large collection of units |
| 226 | if (this.totalUnits < this.parseThreshold) { |
| 227 | parsedUnit = this.parser.parse(sourceUnit, unitResult); |
| 228 | } else { |
| 229 | parsedUnit = this.parser.dietParse(sourceUnit, unitResult); |
| 230 | } |
| 231 | // initial type binding creation |
| 232 | this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/); |
| 233 | addCompilationUnit(sourceUnit, parsedUnit); |
| 234 | this.requestedSources.put(unitResult.getFileName(), sourceUnit); |
| 235 | worked(1); |
| 236 | } finally { |
| 237 | sourceUnits[i] = null; // no longer hold onto the unit |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | // walk the binding keys |
| 242 | this.requestedKeys = new HashtableOfObject(); |
| 243 | for (int i = 0; i < keyLength; i++) { |
| 244 | BindingKeyResolver resolver = new BindingKeyResolver(bindingKeys[i], this, this.lookupEnvironment); |
| 245 | resolver.parse(true/*pause after fully qualified name*/); |
| 246 | // If it doesn't have a type name, then it is either an array type, package or base type, which will definitely not have a compilation unit. |
| 247 | // Skipping it will speed up performance because the call will open jars. (theodora) |
| 248 | CompilationUnitDeclaration parsedUnit = resolver.hasTypeName() ? resolver.getCompilationUnitDeclaration() : null; |
| 249 | if (parsedUnit != null) { |
| 250 | char[] fileName = parsedUnit.compilationResult.getFileName(); |
| 251 | Object existing = this.requestedKeys.get(fileName); |
| 252 | if (existing == null) |
| 253 | this.requestedKeys.put(fileName, resolver); |
| 254 | else if (existing instanceof ArrayList) |
| 255 | ((ArrayList) existing).add(resolver); |
| 256 | else { |
| 257 | ArrayList list = new ArrayList(); |
| 258 | list.add(existing); |
| 259 | list.add(resolver); |
| 260 | this.requestedKeys.put(fileName, list); |
| 261 | } |
| 262 | |
| 263 | } else { |
| 264 | char[] key = resolver.hasTypeName() |
| 265 | ? resolver.getKey().toCharArray() // binary binding |
| 266 | : resolver.hasModuleName() |
| 267 | ? resolver.moduleName() |
| 268 | : CharOperation.concatWith(resolver.compoundName(), '.'); // package binding or base type binding |
| 269 | this.requestedKeys.put(key, resolver); |
| 270 | } |
| 271 | worked(1); |
| 272 | } |
| 273 | |
| 274 | // binding resolution |
| 275 | this.lookupEnvironment.completeTypeBindings(); |
| 276 | } |
| 277 | |
| 278 | IBinding createBinding(String key) { |
| 279 | if (this.bindingTables == null) |
| 280 | throw new RuntimeException("Cannot be called outside ASTParser#createASTs(...)"); //$NON-NLS-1$ |
| 281 | BindingKeyResolver keyResolver = new BindingKeyResolver(key, this, this.lookupEnvironment); |
| 282 | Binding compilerBinding = keyResolver.getCompilerBinding(); |
| 283 | if (compilerBinding == null) return null; |
| 284 | DefaultBindingResolver resolver = new DefaultBindingResolver(this.lookupEnvironment, null/*no owner*/, this.bindingTables, false, this.fromJavaProject); |
| 285 | return resolver.getBinding(compilerBinding); |
| 286 | } |
| 287 | |
| 288 | public static CompilationUnit convert( |
| 289 | CompilationUnitDeclaration compilationUnitDeclaration, |
| 290 | char[] source, |
| 291 | int apiLevel, |
| 292 | Map options, |
| 293 | boolean needToResolveBindings, |
| 294 | WorkingCopyOwner owner, |
| 295 | DefaultBindingResolver.BindingTables bindingTables, |
| 296 | int flags, |
| 297 | IProgressMonitor monitor, |
| 298 | boolean fromJavaProject) { |
| 299 | return convert(compilationUnitDeclaration, source,apiLevel, options, needToResolveBindings, owner, bindingTables, |
| 300 | flags, monitor, fromJavaProject, null); |
| 301 | } |
| 302 | public static CompilationUnit convert( |
| 303 | CompilationUnitDeclaration compilationUnitDeclaration, |
| 304 | char[] source, |
| 305 | int apiLevel, |
| 306 | Map options, |
| 307 | boolean needToResolveBindings, |
| 308 | WorkingCopyOwner owner, |
| 309 | DefaultBindingResolver.BindingTables bindingTables, |
| 310 | int flags, |
| 311 | IProgressMonitor monitor, |
| 312 | boolean fromJavaProject, |
| 313 | IJavaProject project) { |
| 314 | BindingResolver resolver = null; |
| 315 | AST ast = AST.newAST(apiLevel, JavaCore.ENABLED.equals(options.get(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES))); |
| 316 | String sourceModeSetting = (String) options.get(JavaCore.COMPILER_SOURCE); |
| 317 | long sourceLevel = CompilerOptions.versionToJdkLevel(sourceModeSetting); |
| 318 | if (sourceLevel == 0) { |
| 319 | // unknown sourceModeSetting |
| 320 | sourceLevel = ClassFileConstants.JDK1_3; |
| 321 | } |
| 322 | ast.scanner.sourceLevel = sourceLevel; |
| 323 | String compliance = (String) options.get(JavaCore.COMPILER_COMPLIANCE); |
| 324 | long complianceLevel = CompilerOptions.versionToJdkLevel(compliance); |
| 325 | if (complianceLevel == 0) { |
| 326 | // unknown sourceModeSetting |
| 327 | complianceLevel = sourceLevel; |
| 328 | } |
| 329 | ast.scanner.complianceLevel = complianceLevel; |
| 330 | ast.setDefaultNodeFlag(ASTNode.ORIGINAL); |
| 331 | CompilationUnit compilationUnit = null; |
| 332 | ASTConverter converter = new ASTConverter(options, needToResolveBindings, monitor); |
| 333 | if (needToResolveBindings) { |
| 334 | resolver = new DefaultBindingResolver(compilationUnitDeclaration.scope, owner, bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0, fromJavaProject); |
| 335 | ast.setFlag(flags | AST.RESOLVED_BINDINGS); |
| 336 | } else { |
| 337 | resolver = new BindingResolver(); |
| 338 | ast.setFlag(flags); |
| 339 | } |
| 340 | ast.setBindingResolver(resolver); |
| 341 | converter.setAST(ast); |
| 342 | converter.docParser.setProjectPath(CompilationUnitResolver.getProjectPath(project)); |
| 343 | converter.docParser.setProjectSrcClasspath(CompilationUnitResolver.getSourceClassPaths(project)); |
| 344 | compilationUnit = converter.convert(compilationUnitDeclaration, source); |
| 345 | compilationUnit.setLineEndTable(compilationUnitDeclaration.compilationResult.getLineSeparatorPositions()); |
| 346 | ast.setDefaultNodeFlag(0); |
| 347 | ast.setOriginalModificationCount(ast.modificationCount()); |
| 348 | return compilationUnit; |
| 349 | } |
| 350 | |
| 351 | /** |
| 352 | * @return absolute path in local file system, may return {@code null} |
| 353 | */ |
| 354 | private static String getProjectPath(IJavaProject project) { |
| 355 | if(project == null) { |
| 356 | return null; |
| 357 | } |
| 358 | IProject rp = project.getProject(); |
| 359 | if (rp == null) { |
| 360 | return null; |
| 361 | } |
| 362 | IPath location = rp.getLocation(); |
| 363 | if(location == null) { |
| 364 | return null; |
| 365 | } |
| 366 | return location.toOSString(); |
| 367 | } |
| 368 | private static ArrayList<String> getSourceClassPaths(IJavaProject project) { |
| 369 | ArrayList<String> srcClassPath = new ArrayList<>(); |
| 370 | if(project == null) |
| 371 | return srcClassPath; |
| 372 | if(project.getProject() == null) |
| 373 | return srcClassPath; |
| 374 | IClasspathEntry[] resolvedClasspath = null; |
| 375 | try { |
| 376 | resolvedClasspath = project.getResolvedClasspath(true); |
| 377 | } catch (JavaModelException e) { |
| 378 | //do nothing |
| 379 | } |
| 380 | |
| 381 | for (IClasspathEntry entry : resolvedClasspath) { |
| 382 | if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { |
| 383 | if(entry instanceof ClasspathEntry) { |
| 384 | IPath path = ((ClasspathEntry)entry).getPath(); |
| 385 | srcClassPath.add(path.removeFirstSegments(1).toString()); |
| 386 | } |
| 387 | } |
| 388 | } |
| 389 | return srcClassPath; |
| 390 | } |
| 391 | |
| 392 | |
| 393 | protected static CompilerOptions getCompilerOptions(Map options, boolean statementsRecovery) { |
| 394 | CompilerOptions compilerOptions = new CompilerOptions(options); |
| 395 | compilerOptions.performMethodsFullRecovery = statementsRecovery; |
| 396 | compilerOptions.performStatementsRecovery = statementsRecovery; |
| 397 | compilerOptions.parseLiteralExpressionsAsConstants = false; |
| 398 | compilerOptions.storeAnnotations = true /*store annotations in the bindings*/; |
| 399 | compilerOptions.ignoreSourceFolderWarningOption = true; |
| 400 | return compilerOptions; |
| 401 | } |
| 402 | /* |
| 403 | * Low-level API performing the actual compilation |
| 404 | */ |
| 405 | protected static IErrorHandlingPolicy getHandlingPolicy() { |
| 406 | |
| 407 | // passes the initial set of files to the batch oracle (to avoid finding more than once the same units when case insensitive match) |
| 408 | return new IErrorHandlingPolicy() { |
| 409 | @Override |
| 410 | public boolean stopOnFirstError() { |
| 411 | return false; |
| 412 | } |
| 413 | @Override |
| 414 | public boolean proceedOnErrors() { |
| 415 | return false; // stop if there are some errors |
| 416 | } |
| 417 | @Override |
| 418 | public boolean ignoreAllErrors() { |
| 419 | return false; |
| 420 | } |
| 421 | }; |
| 422 | } |
| 423 | |
| 424 | /* |
| 425 | * Answer the component to which will be handed back compilation results from the compiler |
| 426 | */ |
| 427 | protected static ICompilerRequestor getRequestor() { |
| 428 | return new ICompilerRequestor() { |
| 429 | @Override |
| 430 | public void acceptResult(CompilationResult compilationResult) { |
| 431 | // do nothing |
| 432 | } |
| 433 | }; |
| 434 | } |
| 435 | |
| 436 | @Override |
| 437 | public void initializeParser() { |
| 438 | this.parser = new CommentRecorderParser(this.problemReporter, false); |
| 439 | } |
| 440 | @Override |
| 441 | public void process(CompilationUnitDeclaration unit, int i) { |
| 442 | // don't resolve a second time the same unit (this would create the same binding twice) |
| 443 | char[] fileName = unit.compilationResult.getFileName(); |
| 444 | if (this.requestedKeys.get(fileName) == null && this.requestedSources.get(fileName) == null) |
| 445 | super.process(unit, i); |
| 446 | } |
| 447 | /* |
| 448 | * Compiler crash recovery in case of unexpected runtime exceptions |
| 449 | */ |
| 450 | @Override |
| 451 | protected void handleInternalException( |
| 452 | Throwable internalException, |
| 453 | CompilationUnitDeclaration unit, |
| 454 | CompilationResult result) { |
| 455 | super.handleInternalException(internalException, unit, result); |
| 456 | if (unit != null) { |
| 457 | removeUnresolvedBindings(unit); |
| 458 | } |
| 459 | } |
| 460 | |
| 461 | /* |
| 462 | * Compiler recovery in case of internal AbortCompilation event |
| 463 | */ |
| 464 | @Override |
| 465 | protected void handleInternalException( |
| 466 | AbortCompilation abortException, |
| 467 | CompilationUnitDeclaration unit) { |
| 468 | super.handleInternalException(abortException, unit); |
| 469 | if (unit != null) { |
| 470 | removeUnresolvedBindings(unit); |
| 471 | } |
| 472 | this.hasCompilationAborted = true; |
| 473 | this.abortProblem = abortException.problem; |
| 474 | } |
| 475 | |
| 476 | public static void parse(ICompilationUnit[] compilationUnits, ASTRequestor astRequestor, int apiLevel, Map options, int flags, IProgressMonitor monitor) { |
| 477 | CompilerOptions compilerOptions = new CompilerOptions(options); |
| 478 | compilerOptions.ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; |
| 479 | Parser parser = new CommentRecorderParser( |
| 480 | new ProblemReporter( |
| 481 | DefaultErrorHandlingPolicies.proceedWithAllProblems(), |
| 482 | compilerOptions, |
| 483 | new DefaultProblemFactory()), |
| 484 | false); |
| 485 | int unitLength = compilationUnits.length; |
| 486 | SubMonitor subMonitor = SubMonitor.convert(monitor); |
| 487 | for (int i = 0; i < unitLength; i++) { |
| 488 | subMonitor.setWorkRemaining(unitLength - i); |
| 489 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) compilationUnits[i]; |
| 490 | CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, |
| 491 | compilerOptions.maxProblemsPerUnit); |
| 492 | CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult); |
| 493 | |
| 494 | if (compilationUnitDeclaration.ignoreMethodBodies) { |
| 495 | compilationUnitDeclaration.ignoreFurtherInvestigation = true; |
| 496 | // if initial diet parse did not work, no need to dig into method bodies. |
| 497 | continue; |
| 498 | } |
| 499 | |
| 500 | //fill the methods bodies in order for the code to be generated |
| 501 | //real parse of the method.... |
| 502 | org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types; |
| 503 | if (types != null) { |
| 504 | for (int j = 0, typeLength = types.length; j < typeLength; j++) { |
| 505 | types[j].parseMethods(parser, compilationUnitDeclaration); |
| 506 | } |
| 507 | } |
| 508 | |
| 509 | // convert AST |
| 510 | CompilationUnit node = convert(compilationUnitDeclaration, parser.scanner.getSource(), apiLevel, options, |
| 511 | false/* don't resolve binding */, null/* no owner needed */, null/* no binding table needed */, |
| 512 | flags /* flags */, subMonitor.split(1), true); |
| 513 | node.setTypeRoot(compilationUnits[i]); |
| 514 | |
| 515 | // accept AST |
| 516 | astRequestor.acceptAST(compilationUnits[i], node); |
| 517 | } |
| 518 | } |
| 519 | public static void parse( |
| 520 | String[] sourceUnits, |
| 521 | String[] encodings, |
| 522 | FileASTRequestor astRequestor, |
| 523 | int apiLevel, |
| 524 | Map options, |
| 525 | int flags, |
| 526 | IProgressMonitor monitor) { |
| 527 | CompilerOptions compilerOptions = new CompilerOptions(options); |
| 528 | compilerOptions.ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; |
| 529 | Parser parser = new CommentRecorderParser( |
| 530 | new ProblemReporter( |
| 531 | DefaultErrorHandlingPolicies.proceedWithAllProblems(), |
| 532 | compilerOptions, |
| 533 | new DefaultProblemFactory()), |
| 534 | false); |
| 535 | int unitLength = sourceUnits.length; |
| 536 | SubMonitor subMonitor = SubMonitor.convert(monitor, unitLength); |
| 537 | for (int i = 0; i < unitLength; i++) { |
| 538 | SubMonitor iterationMonitor = subMonitor.split(1); |
| 539 | char[] contents = null; |
| 540 | String encoding = encodings != null ? encodings[i] : null; |
| 541 | try { |
| 542 | contents = Util.getFileCharContent(new File(sourceUnits[i]), encoding); |
| 543 | } catch(IOException e) { |
| 544 | // go to the next unit |
| 545 | continue; |
| 546 | } |
| 547 | if (contents == null) { |
| 548 | // go to the next unit |
| 549 | continue; |
| 550 | } |
| 551 | org.eclipse.jdt.internal.compiler.batch.CompilationUnit compilationUnit = new org.eclipse.jdt.internal.compiler.batch.CompilationUnit(contents, sourceUnits[i], encoding); |
| 552 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = compilationUnit; |
| 553 | CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit); |
| 554 | CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult); |
| 555 | |
| 556 | if (compilationUnitDeclaration.ignoreMethodBodies) { |
| 557 | compilationUnitDeclaration.ignoreFurtherInvestigation = true; |
| 558 | // if initial diet parse did not work, no need to dig into method bodies. |
| 559 | continue; |
| 560 | } |
| 561 | |
| 562 | //fill the methods bodies in order for the code to be generated |
| 563 | //real parse of the method.... |
| 564 | org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types; |
| 565 | if (types != null) { |
| 566 | for (int j = 0, typeLength = types.length; j < typeLength; j++) { |
| 567 | types[j].parseMethods(parser, compilationUnitDeclaration); |
| 568 | } |
| 569 | } |
| 570 | |
| 571 | // convert AST |
| 572 | CompilationUnit node = convert(compilationUnitDeclaration, parser.scanner.getSource(), apiLevel, options, |
| 573 | false/* don't resolve binding */, null/* no owner needed */, null/* no binding table needed */, |
| 574 | flags /* flags */, iterationMonitor, true); |
| 575 | node.setTypeRoot(null); |
| 576 | |
| 577 | // accept AST |
| 578 | astRequestor.acceptAST(sourceUnits[i], node); |
| 579 | } |
| 580 | } |
| 581 | |
| 582 | public static CompilationUnitDeclaration parse( |
| 583 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, |
| 584 | NodeSearcher nodeSearcher, |
| 585 | Map settings, |
| 586 | int flags) { |
| 587 | return parse(sourceUnit, nodeSearcher, settings, flags, null); |
| 588 | } |
| 589 | public static CompilationUnitDeclaration parse( |
| 590 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, |
| 591 | NodeSearcher nodeSearcher, |
| 592 | Map settings, |
| 593 | int flags, IJavaProject project) { |
| 594 | if (sourceUnit == null) { |
| 595 | throw new IllegalStateException(); |
| 596 | } |
| 597 | CompilerOptions compilerOptions = new CompilerOptions(settings); |
| 598 | boolean statementsRecovery = (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0; |
| 599 | compilerOptions.performMethodsFullRecovery = statementsRecovery; |
| 600 | compilerOptions.performStatementsRecovery = statementsRecovery; |
| 601 | compilerOptions.ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; |
| 602 | Parser parser = new CommentRecorderParser( |
| 603 | new ProblemReporter( |
| 604 | DefaultErrorHandlingPolicies.proceedWithAllProblems(), |
| 605 | compilerOptions, |
| 606 | new DefaultProblemFactory()), |
| 607 | false); |
| 608 | if (project != null) { |
| 609 | parser.javadocParser.setProjectPath(getProjectPath(project)); |
| 610 | parser.javadocParser.setProjectSrcClasspath(getSourceClassPaths(project)); |
| 611 | |
| 612 | } |
| 613 | CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit); |
| 614 | CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult); |
| 615 | |
| 616 | if (compilationUnitDeclaration.ignoreMethodBodies) { |
| 617 | compilationUnitDeclaration.ignoreFurtherInvestigation = true; |
| 618 | // if initial diet parse did not work, no need to dig into method bodies. |
| 619 | return compilationUnitDeclaration; |
| 620 | } |
| 621 | |
| 622 | if (nodeSearcher != null) { |
| 623 | char[] source = parser.scanner.getSource(); |
| 624 | int searchPosition = nodeSearcher.position; |
| 625 | if (searchPosition < 0 || searchPosition > source.length) { |
| 626 | // the position is out of range. There is no need to search for a node. |
| 627 | return compilationUnitDeclaration; |
| 628 | } |
| 629 | |
| 630 | compilationUnitDeclaration.traverse(nodeSearcher, compilationUnitDeclaration.scope); |
| 631 | |
| 632 | org.eclipse.jdt.internal.compiler.ast.ASTNode node = nodeSearcher.found; |
| 633 | if (node == null) { |
| 634 | return compilationUnitDeclaration; |
| 635 | } |
| 636 | |
| 637 | org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enclosingTypeDeclaration = nodeSearcher.enclosingType; |
| 638 | |
| 639 | if (node instanceof AbstractMethodDeclaration) { |
| 640 | ((AbstractMethodDeclaration)node).parseStatements(parser, compilationUnitDeclaration); |
| 641 | } else if (enclosingTypeDeclaration != null) { |
| 642 | if (node instanceof org.eclipse.jdt.internal.compiler.ast.Initializer) { |
| 643 | ((org.eclipse.jdt.internal.compiler.ast.Initializer) node).parseStatements(parser, enclosingTypeDeclaration, compilationUnitDeclaration); |
| 644 | } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) { |
| 645 | ((org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)node).parseMethods(parser, compilationUnitDeclaration); |
| 646 | } |
| 647 | } |
| 648 | } else { |
| 649 | //fill the methods bodies in order for the code to be generated |
| 650 | //real parse of the method.... |
| 651 | org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types; |
| 652 | if (types != null) { |
| 653 | for (int j = 0, typeLength = types.length; j < typeLength; j++) { |
| 654 | types[j].parseMethods(parser, compilationUnitDeclaration); |
| 655 | } |
| 656 | } |
| 657 | } |
| 658 | return compilationUnitDeclaration; |
| 659 | } |
| 660 | |
| 661 | public static void resolve( |
| 662 | ICompilationUnit[] compilationUnits, |
| 663 | String[] bindingKeys, |
| 664 | ASTRequestor requestor, |
| 665 | int apiLevel, |
| 666 | Map options, |
| 667 | IJavaProject javaProject, |
| 668 | WorkingCopyOwner owner, |
| 669 | int flags, |
| 670 | IProgressMonitor monitor) { |
| 671 | |
| 672 | CancelableNameEnvironment environment = null; |
| 673 | CancelableProblemFactory problemFactory = null; |
| 674 | try { |
| 675 | int amountOfWork = (compilationUnits.length + bindingKeys.length) * 2; // 1 for beginToCompile, 1 for resolve |
| 676 | SubMonitor subMonitor = SubMonitor.convert(monitor, amountOfWork); |
| 677 | environment = new CancelableNameEnvironment(((JavaProject) javaProject), owner, subMonitor); |
| 678 | problemFactory = new CancelableProblemFactory(subMonitor); |
| 679 | CompilerOptions compilerOptions = getCompilerOptions(options, (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0); |
| 680 | compilerOptions.ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; |
| 681 | CompilationUnitResolver resolver = |
| 682 | new CompilationUnitResolver( |
| 683 | environment, |
| 684 | getHandlingPolicy(), |
| 685 | compilerOptions, |
| 686 | getRequestor(), |
| 687 | problemFactory, |
| 688 | subMonitor, |
| 689 | javaProject != null); |
| 690 | resolver.resolve(compilationUnits, bindingKeys, requestor, apiLevel, options, owner, flags); |
| 691 | if (NameLookup.VERBOSE) { |
| 692 | environment.printTimeSpent(); |
| 693 | } |
| 694 | } catch (JavaModelException e) { |
| 695 | // project doesn't exist -> simple parse without resolving |
| 696 | parse(compilationUnits, requestor, apiLevel, options, flags, monitor); |
| 697 | } finally { |
| 698 | if (environment != null) { |
| 699 | environment.setMonitor(null); // don't hold a reference to this external object |
| 700 | } |
| 701 | if (problemFactory != null) { |
| 702 | problemFactory.monitor = null; // don't hold a reference to this external object |
| 703 | } |
| 704 | } |
| 705 | } |
| 706 | public static void resolve( |
| 707 | String[] sourceUnits, |
| 708 | String[] encodings, |
| 709 | String[] bindingKeys, |
| 710 | FileASTRequestor requestor, |
| 711 | int apiLevel, |
| 712 | Map options, |
| 713 | List classpaths, |
| 714 | int flags, |
| 715 | IProgressMonitor monitor) { |
| 716 | |
| 717 | INameEnvironmentWithProgress environment = null; |
| 718 | CancelableProblemFactory problemFactory = null; |
| 719 | try { |
| 720 | int amountOfWork = (sourceUnits.length + bindingKeys.length) * 2; // 1 for beginToCompile, 1 for resolve |
| 721 | SubMonitor subMonitor = SubMonitor.convert(monitor, amountOfWork); |
| 722 | Classpath[] allEntries = new Classpath[classpaths.size()]; |
| 723 | classpaths.toArray(allEntries); |
| 724 | environment = new NameEnvironmentWithProgress(allEntries, null, subMonitor); |
| 725 | problemFactory = new CancelableProblemFactory(subMonitor); |
| 726 | CompilerOptions compilerOptions = getCompilerOptions(options, (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0); |
| 727 | compilerOptions.ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; |
| 728 | CompilationUnitResolver resolver = |
| 729 | new CompilationUnitResolver( |
| 730 | environment, |
| 731 | getHandlingPolicy(), |
| 732 | compilerOptions, |
| 733 | getRequestor(), |
| 734 | problemFactory, |
| 735 | subMonitor, |
| 736 | false); |
| 737 | resolver.resolve(sourceUnits, encodings, bindingKeys, requestor, apiLevel, options, flags); |
| 738 | if (NameLookup.VERBOSE && (environment instanceof CancelableNameEnvironment)) { |
| 739 | CancelableNameEnvironment cancelableNameEnvironment = (CancelableNameEnvironment) environment; |
| 740 | cancelableNameEnvironment.printTimeSpent(); |
| 741 | } |
| 742 | } finally { |
| 743 | if (environment != null) { |
| 744 | environment.setMonitor(null); // don't hold a reference to this external object |
| 745 | } |
| 746 | if (problemFactory != null) { |
| 747 | problemFactory.monitor = null; // don't hold a reference to this external object |
| 748 | } |
| 749 | } |
| 750 | } |
| 751 | public static CompilationUnitDeclaration resolve( |
| 752 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, |
| 753 | IJavaProject javaProject, |
| 754 | List classpaths, |
| 755 | NodeSearcher nodeSearcher, |
| 756 | Map options, |
| 757 | WorkingCopyOwner owner, |
| 758 | int flags, |
| 759 | IProgressMonitor monitor) throws JavaModelException { |
| 760 | |
| 761 | CompilationUnitDeclaration unit = null; |
| 762 | INameEnvironmentWithProgress environment = null; |
| 763 | CancelableProblemFactory problemFactory = null; |
| 764 | CompilationUnitResolver resolver = null; |
| 765 | try { |
| 766 | if (javaProject == null) { |
| 767 | Classpath[] allEntries = new Classpath[classpaths.size()]; |
| 768 | classpaths.toArray(allEntries); |
| 769 | environment = new NameEnvironmentWithProgress(allEntries, null, monitor); |
| 770 | } else { |
| 771 | environment = new CancelableNameEnvironment((JavaProject) javaProject, owner, monitor); |
| 772 | } |
| 773 | problemFactory = new CancelableProblemFactory(monitor); |
| 774 | CompilerOptions compilerOptions = getCompilerOptions(options, (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0); |
| 775 | boolean ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; |
| 776 | compilerOptions.ignoreMethodBodies = ignoreMethodBodies; |
| 777 | resolver = |
| 778 | new CompilationUnitResolver( |
| 779 | environment, |
| 780 | getHandlingPolicy(), |
| 781 | compilerOptions, |
| 782 | getRequestor(), |
| 783 | problemFactory, |
| 784 | monitor, |
| 785 | javaProject != null); |
| 786 | boolean analyzeAndGenerateCode = !ignoreMethodBodies; |
| 787 | unit = |
| 788 | resolver.resolve( |
| 789 | null, // no existing compilation unit declaration |
| 790 | sourceUnit, |
| 791 | nodeSearcher, |
| 792 | true, // method verification |
| 793 | analyzeAndGenerateCode, // analyze code |
| 794 | analyzeAndGenerateCode); // generate code |
| 795 | if (resolver.hasCompilationAborted) { |
| 796 | // the bindings could not be resolved due to missing types in name environment |
| 797 | // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=86541 |
| 798 | CompilationUnitDeclaration unitDeclaration = parse(sourceUnit, nodeSearcher, options, flags); |
| 799 | if (unit != null) { |
| 800 | final int problemCount = unit.compilationResult.problemCount; |
| 801 | if (problemCount != 0) { |
| 802 | unitDeclaration.compilationResult.problems = new CategorizedProblem[problemCount]; |
| 803 | System.arraycopy(unit.compilationResult.problems, 0, unitDeclaration.compilationResult.problems, 0, problemCount); |
| 804 | unitDeclaration.compilationResult.problemCount = problemCount; |
| 805 | } |
| 806 | } else if (resolver.abortProblem != null) { |
| 807 | unitDeclaration.compilationResult.problemCount = 1; |
| 808 | unitDeclaration.compilationResult.problems = new CategorizedProblem[] { resolver.abortProblem }; |
| 809 | } |
| 810 | return unitDeclaration; |
| 811 | } |
| 812 | if (NameLookup.VERBOSE && environment instanceof CancelableNameEnvironment) { |
| 813 | CancelableNameEnvironment cancelableNameEnvironment = (CancelableNameEnvironment) environment; |
| 814 | cancelableNameEnvironment.printTimeSpent(); |
| 815 | } |
| 816 | return unit; |
| 817 | } finally { |
| 818 | if (environment != null) { |
| 819 | // don't hold a reference to this external object |
| 820 | environment.setMonitor(null); |
| 821 | } |
| 822 | if (problemFactory != null) { |
| 823 | problemFactory.monitor = null; // don't hold a reference to this external object |
| 824 | } |
| 825 | } |
| 826 | } |
| 827 | public static IBinding[] resolve( |
| 828 | final IJavaElement[] elements, |
| 829 | int apiLevel, |
| 830 | Map compilerOptions, |
| 831 | IJavaProject javaProject, |
| 832 | WorkingCopyOwner owner, |
| 833 | int flags, |
| 834 | IProgressMonitor monitor) { |
| 835 | |
| 836 | final int length = elements.length; |
| 837 | final HashMap sourceElementPositions = new HashMap(); // a map from ICompilationUnit to int[] (positions in elements) |
| 838 | int cuNumber = 0; |
| 839 | final HashtableOfObjectToInt binaryElementPositions = new HashtableOfObjectToInt(); // a map from String (binding key) to int (position in elements) |
| 840 | for (int i = 0; i < length; i++) { |
| 841 | IJavaElement element = elements[i]; |
| 842 | if (!(element instanceof SourceRefElement)) |
| 843 | throw new IllegalStateException(element + " is not part of a compilation unit or class file"); //$NON-NLS-1$ |
| 844 | Object cu = element.getAncestor(IJavaElement.COMPILATION_UNIT); |
| 845 | if (cu != null) { |
| 846 | // source member |
| 847 | IntArrayList intList = (IntArrayList) sourceElementPositions.get(cu); |
| 848 | if (intList == null) { |
| 849 | sourceElementPositions.put(cu, intList = new IntArrayList()); |
| 850 | cuNumber++; |
| 851 | } |
| 852 | intList.add(i); |
| 853 | } else { |
| 854 | // binary member or method argument |
| 855 | try { |
| 856 | String key; |
| 857 | if (element instanceof BinaryMember) |
| 858 | key = ((BinaryMember) element).getKey(true/*open to get resolved info*/); |
| 859 | else if (element instanceof LocalVariable) |
| 860 | key = ((LocalVariable) element).getKey(true/*open to get resolved info*/); |
| 861 | else if (element instanceof org.eclipse.jdt.internal.core.TypeParameter) |
| 862 | key = ((org.eclipse.jdt.internal.core.TypeParameter) element).getKey(true/*open to get resolved info*/); |
| 863 | else if (element instanceof BinaryModule) |
| 864 | key = ((BinaryModule) element).getKey(true); |
| 865 | else |
| 866 | throw new IllegalArgumentException(element + " has an unexpected type"); //$NON-NLS-1$ |
| 867 | binaryElementPositions.put(key, i); |
| 868 | } catch (JavaModelException e) { |
| 869 | throw new IllegalArgumentException(element + " does not exist", e); //$NON-NLS-1$ |
| 870 | } |
| 871 | } |
| 872 | } |
| 873 | ICompilationUnit[] cus = new ICompilationUnit[cuNumber]; |
| 874 | sourceElementPositions.keySet().toArray(cus); |
| 875 | |
| 876 | int bindingKeyNumber = binaryElementPositions.size(); |
| 877 | String[] bindingKeys = new String[bindingKeyNumber]; |
| 878 | binaryElementPositions.keysToArray(bindingKeys); |
| 879 | |
| 880 | class Requestor extends ASTRequestor { |
| 881 | IBinding[] bindings = new IBinding[length]; |
| 882 | @Override |
| 883 | public void acceptAST(ICompilationUnit source, CompilationUnit ast) { |
| 884 | // TODO (jerome) optimize to visit the AST only once |
| 885 | IntArrayList intList = (IntArrayList) sourceElementPositions.get(source); |
| 886 | for (int i = 0; i < intList.length; i++) { |
| 887 | final int index = intList.list[i]; |
| 888 | SourceRefElement element = (SourceRefElement) elements[index]; |
| 889 | DOMFinder finder = new DOMFinder(ast, element, true/*resolve binding*/); |
| 890 | try { |
| 891 | finder.search(); |
| 892 | } catch (JavaModelException e) { |
| 893 | throw new IllegalArgumentException(element + " does not exist", e); //$NON-NLS-1$ |
| 894 | } |
| 895 | this.bindings[index] = finder.foundBinding; |
| 896 | } |
| 897 | } |
| 898 | @Override |
| 899 | public void acceptBinding(String bindingKey, IBinding binding) { |
| 900 | int index = binaryElementPositions.get(bindingKey); |
| 901 | this.bindings[index] = binding; |
| 902 | } |
| 903 | } |
| 904 | Requestor requestor = new Requestor(); |
| 905 | resolve(cus, bindingKeys, requestor, apiLevel, compilerOptions, javaProject, owner, flags, monitor); |
| 906 | return requestor.bindings; |
| 907 | } |
| 908 | /* |
| 909 | * When unit result is about to be accepted, removed back pointers |
| 910 | * to unresolved bindings |
| 911 | */ |
| 912 | public void removeUnresolvedBindings(CompilationUnitDeclaration compilationUnitDeclaration) { |
| 913 | final org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types; |
| 914 | if (types != null) { |
| 915 | for (int i = 0, max = types.length; i < max; i++) { |
| 916 | removeUnresolvedBindings(types[i]); |
| 917 | } |
| 918 | } |
| 919 | } |
| 920 | private void removeUnresolvedBindings(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration type) { |
| 921 | final org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] memberTypes = type.memberTypes; |
| 922 | if (memberTypes != null) { |
| 923 | for (int i = 0, max = memberTypes.length; i < max; i++){ |
| 924 | removeUnresolvedBindings(memberTypes[i]); |
| 925 | } |
| 926 | } |
| 927 | if (type.binding != null && (type.binding.modifiers & ExtraCompilerModifiers.AccUnresolved) != 0) { |
| 928 | type.binding = null; |
| 929 | } |
| 930 | |
| 931 | final org.eclipse.jdt.internal.compiler.ast.FieldDeclaration[] fields = type.fields; |
| 932 | if (fields != null) { |
| 933 | for (int i = 0, max = fields.length; i < max; i++){ |
| 934 | if (fields[i].binding != null && (fields[i].binding.modifiers & ExtraCompilerModifiers.AccUnresolved) != 0) { |
| 935 | fields[i].binding = null; |
| 936 | } |
| 937 | } |
| 938 | } |
| 939 | |
| 940 | final AbstractMethodDeclaration[] methods = type.methods; |
| 941 | if (methods != null) { |
| 942 | for (int i = 0, max = methods.length; i < max; i++){ |
| 943 | if (methods[i].binding != null && (methods[i].binding.modifiers & ExtraCompilerModifiers.AccUnresolved) != 0) { |
| 944 | methods[i].binding = null; |
| 945 | } |
| 946 | } |
| 947 | } |
| 948 | } |
| 949 | |
| 950 | private void resolve( |
| 951 | ICompilationUnit[] compilationUnits, |
| 952 | String[] bindingKeys, |
| 953 | ASTRequestor astRequestor, |
| 954 | int apiLevel, |
| 955 | Map compilerOptions, |
| 956 | WorkingCopyOwner owner, |
| 957 | int flags) { |
| 958 | |
| 959 | // temporarily connect ourselves to the ASTResolver - must disconnect when done |
| 960 | astRequestor.compilationUnitResolver = this; |
| 961 | this.bindingTables = new DefaultBindingResolver.BindingTables(); |
| 962 | CompilationUnitDeclaration unit = null; |
| 963 | try { |
| 964 | int length = compilationUnits.length; |
| 965 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] sourceUnits = new org.eclipse.jdt.internal.compiler.env.ICompilationUnit[length]; |
| 966 | System.arraycopy(compilationUnits, 0, sourceUnits, 0, length); |
| 967 | beginToCompile(sourceUnits, bindingKeys); |
| 968 | // process all units (some more could be injected in the loop by the lookup environment) |
| 969 | for (int i = 0; i < this.totalUnits; i++) { |
| 970 | if (resolvedRequestedSourcesAndKeys(i)) { |
| 971 | // no need to keep resolving if no more ASTs and no more binding keys are needed |
| 972 | // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=114935 |
| 973 | // cleanup remaining units |
| 974 | for (; i < this.totalUnits; i++) { |
| 975 | this.unitsToProcess[i].cleanUp(); |
| 976 | this.unitsToProcess[i] = null; |
| 977 | } |
| 978 | break; |
| 979 | } |
| 980 | unit = this.unitsToProcess[i]; |
| 981 | try { |
| 982 | super.process(unit, i); // this.process(...) is optimized to not process already known units |
| 983 | |
| 984 | // requested AST |
| 985 | char[] fileName = unit.compilationResult.getFileName(); |
| 986 | ICompilationUnit source = (ICompilationUnit) this.requestedSources.get(fileName); |
| 987 | if (source != null) { |
| 988 | // convert AST |
| 989 | CompilationResult compilationResult = unit.compilationResult; |
| 990 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = compilationResult.compilationUnit; |
| 991 | char[] contents = sourceUnit.getContents(); |
| 992 | AST ast = AST.newAST(apiLevel, JavaCore.ENABLED.equals(this.options.getMap().get(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES))); |
| 993 | ast.setFlag(flags | AST.RESOLVED_BINDINGS); |
| 994 | ast.setDefaultNodeFlag(ASTNode.ORIGINAL); |
| 995 | ASTConverter converter = new ASTConverter(compilerOptions, true/*need to resolve bindings*/, this.monitor); |
| 996 | BindingResolver resolver = new DefaultBindingResolver(unit.scope, owner, this.bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0, this.fromJavaProject); |
| 997 | ast.setBindingResolver(resolver); |
| 998 | converter.setAST(ast); |
| 999 | CompilationUnit compilationUnit = converter.convert(unit, contents); |
| 1000 | compilationUnit.setTypeRoot(source); |
| 1001 | compilationUnit.setLineEndTable(compilationResult.getLineSeparatorPositions()); |
| 1002 | ast.setDefaultNodeFlag(0); |
| 1003 | ast.setOriginalModificationCount(ast.modificationCount()); |
| 1004 | |
| 1005 | // pass it to requestor |
| 1006 | astRequestor.acceptAST(source, compilationUnit); |
| 1007 | |
| 1008 | worked(1); |
| 1009 | |
| 1010 | // remove at the end so that we don't resolve twice if a source and a key for the same file name have been requested |
| 1011 | this.requestedSources.put(fileName, null); // mark it as removed |
| 1012 | } |
| 1013 | |
| 1014 | // requested binding |
| 1015 | Object key = this.requestedKeys.get(fileName); |
| 1016 | if (key != null) { |
| 1017 | if (key instanceof BindingKeyResolver) { |
| 1018 | reportBinding(key, astRequestor, owner, unit); |
| 1019 | worked(1); |
| 1020 | } else if (key instanceof ArrayList) { |
| 1021 | Iterator iterator = ((ArrayList) key).iterator(); |
| 1022 | while (iterator.hasNext()) { |
| 1023 | reportBinding(iterator.next(), astRequestor, owner, unit); |
| 1024 | worked(1); |
| 1025 | } |
| 1026 | } |
| 1027 | |
| 1028 | // remove at the end so that we don't resolve twice if a source and a key for the same file name have been requested |
| 1029 | this.requestedKeys.put(fileName, null); // mark it as removed |
| 1030 | } |
| 1031 | } finally { |
| 1032 | // cleanup compilation unit result |
| 1033 | unit.cleanUp(); |
| 1034 | } |
| 1035 | this.unitsToProcess[i] = null; // release reference to processed unit declaration |
| 1036 | this.requestor.acceptResult(unit.compilationResult.tagAsAccepted()); |
| 1037 | } |
| 1038 | |
| 1039 | // remaining binding keys |
| 1040 | DefaultBindingResolver resolver = new DefaultBindingResolver(this.lookupEnvironment, owner, this.bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0, true); |
| 1041 | Object[] keys = this.requestedKeys.valueTable; |
| 1042 | for (int j = 0, keysLength = keys.length; j < keysLength; j++) { |
| 1043 | BindingKeyResolver keyResolver = (BindingKeyResolver) keys[j]; |
| 1044 | if (keyResolver == null) continue; |
| 1045 | Binding compilerBinding = keyResolver.getCompilerBinding(); |
| 1046 | IBinding binding = compilerBinding == null ? null : resolver.getBinding(compilerBinding); |
| 1047 | // pass it to requestor |
| 1048 | astRequestor.acceptBinding(((BindingKeyResolver) this.requestedKeys.valueTable[j]).getKey(), binding); |
| 1049 | worked(1); |
| 1050 | } |
| 1051 | } catch (OperationCanceledException e) { |
| 1052 | throw e; |
| 1053 | } catch (AbortCompilation e) { |
| 1054 | this.handleInternalException(e, unit); |
| 1055 | } catch (Error | RuntimeException e) { |
| 1056 | this.handleInternalException(e, unit, null); |
| 1057 | throw e; // rethrow |
| 1058 | } finally { |
| 1059 | // disconnect ourselves from ast requestor |
| 1060 | astRequestor.compilationUnitResolver = null; |
| 1061 | } |
| 1062 | } |
| 1063 | |
| 1064 | private void resolve( |
| 1065 | String[] sourceCompilationUnits, |
| 1066 | String[] encodings, |
| 1067 | String[] bindingKeys, |
| 1068 | FileASTRequestor astRequestor, |
| 1069 | int apiLevel, |
| 1070 | Map compilerOptions, |
| 1071 | int flags) { |
| 1072 | |
| 1073 | // temporarily connect ourselves to the ASTResolver - must disconnect when done |
| 1074 | astRequestor.compilationUnitResolver = this; |
| 1075 | this.bindingTables = new DefaultBindingResolver.BindingTables(); |
| 1076 | CompilationUnitDeclaration unit = null; |
| 1077 | try { |
| 1078 | int length = sourceCompilationUnits.length; |
| 1079 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] sourceUnits = new org.eclipse.jdt.internal.compiler.env.ICompilationUnit[length]; |
| 1080 | int count = 0; |
| 1081 | for (int i = 0; i < length; i++) { |
| 1082 | char[] contents = null; |
| 1083 | String encoding = encodings != null ? encodings[i] : null; |
| 1084 | String sourceUnitPath = sourceCompilationUnits[i]; |
| 1085 | try { |
| 1086 | contents = Util.getFileCharContent(new File(sourceUnitPath), encoding); |
| 1087 | } catch(IOException e) { |
| 1088 | // go to the next unit |
| 1089 | continue; |
| 1090 | } |
| 1091 | if (contents == null) { |
| 1092 | // go to the next unit |
| 1093 | continue; |
| 1094 | } |
| 1095 | sourceUnits[count++] = new org.eclipse.jdt.internal.compiler.batch.CompilationUnit(contents, sourceUnitPath, encoding); |
| 1096 | } |
| 1097 | if (count < length) { |
| 1098 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] newArray = new org.eclipse.jdt.internal.compiler.env.ICompilationUnit[count]; |
| 1099 | System.arraycopy(sourceUnits, 0, newArray, 0, count); |
| 1100 | sourceUnits = newArray; |
| 1101 | } |
| 1102 | beginToCompile(sourceUnits, bindingKeys); |
| 1103 | // process all units (some more could be injected in the loop by the lookup environment) |
| 1104 | for (int i = 0; i < this.totalUnits; i++) { |
| 1105 | if (resolvedRequestedSourcesAndKeys(i)) { |
| 1106 | // no need to keep resolving if no more ASTs and no more binding keys are needed |
| 1107 | // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=114935 |
| 1108 | // cleanup remaining units |
| 1109 | for (; i < this.totalUnits; i++) { |
| 1110 | this.unitsToProcess[i].cleanUp(); |
| 1111 | this.unitsToProcess[i] = null; |
| 1112 | } |
| 1113 | break; |
| 1114 | } |
| 1115 | unit = this.unitsToProcess[i]; |
| 1116 | try { |
| 1117 | super.process(unit, i); // this.process(...) is optimized to not process already known units |
| 1118 | |
| 1119 | // requested AST |
| 1120 | char[] fileName = unit.compilationResult.getFileName(); |
| 1121 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit source = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) this.requestedSources.get(fileName); |
| 1122 | if (source != null) { |
| 1123 | // convert AST |
| 1124 | CompilationResult compilationResult = unit.compilationResult; |
| 1125 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = compilationResult.compilationUnit; |
| 1126 | char[] contents = sourceUnit.getContents(); |
| 1127 | AST ast = AST.newAST(apiLevel, JavaCore.ENABLED.equals(compilerOptions.get(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES))); |
| 1128 | ast.setFlag(flags | AST.RESOLVED_BINDINGS); |
| 1129 | ast.setDefaultNodeFlag(ASTNode.ORIGINAL); |
| 1130 | ASTConverter converter = new ASTConverter(compilerOptions, true/*need to resolve bindings*/, this.monitor); |
| 1131 | BindingResolver resolver = new DefaultBindingResolver(unit.scope, null, this.bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0, this.fromJavaProject); |
| 1132 | ast.setBindingResolver(resolver); |
| 1133 | converter.setAST(ast); |
| 1134 | CompilationUnit compilationUnit = converter.convert(unit, contents); |
| 1135 | compilationUnit.setTypeRoot(null); |
| 1136 | compilationUnit.setLineEndTable(compilationResult.getLineSeparatorPositions()); |
| 1137 | ast.setDefaultNodeFlag(0); |
| 1138 | ast.setOriginalModificationCount(ast.modificationCount()); |
| 1139 | |
| 1140 | // pass it to requestor |
| 1141 | astRequestor.acceptAST(new String(source.getFileName()), compilationUnit); |
| 1142 | |
| 1143 | worked(1); |
| 1144 | |
| 1145 | // remove at the end so that we don't resolve twice if a source and a key for the same file name have been requested |
| 1146 | this.requestedSources.put(fileName, null); // mark it as removed |
| 1147 | } |
| 1148 | |
| 1149 | // requested binding |
| 1150 | Object key = this.requestedKeys.get(fileName); |
| 1151 | if (key != null) { |
| 1152 | if (key instanceof BindingKeyResolver) { |
| 1153 | reportBinding(key, astRequestor, unit); |
| 1154 | worked(1); |
| 1155 | } else if (key instanceof ArrayList) { |
| 1156 | Iterator iterator = ((ArrayList) key).iterator(); |
| 1157 | while (iterator.hasNext()) { |
| 1158 | reportBinding(iterator.next(), astRequestor, unit); |
| 1159 | worked(1); |
| 1160 | } |
| 1161 | } |
| 1162 | |
| 1163 | // remove at the end so that we don't resolve twice if a source and a key for the same file name have been requested |
| 1164 | this.requestedKeys.put(fileName, null); // mark it as removed |
| 1165 | } |
| 1166 | } finally { |
| 1167 | // cleanup compilation unit result |
| 1168 | unit.cleanUp(); |
| 1169 | } |
| 1170 | this.unitsToProcess[i] = null; // release reference to processed unit declaration |
| 1171 | this.requestor.acceptResult(unit.compilationResult.tagAsAccepted()); |
| 1172 | } |
| 1173 | |
| 1174 | // remaining binding keys |
| 1175 | DefaultBindingResolver resolver = new DefaultBindingResolver(this.lookupEnvironment, null, this.bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0, true); |
| 1176 | Object[] keys = this.requestedKeys.valueTable; |
| 1177 | for (int j = 0, keysLength = keys.length; j < keysLength; j++) { |
| 1178 | BindingKeyResolver keyResolver = (BindingKeyResolver) keys[j]; |
| 1179 | if (keyResolver == null) continue; |
| 1180 | Binding compilerBinding = keyResolver.getCompilerBinding(); |
| 1181 | IBinding binding = compilerBinding == null ? null : resolver.getBinding(compilerBinding); |
| 1182 | // pass it to requestor |
| 1183 | astRequestor.acceptBinding(((BindingKeyResolver) this.requestedKeys.valueTable[j]).getKey(), binding); |
| 1184 | worked(1); |
| 1185 | } |
| 1186 | } catch (OperationCanceledException e) { |
| 1187 | throw e; |
| 1188 | } catch (AbortCompilation e) { |
| 1189 | this.handleInternalException(e, unit); |
| 1190 | } catch (Error | RuntimeException e) { |
| 1191 | this.handleInternalException(e, unit, null); |
| 1192 | throw e; // rethrow |
| 1193 | } finally { |
| 1194 | // disconnect ourselves from ast requestor |
| 1195 | astRequestor.compilationUnitResolver = null; |
| 1196 | } |
| 1197 | } |
| 1198 | |
| 1199 | private void reportBinding(Object key, ASTRequestor astRequestor, WorkingCopyOwner owner, CompilationUnitDeclaration unit) { |
| 1200 | BindingKeyResolver keyResolver = (BindingKeyResolver) key; |
| 1201 | Binding compilerBinding = keyResolver.getCompilerBinding(); |
| 1202 | if (compilerBinding != null) { |
| 1203 | DefaultBindingResolver resolver = new DefaultBindingResolver(unit.scope, owner, this.bindingTables, false, this.fromJavaProject); |
| 1204 | AnnotationBinding annotationBinding = keyResolver.getAnnotationBinding(); |
| 1205 | IBinding binding; |
| 1206 | if (annotationBinding != null) { |
| 1207 | binding = resolver.getAnnotationInstance(annotationBinding); |
| 1208 | } else { |
| 1209 | binding = resolver.getBinding(compilerBinding); |
| 1210 | } |
| 1211 | if (binding != null) |
| 1212 | astRequestor.acceptBinding(keyResolver.getKey(), binding); |
| 1213 | } |
| 1214 | } |
| 1215 | |
| 1216 | private void reportBinding(Object key, FileASTRequestor astRequestor, CompilationUnitDeclaration unit) { |
| 1217 | BindingKeyResolver keyResolver = (BindingKeyResolver) key; |
| 1218 | Binding compilerBinding = keyResolver.getCompilerBinding(); |
| 1219 | if (compilerBinding != null) { |
| 1220 | DefaultBindingResolver resolver = new DefaultBindingResolver(unit.scope, null, this.bindingTables, false, this.fromJavaProject); |
| 1221 | AnnotationBinding annotationBinding = keyResolver.getAnnotationBinding(); |
| 1222 | IBinding binding; |
| 1223 | if (annotationBinding != null) { |
| 1224 | binding = resolver.getAnnotationInstance(annotationBinding); |
| 1225 | } else { |
| 1226 | binding = resolver.getBinding(compilerBinding); |
| 1227 | } |
| 1228 | if (binding != null) |
| 1229 | astRequestor.acceptBinding(keyResolver.getKey(), binding); |
| 1230 | } |
| 1231 | } |
| 1232 | |
| 1233 | private CompilationUnitDeclaration resolve( |
| 1234 | CompilationUnitDeclaration unit, |
| 1235 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, |
| 1236 | NodeSearcher nodeSearcher, |
| 1237 | boolean verifyMethods, |
| 1238 | boolean analyzeCode, |
| 1239 | boolean generateCode) { |
| 1240 | |
| 1241 | try { |
| 1242 | |
| 1243 | if (unit == null) { |
| 1244 | // build and record parsed units |
| 1245 | this.parseThreshold = 0; // will request a full parse |
| 1246 | beginToCompile(new org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] { sourceUnit }); |
| 1247 | // find the right unit from what was injected via accept(ICompilationUnit,..): |
| 1248 | for (int i=0, max = this.totalUnits; i < max; i++) { |
| 1249 | CompilationUnitDeclaration currentCompilationUnitDeclaration = this.unitsToProcess[i]; |
| 1250 | if (currentCompilationUnitDeclaration != null |
| 1251 | && currentCompilationUnitDeclaration.compilationResult.compilationUnit == sourceUnit) { |
| 1252 | unit = currentCompilationUnitDeclaration; |
| 1253 | break; |
| 1254 | } |
| 1255 | } |
| 1256 | if (unit == null) { |
| 1257 | unit = this.unitsToProcess[0]; // fall back to old behavior |
| 1258 | } |
| 1259 | } else { |
| 1260 | // initial type binding creation |
| 1261 | this.lookupEnvironment.buildTypeBindings(unit, null /*no access restriction*/); |
| 1262 | |
| 1263 | // binding resolution |
| 1264 | this.lookupEnvironment.completeTypeBindings(); |
| 1265 | } |
| 1266 | |
| 1267 | if (nodeSearcher == null) { |
| 1268 | this.parser.getMethodBodies(unit); // no-op if method bodies have already been parsed |
| 1269 | } else { |
| 1270 | int searchPosition = nodeSearcher.position; |
| 1271 | char[] source = sourceUnit.getContents(); |
| 1272 | int length = source.length; |
| 1273 | if (searchPosition >= 0 && searchPosition <= length) { |
| 1274 | unit.traverse(nodeSearcher, unit.scope); |
| 1275 | |
| 1276 | org.eclipse.jdt.internal.compiler.ast.ASTNode node = nodeSearcher.found; |
| 1277 | |
| 1278 | if (node != null) { |
| 1279 | // save existing values to restore them at the end of the parsing process |
| 1280 | // see bug 47079 for more details |
| 1281 | int[] oldLineEnds = this.parser.scanner.lineEnds; |
| 1282 | int oldLinePtr = this.parser.scanner.linePtr; |
| 1283 | |
| 1284 | this.parser.scanner.setSource(source, unit.compilationResult); |
| 1285 | |
| 1286 | org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enclosingTypeDeclaration = nodeSearcher.enclosingType; |
| 1287 | if (node instanceof AbstractMethodDeclaration) { |
| 1288 | ((AbstractMethodDeclaration)node).parseStatements(this.parser, unit); |
| 1289 | } else if (enclosingTypeDeclaration != null) { |
| 1290 | if (node instanceof org.eclipse.jdt.internal.compiler.ast.Initializer) { |
| 1291 | ((org.eclipse.jdt.internal.compiler.ast.Initializer) node).parseStatements(this.parser, enclosingTypeDeclaration, unit); |
| 1292 | } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) { |
| 1293 | ((org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)node).parseMethods(this.parser, unit); |
| 1294 | } |
| 1295 | } |
| 1296 | // this is done to prevent any side effects on the compilation unit result |
| 1297 | // line separator positions array. |
| 1298 | this.parser.scanner.lineEnds = oldLineEnds; |
| 1299 | this.parser.scanner.linePtr = oldLinePtr; |
| 1300 | } |
| 1301 | } |
| 1302 | } |
| 1303 | |
| 1304 | if (unit.scope != null) { |
| 1305 | CompilationUnitDeclaration previousUnit = this.lookupEnvironment.unitBeingCompleted; |
| 1306 | this.lookupEnvironment.unitBeingCompleted = unit; |
| 1307 | try { |
| 1308 | // fault in fields & methods |
| 1309 | unit.scope.faultInTypes(); |
| 1310 | if (unit.scope != null && verifyMethods) { |
| 1311 | // http://dev.eclipse.org/bugs/show_bug.cgi?id=23117 |
| 1312 | // verify inherited methods |
| 1313 | unit.scope.verifyMethods(this.lookupEnvironment.methodVerifier()); |
| 1314 | } |
| 1315 | // type checking |
| 1316 | unit.resolve(); |
| 1317 | |
| 1318 | // flow analysis |
| 1319 | if (analyzeCode) unit.analyseCode(); |
| 1320 | |
| 1321 | // code generation |
| 1322 | if (generateCode) unit.generateCode(); |
| 1323 | |
| 1324 | // finalize problems (suppressWarnings) |
| 1325 | unit.finalizeProblems(); |
| 1326 | } finally { |
| 1327 | this.lookupEnvironment.unitBeingCompleted = previousUnit; // paranoia, always null in org.eclipse.jdt.core.tests.dom.RunAllTests |
| 1328 | } |
| 1329 | } |
| 1330 | if (this.unitsToProcess != null) this.unitsToProcess[0] = null; // release reference to processed unit declaration |
| 1331 | this.requestor.acceptResult(unit.compilationResult.tagAsAccepted()); |
| 1332 | return unit; |
| 1333 | } catch (AbortCompilation e) { |
| 1334 | this.handleInternalException(e, unit); |
| 1335 | return unit == null ? this.unitsToProcess[0] : unit; |
| 1336 | } catch (Error | RuntimeException e) { |
| 1337 | this.handleInternalException(e, unit, null); |
| 1338 | throw e; // rethrow |
| 1339 | } finally { |
| 1340 | // No reset is performed there anymore since, |
| 1341 | // within the CodeAssist (or related tools), |
| 1342 | // the compiler may be called *after* a call |
| 1343 | // to this resolve(...) method. And such a call |
| 1344 | // needs to have a compiler with a non-empty |
| 1345 | // environment. |
| 1346 | // this.reset(); |
| 1347 | } |
| 1348 | } |
| 1349 | /* |
| 1350 | * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process |
| 1351 | */ |
| 1352 | @Override |
| 1353 | public CompilationUnitDeclaration resolve( |
| 1354 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, |
| 1355 | boolean verifyMethods, |
| 1356 | boolean analyzeCode, |
| 1357 | boolean generateCode) { |
| 1358 | |
| 1359 | return resolve( |
| 1360 | null, /* no existing compilation unit declaration*/ |
| 1361 | sourceUnit, |
| 1362 | null/*no node searcher*/, |
| 1363 | verifyMethods, |
| 1364 | analyzeCode, |
| 1365 | generateCode); |
| 1366 | } |
| 1367 | |
| 1368 | boolean resolvedRequestedSourcesAndKeys(int unitIndexToProcess) { |
| 1369 | if (unitIndexToProcess < this.requestedSources.size() && unitIndexToProcess < this.requestedKeys.size()) |
| 1370 | return false; // must process at least this many units before checking to see if all are done |
| 1371 | |
| 1372 | Object[] sources = this.requestedSources.valueTable; |
| 1373 | for (int i = 0, l = sources.length; i < l; i++) |
| 1374 | if (sources[i] != null) return false; |
| 1375 | Object[] keys = this.requestedKeys.valueTable; |
| 1376 | for (int i = 0, l = keys.length; i < l; i++) |
| 1377 | if (keys[i] != null) return false; |
| 1378 | return true; |
| 1379 | } |
| 1380 | |
| 1381 | /* |
| 1382 | * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process |
| 1383 | */ |
| 1384 | @Override |
| 1385 | public CompilationUnitDeclaration resolve( |
| 1386 | CompilationUnitDeclaration unit, |
| 1387 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, |
| 1388 | boolean verifyMethods, |
| 1389 | boolean analyzeCode, |
| 1390 | boolean generateCode) { |
| 1391 | |
| 1392 | return resolve( |
| 1393 | unit, |
| 1394 | sourceUnit, |
| 1395 | null/*no node searcher*/, |
| 1396 | verifyMethods, |
| 1397 | analyzeCode, |
| 1398 | generateCode); |
| 1399 | } |
| 1400 | |
| 1401 | private void worked(int work) { |
| 1402 | if (this.monitor != null) { |
| 1403 | if (this.monitor.isCanceled()) |
| 1404 | throw new OperationCanceledException(); |
| 1405 | this.monitor.worked(work); |
| 1406 | } |
| 1407 | } |
| 1408 | } |
| 1409 |
Members