protected void consumeSingleTypeImportDeclarationName() { // SingleTypeImportDeclarationName ::= 'import' Name /* push an ImportRef build from the last name stored in the identifier stack. */ ImportReference impt; int length; char[][] tokens = new char[length = this.identifierLengthStack[this.identifierLengthPtr--]][]; this.identifierPtr -= length; long[] positions = new long[length]; System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length); System.arraycopy(this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length); pushOnAstStack( impt = newImportReference(tokens, positions, false, ClassFileConstants.AccDefault)); if (this.currentToken == TokenNameSEMICOLON) { impt.declarationSourceEnd = this.scanner.currentPosition - 1; } else { impt.declarationSourceEnd = impt.sourceEnd; } impt.declarationEnd = impt.declarationSourceEnd; // this.endPosition is just before the ; impt.declarationSourceStart = this.intStack[this.intPtr--]; // recovery if (this.currentElement != null) { this.lastCheckPoint = impt.declarationSourceEnd + 1; this.currentElement = this.currentElement.add(impt, 0); this.lastIgnoredToken = -1; this.restartRecovery = true; // used to avoid branching back into the regular automaton } if (this.reportReferenceInfo) { this.requestor.acceptTypeReference(impt.tokens, impt.sourceStart, impt.sourceEnd); } }
protected void consumeSingleStaticImportDeclarationName() { // SingleTypeImportDeclarationName ::= 'import' 'static' Name ImportReference impt; int length; char[][] tokens = new char[length = this.identifierLengthStack[this.identifierLengthPtr--]][]; this.identifierPtr -= length; long[] positions = new long[length]; System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length); System.arraycopy(this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length); pushOnAstStack( impt = newImportReference(tokens, positions, false, ClassFileConstants.AccStatic)); this.modifiers = ClassFileConstants.AccDefault; this.modifiersSourceStart = -1; // <-- see comment into modifiersFlag(int) if (this.currentToken == TokenNameSEMICOLON) { impt.declarationSourceEnd = this.scanner.currentPosition - 1; } else { impt.declarationSourceEnd = impt.sourceEnd; } impt.declarationEnd = impt.declarationSourceEnd; // this.endPosition is just before the ; impt.declarationSourceStart = this.intStack[this.intPtr--]; if (!this.statementRecoveryActivated && this.options.sourceLevel < ClassFileConstants.JDK1_5 && this.lastErrorEndPositionBeforeRecovery < this.scanner.currentPosition) { impt.modifiers = ClassFileConstants .AccDefault; // convert the static import reference to a non-static importe reference problemReporter().invalidUsageOfStaticImports(impt); } // recovery if (this.currentElement != null) { this.lastCheckPoint = impt.declarationSourceEnd + 1; this.currentElement = this.currentElement.add(impt, 0); this.lastIgnoredToken = -1; this.restartRecovery = true; // used to avoid branching back into the regular automaton } if (this.reportReferenceInfo) { // Name for static import is TypeName '.' Identifier // => accept unknown ref on identifier int tokensLength = impt.tokens.length - 1; int start = (int) (impt.sourcePositions[tokensLength] >>> 32); char[] last = impt.tokens[tokensLength]; // accept all possible kind for last name, index users will have to select the right one... // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=86901 this.requestor.acceptFieldReference(last, start); this.requestor.acceptMethodReference(last, 0, start); this.requestor.acceptTypeReference(last, start); // accept type name if (tokensLength > 0) { char[][] compoundName = new char[tokensLength][]; System.arraycopy(impt.tokens, 0, compoundName, 0, tokensLength); int end = (int) impt.sourcePositions[tokensLength - 1]; this.requestor.acceptTypeReference(compoundName, impt.sourceStart, end); } } }
public NameReference getUnspecifiedReference(boolean rejectTypeAnnotations) { /* build a (unspecified) NameReference which may be qualified*/ if (rejectTypeAnnotations) { consumeNonTypeUseName(); } int length; if ((length = this.identifierLengthStack[this.identifierLengthPtr--]) == 1) { // single variable reference SingleNameReference ref = newSingleNameReference( this.identifierStack[this.identifierPtr], this.identifierPositionStack[this.identifierPtr--]); if (this.reportReferenceInfo) { addUnknownRef(ref); } return ref; } else { // Qualified variable reference char[][] tokens = new char[length][]; this.identifierPtr -= length; System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length); long[] positions = new long[length]; System.arraycopy(this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length); QualifiedNameReference ref = newQualifiedNameReference( tokens, positions, (int) (this.identifierPositionStack[this.identifierPtr + 1] >> 32), // sourceStart (int) this.identifierPositionStack[this.identifierPtr + length]); // sourceEnd if (this.reportReferenceInfo) { addUnknownRef(ref); } return ref; } }
/** * Add the initial set of compilation units into the loop -> build compilation unit declarations, * their bindings and record their results. */ protected void internalBeginToCompile(ICompilationUnit[] sourceUnits, int maxUnits) { if (!this.useSingleThread && maxUnits >= ReadManager.THRESHOLD) this.parser.readManager = new ReadManager(sourceUnits, maxUnits); // Switch the current policy and compilation result for this unit to the requested one. for (int i = 0; i < maxUnits; i++) { CompilationResult unitResult = null; try { if (this.options.verbose) { this.out.println( Messages.bind( Messages.compilation_request, new String[] { String.valueOf(i + 1), String.valueOf(maxUnits), new String(sourceUnits[i].getFileName()) })); } // diet parsing for large collection of units CompilationUnitDeclaration parsedUnit; unitResult = new CompilationResult(sourceUnits[i], i, maxUnits, this.options.maxProblemsPerUnit); long parseStart = System.currentTimeMillis(); if (this.totalUnits < this.parseThreshold) { parsedUnit = this.parser.parse(sourceUnits[i], unitResult); } else { parsedUnit = this.parser.dietParse(sourceUnits[i], unitResult); } long resolveStart = System.currentTimeMillis(); this.stats.parseTime += resolveStart - parseStart; // initial type binding creation this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/); this.stats.resolveTime += System.currentTimeMillis() - resolveStart; addCompilationUnit(sourceUnits[i], parsedUnit); ImportReference currentPackage = parsedUnit.currentPackage; if (currentPackage != null) { unitResult.recordPackageName(currentPackage.tokens); } // } catch (AbortCompilationUnit e) { // requestor.acceptResult(unitResult.tagAsAccepted()); } catch (AbortCompilation a) { // best effort to find a way for reporting this problem: if (a.compilationResult == null) a.compilationResult = unitResult; throw a; } finally { sourceUnits[i] = null; // no longer hold onto the unit } } if (this.parser.readManager != null) { this.parser.readManager.shutdown(); this.parser.readManager = null; } // binding resolution this.lookupEnvironment.completeTypeBindings(); }
/** * Bytecode generation for a method * * @param classScope * @param classFile */ public void generateCode(ClassScope classScope, ClassFile classFile) { int problemResetPC = 0; classFile.codeStream.wideMode = false; // reset wideMode to false if (this.ignoreFurtherInvestigation) { // method is known to have errors, dump a problem method if (this.binding == null) return; // handle methods with invalid signature or duplicates int problemsLength; CategorizedProblem[] problems = this.scope.referenceCompilationUnit().compilationResult.getProblems(); CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length]; System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); classFile.addProblemMethod(this, this.binding, problemsCopy); return; } boolean restart = false; boolean abort = false; // regular code generation do { try { problemResetPC = classFile.contentsOffset; this.generateCode(classFile); restart = false; } catch (AbortMethod e) { // a fatal error was detected during code generation, need to restart code gen if possible if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) { // a branch target required a goto_w, restart code gen in wide mode. classFile.contentsOffset = problemResetPC; classFile.methodCount--; classFile.codeStream.resetInWideMode(); // request wide mode restart = true; } else if (e.compilationResult == CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE) { classFile.contentsOffset = problemResetPC; classFile.methodCount--; classFile.codeStream.resetForCodeGenUnusedLocals(); restart = true; } else { restart = false; abort = true; } } } while (restart); // produce a problem method accounting for this fatal error if (abort) { int problemsLength; CategorizedProblem[] problems = this.scope.referenceCompilationUnit().compilationResult.getAllProblems(); CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length]; System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); classFile.addProblemMethod(this, this.binding, problemsCopy, problemResetPC); } }
protected void consumeStaticImportOnDemandDeclarationName() { // TypeImportOnDemandDeclarationName ::= 'import' 'static' Name '.' '*' /* push an ImportRef build from the last name stored in the identifier stack. */ ImportReference impt; int length; char[][] tokens = new char[length = this.identifierLengthStack[this.identifierLengthPtr--]][]; this.identifierPtr -= length; long[] positions = new long[length]; System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length); System.arraycopy(this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length); pushOnAstStack( impt = new ImportReference(tokens, positions, true, ClassFileConstants.AccStatic)); // star end position impt.trailingStarPosition = this.intStack[this.intPtr--]; this.modifiers = ClassFileConstants.AccDefault; this.modifiersSourceStart = -1; // <-- see comment into modifiersFlag(int) if (this.currentToken == TokenNameSEMICOLON) { impt.declarationSourceEnd = this.scanner.currentPosition - 1; } else { impt.declarationSourceEnd = impt.sourceEnd; } impt.declarationEnd = impt.declarationSourceEnd; // this.endPosition is just before the ; impt.declarationSourceStart = this.intStack[this.intPtr--]; if (!this.statementRecoveryActivated && this.options.sourceLevel < ClassFileConstants.JDK1_5 && this.lastErrorEndPositionBeforeRecovery < this.scanner.currentPosition) { impt.modifiers = ClassFileConstants .AccDefault; // convert the static import reference to a non-static importe reference problemReporter().invalidUsageOfStaticImports(impt); } // recovery if (this.currentElement != null) { this.lastCheckPoint = impt.declarationSourceEnd + 1; this.currentElement = this.currentElement.add(impt, 0); this.lastIgnoredToken = -1; this.restartRecovery = true; // used to avoid branching back into the regular automaton } if (this.reportReferenceInfo) { this.requestor.acceptTypeReference(impt.tokens, impt.sourceStart, impt.sourceEnd); } }
public NameReference getUnspecifiedReferenceOptimized() { /* build a (unspecified) NameReference which may be qualified The optimization occurs for qualified reference while we are certain in this case the last item of the qualified name is a field access. This optimization is IMPORTANT while it results that when a NameReference is build, the type checker should always look for that it is not a type reference */ consumeNonTypeUseName(); int length; if ((length = this.identifierLengthStack[this.identifierLengthPtr--]) == 1) { // single variable reference SingleNameReference ref = newSingleNameReference( this.identifierStack[this.identifierPtr], this.identifierPositionStack[this.identifierPtr--]); ref.bits &= ~ASTNode.RestrictiveFlagMASK; ref.bits |= Binding.LOCAL | Binding.FIELD; if (this.reportReferenceInfo) { addUnknownRef(ref); } return ref; } // Qualified-variable-reference // In fact it is variable-reference DOT field-ref , but it would result in a type // conflict tha can be only reduce by making a superclass (or inetrface ) between // nameReference and FiledReference or putting FieldReference under NameReference // or else..........This optimisation is not really relevant so just leave as it is char[][] tokens = new char[length][]; this.identifierPtr -= length; System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length); long[] positions = new long[length]; System.arraycopy(this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length); QualifiedNameReference ref = newQualifiedNameReference( tokens, positions, (int) (this.identifierPositionStack[this.identifierPtr + 1] >> 32), // sourceStart (int) this.identifierPositionStack[this.identifierPtr + length]); // sourceEnd ref.bits &= ~ASTNode.RestrictiveFlagMASK; ref.bits |= Binding.LOCAL | Binding.FIELD; if (this.reportReferenceInfo) { addUnknownRef(ref); } return ref; }
protected void processAnnotations() { int newUnitSize = 0; int newClassFilesSize = 0; int bottom = this.annotationProcessorStartIndex; int top = this.totalUnits; ReferenceBinding[] binaryTypeBindingsTemp = this.referenceBindings; if (top == 0 && binaryTypeBindingsTemp == null) return; this.referenceBindings = null; do { // extract units to process int length = top - bottom; CompilationUnitDeclaration[] currentUnits = new CompilationUnitDeclaration[length]; int index = 0; for (int i = bottom; i < top; i++) { CompilationUnitDeclaration currentUnit = this.unitsToProcess[i]; if ((currentUnit.bits & ASTNode.IsImplicitUnit) == 0) { currentUnits[index++] = currentUnit; } } if (index != length) { System.arraycopy( currentUnits, 0, (currentUnits = new CompilationUnitDeclaration[index]), 0, index); } this.annotationProcessorManager.processAnnotations( currentUnits, binaryTypeBindingsTemp, false); ICompilationUnit[] newUnits = this.annotationProcessorManager.getNewUnits(); newUnitSize = newUnits.length; ReferenceBinding[] newClassFiles = this.annotationProcessorManager.getNewClassFiles(); binaryTypeBindingsTemp = newClassFiles; newClassFilesSize = newClassFiles.length; if (newUnitSize != 0) { ICompilationUnit[] newProcessedUnits = (ICompilationUnit[]) newUnits.clone(); // remember new units in case a source type collision occurs try { this.lookupEnvironment.isProcessingAnnotations = true; internalBeginToCompile(newUnits, newUnitSize); } catch (SourceTypeCollisionException e) { e.newAnnotationProcessorUnits = newProcessedUnits; throw e; } finally { this.lookupEnvironment.isProcessingAnnotations = false; this.annotationProcessorManager.reset(); } bottom = top; top = this.totalUnits; // last unit added } else { bottom = top; this.annotationProcessorManager.reset(); } } while (newUnitSize != 0 || newClassFilesSize != 0); // one more loop to create possible resources // this loop cannot create any java source files this.annotationProcessorManager.processAnnotations(null, null, true); // TODO we might want to check if this loop created new units }
protected void addToResult(char[][] compoundName) { int resultLength = this.result.length; for (int i = 0; i < resultLength; i++) if (CharOperation.equals(this.result[i], compoundName)) return; // already known if (resultLength == this.resultIndex) System.arraycopy( this.result, 0, this.result = new char[resultLength * 2][][], 0, resultLength); this.result[this.resultIndex++] = compoundName; }
/** Process a compilation unit already parsed and build. */ public void process(CompilationUnitDeclaration unit, int i) { this.lookupEnvironment.unitBeingCompleted = unit; long parseStart = System.currentTimeMillis(); this.parser.getMethodBodies(unit); long resolveStart = System.currentTimeMillis(); this.stats.parseTime += resolveStart - parseStart; // fault in fields & methods if (unit.scope != null) unit.scope.faultInTypes(); // verify inherited methods if (unit.scope != null) unit.scope.verifyMethods(this.lookupEnvironment.methodVerifier()); // type checking unit.resolve(); long analyzeStart = System.currentTimeMillis(); this.stats.resolveTime += analyzeStart - resolveStart; // No need of analysis or generation of code if statements are not required if (!this.options.ignoreMethodBodies) unit.analyseCode(); // flow analysis long generateStart = System.currentTimeMillis(); this.stats.analyzeTime += generateStart - analyzeStart; if (!this.options.ignoreMethodBodies) unit.generateCode(); // code generation // reference info if (this.options.produceReferenceInfo && unit.scope != null) unit.scope.storeDependencyInfo(); // finalize problems (suppressWarnings) unit.finalizeProblems(); this.stats.generateTime += System.currentTimeMillis() - generateStart; // refresh the total number of units known at this stage unit.compilationResult.totalUnitsKnown = this.totalUnits; this.lookupEnvironment.unitBeingCompleted = null; }
protected boolean matches(char[][] compoundName) { int length = compoundName.length; if (length == 0) return false; char[] simpleName = compoundName[length - 1]; int last = length - 1; if (this.typeSimpleName == null || this.pattern.matchesName(simpleName, this.typeSimpleName)) { // most frequent case: simple name equals last segment of compoundName char[][] qualification = new char[last][]; System.arraycopy(compoundName, 0, qualification, 0, last); return this.pattern.matchesName( this.typeQualification, CharOperation.concatWith(qualification, '.')); } if (!CharOperation.endsWith(simpleName, this.typeSimpleName)) return false; // member type -> transform A.B.C$D into A.B.C.D System.arraycopy(compoundName, 0, compoundName = new char[length + 1][], 0, last); int dollar = CharOperation.indexOf('$', simpleName); if (dollar == -1) return false; compoundName[last] = CharOperation.subarray(simpleName, 0, dollar); compoundName[length] = CharOperation.subarray(simpleName, dollar + 1, simpleName.length); return this.matches(compoundName); }
protected synchronized void addCompilationUnit( ICompilationUnit sourceUnit, CompilationUnitDeclaration parsedUnit) { // append the unit to the list of ones to process later on int size = this.unitsToProcess.length; if (this.totalUnits == size) // when growing reposition units starting at position 0 System.arraycopy( this.unitsToProcess, 0, (this.unitsToProcess = new CompilationUnitDeclaration[size * 2]), 0, this.totalUnits); this.unitsToProcess[this.totalUnits++] = parsedUnit; }
/** * @see SubRoutineStatement#generateSubRoutineInvocation(BlockScope, CodeStream, Object, int, * LocalVariableBinding) */ public boolean generateSubRoutineInvocation( BlockScope currentScope, CodeStream codeStream, Object targetLocation, int stateIndex, LocalVariableBinding secretLocal) { boolean isStackMapFrameCodeStream = codeStream instanceof StackMapFrameCodeStream; int finallyMode = finallyMode(); switch (finallyMode) { case FINALLY_DOES_NOT_COMPLETE: codeStream.goto_(this.subRoutineStartLabel); return true; case NO_FINALLY: exitDeclaredExceptionHandlers(codeStream); return false; } // optimize subroutine invocation sequences, using the targetLocation (if any) if (targetLocation != null) { boolean reuseTargetLocation = true; if (this.reusableJSRTargetsCount > 0) { nextReusableTarget: for (int i = 0, count = this.reusableJSRTargetsCount; i < count; i++) { Object reusableJSRTarget = this.reusableJSRTargets[i]; differentTarget: { if (targetLocation == reusableJSRTarget) break differentTarget; if (targetLocation instanceof Constant && reusableJSRTarget instanceof Constant && ((Constant) targetLocation).hasSameValue((Constant) reusableJSRTarget)) { break differentTarget; } // cannot reuse current target continue nextReusableTarget; } // current target has been used in the past, simply branch to its label if ((this.reusableJSRStateIndexes[i] != stateIndex) && finallyMode == FINALLY_INLINE) { reuseTargetLocation = false; break nextReusableTarget; } else { codeStream.goto_(this.reusableJSRSequenceStartLabels[i]); return true; } } } else { this.reusableJSRTargets = new Object[3]; this.reusableJSRSequenceStartLabels = new BranchLabel[3]; this.reusableJSRStateIndexes = new int[3]; } if (reuseTargetLocation) { if (this.reusableJSRTargetsCount == this.reusableJSRTargets.length) { System.arraycopy( this.reusableJSRTargets, 0, this.reusableJSRTargets = new Object[2 * this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount); System.arraycopy( this.reusableJSRSequenceStartLabels, 0, this.reusableJSRSequenceStartLabels = new BranchLabel[2 * this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount); System.arraycopy( this.reusableJSRStateIndexes, 0, this.reusableJSRStateIndexes = new int[2 * this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount); } this.reusableJSRTargets[this.reusableJSRTargetsCount] = targetLocation; BranchLabel reusableJSRSequenceStartLabel = new BranchLabel(codeStream); reusableJSRSequenceStartLabel.place(); this.reusableJSRStateIndexes[this.reusableJSRTargetsCount] = stateIndex; this.reusableJSRSequenceStartLabels[this.reusableJSRTargetsCount++] = reusableJSRSequenceStartLabel; } } if (finallyMode == FINALLY_INLINE) { if (isStackMapFrameCodeStream) { ((StackMapFrameCodeStream) codeStream).pushStateIndex(stateIndex); if (this.naturalExitMergeInitStateIndex != -1 || stateIndex != -1) { // reset initialization state, as for a normal catch block codeStream.removeNotDefinitelyAssignedVariables( currentScope, this.naturalExitMergeInitStateIndex); codeStream.addDefinitelyAssignedVariables( currentScope, this.naturalExitMergeInitStateIndex); } } else { if (this.naturalExitMergeInitStateIndex != -1) { // reset initialization state, as for a normal catch block codeStream.removeNotDefinitelyAssignedVariables( currentScope, this.naturalExitMergeInitStateIndex); codeStream.addDefinitelyAssignedVariables( currentScope, this.naturalExitMergeInitStateIndex); } } if (secretLocal != null) { codeStream.addVariable(secretLocal); } // cannot use jsr bytecode, then simply inline the subroutine // inside try block, ensure to deactivate all catch block exception handlers while inlining // finally block exitAnyExceptionHandler(); exitDeclaredExceptionHandlers(codeStream); this.finallyBlock.generateCode(currentScope, codeStream); if (isStackMapFrameCodeStream) { ((StackMapFrameCodeStream) codeStream).popStateIndex(); } } else { // classic subroutine invocation, distinguish case of non-returning subroutine codeStream.jsr(this.subRoutineStartLabel); exitAnyExceptionHandler(); exitDeclaredExceptionHandlers(codeStream); } return false; }
/** * General API -> compile each of supplied files -> recompile any required types for which we have * an incomplete principle structure */ public void compile(ICompilationUnit[] sourceUnits) { this.stats.startTime = System.currentTimeMillis(); // GROOVY start // sort the sourceUnits - java first! might be temporary, hmmm if (this.options.buildGroovyFiles == 2) { int groovyFileIndex = -1; // System.out.println("before"); // for (int u=0,max=sourceUnits.length;u<max;u++) { // System.out.println(sourceUnits[u].getFileName()); // } for (int u = 0, max = sourceUnits.length; u < max; u++) { char[] fn = sourceUnits[u].getFileName(); boolean isDotJava = fn[fn.length - 1] == 'a'; // a means .java if (isDotJava) { if (groovyFileIndex != -1) { // swap them! ICompilationUnit swap = sourceUnits[groovyFileIndex]; sourceUnits[groovyFileIndex] = sourceUnits[u]; sourceUnits[u] = swap; // find the next .groovy file after the groovyFileIndex (worst case it will be 'u') int newGroovyFileIndex = -1; for (int g = groovyFileIndex; g <= u; g++) { char[] fn2 = sourceUnits[g].getFileName(); boolean isDotGroovy = fn2[fn2.length - 1] == 'm'; // ZALUUM if (isDotGroovy) { newGroovyFileIndex = g; break; } } groovyFileIndex = newGroovyFileIndex; } } else { if (groovyFileIndex == -1) { groovyFileIndex = u; } } } // System.out.println("after"); // for (int u=0,max=sourceUnits.length;u<max;u++) { // System.out.println(sourceUnits[u].getFileName()); // } } // GROOVY end CompilationUnitDeclaration unit = null; ProcessTaskManager processingTask = null; try { // build and record parsed units reportProgress(Messages.compilation_beginningToCompile); if (this.annotationProcessorManager == null) { beginToCompile(sourceUnits); } else { ICompilationUnit[] originalUnits = (ICompilationUnit[]) sourceUnits.clone(); // remember source units in case a source type collision occurs try { beginToCompile(sourceUnits); processAnnotations(); if (!this.options.generateClassFiles) { // -proc:only was set on the command line return; } } catch (SourceTypeCollisionException e) { reset(); // a generated type was referenced before it was created // the compiler either created a MissingType or found a BinaryType for it // so add the processor's generated files & start over, // but remember to only pass the generated files to the annotation processor int originalLength = originalUnits.length; int newProcessedLength = e.newAnnotationProcessorUnits.length; ICompilationUnit[] combinedUnits = new ICompilationUnit[originalLength + newProcessedLength]; System.arraycopy(originalUnits, 0, combinedUnits, 0, originalLength); System.arraycopy( e.newAnnotationProcessorUnits, 0, combinedUnits, originalLength, newProcessedLength); this.annotationProcessorStartIndex = originalLength; compile(combinedUnits); return; } } if (this.useSingleThread) { // process all units (some more could be injected in the loop by the lookup environment) for (int i = 0; i < this.totalUnits; i++) { unit = this.unitsToProcess[i]; reportProgress( Messages.bind(Messages.compilation_processing, new String(unit.getFileName()))); try { if (this.options.verbose) this.out.println( Messages.bind( Messages.compilation_process, new String[] { String.valueOf(i + 1), String.valueOf(this.totalUnits), new String(this.unitsToProcess[i].getFileName()) })); process(unit, i); } finally { // cleanup compilation unit result unit.cleanUp(); } this.unitsToProcess[i] = null; // release reference to processed unit declaration reportWorked(1, i); this.stats.lineCount += unit.compilationResult.lineSeparatorPositions.length; long acceptStart = System.currentTimeMillis(); this.requestor.acceptResult(unit.compilationResult.tagAsAccepted()); this.stats.generateTime += System.currentTimeMillis() - acceptStart; // record accept time as part of generation if (this.options.verbose) this.out.println( Messages.bind( Messages.compilation_done, new String[] { String.valueOf(i + 1), String.valueOf(this.totalUnits), new String(unit.getFileName()) })); } } else { processingTask = new ProcessTaskManager(this); int acceptedCount = 0; // process all units (some more could be injected in the loop by the lookup environment) // the processTask can continue to process units until its fixed sized cache is full then it // must wait // for this this thread to accept the units as they appear (it only waits if no units are // available) while (true) { try { unit = processingTask.removeNextUnit(); // waits if no units are in the processed queue } catch (Error e) { unit = processingTask.unitToProcess; throw e; } catch (RuntimeException e) { unit = processingTask.unitToProcess; throw e; } if (unit == null) break; reportWorked(1, acceptedCount++); this.stats.lineCount += unit.compilationResult.lineSeparatorPositions.length; this.requestor.acceptResult(unit.compilationResult.tagAsAccepted()); if (this.options.verbose) this.out.println( Messages.bind( Messages.compilation_done, new String[] { String.valueOf(acceptedCount), String.valueOf(this.totalUnits), new String(unit.getFileName()) })); } } } catch (AbortCompilation e) { this.handleInternalException(e, unit); } catch (Error e) { this.handleInternalException(e, unit, null); throw e; // rethrow } catch (RuntimeException e) { this.handleInternalException(e, unit, null); throw e; // rethrow } finally { if (processingTask != null) { processingTask.shutdown(); processingTask = null; } reset(); this.annotationProcessorStartIndex = 0; this.stats.endTime = System.currentTimeMillis(); } if (this.options.verbose) { if (this.totalUnits > 1) { this.out.println( Messages.bind(Messages.compilation_units, String.valueOf(this.totalUnits))); } else { this.out.println(Messages.bind(Messages.compilation_unit, String.valueOf(this.totalUnits))); } } }
public char[][][] collect() throws JavaModelException { if (this.type != null) { // Collect the paths of the cus that are in the hierarchy of the given type this.result = new char[1][][]; this.resultIndex = 0; JavaProject javaProject = (JavaProject) this.type.getJavaProject(); this.locator.initialize(javaProject, 0); try { if (this.type.isBinary()) { BinaryTypeBinding binding = this.locator.cacheBinaryType(this.type, null); if (binding != null) collectSuperTypeNames(binding); } else { ICompilationUnit unit = this.type.getCompilationUnit(); SourceType sourceType = (SourceType) this.type; boolean isTopLevelOrMember = sourceType.getOuterMostLocalContext() == null; CompilationUnitDeclaration parsedUnit = buildBindings(unit, isTopLevelOrMember); if (parsedUnit != null) { TypeDeclaration typeDecl = new ASTNodeFinder(parsedUnit).findType(this.type); if (typeDecl != null && typeDecl.binding != null) collectSuperTypeNames(typeDecl.binding); } } } catch (AbortCompilation e) { // problem with classpath: report inacurrate matches return null; } if (this.result.length > this.resultIndex) System.arraycopy( this.result, 0, this.result = new char[this.resultIndex][][], 0, this.resultIndex); return this.result; } // Collect the paths of the cus that declare a type which matches declaringQualification + // declaringSimpleName String[] paths = this.getPathsOfDeclaringType(); if (paths == null) return null; // Create bindings from source types and binary types and collect super type names of the type // declaration // that match the given declaring type Util.sort(paths); // sort by projects JavaProject previousProject = null; this.result = new char[1][][]; this.resultIndex = 0; for (int i = 0, length = paths.length; i < length; i++) { try { Openable openable = this.locator.handleFactory.createOpenable(paths[i], this.locator.scope); if (openable == null) continue; // outside classpath IJavaProject project = openable.getJavaProject(); if (!project.equals(previousProject)) { previousProject = (JavaProject) project; this.locator.initialize(previousProject, 0); } if (openable instanceof ICompilationUnit) { ICompilationUnit unit = (ICompilationUnit) openable; CompilationUnitDeclaration parsedUnit = buildBindings( unit, true /*only toplevel and member types are visible to the focus type*/); if (parsedUnit != null) parsedUnit.traverse(new TypeDeclarationVisitor(), parsedUnit.scope); } else if (openable instanceof IClassFile) { IClassFile classFile = (IClassFile) openable; BinaryTypeBinding binding = this.locator.cacheBinaryType(classFile.getType(), null); if (matches(binding)) collectSuperTypeNames(binding); } } catch (AbortCompilation e) { // ignore: continue with next element } catch (JavaModelException e) { // ignore: continue with next element } } if (this.result.length > this.resultIndex) System.arraycopy( this.result, 0, this.result = new char[this.resultIndex][][], 0, this.resultIndex); return this.result; }
/** Locate declaration in the current class file. This class file is always in a jar. */ public void locateMatches(MatchLocator locator, ClassFile classFile, IBinaryType info) throws CoreException { SearchPattern pattern = locator.pattern; // check annotations references matchAnnotations(pattern, locator, classFile, info); // check class definition BinaryType binaryType = (BinaryType) classFile.getType(); if (matchBinary(pattern, info, null)) { binaryType = new ResolvedBinaryType( (JavaElement) binaryType.getParent(), binaryType.getElementName(), binaryType.getKey()); locator.reportBinaryMemberDeclaration(null, binaryType, null, info, SearchMatch.A_ACCURATE); return; } // Define arrays to store methods/fields from binary type if necessary IBinaryMethod[] binaryMethods = info.getMethods(); int bMethodsLength = binaryMethods == null ? 0 : binaryMethods.length; IBinaryMethod[] unresolvedMethods = null; char[][] binaryMethodSignatures = null; boolean hasUnresolvedMethods = false; // Get fields from binary type info IBinaryField[] binaryFields = info.getFields(); int bFieldsLength = binaryFields == null ? 0 : binaryFields.length; IBinaryField[] unresolvedFields = null; boolean hasUnresolvedFields = false; // Report as many accurate matches as possible int accuracy = SearchMatch.A_ACCURATE; boolean mustResolve = pattern.mustResolve; if (mustResolve) { BinaryTypeBinding binding = locator.cacheBinaryType(binaryType, info); if (binding != null) { // filter out element not in hierarchy scope if (!locator.typeInHierarchy(binding)) return; // Search matches on resolved methods MethodBinding[] availableMethods = binding.availableMethods(); int aMethodsLength = availableMethods == null ? 0 : availableMethods.length; hasUnresolvedMethods = bMethodsLength != aMethodsLength; for (int i = 0; i < aMethodsLength; i++) { MethodBinding method = availableMethods[i]; char[] methodSignature = method.genericSignature(); if (methodSignature == null) methodSignature = method.signature(); // Report the match if possible int level = locator.patternLocator.resolveLevel(method); if (level != PatternLocator.IMPOSSIBLE_MATCH) { IMethod methodHandle = binaryType.getMethod( new String( method.isConstructor() ? binding.compoundName[binding.compoundName.length - 1] : method.selector), CharOperation.toStrings( Signature.getParameterTypes(convertClassFileFormat(methodSignature)))); accuracy = level == PatternLocator.ACCURATE_MATCH ? SearchMatch.A_ACCURATE : SearchMatch.A_INACCURATE; locator.reportBinaryMemberDeclaration(null, methodHandle, method, info, accuracy); } // Remove method from unresolved list if (hasUnresolvedMethods) { if (binaryMethodSignatures == null) { // Store binary method signatures to avoid multiple computation binaryMethodSignatures = new char[bMethodsLength][]; for (int j = 0; j < bMethodsLength; j++) { IBinaryMethod binaryMethod = binaryMethods[j]; char[] signature = binaryMethod.getGenericSignature(); if (signature == null) signature = binaryMethod.getMethodDescriptor(); binaryMethodSignatures[j] = signature; } } for (int j = 0; j < bMethodsLength; j++) { if (CharOperation.equals(binaryMethods[j].getSelector(), method.selector) && CharOperation.equals(binaryMethodSignatures[j], methodSignature)) { if (unresolvedMethods == null) { System.arraycopy( binaryMethods, 0, unresolvedMethods = new IBinaryMethod[bMethodsLength], 0, bMethodsLength); } unresolvedMethods[j] = null; break; } } } } // Search matches on resolved fields FieldBinding[] availableFields = binding.availableFields(); int aFieldsLength = availableFields == null ? 0 : availableFields.length; hasUnresolvedFields = bFieldsLength != aFieldsLength; for (int i = 0; i < aFieldsLength; i++) { FieldBinding field = availableFields[i]; // Report the match if possible int level = locator.patternLocator.resolveLevel(field); if (level != PatternLocator.IMPOSSIBLE_MATCH) { IField fieldHandle = binaryType.getField(new String(field.name)); accuracy = level == PatternLocator.ACCURATE_MATCH ? SearchMatch.A_ACCURATE : SearchMatch.A_INACCURATE; locator.reportBinaryMemberDeclaration(null, fieldHandle, field, info, accuracy); } // Remove the field from unresolved list if (hasUnresolvedFields) { for (int j = 0; j < bFieldsLength; j++) { if (CharOperation.equals(binaryFields[j].getName(), field.name)) { if (unresolvedFields == null) { System.arraycopy( binaryFields, 0, unresolvedFields = new IBinaryField[bFieldsLength], 0, bFieldsLength); } unresolvedFields[j] = null; break; } } } } // If all methods/fields were accurate then returns now if (!hasUnresolvedMethods && !hasUnresolvedFields) { return; } } accuracy = SearchMatch.A_INACCURATE; } // Report inaccurate methods if (mustResolve) binaryMethods = unresolvedMethods; bMethodsLength = binaryMethods == null ? 0 : binaryMethods.length; for (int i = 0; i < bMethodsLength; i++) { IBinaryMethod method = binaryMethods[i]; if (method == null) continue; // impossible match or already reported as accurate if (matchBinary(pattern, method, info)) { char[] name; if (method.isConstructor()) { name = info.getName(); int lastSlash = CharOperation.lastIndexOf('/', name); if (lastSlash != -1) { name = CharOperation.subarray(name, lastSlash + 1, name.length); } } else { name = method.getSelector(); } String selector = new String(name); char[] methodSignature = binaryMethodSignatures == null ? null : binaryMethodSignatures[i]; if (methodSignature == null) { methodSignature = method.getGenericSignature(); if (methodSignature == null) methodSignature = method.getMethodDescriptor(); } String[] parameterTypes = CharOperation.toStrings( Signature.getParameterTypes(convertClassFileFormat(methodSignature))); IMethod methodHandle = binaryType.getMethod(selector, parameterTypes); methodHandle = new ResolvedBinaryMethod(binaryType, selector, parameterTypes, methodHandle.getKey()); locator.reportBinaryMemberDeclaration(null, methodHandle, null, info, accuracy); } } // Report inaccurate fields if (mustResolve) binaryFields = unresolvedFields; bFieldsLength = binaryFields == null ? 0 : binaryFields.length; for (int i = 0; i < bFieldsLength; i++) { IBinaryField field = binaryFields[i]; if (field == null) continue; // impossible match or already reported as accurate if (matchBinary(pattern, field, info)) { String fieldName = new String(field.getName()); IField fieldHandle = binaryType.getField(fieldName); fieldHandle = new ResolvedBinaryField(binaryType, fieldName, fieldHandle.getKey()); locator.reportBinaryMemberDeclaration(null, fieldHandle, null, info, accuracy); } } }
public TypeReference getTypeReference(int dim) { /* build a Reference on a variable that may be qualified or not * This variable is a type reference and dim will be its dimensions */ Annotation[][] annotationsOnDimensions = null; TypeReference ref; int length = this.identifierLengthStack[this.identifierLengthPtr--]; if (length < 0) { // flag for precompiled type reference on base types annotationsOnDimensions = getAnnotationsOnDimensions(dim); ref = TypeReference.baseTypeReference(-length, dim, annotationsOnDimensions); ref.sourceStart = this.intStack[this.intPtr--]; if (dim == 0) { ref.sourceEnd = this.intStack[this.intPtr--]; } else { this.intPtr--; // no need to use this position as it is an array ref.sourceEnd = this.rBracketPosition; } if (this.reportReferenceInfo) { this.requestor.acceptTypeReference( ref.getParameterizedTypeName(), ref.sourceStart, ref.sourceEnd); } } else { int numberOfIdentifiers = this.genericsIdentifiersLengthStack[this.genericsIdentifiersLengthPtr--]; if (length != numberOfIdentifiers || this.genericsLengthStack[this.genericsLengthPtr] != 0) { // generic type ref = getTypeReferenceForGenericType(dim, length, numberOfIdentifiers); if (this.reportReferenceInfo) { if (length == 1 && numberOfIdentifiers == 1) { ParameterizedSingleTypeReference parameterizedSingleTypeReference = (ParameterizedSingleTypeReference) ref; this.requestor.acceptTypeReference( parameterizedSingleTypeReference.token, parameterizedSingleTypeReference.sourceStart); } else { ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference = (ParameterizedQualifiedTypeReference) ref; this.requestor.acceptTypeReference( parameterizedQualifiedTypeReference.tokens, parameterizedQualifiedTypeReference.sourceStart, parameterizedQualifiedTypeReference.sourceEnd); } } } else if (length == 1) { // single type reference this.genericsLengthPtr--; // pop the 0 if (dim == 0) { ref = new SingleTypeReference( this.identifierStack[this.identifierPtr], this.identifierPositionStack[this.identifierPtr--]); if (this.reportReferenceInfo) { this.requestor.acceptTypeReference(((SingleTypeReference) ref).token, ref.sourceStart); } } else { annotationsOnDimensions = getAnnotationsOnDimensions(dim); ref = new ArrayTypeReference( this.identifierStack[this.identifierPtr], dim, annotationsOnDimensions, this.identifierPositionStack[this.identifierPtr--]); ref.sourceEnd = this.endPosition; if (annotationsOnDimensions != null) { ref.bits |= ASTNode.HasTypeAnnotations; } if (this.reportReferenceInfo) { this.requestor.acceptTypeReference(((ArrayTypeReference) ref).token, ref.sourceStart); } } } else { // Qualified type reference this.genericsLengthPtr--; char[][] tokens = new char[length][]; this.identifierPtr -= length; long[] positions = new long[length]; System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length); System.arraycopy( this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length); if (dim == 0) { ref = new QualifiedTypeReference(tokens, positions); if (this.reportReferenceInfo) { this.requestor.acceptTypeReference( ((QualifiedTypeReference) ref).tokens, ref.sourceStart, ref.sourceEnd); } } else { annotationsOnDimensions = getAnnotationsOnDimensions(dim); ref = new ArrayQualifiedTypeReference(tokens, dim, annotationsOnDimensions, positions); ref.sourceEnd = this.endPosition; if (annotationsOnDimensions != null) { ref.bits |= ASTNode.HasTypeAnnotations; } if (this.reportReferenceInfo) { this.requestor.acceptTypeReference( ((ArrayQualifiedTypeReference) ref).tokens, ref.sourceStart, ref.sourceEnd); } } } } int levels = ref.getAnnotatableLevels(); for (int i = levels - 1; i >= 0; i--) { if ((length = this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr--]) != 0) { if (ref.annotations == null) ref.annotations = new Annotation[levels][]; System.arraycopy( this.typeAnnotationStack, (this.typeAnnotationPtr -= length) + 1, ref.annotations[i] = new Annotation[length], 0, length); if (i == 0) { ref.sourceStart = ref.annotations[0][0].sourceStart; } ref.bits |= ASTNode.HasTypeAnnotations; } } return ref; }
/** * Resolve annotations, and check duplicates, answers combined tagBits for recognized standard * annotations */ public static void resolveAnnotations( BlockScope scope, Annotation[] sourceAnnotations, Binding recipient) { AnnotationBinding[] annotations = null; int length = sourceAnnotations == null ? 0 : sourceAnnotations.length; if (recipient != null) { switch (recipient.kind()) { case Binding.PACKAGE: PackageBinding packageBinding = (PackageBinding) recipient; if ((packageBinding.tagBits & TagBits.AnnotationResolved) != 0) return; packageBinding.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved); break; case Binding.TYPE: case Binding.GENERIC_TYPE: ReferenceBinding type = (ReferenceBinding) recipient; if ((type.tagBits & TagBits.AnnotationResolved) != 0) return; type.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved); if (length > 0) { annotations = new AnnotationBinding[length]; type.setAnnotations(annotations); } break; case Binding.METHOD: MethodBinding method = (MethodBinding) recipient; if ((method.tagBits & TagBits.AnnotationResolved) != 0) return; method.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved); if (length > 0) { annotations = new AnnotationBinding[length]; method.setAnnotations(annotations); } break; case Binding.FIELD: FieldBinding field = (FieldBinding) recipient; if ((field.tagBits & TagBits.AnnotationResolved) != 0) return; field.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved); if (length > 0) { annotations = new AnnotationBinding[length]; field.setAnnotations(annotations); } break; case Binding.LOCAL: LocalVariableBinding local = (LocalVariableBinding) recipient; if ((local.tagBits & TagBits.AnnotationResolved) != 0) return; local.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved); if (length > 0) { annotations = new AnnotationBinding[length]; local.setAnnotations(annotations); } break; default: return; } } if (sourceAnnotations == null) return; for (int i = 0; i < length; i++) { Annotation annotation = sourceAnnotations[i]; final Binding annotationRecipient = annotation.recipient; if (annotationRecipient != null && recipient != null) { // only local and field can share annnotations switch (recipient.kind()) { case Binding.FIELD: FieldBinding field = (FieldBinding) recipient; field.tagBits = ((FieldBinding) annotationRecipient).tagBits; break; case Binding.LOCAL: LocalVariableBinding local = (LocalVariableBinding) recipient; local.tagBits = ((LocalVariableBinding) annotationRecipient).tagBits; break; } if (annotations != null) { // need to fill the instances array annotations[0] = annotation.getCompilerAnnotation(); for (int j = 1; j < length; j++) { Annotation annot = sourceAnnotations[j]; annotations[j] = annot.getCompilerAnnotation(); } } return; } else { annotation.recipient = recipient; annotation.resolveType(scope); // null if receiver is a package binding if (annotations != null) { annotations[i] = annotation.getCompilerAnnotation(); } } } // check duplicate annotations if (annotations != null) { AnnotationBinding[] distinctAnnotations = annotations; // only copy after 1st duplicate is detected for (int i = 0; i < length; i++) { AnnotationBinding annotation = distinctAnnotations[i]; if (annotation == null) continue; TypeBinding annotationType = annotation.getAnnotationType(); boolean foundDuplicate = false; for (int j = i + 1; j < length; j++) { AnnotationBinding otherAnnotation = distinctAnnotations[j]; if (otherAnnotation == null) continue; if (otherAnnotation.getAnnotationType() == annotationType) { foundDuplicate = true; if (distinctAnnotations == annotations) { System.arraycopy( distinctAnnotations, 0, distinctAnnotations = new AnnotationBinding[length], 0, length); } distinctAnnotations[j] = null; // report it only once scope.problemReporter().duplicateAnnotation(sourceAnnotations[j]); } } if (foundDuplicate) { scope.problemReporter().duplicateAnnotation(sourceAnnotations[i]); } } } }
public TypeReference getTypeReference(int dim) { /* build a Reference on a variable that may be qualified or not * This variable is a type reference and dim will be its dimensions */ int length = this.identifierLengthStack[this.identifierLengthPtr--]; if (length < 0) { // flag for precompiled type reference on base types TypeReference ref = TypeReference.baseTypeReference(-length, dim); ref.sourceStart = this.intStack[this.intPtr--]; if (dim == 0) { ref.sourceEnd = this.intStack[this.intPtr--]; } else { this.intPtr--; // no need to use this position as it is an array ref.sourceEnd = this.endPosition; } if (this.reportReferenceInfo) { this.requestor.acceptTypeReference( ref.getParameterizedTypeName(), ref.sourceStart, ref.sourceEnd); } return ref; } else { int numberOfIdentifiers = this.genericsIdentifiersLengthStack[this.genericsIdentifiersLengthPtr--]; if (length != numberOfIdentifiers || this.genericsLengthStack[this.genericsLengthPtr] != 0) { // generic type TypeReference ref = getTypeReferenceForGenericType(dim, length, numberOfIdentifiers); if (this.reportReferenceInfo) { if (length == 1 && numberOfIdentifiers == 1) { ParameterizedSingleTypeReference parameterizedSingleTypeReference = (ParameterizedSingleTypeReference) ref; this.requestor.acceptTypeReference( parameterizedSingleTypeReference.token, parameterizedSingleTypeReference.sourceStart); } else { ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference = (ParameterizedQualifiedTypeReference) ref; this.requestor.acceptTypeReference( parameterizedQualifiedTypeReference.tokens, parameterizedQualifiedTypeReference.sourceStart, parameterizedQualifiedTypeReference.sourceEnd); } } return ref; } else if (length == 1) { // single variable reference this.genericsLengthPtr--; // pop the 0 if (dim == 0) { SingleTypeReference ref = new SingleTypeReference( this.identifierStack[this.identifierPtr], this.identifierPositionStack[this.identifierPtr--]); if (this.reportReferenceInfo) { this.requestor.acceptTypeReference(ref.token, ref.sourceStart); } return ref; } else { ArrayTypeReference ref = new ArrayTypeReference( this.identifierStack[this.identifierPtr], dim, this.identifierPositionStack[this.identifierPtr--]); ref.sourceEnd = this.endPosition; if (this.reportReferenceInfo) { this.requestor.acceptTypeReference(ref.token, ref.sourceStart); } return ref; } } else { // Qualified variable reference this.genericsLengthPtr--; char[][] tokens = new char[length][]; this.identifierPtr -= length; long[] positions = new long[length]; System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length); System.arraycopy( this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length); if (dim == 0) { QualifiedTypeReference ref = new QualifiedTypeReference(tokens, positions); if (this.reportReferenceInfo) { this.requestor.acceptTypeReference(ref.tokens, ref.sourceStart, ref.sourceEnd); } return ref; } else { ArrayQualifiedTypeReference ref = new ArrayQualifiedTypeReference(tokens, dim, positions); ref.sourceEnd = this.endPosition; if (this.reportReferenceInfo) { this.requestor.acceptTypeReference(ref.tokens, ref.sourceStart, ref.sourceEnd); } return ref; } } } }