Package org.eclipse.jdt.internal.compiler.ast

Source Code of org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration

/*******************************************************************************
* Copyright (c) 2000, 2014 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*     Stephan Herrmann  - Contribution for bug 295551
*     Jesper S Moller   - Contributions for
*                Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335            
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;

import java.util.Arrays;
import java.util.Comparator;

import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.ClassFile;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.impl.IrritantSet;
import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.eclipse.jdt.internal.compiler.lookup.ImportBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.jdt.internal.compiler.parser.NLSTag;
import org.eclipse.jdt.internal.compiler.problem.AbortCompilationUnit;
import org.eclipse.jdt.internal.compiler.problem.AbortMethod;
import org.eclipse.jdt.internal.compiler.problem.AbortType;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
import org.eclipse.jdt.internal.compiler.util.HashSetOfInt;

@SuppressWarnings({ "rawtypes", "unchecked" })
public class CompilationUnitDeclaration extends ASTNode implements ProblemSeverities, ReferenceContext {

  private static final Comparator STRING_LITERAL_COMPARATOR = new Comparator() {
    public int compare(Object o1, Object o2) {
      StringLiteral literal1 = (StringLiteral) o1;
      StringLiteral literal2 = (StringLiteral) o2;
      return literal1.sourceStart - literal2.sourceStart;
    }
  };
  private static final int STRING_LITERALS_INCREMENT = 10;

  public ImportReference currentPackage;
  public ImportReference[] imports;
  public TypeDeclaration[] types;
  public int[][] comments;

  public boolean ignoreFurtherInvestigation = false; // once pointless to investigate due to errors
  public boolean ignoreMethodBodies = false;
  public CompilationUnitScope scope;
  public ProblemReporter problemReporter;
  public CompilationResult compilationResult;

  public LocalTypeBinding[] localTypes;
  public int localTypeCount = 0;

  public boolean isPropagatingInnerClassEmulation;

  public Javadoc javadoc; // 1.5 addition for package-info.java

  public NLSTag[] nlsTags;
  private StringLiteral[] stringLiterals;
  private int stringLiteralsPtr;
  private HashSetOfInt stringLiteralsStart;

  public boolean[] validIdentityComparisonLines;

  IrritantSet[] suppressWarningIrritants;  // irritant for suppressed warnings
  Annotation[] suppressWarningAnnotations;
  long[] suppressWarningScopePositions; // (start << 32) + end
  int suppressWarningsCount;
  public int functionalExpressionsCount;
  public FunctionalExpression[] functionalExpressions;

public CompilationUnitDeclaration(ProblemReporter problemReporter, CompilationResult compilationResult, int sourceLength) {
  this.problemReporter = problemReporter;
  this.compilationResult = compilationResult;
  //by definition of a compilation unit....
  this.sourceStart = 0;
  this.sourceEnd = sourceLength - 1;
}

/*
*  We cause the compilation task to abort to a given extent.
*/
public void abort(int abortLevel, CategorizedProblem problem) {
  switch (abortLevel) {
    case AbortType :
      throw new AbortType(this.compilationResult, problem);
    case AbortMethod :
      throw new AbortMethod(this.compilationResult, problem);
    default :
      throw new AbortCompilationUnit(this.compilationResult, problem);
  }
}

/*
* Dispatch code analysis AND request saturation of inner emulation
*/
public void analyseCode() {
  if (this.ignoreFurtherInvestigation)
    return;
  try {
    if (this.types != null) {
      for (int i = 0, count = this.types.length; i < count; i++) {
        this.types[i].analyseCode(this.scope);
      }
    }
    // request inner emulation propagation
    propagateInnerEmulationForAllLocalTypes();
  } catch (AbortCompilationUnit e) {
    this.ignoreFurtherInvestigation = true;
    return;
  }
}

