/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.core.model; import com.google.dart.tools.core.DartCore; import com.google.dart.tools.core.internal.model.DartModelStatusImpl; import com.google.dart.tools.core.internal.util.Messages; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; /** * The class <code>DartConventions</code> provides methods for checking Dart-specific conventions * such as name syntax. * * @coverage dart.tools.core.model */ public final class DartConventions { @SuppressWarnings("unused") private static class MessageHolder { public static MessageHolder forClassTypeAlias() { return new MessageHolder().initForClassTypeAlias(); } public static MessageHolder forCompilationUnit() { return new MessageHolder().initForCompilationUnit(); } public static MessageHolder forField() { return new MessageHolder().initForField(); } public static MessageHolder forFunction() { return new MessageHolder().initForFunction(); } public static MessageHolder forFunctionTypeAlias() { return new MessageHolder().initForFunctionTypeAlias(); } public static MessageHolder forMethod() { return new MessageHolder().initForMethod(); } public static MessageHolder forParameter() { return new MessageHolder().initForParameter(); } public static MessageHolder forPrefix() { return new MessageHolder().initForPrefix(); } public static MessageHolder forType() { return new MessageHolder().initForType(); } public static MessageHolder forTypeParameter() { return new MessageHolder().initForTypeParameter(); } public static MessageHolder forVariable() { return new MessageHolder().initForVariable(); } private String dollar; private String empty; private String initialCase; private String initialChar; private String internalChar; private String leadingOrTrailingBlanks; private String nullName; private String underscore; public String initialChar(String name) { return Messages.bind(initialChar, name); } public String internalChar(String name) { return Messages.bind(internalChar, name); } private MessageHolder initForClassTypeAlias() { dollar = Messages.convention_classTypeAliasName_dollar; empty = Messages.convention_classTypeAliasName_empty; initialCase = Messages.convention_classTypeAliasName_notLowercase; initialChar = Messages.convention_classTypeAliasName_initialChar; internalChar = Messages.convention_classTypeAliasName_internalChar; leadingOrTrailingBlanks = Messages.convention_classTypeAliasName_leadingOrTrailingBlanks; nullName = Messages.convention_classTypeAliasName_null; underscore = Messages.convention_classTypeAliasName_underscore; return this; } private MessageHolder initForCompilationUnit() { // dollar = Messages.convention_unitName_dollar; empty = Messages.convention_unitName_empty; // initialCase = Messages.convention_unitName_notUppercase; initialChar = Messages.convention_unitName_initialChar; internalChar = Messages.convention_unitName_internalChar; leadingOrTrailingBlanks = Messages.convention_unitName_leadingOrTrailingBlanks; nullName = Messages.convention_unitName_null; // underscore = Messages.convention_unitName_underscore; return this; } private MessageHolder initForField() { dollar = Messages.convention_fieldName_dollar; empty = Messages.convention_fieldName_empty; initialCase = Messages.convention_fieldName_notLowercase; initialChar = Messages.convention_fieldName_initialChar; internalChar = Messages.convention_fieldName_internalChar; leadingOrTrailingBlanks = Messages.convention_fieldName_leadingOrTrailingBlanks; nullName = Messages.convention_fieldName_null; underscore = Messages.convention_fieldName_underscore; return this; } private MessageHolder initForFunction() { dollar = Messages.convention_functionName_dollar; empty = Messages.convention_functionName_empty; initialCase = Messages.convention_functionName_notLowercase; initialChar = Messages.convention_functionName_initialChar; internalChar = Messages.convention_functionName_internalChar; leadingOrTrailingBlanks = Messages.convention_functionName_leadingOrTrailingBlanks; nullName = Messages.convention_functionName_null; underscore = Messages.convention_functionName_underscore; return this; } private MessageHolder initForFunctionTypeAlias() { dollar = Messages.convention_functionTypeAliasName_dollar; empty = Messages.convention_functionTypeAliasName_empty; initialCase = Messages.convention_functionTypeAliasName_notLowercase; initialChar = Messages.convention_functionTypeAliasName_initialChar; internalChar = Messages.convention_functionTypeAliasName_internalChar; leadingOrTrailingBlanks = Messages.convention_functionTypeAliasName_leadingOrTrailingBlanks; nullName = Messages.convention_functionTypeAliasName_null; underscore = Messages.convention_functionTypeAliasName_underscore; return this; } private MessageHolder initForMethod() { dollar = Messages.convention_methodName_dollar; empty = Messages.convention_methodName_empty; initialCase = Messages.convention_methodName_notLowercase; initialChar = Messages.convention_methodName_initialChar; internalChar = Messages.convention_methodName_internalChar; leadingOrTrailingBlanks = Messages.convention_methodName_leadingOrTrailingBlanks; nullName = Messages.convention_methodName_null; underscore = Messages.convention_methodName_underscore; return this; } private MessageHolder initForParameter() { dollar = Messages.convention_parameterName_dollar; empty = Messages.convention_parameterName_empty; initialCase = Messages.convention_parameterName_notLowercase; initialChar = Messages.convention_parameterName_initialChar; internalChar = Messages.convention_parameterName_internalChar; leadingOrTrailingBlanks = Messages.convention_parameterName_leadingOrTrailingBlanks; nullName = Messages.convention_parameterName_null; underscore = Messages.convention_parameterName_underscore; return this; } private MessageHolder initForPrefix() { // dollar = Messages.convention_prefix_dollar; empty = Messages.convention_prefix_empty; // initialCase = Messages.convention_prefix_notUppercase; initialChar = Messages.convention_prefix_initialChar; internalChar = Messages.convention_prefix_internalChar; leadingOrTrailingBlanks = Messages.convention_prefix_leadingOrTrailingBlanks; nullName = Messages.convention_prefix_null; // underscore = Messages.convention_prefix_underscore; return this; } private MessageHolder initForType() { dollar = Messages.convention_typeName_dollar; empty = Messages.convention_typeName_empty; initialCase = Messages.convention_typeName_notUppercase; initialChar = Messages.convention_typeName_initialChar; internalChar = Messages.convention_typeName_internalChar; leadingOrTrailingBlanks = Messages.convention_typeName_leadingOrTrailingBlanks; nullName = Messages.convention_typeName_null; return this; } private MessageHolder initForTypeParameter() { dollar = Messages.convention_typeParameterName_dollar; empty = Messages.convention_typeParameterName_empty; initialCase = Messages.convention_typeParameterName_notUppercase; initialChar = Messages.convention_typeParameterName_initialChar; internalChar = Messages.convention_typeParameterName_internalChar; leadingOrTrailingBlanks = Messages.convention_typeParameterName_leadingOrTrailingBlanks; nullName = Messages.convention_typeParameterName_null; return this; } private MessageHolder initForVariable() { dollar = Messages.convention_variableName_dollar; empty = Messages.convention_variableName_empty; initialCase = Messages.convention_variableName_notLowercase; initialChar = Messages.convention_variableName_initialChar; internalChar = Messages.convention_variableName_internalChar; leadingOrTrailingBlanks = Messages.convention_variableName_leadingOrTrailingBlanks; nullName = Messages.convention_variableName_null; underscore = Messages.convention_variableName_underscore; return this; } } /** * Validate the given field name. Return a status object indicating the validity of the name. The * status will have the code {@link IStatus.OK} if the name is valid as a field name, the code * {@link IStatus.WARNING} if the name is discouraged, or the code {@link IStatus.ERROR} if the * name is illegal. If the identifier is not valid then the status will have a message indicating * why. * * @param name the field name being validated * @return a status object indicating the validity of the name */ public static IStatus validateFieldName(String name) { return validateLowerCamelCase(name, MessageHolder.forField()); } /** * Validate the given function name. Return a status object indicating the validity of the name. * The status will have the code {@link IStatus.OK} if the name is valid as a function name, the * code {@link IStatus.WARNING} if the name is discouraged, or the code {@link IStatus.ERROR} if * the name is illegal. If the identifier is not valid then the status will have a message * indicating why. * * @param name the function name being validated * @return a status object indicating the validity of the name */ public static IStatus validateFunctionName(String name) { return validateLowerCamelCase(name, MessageHolder.forFunction()); } /** * Validate the given function type alias name. Return a status object indicating the validity of * the name. The status will have the code {@link IStatus.OK} if the name is valid as a function * type alias name, the code {@link IStatus.WARNING} if the name is discouraged, or the code * {@link IStatus.ERROR} if the name is illegal. If the identifier is not valid then the status * will have a message indicating why. * * @param name the function name being validated * @return a status object indicating the validity of the name */ public static IStatus validateFunctionTypeAliasName(String name) { return validateUpperCamelCase(name, MessageHolder.forFunctionTypeAlias()); } /** * Validate the given method name. Return a status object indicating the validity of the name. The * status will have the code {@link IStatus.OK} if the name is valid as a method name, the code * {@link IStatus.WARNING} if the name is discouraged, or the code {@link IStatus.ERROR} if the * name is illegal. If the identifier is not valid then the status will have a message indicating * why. * * @param name the method name being validated * @return a status object indicating the validity of the name */ public static IStatus validateMethodName(String name) { return validateLowerCamelCase(name, MessageHolder.forMethod()); } /** * Validate the given parameter name. Return a status object indicating the validity of the name. * The status will have the code {@link IStatus.OK} if the name is valid as a parameter name, the * code {@link IStatus.WARNING} if the name is discouraged, or the code {@link IStatus.ERROR} if * the name is illegal. If the identifier is not valid then the status will have a message * indicating why. * * @param name the parameter name being validated * @return a status object indicating the validity of the name */ public static IStatus validateParameterName(String name) { return validateLowerCamelCase(name, MessageHolder.forParameter()); } /** * Validate the given Dart prefix. Return a status object indicating the validity of the name. The * status will have the code {@link IStatus.OK} if the given name is valid as a Dart prefix, the * code {@link IStatus.WARNING} if the given name is discouraged, or the code * {@link IStatus.ERROR} if the name is illegal. If the identifier is not valid then the status * will have a message indicating why. * * @param prefix the prefix being validated * @return a status object indicating the validity of the name */ public static IStatus validatePrefix(String prefix) { // null if (prefix == null) { return new Status( IStatus.ERROR, DartCore.PLUGIN_ID, -1, Messages.convention_prefix_null, null); } // leading or trailing space String trimmed = prefix.trim(); if (!prefix.equals(trimmed)) { return new Status( IStatus.ERROR, DartCore.PLUGIN_ID, -1, Messages.convention_prefix_leadingOrTrailingBlanks, null); } // is not identifier IStatus status = validateIdentifier(prefix, MessageHolder.forPrefix()); if (!status.isOK()) { return status; } // OK return DartModelStatusImpl.VERIFIED_OK; } /** * Validate the given Dart type name, which can be either simple or qualified. Return a status * object indicating the validity of the name. The status will have the code {@link IStatus.OK} if * the given name is valid as a Dart type name, the code {@link IStatus.WARNING} if the given name * is discouraged, or the code {@link IStatus.ERROR} if the name is illegal. If the identifier is * not valid then the status will have a message indicating why. * <p> * For example, <code>"Object"</code> or <code>"goog$DB.Record"</code>. * * @param name the type name being validated * @return a status object indicating the validity of the name */ public static IStatus validateTypeName(String name) { return validateUpperCamelCase(name, MessageHolder.forType()); } /** * Validate the given type parameter name. Return a status object indicating the validity of the * name. The status will have the code {@link IStatus.OK} if the name is valid as a type parameter * name, the code {@link IStatus.WARNING} if the name is discouraged, or the code * {@link IStatus.ERROR} if the name is illegal. If the identifier is not valid then the status * will have a message indicating why. * * @param name the name being validated * @return a status object indicating the validity of the name */ public static IStatus validateTypeParameterName(String name) { return validateUpperCamelCase(name, MessageHolder.forTypeParameter()); } private static IStatus validateIdentifier(String identifier, MessageHolder messageHolder) { int length = identifier.length(); if (length == 0) { return new Status(IStatus.ERROR, DartCore.PLUGIN_ID, -1, messageHolder.empty, null); } char currentChar = identifier.charAt(0); if (!Character.isLetter(currentChar) && currentChar != '_' && currentChar != '$') { return new Status( IStatus.ERROR, DartCore.PLUGIN_ID, -1, messageHolder.initialChar(identifier), null); } for (int i = 1; i < length; i++) { currentChar = identifier.charAt(i); if (!Character.isLetterOrDigit(currentChar) && currentChar != '_' && currentChar != '$') { return new Status( IStatus.ERROR, DartCore.PLUGIN_ID, -1, messageHolder.internalChar(identifier), null); } } return DartModelStatusImpl.VERIFIED_OK; } /** * Validate the given identifier, which should be lower camel case. Return a status object * indicating the validity of the identifier. The status will have the code {@link IStatus.OK} if * the identifier is valid, {@link IStatus.WARNING} if the identifier is discouraged, or * {@link IStatus.ERROR} if the identifier is illegal. If the identifier is not valid then the * status will have a message indicating why. * * @param identifier the identifier being validated * @param messageHolder a holder of messages explaining problems * @return a status object indicating the validity of the identifier */ private static IStatus validateLowerCamelCase(String identifier, MessageHolder messageHolder) { // null if (identifier == null) { return new Status(IStatus.ERROR, DartCore.PLUGIN_ID, -1, messageHolder.nullName, null); } // has leading/trailing spaces String trimmed = identifier.trim(); if (!identifier.equals(trimmed)) { return new Status( IStatus.ERROR, DartCore.PLUGIN_ID, -1, messageHolder.leadingOrTrailingBlanks, null); } // is not identifier IStatus status = validateIdentifier(identifier, messageHolder); if (!status.isOK()) { return status; } // if (identifier.indexOf('$') >= 0) { // return new Status(IStatus.WARNING, DartCore.PLUGIN_ID, -1, messageHolder.dollar, null); // } // if (identifier.indexOf('_') >= 0) { // return new Status(IStatus.WARNING, DartCore.PLUGIN_ID, -1, messageHolder.underscore, null); // } // is private, OK if (identifier.charAt(0) == '_') { return DartModelStatusImpl.VERIFIED_OK; } // does not start with lower case if (!Character.isLowerCase(identifier.charAt(0))) { return new Status(IStatus.WARNING, DartCore.PLUGIN_ID, -1, messageHolder.initialCase, null); } // OK return DartModelStatusImpl.VERIFIED_OK; } /** * Validate the given identifier, which should be upper camel case. Return a status object * indicating the validity of the identifier. The status will have the code {@link IStatus.OK} if * the identifier is valid, {@link IStatus.WARNING} if the identifier is discouraged, or * {@link IStatus.ERROR} if the identifier is illegal. If the identifier is not valid then the * status will have a message indicating why. * * @param identifier the identifier being validated * @param messageHolder a holder of messages explaining problems * @return a status object indicating the validity of the identifier */ private static IStatus validateUpperCamelCase(String identifier, MessageHolder messageHolder) { // null if (identifier == null) { return new Status(IStatus.ERROR, DartCore.PLUGIN_ID, -1, messageHolder.nullName, null); } // leading or trailing spaces String trimmed = identifier.trim(); if (!identifier.equals(trimmed)) { return new Status( IStatus.ERROR, DartCore.PLUGIN_ID, -1, messageHolder.leadingOrTrailingBlanks, null); } // is not identifier IStatus status = validateIdentifier(identifier, messageHolder); if (!status.isOK()) { return status; } // if (identifier.indexOf('$') >= 0) { // return new Status(IStatus.WARNING, DartCore.PLUGIN_ID, -1, messageHolder.dollar, null); // } // if (identifier.indexOf('_') >= 0) { // return new Status(IStatus.WARNING, DartCore.PLUGIN_ID, -1, messageHolder.underscore, null); // } // is private, OK if (identifier.charAt(0) == '_') { return DartModelStatusImpl.VERIFIED_OK; } // does not start with upper case if (!Character.isUpperCase(identifier.charAt(0))) { return new Status(IStatus.WARNING, DartCore.PLUGIN_ID, -1, messageHolder.initialCase, null); } // OK return DartModelStatusImpl.VERIFIED_OK; } /** * Prevent the creation of instances of this class. */ private DartConventions() { super(); } }