/******************************************************************************* * 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: *

*

* * @param name * the name of a compilation unit * @return a status object with code 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: * *

* * @param name * the name of a .class file * @return a status object with code 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: *

* * Note that the classpath entries are not validated automatically. Only * bound variables or containers are considered in the checking process * (this allows to perform a consistency check on a classpath which has * references to yet non existing projects, folders, ...). *

* 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 */); // } }