/*
* When unit result is about to be accepted, removed back pointers
* to compiler structures.
*/
public void cleanUp() {
  if (this.types != null) {
    for (int i = 0, max = this.types.length; i < max; i++) {
      cleanUp(this.types[i]);
    }
    for (int i = 0, max = this.localTypeCount; i < max; i++) {
        LocalTypeBinding localType = this.localTypes[i];
      // null out the type's scope backpointers
      localType.scope = null; // local members are already in the list
      localType.enclosingCase = null;
    }
  }

  this.compilationResult.recoveryScannerData = null; // recovery is already done

  ClassFile[] classFiles = this.compilationResult.getClassFiles();
  for (int i = 0, max = classFiles.length; i < max; i++) {
    // clear the classFile back pointer to the bindings
    ClassFile classFile = classFiles[i];
    // null out the classfile backpointer to a type binding
    classFile.referenceBinding = null;
    classFile.innerClassesBindings = null;
    classFile.bootstrapMethods = null;
    classFile.missingTypes = null;
    classFile.visitedTypes = null;
  }

  this.suppressWarningAnnotations = null;
}

private void cleanUp(TypeDeclaration type) {
  if (type.memberTypes != null) {
    for (int i = 0, max = type.memberTypes.length; i < max; i++){
      cleanUp(type.memberTypes[i]);
    }
  }
  if (type.binding != null && type.binding.isAnnotationType())
    this.compilationResult.hasAnnotations = true;
  if (type.binding != null) {
    // null out the type's scope backpointers
    type.binding.scope = null;
  }
}

public void checkUnusedImports(){
  if (this.scope.imports != null){
    for (int i = 0, max = this.scope.imports.length; i < max; i++){
      ImportBinding importBinding = this.scope.imports[i];
      ImportReference importReference = importBinding.reference;
      if (importReference != null && ((importReference.bits & ASTNode.Used) == 0)){
        this.scope.problemReporter().unusedImport(importReference);
      }
    }
  }
}

public CompilationResult compilationResult() {
  return this.compilationResult;
}

public void createPackageInfoType() {
  TypeDeclaration declaration = new TypeDeclaration(this.compilationResult);
  declaration.name = TypeConstants.PACKAGE_INFO_NAME;
  declaration.modifiers = ClassFileConstants.AccDefault | ClassFileConstants.AccInterface;
  declaration.javadoc = this.javadoc;
  this.types[0] = declaration; // Assumes the first slot is meant for this type
}

/*
* Finds the matching type amoung this compilation unit types.
* Returns null if no type with this name is found.
* The type name is a compound name
* e.g. if we're looking for X.A.B then a type name would be {X, A, B}
*/
public TypeDeclaration declarationOfType(char[][] typeName) {
  for (int i = 0; i < this.types.length; i++) {
    TypeDeclaration typeDecl = this.types[i].declarationOfType(typeName);
    if (typeDecl != null) {
      return typeDecl;
    }
  }
  return null;
}

