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;
  }
Exemple #8
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
 }
  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;
  }
Exemple #10
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;
  }
  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);
  }
Exemple #12
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;
  }
  /**
   * @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;
  }
Exemple #14
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 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;
 }
Exemple #18
0
 /**
  * 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;
       }
     }
   }
 }