/******************************************************************************* * Copyright (c) 2000, 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package net.sourceforge.phpdt.core; //import java.util.StringTokenizer; //import net.sourceforge.phpdt.core.compiler.CharOperation; import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; import net.sourceforge.phpdt.core.compiler.ITerminalSymbols.TokenName; import net.sourceforge.phpdt.core.compiler.InvalidInputException; import net.sourceforge.phpdt.internal.compiler.parser.Scanner; //import net.sourceforge.phpdt.internal.core.ClasspathEntry; import net.sourceforge.phpdt.internal.core.JavaModelStatus; import net.sourceforge.phpdt.internal.core.util.Util; import org.eclipse.core.resources.IResource; //import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; //import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; /** * Provides methods for checking Java-specific conventions such as name syntax. *
* This class provides static methods and constants only; it is not intended to * be instantiated or subclassed by clients. *
*/ public final class JavaConventions { //private final static char DOT = '.'; private final static Scanner SCANNER = new Scanner(); private JavaConventions() { // Not instantiable } /** * Returns whether the given package fragment root paths are considered to * overlap. *
* Two root paths overlap if one is a prefix of the other, or they point to
* the same location. However, a JAR is allowed to be nested in a root.
*
* @param rootPath1
* the first root path
* @param rootPath2
* the second root path
* @return true if the given package fragment root paths are considered to
* overlap, false otherwise
* @deprecated Overlapping roots are allowed in 2.1
*/
// public static boolean isOverlappingRoots(IPath rootPath1, IPath rootPath2) {
// if (rootPath1 == null || rootPath2 == null) {
// return false;
// }
// // String extension1 = rootPath1.getFileExtension();
// // String extension2 = rootPath2.getFileExtension();
// // if (extension1 != null &&
// // (extension1.equalsIgnoreCase(SuffixConstants.EXTENSION_JAR) ||
// // extension1.equalsIgnoreCase(SuffixConstants.EXTENSION_ZIP))) {
// // return false;
// // }
// // if (extension2 != null &&
// // (extension2.equalsIgnoreCase(SuffixConstants.EXTENSION_JAR) ||
// // extension2.equalsIgnoreCase(SuffixConstants.EXTENSION_ZIP))) {
// // return false;
// // }
// return rootPath1.isPrefixOf(rootPath2)
// || rootPath2.isPrefixOf(rootPath1);
// }
/*
* Returns the current identifier extracted by the scanner (without unicode
* escapes) from the given id. Returns null
if the id was not
* valid
*/
private static synchronized char[] scannedIdentifier(String id) {
if (id == null) {
return null;
}
String trimmed = id.trim();
if (!trimmed.equals(id)) {
return null;
}
try {
SCANNER.setSource(id.toCharArray());
TokenName token = SCANNER.getNextToken();
char[] currentIdentifier;
try {
currentIdentifier = SCANNER.getCurrentIdentifierSource();
} catch (ArrayIndexOutOfBoundsException e) {
return null;
}
TokenName nextToken = SCANNER.getNextToken();
if (token == ITerminalSymbols.TokenName.IDENTIFIER
&& nextToken == ITerminalSymbols.TokenName.EOF
&& SCANNER.startPosition == SCANNER.source.length) { // to
// handle
// case
// where
// we
// had
// an
// ArrayIndexOutOfBoundsException
// while reading the last token
return currentIdentifier;
} else {
return null;
}
} catch (InvalidInputException e) {
return null;
}
}
/**
* Validate the given compilation unit name. A compilation unit name must
* obey the following rules:
*
".java"
suffix
* IStatus.OK
if the given
* name is valid as a compilation unit name, otherwise a status
* object indicating what is wrong with the name
*/
public static IStatus validateCompilationUnitName(String name) {
if (name == null) {
return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util
.bind("convention.unit.nullName"), null); //$NON-NLS-1$
}
if (!net.sourceforge.phpdt.internal.compiler.util.Util
.isJavaFileName(name)) {
return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util
.bind("convention.unit.notJavaName"), null); //$NON-NLS-1$
}
String identifier;
int index;
index = name.lastIndexOf('.');
if (index == -1) {
return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util
.bind("convention.unit.notJavaName"), null); //$NON-NLS-1$
}
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")) { //$NON-NLS-1$
IStatus status = validateIdentifier(identifier);
if (!status.isOK()) {
return status;
}
}
IStatus status = ResourcesPlugin.getWorkspace().validateName(name,
IResource.FILE);
if (!status.isOK()) {
return status;
}
return JavaModelStatus.VERIFIED_OK;
}
/**
* Validate the given .class file name. A .class file name must obey the
* following rules:
* ".class"
suffix
* IStatus.OK
if the given
* name is valid as a .class file name, otherwise a status object
* indicating what is wrong with the name
* @since 2.0
*/
// public static IStatus validateClassFileName(String name) {
// if (name == null) {
// return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
// Util.bind("convention.classFile.nullName"), null); //$NON-NLS-1$
// }
// if
// (!net.sourceforge.phpdt.internal.compiler.util.Util.isClassFileName(name))
// {
// return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
// Util.bind("convention.classFile.notClassFileName"), null); //$NON-NLS-1$
// }
// String identifier;
// int index;
// index = name.lastIndexOf('.');
// if (index == -1) {
// return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
// Util.bind("convention.classFile.notClassFileName"), null); //$NON-NLS-1$
// }
// identifier = name.substring(0, index);
// IStatus status = validateIdentifier(identifier);
// if (!status.isOK()) {
// return status;
// }
// status = ResourcesPlugin.getWorkspace().validateName(name,
// IResource.FILE);
// if (!status.isOK()) {
// return status;
// }
// return JavaModelStatus.VERIFIED_OK;
// }
/**
* Validate the given field name.
*
* Syntax of a field name corresponds to VariableDeclaratorId (JLS2 8.3).
* For example, "x"
.
*
* @param name
* the name of a field
* @return a status object with code IStatus.OK
if the given
* name is valid as a field name, otherwise a status object
* indicating what is wrong with the name
*/
public static IStatus validateFieldName(String name) {
return validateIdentifier(name);
}
/**
* Validate the given Java identifier. The identifier must not have the same
* spelling as a Java keyword, boolean literal ("true"
,
* "false"
), or null literal ("null"
). See
* section 3.8 of the Java Language Specification, Second Edition
* (JLS2). A valid identifier can act as a simple type name, method name or
* field name.
*
* @param id
* the Java identifier
* @return a status object with code IStatus.OK
if the given
* identifier is a valid Java identifier, otherwise a status object
* indicating what is wrong with the identifier
*/
public static IStatus validateIdentifier(String id) {
if (scannedIdentifier(id) != null) {
return JavaModelStatus.VERIFIED_OK;
} else {
return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util.bind(
"convention.illegalIdentifier", id), null); //$NON-NLS-1$
}
}
/**
* Validate the given import declaration name.
*
* The name of an import corresponds to a fully qualified type name or an
* on-demand package name as defined by ImportDeclaration (JLS2 7.5). For
* example, "java.util.*"
or
* "java.util.Hashtable"
.
*
* @param name
* the import declaration
* @return a status object with code IStatus.OK
if the given
* name is valid as an import declaration, otherwise a status object
* indicating what is wrong with the name
*/
// public static IStatus validateImportDeclaration(String name) {
// if (name == null || name.length() == 0) {
// return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util
// .bind("convention.import.nullImport"), null); //$NON-NLS-1$
// }
// if (name.charAt(name.length() - 1) == '*') {
// if (name.charAt(name.length() - 2) == '.') {
// return validatePackageName(name.substring(0, name.length() - 2));
// } else {
// return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util
// .bind("convention.import.unqualifiedImport"), null); //$NON-NLS-1$
// }
// }
// return validatePackageName(name);
// }
/**
* Validate the given Java type name, either simple or qualified. For
* example, "java.lang.Object"
, or "Object"
.
*
*
* @param name
* the name of a type
* @return a status object with code IStatus.OK
if the given
* name is valid as a Java type name, a status with code
* IStatus.WARNING
indicating why the given name is
* discouraged, otherwise a status object indicating what is wrong
* with the name
*/
// public static IStatus validateJavaTypeName(String name) {
// if (name == null) {
// return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util
// .bind("convention.type.nullName"), null); //$NON-NLS-1$
// }
// String trimmed = name.trim();
// if (!name.equals(trimmed)) {
// return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util
// .bind("convention.type.nameWithBlanks"), null); //$NON-NLS-1$
// }
// int index = name.lastIndexOf('.');
// char[] scannedID;
// if (index == -1) {
// // simple name
// scannedID = scannedIdentifier(name);
// } else {
// // qualified name
// String pkg = name.substring(0, index).trim();
// IStatus status = validatePackageName(pkg);
// if (!status.isOK()) {
// return status;
// }
// String type = name.substring(index + 1).trim();
// scannedID = scannedIdentifier(type);
// }
//
// if (scannedID != null) {
// IStatus status = ResourcesPlugin.getWorkspace().validateName(
// new String(scannedID), IResource.FILE);
// if (!status.isOK()) {
// return status;
// }
// if (CharOperation.contains('$', scannedID)) {
// return new Status(IStatus.WARNING, JavaCore.PLUGIN_ID, -1, Util
// .bind("convention.type.dollarName"), null); //$NON-NLS-1$
// }
// if ((scannedID.length > 0 && Character.isLowerCase(scannedID[0]))) {
// return new Status(IStatus.WARNING, JavaCore.PLUGIN_ID, -1, Util
// .bind("convention.type.lowercaseName"), null); //$NON-NLS-1$
// }
// return JavaModelStatus.VERIFIED_OK;
// } else {
// return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util.bind(
// "convention.type.invalidName", name), null); //$NON-NLS-1$
// }
// }
/**
* Validate the given method name. The special names "<init>" and
* "<clinit>" are not valid.
*
* The syntax for a method name is defined by Identifier of MethodDeclarator
* (JLS2 8.4). For example "println".
*
* @param name
* the name of a method
* @return a status object with code IStatus.OK
if the given
* name is valid as a method name, otherwise a status object
* indicating what is wrong with the name
*/
// public static IStatus validateMethodName(String name) {
//
// return validateIdentifier(name);
// }
/**
* Validate the given package name.
*
* The syntax of a package name corresponds to PackageName as defined by
* PackageDeclaration (JLS2 7.4). For example, "java.lang"
.
*
* Note that the given name must be a non-empty package name (that is,
* attempting to validate the default package will return an error status.)
* Also it must not contain any characters or substrings that are not valid
* on the file system on which workspace root is located.
*
* @param name
* the name of a package
* @return a status object with code IStatus.OK
if the given
* name is valid as a package name, otherwise a status object
* indicating what is wrong with the name
*/
// public static IStatus validatePackageName(String name) {
//
// if (name == null) {
// return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util
// .bind("convention.package.nullName"), null); //$NON-NLS-1$
// }
// int length;
// if ((length = name.length()) == 0) {
// return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util
// .bind("convention.package.emptyName"), null); //$NON-NLS-1$
// }
// if (name.charAt(0) == DOT || name.charAt(length - 1) == DOT) {
// return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util
// .bind("convention.package.dotName"), null); //$NON-NLS-1$
// }
// if (CharOperation.isWhitespace(name.charAt(0))
// || CharOperation.isWhitespace(name.charAt(name.length() - 1))) {
// return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util
// .bind("convention.package.nameWithBlanks"), null); //$NON-NLS-1$
// }
// int dot = 0;
// while (dot != -1 && dot < length - 1) {
// if ((dot = name.indexOf(DOT, dot + 1)) != -1 && dot < length - 1
// && name.charAt(dot + 1) == DOT) {
// return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util
// .bind("convention.package.consecutiveDotsName"), null); //$NON-NLS-1$
// }
// }
// IWorkspace workspace = ResourcesPlugin.getWorkspace();
// StringTokenizer st = new StringTokenizer(name, new String(
// new char[] { DOT }));
// boolean firstToken = true;
// IStatus warningStatus = null;
// while (st.hasMoreTokens()) {
// String typeName = st.nextToken();
// typeName = typeName.trim(); // grammar allows spaces
// char[] scannedID = scannedIdentifier(typeName);
// if (scannedID == null) {
// return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util
// .bind("convention.illegalIdentifier", typeName), null); //$NON-NLS-1$
// }
// IStatus status = workspace.validateName(new String(scannedID),
// IResource.FOLDER);
// if (!status.isOK()) {
// return status;
// }
// if (firstToken && scannedID.length > 0
// && Character.isUpperCase(scannedID[0])) {
// if (warningStatus == null) {
// warningStatus = new Status(IStatus.WARNING,
// JavaCore.PLUGIN_ID, -1,
// Util.bind("convention.package.uppercaseName"), null); //$NON-NLS-1$
// }
// }
// firstToken = false;
// }
// if (warningStatus != null) {
// return warningStatus;
// }
// return JavaModelStatus.VERIFIED_OK;
// }
/**
* Validate a given classpath and output location for a project, using the
* following rules:
*
* This validation is intended to anticipate classpath issues prior to * assigning it to a project. In particular, it will automatically be * performed during the classpath setting operation (if validation fails, * the classpath setting will not complete). *
*
* @param javaProject
* the given java project
* @param rawClasspath
* the given classpath
* @param projectOutputLocation
* the given output location
* @return a status object with code IStatus.OK
if the given
* classpath and output location are compatible, otherwise a status
* object indicating what is wrong with the classpath or output
* location
* @since 2.0
*/
// public static IJavaModelStatus validateClasspath(IJavaProject javaProject,
// IClasspathEntry[] rawClasspath, IPath projectOutputLocation) {
//
// return ClasspathEntry.validateClasspath(javaProject, rawClasspath,
// projectOutputLocation);
// }
/**
* Returns a Java model status describing the problem related to this
* classpath entry if any, a status object with code IStatus.OK
* if the entry is fine (that is, if the given classpath entry denotes a
* valid element to be referenced onto a classpath).
*
* @param project
* the given java project
* @param entry
* the given classpath entry
* @param checkSourceAttachment
* a flag to determine if source attachement should be checked
* @return a java model status describing the problem related to this
* classpath entry if any, a status object with code
* IStatus.OK
if the entry is fine
* @since 2.0
*/
// public static IJavaModelStatus validateClasspathEntry(IJavaProject project,
// IClasspathEntry entry, boolean checkSourceAttachment) {
// return ClasspathEntry.validateClasspathEntry(project, entry,
// checkSourceAttachment, true/* recurse in container */);
// }
}