public void finalizeProblems() {
  if (this.suppressWarningsCount == 0) return;
  int removed = 0;
  CategorizedProblem[] problems = this.compilationResult.problems;
  int problemCount = this.compilationResult.problemCount;
  IrritantSet[] foundIrritants = new IrritantSet[this.suppressWarningsCount];
  CompilerOptions options = this.scope.compilerOptions();
  boolean hasMandatoryErrors = false;
  nextProblem: for (int iProblem = 0, length = problemCount; iProblem < length; iProblem++) {
    CategorizedProblem problem = problems[iProblem];
    int problemID = problem.getID();
    int irritant = ProblemReporter.getIrritant(problemID);
    boolean isError = problem.isError();
    if (isError) {
      if (irritant == 0) {
        // tolerate unused warning tokens when mandatory errors
        hasMandatoryErrors = true;
        continue;
      }
      if (!options.suppressOptionalErrors) {
        continue;
      }
    }
    int start = problem.getSourceStart();
    int end = problem.getSourceEnd();
    nextSuppress: for (int iSuppress = 0, suppressCount = this.suppressWarningsCount; iSuppress < suppressCount; iSuppress++) {
      long position = this.suppressWarningScopePositions[iSuppress];
      int startSuppress = (int) (position >>> 32);
      int endSuppress = (int) position;
      if (start < startSuppress) continue nextSuppress;
      if (end > endSuppress) continue nextSuppress;
      if (!this.suppressWarningIrritants[iSuppress].isSet(irritant))
        continue nextSuppress;
      // discard suppressed warning
      removed++;
      problems[iProblem] = null;
      this.compilationResult.removeProblem(problem);
      if (foundIrritants[iSuppress] == null){
        foundIrritants[iSuppress] = new IrritantSet(irritant);
      } else {
        foundIrritants[iSuppress].set(irritant);
      }
      continue nextProblem;
    }
  }
  // compact remaining problems
  if (removed > 0) {
    for (int i = 0, index = 0; i < problemCount; i++) {
      CategorizedProblem problem;
      if ((problem = problems[i]) != null) {
        if (i > index) {
          problems[index++] = problem;
        } else {
          index++;
        }
      }
    }
  }
  // flag SuppressWarnings which had no effect (only if no (mandatory) error got detected within unit
  if (!hasMandatoryErrors) {
    int severity = options.getSeverity(CompilerOptions.UnusedWarningToken);
    if (severity != ProblemSeverities.Ignore) {
      boolean unusedWarningTokenIsWarning = (severity & ProblemSeverities.Error) == 0;
      for (int iSuppress = 0, suppressCount = this.suppressWarningsCount; iSuppress < suppressCount; iSuppress++) {
        Annotation annotation = this.suppressWarningAnnotations[iSuppress];
        if (annotation == null) continue; // implicit annotation
        IrritantSet irritants = this.suppressWarningIrritants[iSuppress];
        if (unusedWarningTokenIsWarning && irritants.areAllSet()) continue; // @SuppressWarnings("all") also suppresses unused warning token
        if (irritants != foundIrritants[iSuppress]) { // mismatch, some warning tokens were unused
          MemberValuePair[] pairs = annotation.memberValuePairs();
          pairLoop: for (int iPair = 0, pairCount = pairs.length; iPair < pairCount; iPair++) {
            MemberValuePair pair = pairs[iPair];
            if (CharOperation.equals(pair.name, TypeConstants.VALUE)) {
              Expression value = pair.value;
              if (value instanceof ArrayInitializer) {
                ArrayInitializer initializer = (ArrayInitializer) value;
                Expression[] inits = initializer.expressions;
                if (inits != null) {
                  for (int iToken = 0, tokenCount = inits.length; iToken < tokenCount; iToken++) {
                    Constant cst = inits[iToken].constant;
                    if (cst != Constant.NotAConstant && cst.typeID() == TypeIds.T_JavaLangString) {
                      IrritantSet tokenIrritants = CompilerOptions.warningTokenToIrritants(cst.stringValue());
                      if (tokenIrritants != null
                          && !tokenIrritants.areAllSet() // no complaint against @SuppressWarnings("all")
                          && options.isAnyEnabled(tokenIrritants) // if irritant is effectively enabled
                          && (foundIrritants[iSuppress] == null || !foundIrritants[iSuppress].isAnySet(tokenIrritants))) { // if irritant had no matching problem
                        if (unusedWarningTokenIsWarning) {
                          int start = value.sourceStart, end = value.sourceEnd;
                          nextSuppress: for (int jSuppress = iSuppress - 1; jSuppress >= 0; jSuppress--) {
                            long position = this.suppressWarningScopePositions[jSuppress];
                            int startSuppress = (int) (position >>> 32);
                            int endSuppress = (int) position;
                            if (start < startSuppress) continue nextSuppress;
                            if (end > endSuppress) continue nextSuppress;
                            if (this.suppressWarningIrritants[jSuppress].areAllSet()) break pairLoop; // suppress all?
                          }
                        }
                        this.scope.problemReporter().unusedWarningToken(inits[iToken]);
                      }
                    }
                  }
                }
              } else {
                Constant cst = value.constant;
                if (cst != Constant.NotAConstant && cst.typeID() == T_JavaLangString) {
                  IrritantSet tokenIrritants = CompilerOptions.warningTokenToIrritants(cst.stringValue());
                  if (tokenIrritants != null
                      && !tokenIrritants.areAllSet() // no complaint against @SuppressWarnings("all")
                      && options.isAnyEnabled(tokenIrritants) // if irritant is effectively enabled
                      && (foundIrritants[iSuppress] == null || !foundIrritants[iSuppress].isAnySet(tokenIrritants))) { // if irritant had no matching problem
                    if (unusedWarningTokenIsWarning) {
                      int start = value.sourceStart, end = value.sourceEnd;
                      nextSuppress: for (int jSuppress = iSuppress - 1; jSuppress >= 0; jSuppress--) {
                        long position = this.suppressWarningScopePositions[jSuppress];
                        int startSuppress = (int) (position >>> 32);
                        int endSuppress = (int) position;
                        if (start < startSuppress) continue nextSuppress;
                        if (end > endSuppress) continue nextSuppress;
                        if (this.suppressWarningIrritants[jSuppress].areAllSet()) break pairLoop; // suppress all?
                      }
                    }
                    this.scope.problemReporter().unusedWarningToken(value);
                  }
                }
              }
              break pairLoop;
            }
          }
        }
      }
    }
  }
}

