PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/Microsoft.Build/Microsoft.Build/Microsoft/Build/Evaluation/ExpressionShredder.cs

#
C# | 635 lines | 627 code | 8 blank | 0 comment | 74 complexity | a447007d7632df23d6649e584473c55f MD5 | raw file
Possible License(s): Apache-2.0, LGPL-3.0
  1. namespace Microsoft.Build.Evaluation
  2. {
  3. using Microsoft.Build.Collections;
  4. using Microsoft.Build.Shared;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Runtime;
  8. internal static class ExpressionShredder
  9. {
  10. internal static bool ContainsMetadataExpressionOutsideTransform(string expression)
  11. {
  12. ItemsAndMetadataPair pair = new ItemsAndMetadataPair(null, null);
  13. GetReferencedItemNamesAndMetadata(expression, 0, expression.Length, ref pair, ShredderOptions.MetadataOutsideTransforms);
  14. return ((pair.Metadata != null) && (pair.Metadata.Count > 0));
  15. }
  16. internal static List<ItemExpressionCapture> GetReferencedItemExpressions(string expression)
  17. {
  18. return GetReferencedItemExpressions(expression, 0, expression.Length);
  19. }
  20. internal static List<ItemExpressionCapture> GetReferencedItemExpressions(string expression, int start, int end)
  21. {
  22. List<ItemExpressionCapture> list = null;
  23. if (expression.IndexOf('@') < 0)
  24. {
  25. return null;
  26. }
  27. for (int i = start; i < end; i++)
  28. {
  29. if (!Sink(expression, ref i, end, '@', '('))
  30. {
  31. continue;
  32. }
  33. List<ItemExpressionCapture> captures = null;
  34. string itemType = null;
  35. string separator = null;
  36. int separatorStart = -1;
  37. int length = -1;
  38. int num2 = i - 1;
  39. int index = i - 2;
  40. SinkWhitespace(expression, ref i);
  41. int startIndex = i;
  42. if (!SinkValidName(expression, ref i, end))
  43. {
  44. i = num2;
  45. continue;
  46. }
  47. if (((end > i) && (expression[i - 1] == '-')) && (expression[i] == '>'))
  48. {
  49. i--;
  50. }
  51. itemType = expression.Substring(startIndex, i - startIndex);
  52. SinkWhitespace(expression, ref i);
  53. bool flag = true;
  54. while (Sink(expression, ref i, end, '-', '>') && flag)
  55. {
  56. SinkWhitespace(expression, ref i);
  57. int startTransform = i;
  58. bool flag2 = SinkSingleQuotedExpression(expression, ref i, end);
  59. if (flag2)
  60. {
  61. int num8 = startTransform + 1;
  62. int num9 = i - 1;
  63. if (captures == null)
  64. {
  65. captures = new List<ItemExpressionCapture>();
  66. }
  67. captures.Add(new ItemExpressionCapture(num8, num9 - num8, expression.Substring(num8, num9 - num8)));
  68. }
  69. else
  70. {
  71. startTransform = i;
  72. ItemExpressionCapture item = SinkItemFunctionExpression(expression, startTransform, ref i, end);
  73. if (item != null)
  74. {
  75. if (captures == null)
  76. {
  77. captures = new List<ItemExpressionCapture>();
  78. }
  79. captures.Add(item);
  80. continue;
  81. }
  82. if (!flag2 && (item == null))
  83. {
  84. i = num2;
  85. flag = false;
  86. }
  87. }
  88. }
  89. if (flag)
  90. {
  91. SinkWhitespace(expression, ref i);
  92. if (Sink(expression, ref i, ','))
  93. {
  94. SinkWhitespace(expression, ref i);
  95. if (!Sink(expression, ref i, '\''))
  96. {
  97. i = num2;
  98. continue;
  99. }
  100. int num10 = expression.IndexOf('\'', i);
  101. if (num10 == -1)
  102. {
  103. i = num2;
  104. continue;
  105. }
  106. separatorStart = i - index;
  107. length = num10 - i;
  108. separator = expression.Substring(i, length);
  109. i = num10 + 1;
  110. }
  111. SinkWhitespace(expression, ref i);
  112. if (!Sink(expression, ref i, ')'))
  113. {
  114. i = num2;
  115. }
  116. else
  117. {
  118. int num11 = i;
  119. i--;
  120. if (list == null)
  121. {
  122. list = new List<ItemExpressionCapture>();
  123. }
  124. ItemExpressionCapture capture2 = new ItemExpressionCapture(index, num11 - index, expression.Substring(index, num11 - index), itemType, separator, separatorStart, length, captures);
  125. list.Add(capture2);
  126. }
  127. }
  128. }
  129. return list;
  130. }
  131. internal static ItemsAndMetadataPair GetReferencedItemNamesAndMetadata(List<string> expressions)
  132. {
  133. ItemsAndMetadataPair pair = new ItemsAndMetadataPair(null, null);
  134. foreach (string str in expressions)
  135. {
  136. GetReferencedItemNamesAndMetadata(str, 0, str.Length, ref pair, ShredderOptions.All);
  137. }
  138. return pair;
  139. }
  140. private static void GetReferencedItemNamesAndMetadata(string expression, int start, int end, ref ItemsAndMetadataPair pair, ShredderOptions whatToShredFor)
  141. {
  142. for (int i = start; i < end; i++)
  143. {
  144. int num2;
  145. if (Sink(expression, ref i, end, '@', '('))
  146. {
  147. num2 = i - 1;
  148. SinkWhitespace(expression, ref i);
  149. int startIndex = i;
  150. if (!SinkValidName(expression, ref i, end))
  151. {
  152. i = num2;
  153. }
  154. else
  155. {
  156. if (((end > i) && (expression[i - 1] == '-')) && (expression[i] == '>'))
  157. {
  158. i--;
  159. }
  160. string item = expression.Substring(startIndex, i - startIndex);
  161. SinkWhitespace(expression, ref i);
  162. bool flag = true;
  163. while (Sink(expression, ref i, end, '-', '>') && flag)
  164. {
  165. SinkWhitespace(expression, ref i);
  166. int startTransform = i;
  167. bool flag2 = SinkSingleQuotedExpression(expression, ref i, end);
  168. if (!flag2)
  169. {
  170. ItemExpressionCapture capture = SinkItemFunctionExpression(expression, startTransform, ref i, end);
  171. if (((capture == null) && !flag2) && (capture == null))
  172. {
  173. i = num2;
  174. flag = false;
  175. }
  176. }
  177. }
  178. if (flag)
  179. {
  180. SinkWhitespace(expression, ref i);
  181. if (Sink(expression, ref i, ','))
  182. {
  183. SinkWhitespace(expression, ref i);
  184. if (!Sink(expression, ref i, '\''))
  185. {
  186. i = num2;
  187. continue;
  188. }
  189. int index = expression.IndexOf('\'', i);
  190. if (index == -1)
  191. {
  192. i = num2;
  193. continue;
  194. }
  195. GetReferencedItemNamesAndMetadata(expression, i, index, ref pair, ShredderOptions.MetadataOutsideTransforms);
  196. i = index + 1;
  197. }
  198. SinkWhitespace(expression, ref i);
  199. if (!Sink(expression, ref i, ')'))
  200. {
  201. i = num2;
  202. }
  203. else
  204. {
  205. if ((whatToShredFor & ShredderOptions.ItemTypes) != ShredderOptions.Invalid)
  206. {
  207. pair.Items = pair.Items ?? new HashSet<string>(MSBuildNameIgnoreCaseComparer.Default);
  208. pair.Items.Add(item);
  209. }
  210. i--;
  211. }
  212. }
  213. }
  214. }
  215. else if (Sink(expression, ref i, end, '%', '('))
  216. {
  217. num2 = i - 1;
  218. SinkWhitespace(expression, ref i);
  219. int num6 = i;
  220. if (!SinkValidName(expression, ref i, end))
  221. {
  222. i = num2;
  223. }
  224. else
  225. {
  226. string str4;
  227. string str5;
  228. string str2 = expression.Substring(num6, i - num6);
  229. string itemName = null;
  230. SinkWhitespace(expression, ref i);
  231. if (Sink(expression, ref i, '.'))
  232. {
  233. SinkWhitespace(expression, ref i);
  234. num6 = i;
  235. if (!SinkValidName(expression, ref i, end))
  236. {
  237. i = num2;
  238. continue;
  239. }
  240. itemName = str2;
  241. str4 = expression.Substring(num6, i - num6);
  242. str5 = itemName + "." + str4;
  243. }
  244. else
  245. {
  246. str4 = str2;
  247. str5 = str4;
  248. }
  249. SinkWhitespace(expression, ref i);
  250. if (!Sink(expression, ref i, ')'))
  251. {
  252. i = num2;
  253. }
  254. else
  255. {
  256. if ((whatToShredFor & ShredderOptions.MetadataOutsideTransforms) != ShredderOptions.Invalid)
  257. {
  258. pair.Metadata = pair.Metadata ?? new Dictionary<string, MetadataReference>(MSBuildNameIgnoreCaseComparer.Default);
  259. pair.Metadata[str5] = new MetadataReference(itemName, str4);
  260. }
  261. i--;
  262. }
  263. }
  264. }
  265. }
  266. }
  267. private static bool Sink(string expression, ref int i, char c)
  268. {
  269. if ((i < expression.Length) && (expression[i] == c))
  270. {
  271. i++;
  272. return true;
  273. }
  274. return false;
  275. }
  276. private static bool Sink(string expression, ref int i, int end, char c1, char c2)
  277. {
  278. if (((i < (end - 1)) && (expression[i] == c1)) && (expression[i + 1] == c2))
  279. {
  280. i += 2;
  281. return true;
  282. }
  283. return false;
  284. }
  285. private static unsafe bool SinkArgumentsInParentheses(string expression, ref int i, int end)
  286. {
  287. int num = 0;
  288. int length = expression.Length;
  289. fixed (char* str = ((char*) expression))
  290. {
  291. char ch;
  292. char* chPtr = str;
  293. if (chPtr[i] == '(')
  294. {
  295. num++;
  296. i++;
  297. goto Label_0085;
  298. }
  299. return false;
  300. Label_0036:
  301. ch = chPtr[i];
  302. switch (ch)
  303. {
  304. case '\'':
  305. case '`':
  306. case '"':
  307. {
  308. int num3 = i;
  309. if (!SinkUntilClosingQuote(ch, expression, ref i, end))
  310. {
  311. i = num3;
  312. return false;
  313. }
  314. break;
  315. }
  316. case '(':
  317. num++;
  318. break;
  319. case ')':
  320. num--;
  321. break;
  322. }
  323. i++;
  324. Label_0085:
  325. if (((i < length) && (i < end)) && (num > 0))
  326. {
  327. goto Label_0036;
  328. }
  329. }
  330. return (num == 0);
  331. }
  332. private static ItemExpressionCapture SinkItemFunctionExpression(string expression, int startTransform, ref int i, int end)
  333. {
  334. if (!SinkValidName(expression, ref i, end))
  335. {
  336. return null;
  337. }
  338. int num = i;
  339. SinkWhitespace(expression, ref i);
  340. int startIndex = i + 1;
  341. if (!SinkArgumentsInParentheses(expression, ref i, end))
  342. {
  343. return null;
  344. }
  345. int num3 = i - 1;
  346. ItemExpressionCapture capture = new ItemExpressionCapture(startTransform, i - startTransform, expression.Substring(startTransform, i - startTransform)) {
  347. FunctionName = expression.Substring(startTransform, num - startTransform)
  348. };
  349. if (num3 > startIndex)
  350. {
  351. capture.FunctionArguments = expression.Substring(startIndex, num3 - startIndex);
  352. }
  353. return capture;
  354. }
  355. private static bool SinkSingleQuotedExpression(string expression, ref int i, int end)
  356. {
  357. if (Sink(expression, ref i, '\''))
  358. {
  359. while ((i < end) && (expression[i] != '\''))
  360. {
  361. i++;
  362. }
  363. i++;
  364. if (end <= i)
  365. {
  366. return false;
  367. }
  368. return true;
  369. }
  370. return false;
  371. }
  372. private static unsafe bool SinkUntilClosingQuote(char quoteChar, string expression, ref int i, int end)
  373. {
  374. fixed (char* str = ((char*) expression))
  375. {
  376. char* chPtr = str;
  377. i++;
  378. while ((i < expression.Length) && (i < end))
  379. {
  380. if (chPtr[i] == quoteChar)
  381. {
  382. return true;
  383. }
  384. i++;
  385. }
  386. }
  387. return false;
  388. }
  389. private static bool SinkValidName(string expression, ref int i, int end)
  390. {
  391. if ((end <= i) || !XmlUtilities.IsValidInitialElementNameCharacter(expression[i]))
  392. {
  393. return false;
  394. }
  395. i++;
  396. while ((end > i) && XmlUtilities.IsValidSubsequentElementNameCharacter(expression[i]))
  397. {
  398. i++;
  399. }
  400. return true;
  401. }
  402. private static void SinkWhitespace(string expression, ref int i)
  403. {
  404. while ((i < expression.Length) && char.IsWhiteSpace(expression[i]))
  405. {
  406. i++;
  407. }
  408. }
  409. internal static IList<string> SplitSemiColonSeparatedList(string expression)
  410. {
  411. string str;
  412. expression = expression.Trim();
  413. if (expression.Length == 0)
  414. {
  415. return ReadOnlyEmptyList<string>.Instance;
  416. }
  417. List<string> list = new List<string>(1);
  418. int startIndex = 0;
  419. bool flag = false;
  420. bool flag2 = false;
  421. for (int i = 0; i < expression.Length; i++)
  422. {
  423. switch (expression[i])
  424. {
  425. case '\'':
  426. if (flag)
  427. {
  428. flag2 = !flag2;
  429. }
  430. break;
  431. case ')':
  432. if (flag && !flag2)
  433. {
  434. flag = false;
  435. }
  436. break;
  437. case ';':
  438. if (!flag)
  439. {
  440. str = expression.Substring(startIndex, i - startIndex).Trim();
  441. if (str.Length > 0)
  442. {
  443. list.Add(str);
  444. }
  445. startIndex = i + 1;
  446. }
  447. break;
  448. case '@':
  449. if ((expression.Length > (i + 1)) && (expression[i + 1] == '('))
  450. {
  451. flag = true;
  452. }
  453. break;
  454. }
  455. }
  456. str = expression.Substring(startIndex, expression.Length - startIndex).Trim();
  457. if (str.Length > 0)
  458. {
  459. list.Add(str);
  460. }
  461. return list;
  462. }
  463. internal class ItemExpressionCapture
  464. {
  465. private List<ExpressionShredder.ItemExpressionCapture> captures;
  466. private string functionArguments;
  467. private string functionName;
  468. private int index;
  469. private string itemType;
  470. private int length;
  471. private string separator;
  472. private int separatorLength;
  473. private int separatorStart;
  474. private string value;
  475. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  476. public ItemExpressionCapture(int index, int length, string subExpression) : this(index, length, subExpression, null, null, -1, -1, null)
  477. {
  478. }
  479. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  480. public ItemExpressionCapture(int index, int length, string subExpression, string itemType, string separator, int separatorStart, int separatorLength, List<ExpressionShredder.ItemExpressionCapture> captures)
  481. {
  482. this.index = index;
  483. this.length = length;
  484. this.value = subExpression;
  485. this.itemType = itemType;
  486. this.separator = separator;
  487. this.separatorStart = separatorStart;
  488. this.separatorLength = separatorLength;
  489. this.captures = captures;
  490. }
  491. public override string ToString()
  492. {
  493. return this.value;
  494. }
  495. public List<ExpressionShredder.ItemExpressionCapture> Captures
  496. {
  497. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  498. get
  499. {
  500. return this.captures;
  501. }
  502. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  503. set
  504. {
  505. this.captures = value;
  506. }
  507. }
  508. public string FunctionArguments
  509. {
  510. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  511. get
  512. {
  513. return this.functionArguments;
  514. }
  515. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  516. set
  517. {
  518. this.functionArguments = value;
  519. }
  520. }
  521. public string FunctionName
  522. {
  523. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  524. get
  525. {
  526. return this.functionName;
  527. }
  528. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  529. set
  530. {
  531. this.functionName = value;
  532. }
  533. }
  534. public int Index
  535. {
  536. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  537. get
  538. {
  539. return this.index;
  540. }
  541. }
  542. public string ItemType
  543. {
  544. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  545. get
  546. {
  547. return this.itemType;
  548. }
  549. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  550. set
  551. {
  552. this.itemType = value;
  553. }
  554. }
  555. public int Length
  556. {
  557. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  558. get
  559. {
  560. return this.length;
  561. }
  562. }
  563. public string Separator
  564. {
  565. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  566. get
  567. {
  568. return this.separator;
  569. }
  570. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  571. set
  572. {
  573. this.separator = value;
  574. }
  575. }
  576. public int SeparatorLength
  577. {
  578. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  579. get
  580. {
  581. return this.separatorLength;
  582. }
  583. }
  584. public int SeparatorStart
  585. {
  586. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  587. get
  588. {
  589. return this.separatorStart;
  590. }
  591. }
  592. public string Value
  593. {
  594. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  595. get
  596. {
  597. return this.value;
  598. }
  599. }
  600. }
  601. }
  602. }