/**
  * Validate the given compilation unit name for the given source and compliance levels.
  *
  * <p>A compilation unit name must obey the following rules:
  *
  * <ul>
  *   <li>it must not be null
  *   <li>it must be suffixed by a dot ('.') followed by one of the {@link
  *       JavaCore#getJavaLikeExtensions() Java-like extensions}
  *   <li>its prefix must be a valid identifier
  *   <li>it must not contain any characters or substrings that are not valid on the file system on
  *       which workspace root is located.
  * </ul>
  *
  * @param name the name of a compilation unit
  * @param sourceLevel the source level
  * @param complianceLevel the compliance level
  * @return a status object with code <code>IStatus.OK</code> if the given name is valid as a
  *     compilation unit name, otherwise a status object indicating what is wrong with the name
  * @since 3.3
  */
 public static IStatus validateCompilationUnitName(
     String name, String sourceLevel, String complianceLevel) {
   if (name == null) {
     return new Status(
         IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.convention_unit_nullName, null);
   }
   if (!org.aspectj.org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(name)) {
     return new Status(
         IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.convention_unit_notJavaName, null);
   }
   String identifier;
   int index;
   index = name.lastIndexOf('.');
   if (index == -1) {
     return new Status(
         IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.convention_unit_notJavaName, null);
   }
   identifier = name.substring(0, index);
   // JSR-175 metadata strongly recommends "package-info.java" as the
   // file in which to store package annotations and
   // the package-level spec (replaces package.html)
   if (!identifier.equals(PACKAGE_INFO)) {
     IStatus status = validateIdentifier(identifier, sourceLevel, complianceLevel);
     if (!status.isOK()) {
       return status;
     }
   }
   IStatus status = ResourcesPlugin.getWorkspace().validateName(name, IResource.FILE);
   if (!status.isOK()) {
     return status;
   }
   return JavaModelStatus.VERIFIED_OK;
 }
 public int hashCode() {
   return Util.combineHashCodes(this.parent.hashCode(), this.nameStart);
 }
 /*
  * Creates the value wrapper from the given expression, and sets the valueKind on the given memberValuePair
  */
 private Object getAnnotationMemberValue(
     MemberValuePair memberValuePair, Expression expression, JavaElement parentElement) {
   if (expression instanceof NullLiteral) {
     return null;
   } else if (expression instanceof Literal) {
     ((Literal) expression).computeConstant();
     return Util.getAnnotationMemberValue(memberValuePair, expression.constant);
   } else if (expression instanceof org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation) {
     memberValuePair.valueKind = IMemberValuePair.K_ANNOTATION;
     return getAnnotation(
         (org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation) expression, parentElement);
   } else if (expression instanceof ClassLiteralAccess) {
     ClassLiteralAccess classLiteral = (ClassLiteralAccess) expression;
     char[] typeName = CharOperation.concatWith(classLiteral.type.getTypeName(), '.');
     memberValuePair.valueKind = IMemberValuePair.K_CLASS;
     return new String(typeName);
   } else if (expression instanceof QualifiedNameReference) {
     char[] qualifiedName =
         CharOperation.concatWith(((QualifiedNameReference) expression).tokens, '.');
     memberValuePair.valueKind = IMemberValuePair.K_QUALIFIED_NAME;
     return new String(qualifiedName);
   } else if (expression instanceof SingleNameReference) {
     char[] simpleName = ((SingleNameReference) expression).token;
     if (simpleName == RecoveryScanner.FAKE_IDENTIFIER) {
       memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN;
       return null;
     }
     memberValuePair.valueKind = IMemberValuePair.K_SIMPLE_NAME;
     return new String(simpleName);
   } else if (expression instanceof ArrayInitializer) {
     memberValuePair.valueKind = -1; // modified below by the first call to getMemberValue(...)
     Expression[] expressions = ((ArrayInitializer) expression).expressions;
     int length = expressions == null ? 0 : expressions.length;
     Object[] values = new Object[length];
     for (int i = 0; i < length; i++) {
       int previousValueKind = memberValuePair.valueKind;
       Object value = getAnnotationMemberValue(memberValuePair, expressions[i], parentElement);
       if (previousValueKind != -1 && memberValuePair.valueKind != previousValueKind) {
         // values are heterogeneous, value kind is thus unknown
         memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN;
       }
       values[i] = value;
     }
     if (memberValuePair.valueKind == -1) memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN;
     return values;
   } else if (expression
       instanceof UnaryExpression) { // to deal with negative numerals (see bug - 248312)
     UnaryExpression unaryExpression = (UnaryExpression) expression;
     if ((unaryExpression.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT
         == OperatorIds.MINUS) {
       if (unaryExpression.expression instanceof Literal) {
         Literal subExpression = (Literal) unaryExpression.expression;
         subExpression.computeConstant();
         return Util.getNegativeAnnotationMemberValue(memberValuePair, subExpression.constant);
       }
     }
     memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN;
     return null;
   } else {
     memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN;
     return null;
   }
 }