/**
* Bytecode generation
*/
public void generateCode() {
  if (this.ignoreFurtherInvestigation) {
    if (this.types != null) {
      for (int i = 0, count = this.types.length; i < count; i++) {
        this.types[i].ignoreFurtherInvestigation = true;
        // propagate the flag to request problem type creation
        this.types[i].generateCode(this.scope);
      }
    }
    return;
  }
  try {
    if (this.types != null) {
      for (int i = 0, count = this.types.length; i < count; i++)
        this.types[i].generateCode(this.scope);
    }
  } catch (AbortCompilationUnit e) {
    // ignore
  }
}

public CompilationUnitDeclaration getCompilationUnitDeclaration() {
  return this;
}

public char[] getFileName() {
  return this.compilationResult.getFileName();
}

public char[] getMainTypeName() {
  if (this.compilationResult.compilationUnit == null) {
    char[] fileName = this.compilationResult.getFileName();

    int start = CharOperation.lastIndexOf('/', fileName) + 1;
    if (start == 0 || start < CharOperation.lastIndexOf('\\', fileName))
      start = CharOperation.lastIndexOf('\\', fileName) + 1;

    int end = CharOperation.lastIndexOf('.', fileName);
    if (end == -1)
      end = fileName.length;

    return CharOperation.subarray(fileName, start, end);
  } else {
    return this.compilationResult.compilationUnit.getMainTypeName();
  }
}

public boolean isEmpty() {
  return (this.currentPackage == null) && (this.imports == null) && (this.types == null);
}

public boolean isPackageInfo() {
  return CharOperation.equals(getMainTypeName(), TypeConstants.PACKAGE_INFO_NAME);
}

public boolean isSuppressed(CategorizedProblem problem) {
  if (this.suppressWarningsCount == 0) return false;
  int irritant = ProblemReporter.getIrritant(problem.getID());
  if (irritant == 0) return false;
  int start = problem.getSourceStart();
  int end = problem.getSourceEnd();
  nextSuppress: for (int iSuppress = 0, suppressCount = this.suppressWarningsCount; iSuppress < suppressCount; iSuppress++) {
    long position = this.suppressWarningScopePositions[iSuppress];
    int startSuppress = (int) (position >>> 32);
    int endSuppress = (int) position;
    if (start < startSuppress) continue nextSuppress;
    if (end > endSuppress) continue nextSuppress;
    if (this.suppressWarningIrritants[iSuppress].isSet(irritant))
      return true;
  }
  return false;
}

public boolean hasFunctionalTypes() {
  return this.compilationResult.hasFunctionalTypes;
}

public boolean hasErrors() {
  return this.ignoreFurtherInvestigation;
}

public StringBuffer print(int indent, StringBuffer output) {
  if (this.currentPackage != null) {
    printIndent(indent, output).append("package "); //$NON-NLS-1$
    this.currentPackage.print(0, output, false).append(";\n"); //$NON-NLS-1$
  }
  if (this.imports != null)
    for (int i = 0; i < this.imports.length; i++) {
      printIndent(indent, output).append("import "); //$NON-NLS-1$
      ImportReference currentImport = this.imports[i];
      if (currentImport.isStatic()) {
        output.append("static "); //$NON-NLS-1$
      }
      currentImport.print(0, output).append(";\n"); //$NON-NLS-1$
    }

  if (this.types != null) {
    for (int i = 0; i < this.types.length; i++) {
      this.types[i].print(indent, output).append("\n"); //$NON-NLS-1$
    }
  }
  return output;
}

/*
* Force inner local types to update their innerclass emulation
*/
public void propagateInnerEmulationForAllLocalTypes() {
  this.isPropagatingInnerClassEmulation = true;
  for (int i = 0, max = this.localTypeCount; i < max; i++) {
    LocalTypeBinding localType = this.localTypes[i];
    // only propagate for reachable local types
    if ((localType.scope.referenceType().bits & IsReachable) != 0) {
      localType.updateInnerEmulationDependents();
    }
  }
}

