public TypeReferencePattern(char[] qualification, char[] simpleName, int matchRule) {
    this(matchRule);

    this.qualification =
        this.isCaseSensitive ? qualification : CharOperation.toLowerCase(qualification);
    this.simpleName =
        (this.isCaseSensitive || this.isCamelCase)
            ? simpleName
            : CharOperation.toLowerCase(simpleName);

    if (simpleName == null)
      this.segments =
          this.qualification == null
              ? ONE_STAR_CHAR
              : CharOperation.splitOn('.', this.qualification);
    else this.segments = null;

    if (this.segments == null)
      if (this.qualification == null) this.segmentsSize = 0;
      else this.segmentsSize = CharOperation.occurencesOf('.', this.qualification) + 1;
    else this.segmentsSize = this.segments.length;

    this.mustResolve =
        true; // always resolve (in case of a simple name reference being a potential match)
  }
 /*
  * Instanciate a type reference pattern with additional information for generics search, search elements nature and fine grain information
  */
 public TypeReferencePattern(
     char[] qualification,
     char[] simpleName,
     String typeSignature,
     int limitTo,
     char typeSuffix,
     int matchRule) {
   this(qualification, simpleName, matchRule);
   this.typeSuffix = typeSuffix;
   if (typeSignature != null) {
     // store type signatures and arguments
     this.typeSignatures = Util.splitTypeLevelsSignature(typeSignature);
     setTypeArguments(Util.getAllTypeArguments(this.typeSignatures));
     if (hasTypeArguments()) {
       this.segmentsSize =
           getTypeArguments().length + CharOperation.occurencesOf('/', this.typeSignatures[0]) - 1;
     }
   }
   this.fineGrain = limitTo & 0xFFFFFFF0;
   if (this.fineGrain == IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE) {
     this.categories = CATEGORIES_ANNOT_REF;
   }
 }
  /**
   * In case emulating local variables, wrap the (recovered) statements inside a try statement so as
   * to achieve local state commiting (copy local vars back to fields). The CSToCuMapper could not
   * be used, since it could have interfered with the syntax recovery specific to code snippets.
   */
  protected void consumeMethodDeclaration(boolean isNotAbstract) {
    // MethodDeclaration ::= MethodHeader MethodBody
    // AbstractMethodDeclaration ::= MethodHeader ';'

    super.consumeMethodDeclaration(isNotAbstract);

    // now we know that we have a method declaration at the top of the ast stack
    MethodDeclaration methodDecl = (MethodDeclaration) this.astStack[this.astPtr];

    // automatically wrap the last statement inside a return statement, if it is an expression
    // support have to be defined at toplevel only
    if (this.isTopLevelType()) {
      int last = methodDecl.statements == null ? -1 : methodDecl.statements.length - 1;
      if (last >= 0 && methodDecl.statements[last] instanceof Expression) {
        Expression lastExpression = (Expression) methodDecl.statements[last];
        methodDecl.statements[last] =
            new CodeSnippetReturnStatement(
                lastExpression, lastExpression.sourceStart, lastExpression.sourceEnd);
      }
    }

    int start = methodDecl.bodyStart - 1, end = start;
    long position = ((long) start << 32) + end;
    long[] positions = new long[] {position};
    if (this.evaluationContext.localVariableNames != null) {

      int varCount =
          this.evaluationContext.localVariableNames.length; // n local decls+ try statement

      // generate n local variable declarations: [type] [name] = val$[name];
      Statement[] newStatements = new Statement[varCount + 1];
      for (int i = 0; i < varCount; i++) {
        char[] trimmedTypeName = this.evaluationContext.localVariableTypeNames[i];
        int nameEnd = CharOperation.indexOf('[', trimmedTypeName);
        if (nameEnd >= 0) {
          trimmedTypeName = CharOperation.subarray(trimmedTypeName, 0, nameEnd);
        }
        nameEnd = CharOperation.indexOf(' ', trimmedTypeName);
        if (nameEnd >= 0) {
          trimmedTypeName = CharOperation.subarray(trimmedTypeName, 0, nameEnd);
        }
        TypeReference typeReference =
            new QualifiedTypeReference(CharOperation.splitOn('.', trimmedTypeName), positions);
        int dimCount =
            CharOperation.occurencesOf('[', this.evaluationContext.localVariableTypeNames[i]);
        if (dimCount > 0) {
          typeReference = this.copyDims(typeReference, dimCount);
        }
        NameReference init =
            new SingleNameReference(
                CharOperation.concat(
                    LOCAL_VAR_PREFIX, this.evaluationContext.localVariableNames[i]),
                position);
        LocalDeclaration declaration =
            new LocalDeclaration(this.evaluationContext.localVariableNames[i], start, end);
        declaration.initialization = init;
        declaration.type = typeReference;
        declaration.modifiers = this.evaluationContext.localVariableModifiers[i];
        newStatements[i] = declaration;
      }

      // generate try { [snippet] } finally { [save locals to fields] }
      // try block
      TryStatement tryStatement = new TryStatement();
      Block tryBlock = new Block(methodDecl.explicitDeclarations);
      tryBlock.sourceStart = start;
      tryBlock.sourceEnd = end;
      tryBlock.statements = methodDecl.statements; // snippet statements
      tryStatement.tryBlock = tryBlock;
      // finally block
      Block finallyBlock = new Block(0);
      finallyBlock.sourceStart = start;
      finallyBlock.sourceEnd = end;
      finallyBlock.statements = new Statement[varCount];
      for (int i = 0; i < varCount; i++) {
        finallyBlock.statements[i] =
            new Assignment(
                new SingleNameReference(
                    CharOperation.concat(
                        LOCAL_VAR_PREFIX, this.evaluationContext.localVariableNames[i]),
                    position),
                new SingleNameReference(this.evaluationContext.localVariableNames[i], position),
                (int) position);
      }
      tryStatement.finallyBlock = finallyBlock;

      newStatements[varCount] = tryStatement;
      methodDecl.statements = newStatements;
    }
  }