UniqueCodeIdentifierScope.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Description
  5. {
  6. using System;
  7. using System.CodeDom;
  8. using System.Collections.Generic;
  9. using System.Globalization;
  10. using System.Runtime;
  11. using System.Text;
  12. class UniqueCodeIdentifierScope
  13. {
  14. const int MaxIdentifierLength = 511;
  15. SortedList<string, string> names;
  16. // assumes identifier is valid
  17. protected virtual void AddIdentifier(string identifier)
  18. {
  19. if (names == null)
  20. names = new SortedList<string, string>(StringComparer.OrdinalIgnoreCase);
  21. names.Add(identifier, identifier);
  22. }
  23. // assumes identifier is valid
  24. public void AddReserved(string identifier)
  25. {
  26. Fx.Assert(IsUnique(identifier), "");
  27. AddIdentifier(identifier);
  28. }
  29. // validates name before trying to add
  30. public string AddUnique(string name, string defaultName)
  31. {
  32. string validIdentifier = MakeValid(name, defaultName);
  33. string uniqueIdentifier = validIdentifier;
  34. int i = 1;
  35. while (!IsUnique(uniqueIdentifier))
  36. {
  37. uniqueIdentifier = validIdentifier + (i++).ToString(CultureInfo.InvariantCulture);
  38. }
  39. AddIdentifier(uniqueIdentifier);
  40. return uniqueIdentifier;
  41. }
  42. // assumes identifier is valid
  43. public virtual bool IsUnique(string identifier)
  44. {
  45. return names == null || !names.ContainsKey(identifier);
  46. }
  47. static bool IsValidStart(char c)
  48. {
  49. return (Char.GetUnicodeCategory(c) != UnicodeCategory.DecimalDigitNumber);
  50. }
  51. static bool IsValid(char c)
  52. {
  53. UnicodeCategory uc = Char.GetUnicodeCategory(c);
  54. // each char must be Lu, Ll, Lt, Lm, Lo, Nd, Mn, Mc, Pc
  55. switch (uc)
  56. {
  57. case UnicodeCategory.UppercaseLetter: // Lu
  58. case UnicodeCategory.LowercaseLetter: // Ll
  59. case UnicodeCategory.TitlecaseLetter: // Lt
  60. case UnicodeCategory.ModifierLetter: // Lm
  61. case UnicodeCategory.OtherLetter: // Lo
  62. case UnicodeCategory.DecimalDigitNumber: // Nd
  63. case UnicodeCategory.NonSpacingMark: // Mn
  64. case UnicodeCategory.SpacingCombiningMark: // Mc
  65. case UnicodeCategory.ConnectorPunctuation: // Pc
  66. return true;
  67. default:
  68. return false;
  69. }
  70. }
  71. public static string MakeValid(string identifier, string defaultIdentifier)
  72. {
  73. if (String.IsNullOrEmpty(identifier))
  74. return defaultIdentifier;
  75. if (identifier.Length <= MaxIdentifierLength && System.CodeDom.Compiler.CodeGenerator.IsValidLanguageIndependentIdentifier(identifier))
  76. return identifier;
  77. StringBuilder builder = new StringBuilder();
  78. for (int i = 0; i < identifier.Length && builder.Length < MaxIdentifierLength; i++)
  79. {
  80. char c = identifier[i];
  81. if (IsValid(c))
  82. {
  83. if (builder.Length == 0)
  84. {
  85. // check for valid start char
  86. if (!IsValidStart(c))
  87. builder.Append('_');
  88. }
  89. builder.Append(c);
  90. }
  91. }
  92. if (builder.Length == 0)
  93. return defaultIdentifier;
  94. return builder.ToString();
  95. }
  96. }
  97. class UniqueCodeNamespaceScope : UniqueCodeIdentifierScope
  98. {
  99. CodeNamespace codeNamespace;
  100. // possible direction: add an option to cache for multi-use cases
  101. public UniqueCodeNamespaceScope(CodeNamespace codeNamespace)
  102. {
  103. this.codeNamespace = codeNamespace;
  104. }
  105. public CodeNamespace CodeNamespace
  106. {
  107. get { return this.codeNamespace; }
  108. }
  109. protected override void AddIdentifier(string identifier)
  110. {
  111. }
  112. public CodeTypeReference AddUnique(CodeTypeDeclaration codeType, string name, string defaultName)
  113. {
  114. codeType.Name = base.AddUnique(name, defaultName);
  115. codeNamespace.Types.Add(codeType);
  116. return ServiceContractGenerator.NamespaceHelper.GetCodeTypeReference(this.codeNamespace, codeType);
  117. }
  118. public override bool IsUnique(string identifier)
  119. {
  120. return !NamespaceContainsType(identifier);
  121. }
  122. bool NamespaceContainsType(string typeName)
  123. {
  124. foreach (CodeTypeDeclaration codeType in codeNamespace.Types)
  125. {
  126. if (String.Compare(codeType.Name, typeName, StringComparison.OrdinalIgnoreCase) == 0)
  127. {
  128. return true;
  129. }
  130. }
  131. return false;
  132. }
  133. }
  134. }