public void recordStringLiteral(StringLiteral literal, boolean fromRecovery) {
  if (this.stringLiteralsStart != null) {
    if (this.stringLiteralsStart.contains(literal.sourceStart)) return;
    this.stringLiteralsStart.add(literal.sourceStart);
  } else if (fromRecovery) {
    this.stringLiteralsStart = new HashSetOfInt(this.stringLiteralsPtr + STRING_LITERALS_INCREMENT);
    for (int i = 0; i < this.stringLiteralsPtr; i++) {
      this.stringLiteralsStart.add(this.stringLiterals[i].sourceStart);
    }

    if (this.stringLiteralsStart.contains(literal.sourceStart)) return;
    this.stringLiteralsStart.add(literal.sourceStart);
  }

  if (this.stringLiterals == null) {
    this.stringLiterals = new StringLiteral[STRING_LITERALS_INCREMENT];
    this.stringLiteralsPtr = 0;
  } else {
    int stackLength = this.stringLiterals.length;
    if (this.stringLiteralsPtr == stackLength) {
      System.arraycopy(
        this.stringLiterals,
        0,
        this.stringLiterals = new StringLiteral[stackLength + STRING_LITERALS_INCREMENT],
        0,
        stackLength);
    }
  }
  this.stringLiterals[this.stringLiteralsPtr++] = literal;
}

public void recordSuppressWarnings(IrritantSet irritants, Annotation annotation, int scopeStart, int scopeEnd) {
  if (this.suppressWarningIrritants == null) {
    this.suppressWarningIrritants = new IrritantSet[3];
    this.suppressWarningAnnotations = new Annotation[3];
    this.suppressWarningScopePositions = new long[3];
  } else if (this.suppressWarningIrritants.length == this.suppressWarningsCount) {
    System.arraycopy(this.suppressWarningIrritants, 0,this.suppressWarningIrritants = new IrritantSet[2*this.suppressWarningsCount], 0, this.suppressWarningsCount);
    System.arraycopy(this.suppressWarningAnnotations, 0,this.suppressWarningAnnotations = new Annotation[2*this.suppressWarningsCount], 0, this.suppressWarningsCount);
    System.arraycopy(this.suppressWarningScopePositions, 0,this.suppressWarningScopePositions = new long[2*this.suppressWarningsCount], 0, this.suppressWarningsCount);
  }
  final long scopePositions = ((long)scopeStart<<32) + scopeEnd;
  for (int i = 0, max = this.suppressWarningsCount; i < max; i++) {
    if (this.suppressWarningAnnotations[i] == annotation
        && this.suppressWarningScopePositions[i] == scopePositions
        && this.suppressWarningIrritants[i].hasSameIrritants(irritants)) {
      // annotation data already recorded
      return;
    }
  }
  this.suppressWarningIrritants[this.suppressWarningsCount] = irritants;
  this.suppressWarningAnnotations[this.suppressWarningsCount] = annotation;
  this.suppressWarningScopePositions[this.suppressWarningsCount++] = scopePositions;
}

/*
* Keep track of all local types, so as to update their innerclass
* emulation later on.
*/
public void record(LocalTypeBinding localType) {
  if (this.localTypeCount == 0) {
    this.localTypes = new LocalTypeBinding[5];
  } else if (this.localTypeCount == this.localTypes.length) {
    System.arraycopy(this.localTypes, 0, (this.localTypes = new LocalTypeBinding[this.localTypeCount * 2]), 0, this.localTypeCount);
  }
  this.localTypes[this.localTypeCount++] = localType;
}

/*
* Keep track of all lambda/method reference expressions, so as to be able to look it up later without
* having to traverse AST. Return the 1 based "ordinal" in the CUD.
*/
public int record(FunctionalExpression expression) {
  if (this.functionalExpressionsCount == 0) {
    this.functionalExpressions = new FunctionalExpression[5];
  } else if (this.functionalExpressionsCount == this.functionalExpressions.length) {
    System.arraycopy(this.functionalExpressions, 0, (this.functionalExpressions = new FunctionalExpression[this.functionalExpressionsCount * 2]), 0, this.functionalExpressionsCount);
  }
  this.functionalExpressions[this.functionalExpressionsCount] = expression;
  return ++this.functionalExpressionsCount;
}

