private static bool IsValidInheritedType(string str, out string err, out CSharpClassNameValidationResult init) { if (string.IsNullOrWhiteSpace(str)) { init = null; err = "Missing inherited class specifier."; return(false); } init = CSharpClassNameValidator.ValidateInitialization(str, true); if (!init.Success) { err = init.ErrorDescription; return(false); } if (CSharpKeywords.IsTypeAliasKeyword(init.BaseName)) { err = string.Format("Cannot inherit from the built in type alias '{0}'.", init.BaseName); init = null; return(false); } err = null; return(true); }
private static bool IsValidTypeConstraint(string str, out string err, out CSharpTypeConstraintValidationResult init) { if (string.IsNullOrWhiteSpace(str)) { init = null; err = "Missing type constraint specifier."; return(false); } init = new CSharpTypeConstraintValidationResult(); if (str == "class") { init.ConstraintType = CSharpTypeConstraintType.Class; err = null; return(true); } if (str == "struct") { init.ConstraintType = CSharpTypeConstraintType.Struct; err = null; return(true); } if (Regex.IsMatch(str, @"^new\(\s*\)$")) { init.ConstraintType = CSharpTypeConstraintType.New; err = null; return(true); } init.TypeSignature = CSharpClassNameValidator.ValidateInitialization(str, true); init.ConstraintType = CSharpTypeConstraintType.Type; if (!init.TypeSignature.Success) { err = init.TypeSignature.ErrorDescription; init = null; return(false); } if (CSharpKeywords.IsTypeAliasKeyword(init.TypeSignature.BaseName)) { err = string.Format("Cannot use the built in type alias '{0}' as a type constraint.", init.TypeSignature.BaseName); init = null; return(false); } err = null; return(true); }
private static CSharpClassNameValidationResult _Validate(string input, ClassSigType signatureType, bool allowBuiltinAliases, CSharpParsedTypeValidateTypeCallback validateTypeCallback, int index) { if (input == null) { throw new ArgumentNullException("input", "Class name/signature string cannot be null!"); } if (string.IsNullOrWhiteSpace(input)) { return(new CSharpClassNameValidationResult { Success = false, ErrorDescription = "Class name/signature cannot be whitespace.", ErrorIndex = index, }); } string fullyQualifiedName = ""; var genericArgs = new GenericArray <CSharpClassNameValidationResult>(); var qualifications = new GenericArray <Qualification>() { new Qualification(new StringBuilder(), index) }; string genericPart = ""; bool isGeneric = false; int genericBrackets = 0; foreach (var c in input) { //enter generic arguments if (c == '<') { isGeneric = true; genericBrackets++; } //check if we have gotten to the generic part of the type signature yet (if any) if (!isGeneric) { if (c == '.') { //qualifier operator is not allowed anywhere in declaration signatures because //they only consist of a raw type name and generic argument specifications if (signatureType == ClassSigType.Declaration) { return(new CSharpClassNameValidationResult { Success = false, ErrorDescription = string.Format( "'.' name qualifier operator is not valid in a class declaration/generic " + "type placeholder name."), ErrorIndex = index, }); } //detect a missing qualifier section that's terminated with a dot. if (string.IsNullOrWhiteSpace(qualifications.Last().ToString())) { return(new CSharpClassNameValidationResult { Success = false, ErrorDescription = "\'..\' is an invalid use of the qualification operator.", ErrorIndex = index, }); } qualifications.Add(new Qualification(new StringBuilder(), index + 1)); } else { qualifications.Last().Builder.Append(c); } } if (genericBrackets == 0 && !isGeneric) { //accumulate to our fully qualified name fullyQualifiedName += c; } else if (genericBrackets == 0 && isGeneric) { //we have exited even pairs of brackets and are on the //other side of the generic arguments at the end of the signature //there should not be anything here return(new CSharpClassNameValidationResult { Success = false, ErrorDescription = "extra content found after generic argument list.", ErrorIndex = index }); } else if (!(genericBrackets == 1 && c == '<')) { //passed the start of the first < in the signature by 1 if ((c == ',' || c == '>') && genericBrackets == 1) { //we have accumulated a type argument suitable for recursive decent //validate it recursively var validateGenericArgument = _Validate(genericPart.Trim(), signatureType, allowBuiltinAliases, validateTypeCallback, index - genericPart.Length); //return immediately on failure if (!validateGenericArgument.Success) { return(validateGenericArgument); } //add the validated 'tree' genericArgs.Add(validateGenericArgument); //reset the accumulator genericPart = ""; } else { //accumulate until we hit a comma or the > character genericPart += c; } } if (c == '>') { //exit a generic type scope genericBrackets--; } index++; } if (genericBrackets > 0) { //something is amiss with bracket matching return(new CSharpClassNameValidationResult { Success = false, ErrorDescription = "mismatched generic type brackets.", ErrorIndex = index }); } //there may be only one qualification, in which case //the base name is also the fully qualified name. var baseName = qualifications.Last(); if (qualifications.Count > 1) { //uses qualified names, this is definitely an initialization signature //because the qualifier '.' operator returns an error in declaration signatures //above the recursive call to validate foreach (var name in qualifications) { if (string.IsNullOrWhiteSpace(name.Builder.ToString())) { return(new CSharpClassNameValidationResult { Success = false, ErrorDescription = string.Format("qualified type name '{0}' is incomplete.", fullyQualifiedName), ErrorIndex = name.StartIndex }); } } foreach (var name in qualifications) { //check for syntax errors in the qualified name pieces, they need to be valid ID's and not keywords //IsValidIdentifier takes care of both these criteria if (!CSharpIDValidator.IsValidIdentifier(name.Builder.ToString())) { //sound something funky return(new CSharpClassNameValidationResult { Success = false, ErrorDescription = string.Format( "'{0}' is not valid in the given qualified type name '{1}'.", name.Builder, fullyQualifiedName), ErrorIndex = name.StartIndex }); } } } else { var shortName = baseName.Builder.ToString(); //single type argument to a generic type if (string.IsNullOrWhiteSpace(shortName)) { return(new CSharpClassNameValidationResult { Success = false, ErrorDescription = string.Format("missing generic {0} name.", signatureType == ClassSigType.Initialization ? "type argument" : "placeholder type"), ErrorIndex = baseName.StartIndex, }); } bool aliasInitialization = allowBuiltinAliases && CSharpKeywords.BuiltInTypeMap.ContainsKey(shortName) && signatureType == ClassSigType.Initialization; if (!aliasInitialization && !CSharpIDValidator.IsValidIdentifier(baseName.Builder.ToString())) { return(new CSharpClassNameValidationResult { Success = false, ErrorDescription = string.Format("'{0}' is not an allowed CSharp identifier.", baseName.Builder), ErrorIndex = baseName.StartIndex }); } } var baseNameString = baseName.Builder.ToString(); if (isGeneric && CSharpKeywords.IsTypeAliasKeyword(fullyQualifiedName)) { return(new CSharpClassNameValidationResult { Success = false, ErrorDescription = string.Format("Built in type alias '{0}' is not a generic type.", baseName.Builder), ErrorIndex = baseName.StartIndex }); } //success var classDescription = new CSharpClassNameValidationResult() { QualifiedName = fullyQualifiedName, BaseName = baseNameString, GenericArguments = genericArgs, IsGeneric = isGeneric, Success = true }; if (isGeneric) { classDescription.FullSignature = fullyQualifiedName + "<" + string.Join(", ", classDescription.GenericArguments.Select(x => x.FullSignature)) + ">"; } else { classDescription.FullSignature = fullyQualifiedName; } if (validateTypeCallback == null || signatureType != ClassSigType.Initialization) { return(classDescription); } var typeCheckResult = validateTypeCallback(classDescription); if (typeCheckResult.IsValid) { return(classDescription); } classDescription.FullSignature = null; classDescription.ErrorIndex = qualifications.First().StartIndex; classDescription.ErrorDescription = typeCheckResult.ErrorMessage; classDescription.Success = false; return(classDescription); }