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; } }
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); } } }
/** * 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(); }
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 }
/** 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 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; }
/** * 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 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; }
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; } } } }
/** 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); } } }