public void resolve() {
  int startingTypeIndex = 0;
  boolean isPackageInfo = isPackageInfo();
  if (this.types != null && isPackageInfo) {
    // resolve synthetic type declaration
    final TypeDeclaration syntheticTypeDeclaration = this.types[0];
    // set empty javadoc to avoid missing warning (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=95286)
    if (syntheticTypeDeclaration.javadoc == null) {
      syntheticTypeDeclaration.javadoc = new Javadoc(syntheticTypeDeclaration.declarationSourceStart, syntheticTypeDeclaration.declarationSourceStart);
    }
    syntheticTypeDeclaration.resolve(this.scope);
    /*
     * resolve javadoc package if any, skip this step if we don't have a valid scope due to an earlier error (bug 252555)
     * we do it now as the javadoc in the fake type won't be resolved. The peculiar usage of MethodScope to resolve the
     * package level javadoc is because the CU level resolve method  is a NOP to mimic Javadoc's behavior and can't be used
     * as such.
     */
    if (this.javadoc != null && syntheticTypeDeclaration.staticInitializerScope != null) {
      this.javadoc.resolve(syntheticTypeDeclaration.staticInitializerScope);
    }
    startingTypeIndex = 1;
  } else {
    // resolve compilation unit javadoc package if any
    if (this.javadoc != null) {
      this.javadoc.resolve(this.scope);
    }
  }
  if (this.currentPackage != null && this.currentPackage.annotations != null && !isPackageInfo) {
    this.scope.problemReporter().invalidFileNameForPackageAnnotations(this.currentPackage.annotations[0]);
  }
  try {
    if (this.types != null) {
      for (int i = startingTypeIndex, count = this.types.length; i < count; i++) {
        this.types[i].resolve(this.scope);
      }
    }
    if (!this.compilationResult.hasMandatoryErrors()) checkUnusedImports();
    reportNLSProblems();
  } catch (AbortCompilationUnit e) {
    this.ignoreFurtherInvestigation = true;
    return;
  }
}

