001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.core;
011:
012: import java.util.StringTokenizer;
013:
014: import org.eclipse.core.resources.IResource;
015: import org.eclipse.core.resources.IWorkspace;
016: import org.eclipse.core.resources.ResourcesPlugin;
017: import org.eclipse.core.runtime.IPath;
018: import org.eclipse.core.runtime.IStatus;
019: import org.eclipse.core.runtime.Status;
020: import org.eclipse.jdt.core.compiler.*;
021: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
022: import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
023: import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
024: import org.eclipse.jdt.internal.compiler.parser.Scanner;
025: import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
026: import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
027: import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
028: import org.eclipse.jdt.internal.core.*;
029: import org.eclipse.jdt.internal.core.util.Messages;
030:
031: /**
032: * Provides methods for checking Java-specific conventions such as name syntax.
033: * <p>
034: * This class provides static methods and constants only; it is not intended to be
035: * instantiated or subclassed by clients.
036: * </p>
037: */
038: public final class JavaConventions {
039:
040: private static final char DOT = '.';
041: private static final String PACKAGE_INFO = new String(
042: TypeConstants.PACKAGE_INFO_NAME);
043: private static final Scanner SCANNER = new Scanner(
044: false /*comment*/, true /*whitespace*/, false /*nls*/,
045: ClassFileConstants.JDK1_3 /*sourceLevel*/,
046: null/*taskTag*/, null/*taskPriorities*/, true /*taskCaseSensitive*/);
047:
048: private JavaConventions() {
049: // Not instantiable
050: }
051:
052: /**
053: * Returns whether the given package fragment root paths are considered
054: * to overlap.
055: * <p>
056: * Two root paths overlap if one is a prefix of the other, or they point to
057: * the same location. However, a JAR is allowed to be nested in a root.
058: *
059: * @param rootPath1 the first root path
060: * @param rootPath2 the second root path
061: * @return true if the given package fragment root paths are considered to overlap, false otherwise
062: * @deprecated Overlapping roots are allowed in 2.1
063: */
064: public static boolean isOverlappingRoots(IPath rootPath1,
065: IPath rootPath2) {
066: if (rootPath1 == null || rootPath2 == null) {
067: return false;
068: }
069: String extension1 = rootPath1.getFileExtension();
070: String extension2 = rootPath2.getFileExtension();
071: if (extension1 != null
072: && (extension1
073: .equalsIgnoreCase(SuffixConstants.EXTENSION_JAR) || extension1
074: .equalsIgnoreCase(SuffixConstants.EXTENSION_ZIP))) {
075: return false;
076: }
077: if (extension2 != null
078: && (extension2
079: .equalsIgnoreCase(SuffixConstants.EXTENSION_JAR) || extension2
080: .equalsIgnoreCase(SuffixConstants.EXTENSION_ZIP))) {
081: return false;
082: }
083: return rootPath1.isPrefixOf(rootPath2)
084: || rootPath2.isPrefixOf(rootPath1);
085: }
086:
087: /*
088: * Returns the current identifier extracted by the scanner (without unicode
089: * escapes) from the given id and for the given source and compliance levels.
090: * Returns <code>null</code> if the id was not valid
091: */
092: private static synchronized char[] scannedIdentifier(String id,
093: String sourceLevel, String complianceLevel) {
094: if (id == null) {
095: return null;
096: }
097: // Set scanner for given source and compliance levels
098: SCANNER.sourceLevel = sourceLevel == null ? ClassFileConstants.JDK1_3
099: : CompilerOptions.versionToJdkLevel(sourceLevel);
100: SCANNER.complianceLevel = complianceLevel == null ? ClassFileConstants.JDK1_3
101: : CompilerOptions.versionToJdkLevel(complianceLevel);
102:
103: try {
104: SCANNER.setSource(id.toCharArray());
105: int token = SCANNER.scanIdentifier();
106: if (token != TerminalTokens.TokenNameIdentifier)
107: return null;
108: if (SCANNER.currentPosition == SCANNER.eofPosition) { // to handle case where we had an ArrayIndexOutOfBoundsException
109: try {
110: return SCANNER.getCurrentIdentifierSource();
111: } catch (ArrayIndexOutOfBoundsException e) {
112: return null;
113: }
114: } else {
115: return null;
116: }
117: } catch (InvalidInputException e) {
118: return null;
119: }
120: }
121:
122: /**
123: * Validate the given compilation unit name.
124: * <p>
125: * A compilation unit name must obey the following rules:
126: * <ul>
127: * <li> it must not be null
128: * <li> it must be suffixed by a dot ('.') followed by one of the
129: * {@link JavaCore#getJavaLikeExtensions() Java-like extensions}
130: * <li> its prefix must be a valid identifier
131: * <li> it must not contain any characters or substrings that are not valid
132: * on the file system on which workspace root is located.
133: * </ul>
134: * </p>
135: * @param name the name of a compilation unit
136: * @return a status object with code <code>IStatus.OK</code> if
137: * the given name is valid as a compilation unit name, otherwise a status
138: * object indicating what is wrong with the name
139: * @deprecated Use {@link #validateCompilationUnitName(String id, String sourceLevel, String complianceLevel)} instead
140: */
141: public static IStatus validateCompilationUnitName(String name) {
142: return validateCompilationUnitName(name,
143: CompilerOptions.VERSION_1_3,
144: CompilerOptions.VERSION_1_3);
145: }
146:
147: /**
148: * Validate the given compilation unit name for the given source and compliance levels.
149: * <p>
150: * A compilation unit name must obey the following rules:
151: * <ul>
152: * <li> it must not be null
153: * <li> it must be suffixed by a dot ('.') followed by one of the
154: * {@link JavaCore#getJavaLikeExtensions() Java-like extensions}
155: * <li> its prefix must be a valid identifier
156: * <li> it must not contain any characters or substrings that are not valid
157: * on the file system on which workspace root is located.
158: * </ul>
159: * </p>
160: * @param name the name of a compilation unit
161: * @param sourceLevel the source level
162: * @param complianceLevel the compliance level
163: * @return a status object with code <code>IStatus.OK</code> if
164: * the given name is valid as a compilation unit name, otherwise a status
165: * object indicating what is wrong with the name
166: * @since 3.3
167: */
168: public static IStatus validateCompilationUnitName(String name,
169: String sourceLevel, String complianceLevel) {
170: if (name == null) {
171: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
172: Messages.convention_unit_nullName, null);
173: }
174: if (!org.eclipse.jdt.internal.core.util.Util
175: .isJavaLikeFileName(name)) {
176: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
177: Messages.convention_unit_notJavaName, null);
178: }
179: String identifier;
180: int index;
181: index = name.lastIndexOf('.');
182: if (index == -1) {
183: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
184: Messages.convention_unit_notJavaName, null);
185: }
186: identifier = name.substring(0, index);
187: // JSR-175 metadata strongly recommends "package-info.java" as the
188: // file in which to store package annotations and
189: // the package-level spec (replaces package.html)
190: if (!identifier.equals(PACKAGE_INFO)) {
191: IStatus status = validateIdentifier(identifier,
192: sourceLevel, complianceLevel);
193: if (!status.isOK()) {
194: return status;
195: }
196: }
197: IStatus status = ResourcesPlugin.getWorkspace().validateName(
198: name, IResource.FILE);
199: if (!status.isOK()) {
200: return status;
201: }
202: return JavaModelStatus.VERIFIED_OK;
203: }
204:
205: /**
206: * Validate the given .class file name.
207: * <p>
208: * A .class file name must obey the following rules:
209: * <ul>
210: * <li> it must not be null
211: * <li> it must include the <code>".class"</code> suffix
212: * <li> its prefix must be a valid identifier
213: * <li> it must not contain any characters or substrings that are not valid
214: * on the file system on which workspace root is located.
215: * </ul>
216: * </p>
217: * @param name the name of a .class file
218: * @return a status object with code <code>IStatus.OK</code> if
219: * the given name is valid as a .class file name, otherwise a status
220: * object indicating what is wrong with the name
221: * @since 2.0
222: * @deprecated Use {@link #validateClassFileName(String id, String sourceLevel, String complianceLevel)} instead
223: */
224: public static IStatus validateClassFileName(String name) {
225: return validateClassFileName(name, CompilerOptions.VERSION_1_3,
226: CompilerOptions.VERSION_1_3);
227: }
228:
229: /**
230: * Validate the given .class file name for the given source and compliance levels.
231: * <p>
232: * A .class file name must obey the following rules:
233: * <ul>
234: * <li> it must not be null
235: * <li> it must include the <code>".class"</code> suffix
236: * <li> its prefix must be a valid identifier
237: * <li> it must not contain any characters or substrings that are not valid
238: * on the file system on which workspace root is located.
239: * </ul>
240: * </p>
241: * @param name the name of a .class file
242: * @param sourceLevel the source level
243: * @param complianceLevel the compliance level
244: * @return a status object with code <code>IStatus.OK</code> if
245: * the given name is valid as a .class file name, otherwise a status
246: * object indicating what is wrong with the name
247: * @since 3.3
248: */
249: public static IStatus validateClassFileName(String name,
250: String sourceLevel, String complianceLevel) {
251: if (name == null) {
252: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
253: Messages.convention_classFile_nullName, null);
254: }
255: if (!org.eclipse.jdt.internal.compiler.util.Util
256: .isClassFileName(name)) {
257: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
258: Messages.convention_classFile_notClassFileName,
259: null);
260: }
261: String identifier;
262: int index;
263: index = name.lastIndexOf('.');
264: if (index == -1) {
265: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
266: Messages.convention_classFile_notClassFileName,
267: null);
268: }
269: identifier = name.substring(0, index);
270: // JSR-175 metadata strongly recommends "package-info.java" as the
271: // file in which to store package annotations and
272: // the package-level spec (replaces package.html)
273: if (!identifier.equals(PACKAGE_INFO)) {
274: IStatus status = validateIdentifier(identifier,
275: sourceLevel, complianceLevel);
276: if (!status.isOK()) {
277: return status;
278: }
279: }
280: IStatus status = ResourcesPlugin.getWorkspace().validateName(
281: name, IResource.FILE);
282: if (!status.isOK()) {
283: return status;
284: }
285: return JavaModelStatus.VERIFIED_OK;
286: }
287:
288: /**
289: * Validate the given field name.
290: * <p>
291: * Syntax of a field name corresponds to VariableDeclaratorId (JLS2 8.3).
292: * For example, <code>"x"</code>.
293: *
294: * @param name the name of a field
295: * @return a status object with code <code>IStatus.OK</code> if
296: * the given name is valid as a field name, otherwise a status
297: * object indicating what is wrong with the name
298: * @deprecated Use {@link #validateFieldName(String id, String sourceLevel, String complianceLevel)} instead
299: */
300: public static IStatus validateFieldName(String name) {
301: return validateIdentifier(name, CompilerOptions.VERSION_1_3,
302: CompilerOptions.VERSION_1_3);
303: }
304:
305: /**
306: * Validate the given field name for the given source and compliance levels.
307: * <p>
308: * Syntax of a field name corresponds to VariableDeclaratorId (JLS2 8.3).
309: * For example, <code>"x"</code>.
310: *
311: * @param name the name of a field
312: * @param sourceLevel the source level
313: * @param complianceLevel the compliance level
314: * @return a status object with code <code>IStatus.OK</code> if
315: * the given name is valid as a field name, otherwise a status
316: * object indicating what is wrong with the name
317: * @since 3.3
318: */
319: public static IStatus validateFieldName(String name,
320: String sourceLevel, String complianceLevel) {
321: return validateIdentifier(name, sourceLevel, complianceLevel);
322: }
323:
324: /**
325: * Validate the given Java identifier.
326: * The identifier must not have the same spelling as a Java keyword,
327: * boolean literal (<code>"true"</code>, <code>"false"</code>), or null literal (<code>"null"</code>).
328: * See section 3.8 of the <em>Java Language Specification, Second Edition</em> (JLS2).
329: * A valid identifier can act as a simple type name, method name or field name.
330: *
331: * @param id the Java identifier
332: * @return a status object with code <code>IStatus.OK</code> if
333: * the given identifier is a valid Java identifier, otherwise a status
334: * object indicating what is wrong with the identifier
335: * @deprecated Use {@link #validateIdentifier(String id, String sourceLevel, String complianceLevel)} instead
336: */
337: public static IStatus validateIdentifier(String id) {
338: return validateIdentifier(id, CompilerOptions.VERSION_1_3,
339: CompilerOptions.VERSION_1_3);
340: }
341:
342: /**
343: * Validate the given Java identifier for the given source and compliance levels
344: * The identifier must not have the same spelling as a Java keyword,
345: * boolean literal (<code>"true"</code>, <code>"false"</code>), or null literal (<code>"null"</code>).
346: * See section 3.8 of the <em>Java Language Specification, Second Edition</em> (JLS2).
347: * A valid identifier can act as a simple type name, method name or field name.
348: *
349: * @param id the Java identifier
350: * @param sourceLevel the source level
351: * @param complianceLevel the compliance level
352: * @return a status object with code <code>IStatus.OK</code> if
353: * the given identifier is a valid Java identifier, otherwise a status
354: * object indicating what is wrong with the identifier
355: * @since 3.3
356: */
357: public static IStatus validateIdentifier(String id,
358: String sourceLevel, String complianceLevel) {
359: if (scannedIdentifier(id, sourceLevel, complianceLevel) != null) {
360: return JavaModelStatus.VERIFIED_OK;
361: } else {
362: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
363: Messages.bind(
364: Messages.convention_illegalIdentifier, id),
365: null);
366: }
367: }
368:
369: /**
370: * Validate the given import declaration name.
371: * <p>
372: * The name of an import corresponds to a fully qualified type name
373: * or an on-demand package name as defined by ImportDeclaration (JLS2 7.5).
374: * For example, <code>"java.util.*"</code> or <code>"java.util.Hashtable"</code>.
375: *
376: * @param name the import declaration
377: * @return a status object with code <code>IStatus.OK</code> if
378: * the given name is valid as an import declaration, otherwise a status
379: * object indicating what is wrong with the name
380: * @deprecated Use {@link #validateImportDeclaration(String id, String sourceLevel, String complianceLevel)} instead
381: */
382: public static IStatus validateImportDeclaration(String name) {
383: return validateImportDeclaration(name,
384: CompilerOptions.VERSION_1_3,
385: CompilerOptions.VERSION_1_3);
386: }
387:
388: /**
389: * Validate the given import declaration name for the given source and compliance levels.
390: * <p>
391: * The name of an import corresponds to a fully qualified type name
392: * or an on-demand package name as defined by ImportDeclaration (JLS2 7.5).
393: * For example, <code>"java.util.*"</code> or <code>"java.util.Hashtable"</code>.
394: *
395: * @param name the import declaration
396: * @param sourceLevel the source level
397: * @param complianceLevel the compliance level
398: * @return a status object with code <code>IStatus.OK</code> if
399: * the given name is valid as an import declaration, otherwise a status
400: * object indicating what is wrong with the name
401: * @since 3.3
402: */
403: public static IStatus validateImportDeclaration(String name,
404: String sourceLevel, String complianceLevel) {
405: if (name == null || name.length() == 0) {
406: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
407: Messages.convention_import_nullImport, null);
408: }
409: if (name.charAt(name.length() - 1) == '*') {
410: if (name.charAt(name.length() - 2) == '.') {
411: return validatePackageName(name.substring(0, name
412: .length() - 2), sourceLevel, complianceLevel);
413: } else {
414: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID,
415: -1,
416: Messages.convention_import_unqualifiedImport,
417: null);
418: }
419: }
420: return validatePackageName(name, sourceLevel, complianceLevel);
421: }
422:
423: /**
424: * Validate the given Java type name, either simple or qualified.
425: * For example, <code>"java.lang.Object"</code>, or <code>"Object"</code>.
426: * <p>
427: *
428: * @param name the name of a type
429: * @return a status object with code <code>IStatus.OK</code> if
430: * the given name is valid as a Java type name,
431: * a status with code <code>IStatus.WARNING</code>
432: * indicating why the given name is discouraged,
433: * otherwise a status object indicating what is wrong with
434: * the name
435: * @deprecated Use {@link #validateJavaTypeName(String id, String sourceLevel, String complianceLevel)} instead
436: */
437: public static IStatus validateJavaTypeName(String name) {
438: return validateJavaTypeName(name, CompilerOptions.VERSION_1_3,
439: CompilerOptions.VERSION_1_3);
440: }
441:
442: /**
443: * Validate the given Java type name, either simple or qualified, for the given source and compliance levels.
444: * For example, <code>"java.lang.Object"</code>, or <code>"Object"</code>.
445: * <p>
446: *
447: * @param name the name of a type
448: * @param sourceLevel the source level
449: * @param complianceLevel the compliance level
450: * @return a status object with code <code>IStatus.OK</code> if
451: * the given name is valid as a Java type name,
452: * a status with code <code>IStatus.WARNING</code>
453: * indicating why the given name is discouraged,
454: * otherwise a status object indicating what is wrong with
455: * the name
456: * @since 3.3
457: */
458: public static IStatus validateJavaTypeName(String name,
459: String sourceLevel, String complianceLevel) {
460: if (name == null) {
461: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
462: Messages.convention_type_nullName, null);
463: }
464: String trimmed = name.trim();
465: if (!name.equals(trimmed)) {
466: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
467: Messages.convention_type_nameWithBlanks, null);
468: }
469: int index = name.lastIndexOf('.');
470: char[] scannedID;
471: if (index == -1) {
472: // simple name
473: scannedID = scannedIdentifier(name, sourceLevel,
474: complianceLevel);
475: } else {
476: // qualified name
477: String pkg = name.substring(0, index).trim();
478: IStatus status = validatePackageName(pkg, sourceLevel,
479: complianceLevel);
480: if (!status.isOK()) {
481: return status;
482: }
483: String type = name.substring(index + 1).trim();
484: scannedID = scannedIdentifier(type, sourceLevel,
485: complianceLevel);
486: }
487:
488: if (scannedID != null) {
489: IStatus status = ResourcesPlugin
490: .getWorkspace()
491: .validateName(new String(scannedID), IResource.FILE);
492: if (!status.isOK()) {
493: return status;
494: }
495: if (CharOperation.contains('$', scannedID)) {
496: return new Status(IStatus.WARNING, JavaCore.PLUGIN_ID,
497: -1, Messages.convention_type_dollarName, null);
498: }
499: if ((scannedID.length > 0 && ScannerHelper
500: .isLowerCase(scannedID[0]))) {
501: return new Status(IStatus.WARNING, JavaCore.PLUGIN_ID,
502: -1, Messages.convention_type_lowercaseName,
503: null);
504: }
505: return JavaModelStatus.VERIFIED_OK;
506: } else {
507: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
508: Messages.bind(Messages.convention_type_invalidName,
509: name), null);
510: }
511: }
512:
513: /**
514: * Validate the given method name.
515: * The special names "<init>" and "<clinit>" are not valid.
516: * <p>
517: * The syntax for a method name is defined by Identifier
518: * of MethodDeclarator (JLS2 8.4). For example "println".
519: *
520: * @param name the name of a method
521: * @return a status object with code <code>IStatus.OK</code> if
522: * the given name is valid as a method name, otherwise a status
523: * object indicating what is wrong with the name
524: * @deprecated Use {@link #validateMethodName(String id, String sourceLevel, String complianceLevel)} instead
525: */
526: public static IStatus validateMethodName(String name) {
527: return validateMethodName(name, CompilerOptions.VERSION_1_3,
528: CompilerOptions.VERSION_1_3);
529: }
530:
531: /**
532: * Validate the given method name for the given source and compliance levels.
533: * The special names "<init>" and "<clinit>" are not valid.
534: * <p>
535: * The syntax for a method name is defined by Identifier
536: * of MethodDeclarator (JLS2 8.4). For example "println".
537: *
538: * @param name the name of a method
539: * @param sourceLevel the source level
540: * @param complianceLevel the compliance level
541: * @return a status object with code <code>IStatus.OK</code> if
542: * the given name is valid as a method name, otherwise a status
543: * object indicating what is wrong with the name
544: * @since 3.3
545: */
546: public static IStatus validateMethodName(String name,
547: String sourceLevel, String complianceLevel) {
548: return validateIdentifier(name, sourceLevel, complianceLevel);
549: }
550:
551: /**
552: * Validate the given package name.
553: * <p>
554: * The syntax of a package name corresponds to PackageName as
555: * defined by PackageDeclaration (JLS2 7.4). For example, <code>"java.lang"</code>.
556: * <p>
557: * Note that the given name must be a non-empty package name (that is, attempting to
558: * validate the default package will return an error status.)
559: * Also it must not contain any characters or substrings that are not valid
560: * on the file system on which workspace root is located.
561: *
562: * @param name the name of a package
563: * @return a status object with code <code>IStatus.OK</code> if
564: * the given name is valid as a package name, otherwise a status
565: * object indicating what is wrong with the name
566: * @deprecated Use {@link #validatePackageName(String id, String sourceLevel, String complianceLevel)} instead
567: */
568: public static IStatus validatePackageName(String name) {
569: return validatePackageName(name, CompilerOptions.VERSION_1_3,
570: CompilerOptions.VERSION_1_3);
571: }
572:
573: /**
574: * Validate the given package name for the given source and compliance levels.
575: * <p>
576: * The syntax of a package name corresponds to PackageName as
577: * defined by PackageDeclaration (JLS2 7.4). For example, <code>"java.lang"</code>.
578: * <p>
579: * Note that the given name must be a non-empty package name (that is, attempting to
580: * validate the default package will return an error status.)
581: * Also it must not contain any characters or substrings that are not valid
582: * on the file system on which workspace root is located.
583: *
584: * @param name the name of a package
585: * @param sourceLevel the source level
586: * @param complianceLevel the compliance level
587: * @return a status object with code <code>IStatus.OK</code> if
588: * the given name is valid as a package name, otherwise a status
589: * object indicating what is wrong with the name
590: * @since 3.3
591: */
592: public static IStatus validatePackageName(String name,
593: String sourceLevel, String complianceLevel) {
594:
595: if (name == null) {
596: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
597: Messages.convention_package_nullName, null);
598: }
599: int length;
600: if ((length = name.length()) == 0) {
601: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
602: Messages.convention_package_emptyName, null);
603: }
604: if (name.charAt(0) == DOT || name.charAt(length - 1) == DOT) {
605: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
606: Messages.convention_package_dotName, null);
607: }
608: if (CharOperation.isWhitespace(name.charAt(0))
609: || CharOperation.isWhitespace(name
610: .charAt(name.length() - 1))) {
611: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1,
612: Messages.convention_package_nameWithBlanks, null);
613: }
614: int dot = 0;
615: while (dot != -1 && dot < length - 1) {
616: if ((dot = name.indexOf(DOT, dot + 1)) != -1
617: && dot < length - 1 && name.charAt(dot + 1) == DOT) {
618: return new Status(
619: IStatus.ERROR,
620: JavaCore.PLUGIN_ID,
621: -1,
622: Messages.convention_package_consecutiveDotsName,
623: null);
624: }
625: }
626: IWorkspace workspace = ResourcesPlugin.getWorkspace();
627: StringTokenizer st = new StringTokenizer(name, "."); //$NON-NLS-1$
628: boolean firstToken = true;
629: IStatus warningStatus = null;
630: while (st.hasMoreTokens()) {
631: String typeName = st.nextToken();
632: typeName = typeName.trim(); // grammar allows spaces
633: char[] scannedID = scannedIdentifier(typeName, sourceLevel,
634: complianceLevel);
635: if (scannedID == null) {
636: return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID,
637: -1, Messages.bind(
638: Messages.convention_illegalIdentifier,
639: typeName), null);
640: }
641: IStatus status = workspace.validateName(new String(
642: scannedID), IResource.FOLDER);
643: if (!status.isOK()) {
644: return status;
645: }
646: if (firstToken && scannedID.length > 0
647: && ScannerHelper.isUpperCase(scannedID[0])) {
648: if (warningStatus == null) {
649: warningStatus = new Status(IStatus.WARNING,
650: JavaCore.PLUGIN_ID, -1,
651: Messages.convention_package_uppercaseName,
652: null);
653: }
654: }
655: firstToken = false;
656: }
657: if (warningStatus != null) {
658: return warningStatus;
659: }
660: return JavaModelStatus.VERIFIED_OK;
661: }
662:
663: /**
664: * Validate a given classpath and output location for a project, using the following rules:
665: * <ul>
666: * <li> Classpath entries cannot collide with each other; that is, all entry paths must be unique.
667: * <li> The project output location path cannot be null, must be absolute and located inside the project.
668: * <li> Specific output locations (specified on source entries) can be null, if not they must be located inside the project,
669: * <li> A project entry cannot refer to itself directly (that is, a project cannot prerequisite itself).
670: * <li> Classpath entries or output locations cannot coincidate or be nested in each other, except for the following scenarii listed below:
671: * <ul><li> A source folder can coincidate with its own output location, in which case this output can then contain library archives.
672: * However, a specific output location cannot coincidate with any library or a distinct source folder than the one referring to it. </li>
673: * <li> A source/library folder can be nested in any source folder as long as the nested folder is excluded from the enclosing one. </li>
674: * <li> An output location can be nested in a source folder, if the source folder coincidates with the project itself, or if the output
675: * location is excluded from the source folder.
676: * </ul>
677: * </ul>
678: *
679: * Note that the classpath entries are not validated automatically. Only bound variables or containers are considered
680: * in the checking process (this allows to perform a consistency check on a classpath which has references to
681: * yet non existing projects, folders, ...).
682: * <p>
683: * This validation is intended to anticipate classpath issues prior to assigning it to a project. In particular, it will automatically
684: * be performed during the classpath setting operation (if validation fails, the classpath setting will not complete).
685: * <p>
686: * @param javaProject the given java project
687: * @param rawClasspath the given classpath
688: * @param projectOutputLocation the given output location
689: * @return a status object with code <code>IStatus.OK</code> if
690: * the given classpath and output location are compatible, otherwise a status
691: * object indicating what is wrong with the classpath or output location
692: * @since 2.0
693: */
694: public static IJavaModelStatus validateClasspath(
695: IJavaProject javaProject, IClasspathEntry[] rawClasspath,
696: IPath projectOutputLocation) {
697:
698: return ClasspathEntry.validateClasspath(javaProject,
699: rawClasspath, projectOutputLocation);
700: }
701:
702: /**
703: * Returns a Java model status describing the problem related to this classpath entry if any,
704: * a status object with code <code>IStatus.OK</code> if the entry is fine (that is, if the
705: * given classpath entry denotes a valid element to be referenced onto a classpath).
706: *
707: * @param project the given java project
708: * @param entry the given classpath entry
709: * @param checkSourceAttachment a flag to determine if source attachement should be checked
710: * @return a java model status describing the problem related to this classpath entry if any, a status object with code <code>IStatus.OK</code> if the entry is fine
711: * @since 2.0
712: */
713: public static IJavaModelStatus validateClasspathEntry(
714: IJavaProject project, IClasspathEntry entry,
715: boolean checkSourceAttachment) {
716: IJavaModelStatus status = ClasspathEntry
717: .validateClasspathEntry(project, entry,
718: checkSourceAttachment, true/*recurse in container*/);
719: if (status.getCode() == IJavaModelStatusConstants.INVALID_CLASSPATH
720: && ((ClasspathEntry) entry).isOptional())
721: return JavaModelStatus.VERIFIED_OK;
722: return status;
723: }
724:
725: /**
726: * Validate the given type variable name.
727: * <p>
728: * Syntax of a type variable name corresponds to a Java identifier (JLS3 4.3).
729: * For example, <code>"E"</code>.
730: *
731: * @param name the name of a type variable
732: * @return a status object with code <code>IStatus.OK</code> if
733: * the given name is valid as a type variable name, otherwise a status
734: * object indicating what is wrong with the name
735: * @since 3.1
736: * @deprecated Use {@link #validateTypeVariableName(String id, String sourceLevel, String complianceLevel)} instead
737: */
738: public static IStatus validateTypeVariableName(String name) {
739: return validateIdentifier(name, CompilerOptions.VERSION_1_3,
740: CompilerOptions.VERSION_1_3);
741: }
742:
743: /**
744: * Validate the given type variable name for the given source and compliance levels.
745: * <p>
746: * Syntax of a type variable name corresponds to a Java identifier (JLS3 4.3).
747: * For example, <code>"E"</code>.
748: *
749: * @param name the name of a type variable
750: * @param sourceLevel the source level
751: * @param complianceLevel the compliance level
752: * @return a status object with code <code>IStatus.OK</code> if
753: * the given name is valid as a type variable name, otherwise a status
754: * object indicating what is wrong with the name
755: * @since 3.3
756: */
757: public static IStatus validateTypeVariableName(String name,
758: String sourceLevel, String complianceLevel) {
759: return validateIdentifier(name, sourceLevel, complianceLevel);
760: }
761:
762: /**
763: * Validate that all compiler options of the given project match keys and values
764: * described in {@link JavaCore#getDefaultOptions()} method.
765: *
766: * @param javaProject the given java project
767: * @param inheritJavaCoreOptions inherit project options from JavaCore or not.
768: * @return a status object with code <code>IStatus.OK</code> if all project
769: * compiler options are valid, otherwise a status object indicating what is wrong
770: * with the keys and their value.
771: * @since 3.1
772: * TODO (frederic) finalize for all possible options (JavaCore, DefaultCodeFormatterOptions, AssistOptions) and open to API
773: */
774: /*
775: public static IStatus validateCompilerOptions(IJavaProject javaProject, boolean inheritJavaCoreOptions) {
776: return validateCompilerOptions(javaProject.getOptions(inheritJavaCoreOptions));
777: }
778: */
779:
780: /**
781: * Validate that all compiler options of the given project match keys and values
782: * described in {@link JavaCore#getDefaultOptions()} method.
783: *
784: * @param compilerOptions Map of options
785: * @return a status object with code <code>IStatus.OK</code> if all
786: * compiler options are valid, otherwise a status object indicating what is wrong
787: * with the keys and their value.
788: * @since 3.1
789: */
790: /*
791: public static IStatus validateCompilerOptions(Map compilerOptions) {
792:
793: // Get current options
794: String compliance = (String) compilerOptions.get(JavaCore.COMPILER_COMPLIANCE);
795: String source = (String) compilerOptions.get(JavaCore.COMPILER_SOURCE);
796: String target = (String) compilerOptions.get(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM);
797: if (compliance == null && source == null && target == null) {
798: return JavaModelStatus.VERIFIED_OK; // default is OK
799: }
800:
801: // Initialize multi-status
802: List errors = new ArrayList();
803:
804: // Set default for compliance if necessary (not set on project and not inherited...)
805: if (compliance == null) {
806: compliance = JavaCore.getOption(JavaCore.COMPILER_COMPLIANCE);
807: }
808:
809: // Verify compliance level value and set source and target default if necessary
810: long complianceLevel = 0;
811: long sourceLevel = 0;
812: long targetLevel = 0;
813: if (JavaCore.VERSION_1_3.equals(compliance)) {
814: complianceLevel = ClassFileConstants.JDK1_3;
815: if (source == null) {
816: source = JavaCore.VERSION_1_3;
817: sourceLevel = ClassFileConstants.JDK1_3;
818: }
819: if (target == null) {
820: target = JavaCore.VERSION_1_1;
821: targetLevel = ClassFileConstants.JDK1_1;
822: }
823: } else if (JavaCore.VERSION_1_4.equals(compliance)) {
824: complianceLevel = ClassFileConstants.JDK1_4;
825: if (source == null) {
826: source = JavaCore.VERSION_1_3;
827: sourceLevel = ClassFileConstants.JDK1_3;
828: }
829: if (target == null) {
830: target = JavaCore.VERSION_1_2;
831: targetLevel = ClassFileConstants.JDK1_2;
832: }
833: } else if (JavaCore.VERSION_1_5.equals(compliance)) {
834: complianceLevel = ClassFileConstants.JDK1_5;
835: if (source == null) {
836: source = JavaCore.VERSION_1_5;
837: sourceLevel = ClassFileConstants.JDK1_5;
838: }
839: if (target == null) {
840: target = JavaCore.VERSION_1_5;
841: targetLevel = ClassFileConstants.JDK1_5;
842: }
843: } else {
844: // compliance is not valid
845: errors.add(new JavaModelStatus(IStatus.ERROR, Util.bind("convention.compiler.invalidCompilerOption", compliance==null?"":compliance, JavaCore.COMPILER_COMPLIANCE))); //$NON-NLS-1$ //$NON-NLS-2$
846: }
847:
848: // Verify source value and set default for target if necessary
849: if (JavaCore.VERSION_1_4.equals(source)) {
850: sourceLevel = ClassFileConstants.JDK1_4;
851: if (target == null) {
852: target = JavaCore.VERSION_1_4;
853: targetLevel = ClassFileConstants.JDK1_4;
854: }
855: } else if (JavaCore.VERSION_1_5.equals(source)) {
856: sourceLevel = ClassFileConstants.JDK1_5;
857: if (target == null) {
858: target = JavaCore.VERSION_1_5;
859: targetLevel = ClassFileConstants.JDK1_5;
860: }
861: } else if (JavaCore.VERSION_1_3.equals(source)) {
862: sourceLevel = ClassFileConstants.JDK1_3;
863: } else {
864: // source is not valid
865: errors.add(new JavaModelStatus(IStatus.ERROR, Util.bind("convention.compiler.invalidCompilerOption", source==null?"":source, JavaCore.COMPILER_SOURCE))); //$NON-NLS-1$ //$NON-NLS-2$
866: }
867:
868: // Verify target value
869: if (targetLevel == 0) {
870: targetLevel = CompilerOptions.versionToJdkLevel(target);
871: if (targetLevel == 0) {
872: // target is not valid
873: errors.add(new JavaModelStatus(IStatus.ERROR, Util.bind("convention.compiler.invalidCompilerOption", target==null?"":target, JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM))); //$NON-NLS-1$ //$NON-NLS-2$
874: }
875: }
876:
877: // Check and set compliance/source/target compatibilities (only if they have valid values)
878: if (complianceLevel != 0 && sourceLevel != 0 && targetLevel != 0) {
879: // target must be 1.5 if source is 1.5
880: if (sourceLevel >= ClassFileConstants.JDK1_5 && targetLevel < ClassFileConstants.JDK1_5) {
881: errors.add(new JavaModelStatus(IStatus.ERROR, Util.bind("convention.compiler.incompatibleTargetForSource", target, JavaCore.VERSION_1_5))); //$NON-NLS-1$
882: }
883: else
884: // target must be 1.4 if source is 1.4
885: if (sourceLevel >= ClassFileConstants.JDK1_4 && targetLevel < ClassFileConstants.JDK1_4) {
886: errors.add(new JavaModelStatus(IStatus.ERROR, Util.bind("convention.compiler.incompatibleTargetForSource", target, JavaCore.VERSION_1_4))); //$NON-NLS-1$
887: }
888: // target cannot be greater than compliance level
889: if (complianceLevel < targetLevel){
890: errors.add(new JavaModelStatus(IStatus.ERROR, Util.bind("convention.compiler.incompatibleComplianceForTarget", compliance, JavaCore.VERSION_1_4))); //$NON-NLS-1$
891: }
892: // compliance must be 1.5 if source is 1.5
893: if (source.equals(JavaCore.VERSION_1_5) && complianceLevel < ClassFileConstants.JDK1_5) {
894: errors.add(new JavaModelStatus(IStatus.ERROR, Util.bind("convention.compiler.incompatibleComplianceForSource", compliance, JavaCore.VERSION_1_5))); //$NON-NLS-1$
895: } else
896: // compliance must be 1.4 if source is 1.4
897: if (source.equals(JavaCore.VERSION_1_4) && complianceLevel < ClassFileConstants.JDK1_4) {
898: errors.add(new JavaModelStatus(IStatus.ERROR, Util.bind("convention.compiler.incompatibleComplianceForSource", compliance, JavaCore.VERSION_1_4))); //$NON-NLS-1$
899: }
900: }
901:
902: // Return status
903: int size = errors.size();
904: switch (size) {
905: case 0:
906: return JavaModelStatus.VERIFIED_OK;
907: case 1:
908: return (IStatus) errors.get(0);
909: default:
910: IJavaModelStatus[] allStatus = new IJavaModelStatus[size];
911: errors.toArray(allStatus);
912: return JavaModelStatus.newMultiStatus(allStatus);
913: }
914: }
915: */
916: }
|