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);
      }
    }
  }
Example #4
0
  /**
   * 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;
  }
Example #7
0
 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
 }
Example #8
0
  /** 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;
  }
Example #9
0
  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;
  }
Example #10
0
  /**
   * 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);
      }
    }
  }