private void reportNLSProblems() {
  if (this.nlsTags != null || this.stringLiterals != null) {
    final int stringLiteralsLength = this.stringLiteralsPtr;
    final int nlsTagsLength = this.nlsTags == null ? 0 : this.nlsTags.length;
    if (stringLiteralsLength == 0) {
      if (nlsTagsLength != 0) {
        for (int i = 0; i < nlsTagsLength; i++) {
          NLSTag tag = this.nlsTags[i];
          if (tag != null) {
            this.scope.problemReporter().unnecessaryNLSTags(tag.start, tag.end);
          }
        }
      }
    } else if (nlsTagsLength == 0) {
      // resize string literals
      if (this.stringLiterals.length != stringLiteralsLength) {
        System.arraycopy(this.stringLiterals, 0, (this.stringLiterals = new StringLiteral[stringLiteralsLength]), 0, stringLiteralsLength);
      }
      Arrays.sort(this.stringLiterals, STRING_LITERAL_COMPARATOR);
      for (int i = 0; i < stringLiteralsLength; i++) {
        this.scope.problemReporter().nonExternalizedStringLiteral(this.stringLiterals[i]);
      }
    } else {
      // need to iterate both arrays to find non matching elements
      if (this.stringLiterals.length != stringLiteralsLength) {
        System.arraycopy(this.stringLiterals, 0, (this.stringLiterals = new StringLiteral[stringLiteralsLength]), 0, stringLiteralsLength);
      }
      Arrays.sort(this.stringLiterals, STRING_LITERAL_COMPARATOR);
      int indexInLine = 1;
      int lastLineNumber = -1;
      StringLiteral literal = null;
      int index = 0;
      int i = 0;
      stringLiteralsLoop: for (; i < stringLiteralsLength; i++) {
        literal = this.stringLiterals[i];
        final int literalLineNumber = literal.lineNumber;
        if (lastLineNumber != literalLineNumber) {
          indexInLine = 1;
          lastLineNumber = literalLineNumber;
        } else {
          indexInLine++;
        }
        if (index < nlsTagsLength) {
          nlsTagsLoop: for (; index < nlsTagsLength; index++) {
            NLSTag tag = this.nlsTags[index];
            if (tag == null) continue nlsTagsLoop;
            int tagLineNumber = tag.lineNumber;
            if (literalLineNumber < tagLineNumber) {
              this.scope.problemReporter().nonExternalizedStringLiteral(literal);
              continue stringLiteralsLoop;
            } else if (literalLineNumber == tagLineNumber) {
              if (tag.index == indexInLine) {
                this.nlsTags[index] = null;
                index++;
                continue stringLiteralsLoop;
              } else {
                nlsTagsLoop2: for (int index2 = index + 1; index2 < nlsTagsLength; index2++) {
                  NLSTag tag2 = this.nlsTags[index2];
                  if (tag2 == null) continue nlsTagsLoop2;
                  int tagLineNumber2 = tag2.lineNumber;
                  if (literalLineNumber == tagLineNumber2) {
                    if (tag2.index == indexInLine) {
                      this.nlsTags[index2] = null;
                      continue stringLiteralsLoop;
                    } else {
                      continue nlsTagsLoop2;
                    }
                  } else {
                    this.scope.problemReporter().nonExternalizedStringLiteral(literal);
                    continue stringLiteralsLoop;
                  }
                }
                this.scope.problemReporter().nonExternalizedStringLiteral(literal);
                continue stringLiteralsLoop;
              }
            } else {
              this.scope.problemReporter().unnecessaryNLSTags(tag.start, tag.end);
              continue nlsTagsLoop;
            }
          }
        }
        // all nls tags have been processed, so remaining string literals are not externalized
        break stringLiteralsLoop;
      }
      for (; i < stringLiteralsLength; i++) {
        this.scope.problemReporter().nonExternalizedStringLiteral(this.stringLiterals[i]);
      }
      if (index < nlsTagsLength) {
        for (; index < nlsTagsLength; index++) {
          NLSTag tag = this.nlsTags[index];
          if (tag != null) {
            this.scope.problemReporter().unnecessaryNLSTags(tag.start, tag.end);
          }
        }
      }
    }
  }
}

public void tagAsHavingErrors() {
  this.ignoreFurtherInvestigation = true;
}

public void tagAsHavingIgnoredMandatoryErrors(int problemId) {
  // Nothing to do for this context;
}

public void traverse(ASTVisitor visitor, CompilationUnitScope unitScope) {
  traverse(visitor, unitScope, true);
}
public void traverse(ASTVisitor visitor, CompilationUnitScope unitScope, boolean skipOnError) {
  if (skipOnError && this.ignoreFurtherInvestigation)
    return;
  try {
    if (visitor.visit(this, this.scope)) {
      if (this.types != null && isPackageInfo()) {
              // resolve synthetic type declaration
        final TypeDeclaration syntheticTypeDeclaration = this.types[0];
        // resolve javadoc package if any
        final MethodScope methodScope = syntheticTypeDeclaration.staticInitializerScope;
        // Don't traverse in null scope and invite trouble a la bug 252555.
        if (this.javadoc != null && methodScope != null) {
          this.javadoc.traverse(visitor, methodScope);
        }
        // Don't traverse in null scope and invite trouble a la bug 252555.
        if (this.currentPackage != null && methodScope != null) {
          final Annotation[] annotations = this.currentPackage.annotations;
          if (annotations != null) {
            int annotationsLength = annotations.length;
            for (int i = 0; i < annotationsLength; i++) {
              annotations[i].traverse(visitor, methodScope);
            }
          }
        }
      }
      if (this.currentPackage != null) {
        this.currentPackage.traverse(visitor, this.scope);
      }
      if (this.imports != null) {
        int importLength = this.imports.length;
        for (int i = 0; i < importLength; i++) {
          this.imports[i].traverse(visitor, this.scope);
        }
      }
      if (this.types != null) {
        int typesLength = this.types.length;
        for (int i = 0; i < typesLength; i++) {
          this.types[i].traverse(visitor, this.scope);
        }
      }
    }
    visitor.endVisit(this, this.scope);
  } catch (AbortCompilationUnit e) {
    // ignore
  }
}
}
TOP

Related Classes of org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.