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

/ILSpy/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs

http://simple-assembly-explorer.googlecode.com/
C# | 813 lines | 732 code | 42 blank | 39 comment | 223 complexity | e88ea7dd158073d2bc3e8cc116a1bcce MD5 | raw file
Possible License(s): GPL-3.0, MIT, CC-BY-SA-3.0
  1. //
  2. // CSharpCompletionEngineBase.cs
  3. //
  4. // Author:
  5. // Mike Krüger <mkrueger@xamarin.com>
  6. //
  7. // Copyright (c) 2011 Xamarin Inc. (http://xamarin.com)
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining a copy
  10. // of this software and associated documentation files (the "Software"), to deal
  11. // in the Software without restriction, including without limitation the rights
  12. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. // copies of the Software, and to permit persons to whom the Software is
  14. // furnished to do so, subject to the following conditions:
  15. //
  16. // The above copyright notice and this permission notice shall be included in
  17. // all copies or substantial portions of the Software.
  18. //
  19. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. // THE SOFTWARE.
  26. using System;
  27. using System.Collections.Generic;
  28. using System.Linq;
  29. using System.Text;
  30. using ICSharpCode.NRefactory.CSharp.Resolver;
  31. using ICSharpCode.NRefactory.Editor;
  32. using ICSharpCode.NRefactory.TypeSystem;
  33. using ICSharpCode.NRefactory.Semantics;
  34. using ICSharpCode.NRefactory.TypeSystem.Implementation;
  35. using ICSharpCode.NRefactory.CSharp.TypeSystem;
  36. namespace ICSharpCode.NRefactory.CSharp.Completion
  37. {
  38. /// <summary>
  39. /// Acts as a common base between code completion and parameter completion.
  40. /// </summary>
  41. public class CSharpCompletionEngineBase
  42. {
  43. protected IDocument document;
  44. protected int offset;
  45. protected TextLocation location;
  46. protected IUnresolvedTypeDefinition currentType;
  47. protected IUnresolvedMember currentMember;
  48. #region Input properties
  49. public CSharpTypeResolveContext ctx { get; private set; }
  50. public IProjectContent ProjectContent { get; private set; }
  51. ICompilation compilation;
  52. protected ICompilation Compilation {
  53. get {
  54. if (compilation == null)
  55. compilation = ProjectContent.Resolve (ctx).Compilation;
  56. return compilation;
  57. }
  58. }
  59. #endregion
  60. protected CSharpCompletionEngineBase(IProjectContent content, ICompletionContextProvider completionContextProvider, CSharpTypeResolveContext ctx)
  61. {
  62. if (content == null)
  63. throw new ArgumentNullException("content");
  64. if (ctx == null)
  65. throw new ArgumentNullException("ctx");
  66. if (completionContextProvider == null)
  67. throw new ArgumentNullException("completionContextProvider");
  68. this.ProjectContent = content;
  69. this.CompletionContextProvider = completionContextProvider;
  70. this.ctx = ctx;
  71. }
  72. public ICompletionContextProvider CompletionContextProvider {
  73. get;
  74. private set;
  75. }
  76. public void SetOffset (int offset)
  77. {
  78. Reset ();
  79. this.offset = offset;
  80. this.location = document.GetLocation (offset);
  81. CompletionContextProvider.GetCurrentMembers (offset, out currentType, out currentMember);
  82. }
  83. public bool GetParameterCompletionCommandOffset (out int cpos)
  84. {
  85. // Start calculating the parameter offset from the beginning of the
  86. // current member, instead of the beginning of the file.
  87. cpos = offset - 1;
  88. var mem = currentMember;
  89. if (mem == null || (mem is IType)) {
  90. return false;
  91. }
  92. int startPos = document.GetOffset (mem.Region.BeginLine, mem.Region.BeginColumn);
  93. int parenDepth = 0;
  94. int chevronDepth = 0;
  95. Stack<int> indexStack = new Stack<int> ();
  96. while (cpos > startPos) {
  97. char c = document.GetCharAt (cpos);
  98. if (c == ')') {
  99. parenDepth++;
  100. }
  101. if (c == '>') {
  102. chevronDepth++;
  103. }
  104. if (c == '}') {
  105. if (indexStack.Count > 0) {
  106. parenDepth = indexStack.Pop ();
  107. } else {
  108. parenDepth = 0;
  109. }
  110. chevronDepth = 0;
  111. }
  112. if (indexStack.Count == 0 && (parenDepth == 0 && c == '(' || chevronDepth == 0 && c == '<')) {
  113. int p = GetCurrentParameterIndex (startPos, cpos + 1);
  114. if (p != -1) {
  115. cpos++;
  116. return true;
  117. } else {
  118. return false;
  119. }
  120. }
  121. if (c == '(') {
  122. parenDepth--;
  123. }
  124. if (c == '<') {
  125. chevronDepth--;
  126. }
  127. if (c == '{') {
  128. indexStack.Push (parenDepth);
  129. chevronDepth = 0;
  130. }
  131. cpos--;
  132. }
  133. return false;
  134. }
  135. public int GetCurrentParameterIndex (int triggerOffset, int endOffset)
  136. {
  137. char lastChar = document.GetCharAt (endOffset - 1);
  138. if (lastChar == '(' || lastChar == '<') {
  139. return 0;
  140. }
  141. var parameter = new Stack<int> ();
  142. var bracketStack = new Stack<Stack<int>> ();
  143. bool inSingleComment = false, inString = false, inVerbatimString = false, inChar = false, inMultiLineComment = false;
  144. for (int i = triggerOffset; i < endOffset; i++) {
  145. char ch = document.GetCharAt (i);
  146. char nextCh = i + 1 < document.TextLength ? document.GetCharAt (i + 1) : '\0';
  147. switch (ch) {
  148. case '{':
  149. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
  150. break;
  151. }
  152. bracketStack.Push (parameter);
  153. parameter = new Stack<int> ();
  154. break;
  155. case '[':
  156. case '(':
  157. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
  158. break;
  159. }
  160. parameter.Push (0);
  161. break;
  162. case '}':
  163. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
  164. break;
  165. }
  166. if (bracketStack.Count > 0) {
  167. parameter = bracketStack.Pop ();
  168. } else {
  169. return -1;
  170. }
  171. break;
  172. case ']':
  173. case ')':
  174. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
  175. break;
  176. }
  177. if (parameter.Count > 0) {
  178. parameter.Pop ();
  179. } else {
  180. return -1;
  181. }
  182. break;
  183. case '<':
  184. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
  185. break;
  186. }
  187. parameter.Push (0);
  188. break;
  189. case '>':
  190. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
  191. break;
  192. }
  193. if (parameter.Count > 0) {
  194. parameter.Pop ();
  195. }
  196. break;
  197. case ',':
  198. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
  199. break;
  200. }
  201. if (parameter.Count > 0) {
  202. parameter.Push (parameter.Pop () + 1);
  203. }
  204. break;
  205. case '/':
  206. if (inString || inChar || inVerbatimString) {
  207. break;
  208. }
  209. if (nextCh == '/') {
  210. i++;
  211. inSingleComment = true;
  212. }
  213. if (nextCh == '*') {
  214. inMultiLineComment = true;
  215. }
  216. break;
  217. case '*':
  218. if (inString || inChar || inVerbatimString || inSingleComment) {
  219. break;
  220. }
  221. if (nextCh == '/') {
  222. i++;
  223. inMultiLineComment = false;
  224. }
  225. break;
  226. case '@':
  227. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
  228. break;
  229. }
  230. if (nextCh == '"') {
  231. i++;
  232. inVerbatimString = true;
  233. }
  234. break;
  235. case '\n':
  236. case '\r':
  237. inSingleComment = false;
  238. inString = false;
  239. inChar = false;
  240. break;
  241. case '\\':
  242. if (inString || inChar) {
  243. i++;
  244. }
  245. break;
  246. case '"':
  247. if (inSingleComment || inMultiLineComment || inChar) {
  248. break;
  249. }
  250. if (inVerbatimString) {
  251. if (nextCh == '"') {
  252. i++;
  253. break;
  254. }
  255. inVerbatimString = false;
  256. break;
  257. }
  258. inString = !inString;
  259. break;
  260. case '\'':
  261. if (inSingleComment || inMultiLineComment || inString || inVerbatimString) {
  262. break;
  263. }
  264. inChar = !inChar;
  265. break;
  266. }
  267. }
  268. if (parameter.Count == 0 || bracketStack.Count > 0) {
  269. return -1;
  270. }
  271. return parameter.Pop() + 1;
  272. }
  273. #region Context helper methods
  274. public class MiniLexer
  275. {
  276. readonly string text;
  277. public bool IsFistNonWs = true;
  278. public bool IsInSingleComment = false;
  279. public bool IsInString = false;
  280. public bool IsInVerbatimString = false;
  281. public bool IsInChar = false;
  282. public bool IsInMultiLineComment = false;
  283. public bool IsInPreprocessorDirective = false;
  284. public MiniLexer(string text)
  285. {
  286. this.text = text;
  287. }
  288. public void Parse(Action<char> act = null)
  289. {
  290. Parse(0, text.Length, act);
  291. }
  292. public void Parse(int start, int length, Action<char> act = null)
  293. {
  294. for (int i = start; i < length; i++) {
  295. char ch = text [i];
  296. char nextCh = i + 1 < text.Length ? text [i + 1] : '\0';
  297. switch (ch) {
  298. case '#':
  299. if (IsFistNonWs)
  300. IsInPreprocessorDirective = true;
  301. break;
  302. case '/':
  303. if (IsInString || IsInChar || IsInVerbatimString)
  304. break;
  305. if (nextCh == '/') {
  306. i++;
  307. IsInSingleComment = true;
  308. }
  309. if (nextCh == '*')
  310. IsInMultiLineComment = true;
  311. break;
  312. case '*':
  313. if (IsInString || IsInChar || IsInVerbatimString || IsInSingleComment)
  314. break;
  315. if (nextCh == '/') {
  316. i++;
  317. IsInMultiLineComment = false;
  318. }
  319. break;
  320. case '@':
  321. if (IsInString || IsInChar || IsInVerbatimString || IsInSingleComment || IsInMultiLineComment)
  322. break;
  323. if (nextCh == '"') {
  324. i++;
  325. IsInVerbatimString = true;
  326. }
  327. break;
  328. case '\n':
  329. case '\r':
  330. IsInSingleComment = false;
  331. IsInString = false;
  332. IsInChar = false;
  333. IsFistNonWs = true;
  334. IsInPreprocessorDirective = false;
  335. break;
  336. case '\\':
  337. if (IsInString || IsInChar)
  338. i++;
  339. break;
  340. case '"':
  341. if (IsInSingleComment || IsInMultiLineComment || IsInChar)
  342. break;
  343. if (IsInVerbatimString) {
  344. if (nextCh == '"') {
  345. i++;
  346. break;
  347. }
  348. IsInVerbatimString = false;
  349. break;
  350. }
  351. IsInString = !IsInString;
  352. break;
  353. case '\'':
  354. if (IsInSingleComment || IsInMultiLineComment || IsInString || IsInVerbatimString)
  355. break;
  356. IsInChar = !IsInChar;
  357. break;
  358. }
  359. if (act != null)
  360. act(ch);
  361. IsFistNonWs &= ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
  362. }
  363. }
  364. }
  365. protected bool IsInsideCommentStringOrDirective(int offset)
  366. {
  367. var lexer = new MiniLexer(document.Text);
  368. lexer.Parse(0, offset);
  369. return
  370. lexer.IsInSingleComment ||
  371. lexer.IsInString ||
  372. lexer.IsInVerbatimString ||
  373. lexer.IsInChar ||
  374. lexer.IsInMultiLineComment ||
  375. lexer.IsInPreprocessorDirective;
  376. }
  377. protected bool IsInsideCommentStringOrDirective()
  378. {
  379. var text = GetMemberTextToCaret();
  380. var lexer = new MiniLexer(text.Item1);
  381. lexer.Parse();
  382. return
  383. lexer.IsInSingleComment ||
  384. lexer.IsInString ||
  385. lexer.IsInVerbatimString ||
  386. lexer.IsInChar ||
  387. lexer.IsInMultiLineComment ||
  388. lexer.IsInPreprocessorDirective;
  389. }
  390. protected bool IsInsideDocComment ()
  391. {
  392. var text = GetMemberTextToCaret ();
  393. bool inSingleComment = false, inString = false, inVerbatimString = false, inChar = false, inMultiLineComment = false;
  394. bool singleLineIsDoc = false;
  395. for (int i = 0; i < text.Item1.Length - 1; i++) {
  396. char ch = text.Item1 [i];
  397. char nextCh = text.Item1 [i + 1];
  398. switch (ch) {
  399. case '/':
  400. if (inString || inChar || inVerbatimString)
  401. break;
  402. if (nextCh == '/') {
  403. i++;
  404. inSingleComment = true;
  405. singleLineIsDoc = i + 1 < text.Item1.Length && text.Item1 [i + 1] == '/';
  406. if (singleLineIsDoc) {
  407. i++;
  408. }
  409. }
  410. if (nextCh == '*')
  411. inMultiLineComment = true;
  412. break;
  413. case '*':
  414. if (inString || inChar || inVerbatimString || inSingleComment)
  415. break;
  416. if (nextCh == '/') {
  417. i++;
  418. inMultiLineComment = false;
  419. }
  420. break;
  421. case '@':
  422. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment)
  423. break;
  424. if (nextCh == '"') {
  425. i++;
  426. inVerbatimString = true;
  427. }
  428. break;
  429. case '\n':
  430. case '\r':
  431. inSingleComment = false;
  432. inString = false;
  433. inChar = false;
  434. break;
  435. case '\\':
  436. if (inString || inChar)
  437. i++;
  438. break;
  439. case '"':
  440. if (inSingleComment || inMultiLineComment || inChar)
  441. break;
  442. if (inVerbatimString) {
  443. if (nextCh == '"') {
  444. i++;
  445. break;
  446. }
  447. inVerbatimString = false;
  448. break;
  449. }
  450. inString = !inString;
  451. break;
  452. case '\'':
  453. if (inSingleComment || inMultiLineComment || inString || inVerbatimString)
  454. break;
  455. inChar = !inChar;
  456. break;
  457. }
  458. }
  459. return inSingleComment && singleLineIsDoc;
  460. }
  461. protected CSharpResolver GetState ()
  462. {
  463. return new CSharpResolver (ctx);
  464. /*var state = new CSharpResolver (ctx);
  465. state.CurrentMember = currentMember;
  466. state.CurrentTypeDefinition = currentType;
  467. state.CurrentUsingScope = CSharpUnresolvedFile.GetUsingScope (location);
  468. if (state.CurrentMember != null) {
  469. var node = Unit.GetNodeAt (location);
  470. if (node == null)
  471. return state;
  472. var navigator = new NodeListResolveVisitorNavigator (new[] { node });
  473. var visitor = new ResolveVisitor (state, CSharpUnresolvedFile, navigator);
  474. Unit.AcceptVisitor (visitor, null);
  475. try {
  476. var newState = visitor.GetResolverStateBefore (node);
  477. if (newState != null)
  478. state = newState;
  479. } catch (Exception) {
  480. }
  481. }
  482. return state;*/
  483. }
  484. #endregion
  485. #region Basic parsing/resolving functions
  486. static Stack<Tuple<char, int>> GetBracketStack (string memberText)
  487. {
  488. var bracketStack = new Stack<Tuple<char, int>> ();
  489. bool inSingleComment = false, inString = false, inVerbatimString = false, inChar = false, inMultiLineComment = false;
  490. for (int i = 0; i < memberText.Length; i++) {
  491. char ch = memberText [i];
  492. char nextCh = i + 1 < memberText.Length ? memberText [i + 1] : '\0';
  493. switch (ch) {
  494. case '(':
  495. case '[':
  496. case '{':
  497. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment)
  498. break;
  499. bracketStack.Push (Tuple.Create (ch, i));
  500. break;
  501. case ')':
  502. case ']':
  503. case '}':
  504. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment)
  505. break;
  506. if (bracketStack.Count > 0)
  507. bracketStack.Pop ();
  508. break;
  509. case '/':
  510. if (inString || inChar || inVerbatimString)
  511. break;
  512. if (nextCh == '/') {
  513. i++;
  514. inSingleComment = true;
  515. }
  516. if (nextCh == '*')
  517. inMultiLineComment = true;
  518. break;
  519. case '*':
  520. if (inString || inChar || inVerbatimString || inSingleComment)
  521. break;
  522. if (nextCh == '/') {
  523. i++;
  524. inMultiLineComment = false;
  525. }
  526. break;
  527. case '@':
  528. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment)
  529. break;
  530. if (nextCh == '"') {
  531. i++;
  532. inVerbatimString = true;
  533. }
  534. break;
  535. case '\n':
  536. case '\r':
  537. inSingleComment = false;
  538. inString = false;
  539. inChar = false;
  540. break;
  541. case '\\':
  542. if (inString || inChar)
  543. i++;
  544. break;
  545. case '"':
  546. if (inSingleComment || inMultiLineComment || inChar)
  547. break;
  548. if (inVerbatimString) {
  549. if (nextCh == '"') {
  550. i++;
  551. break;
  552. }
  553. inVerbatimString = false;
  554. break;
  555. }
  556. inString = !inString;
  557. break;
  558. case '\'':
  559. if (inSingleComment || inMultiLineComment || inString || inVerbatimString)
  560. break;
  561. inChar = !inChar;
  562. break;
  563. default :
  564. break;
  565. }
  566. }
  567. return bracketStack;
  568. }
  569. public static void AppendMissingClosingBrackets (StringBuilder wrapper, string memberText, bool appendSemicolon)
  570. {
  571. var bracketStack = GetBracketStack (memberText);
  572. bool didAppendSemicolon = !appendSemicolon;
  573. //char lastBracket = '\0';
  574. while (bracketStack.Count > 0) {
  575. var t = bracketStack.Pop ();
  576. switch (t.Item1) {
  577. case '(':
  578. wrapper.Append (')');
  579. if (appendSemicolon)
  580. didAppendSemicolon = false;
  581. //lastBracket = ')';
  582. break;
  583. case '[':
  584. wrapper.Append (']');
  585. if (appendSemicolon)
  586. didAppendSemicolon = false;
  587. //lastBracket = ']';
  588. break;
  589. case '<':
  590. wrapper.Append ('>');
  591. if (appendSemicolon)
  592. didAppendSemicolon = false;
  593. //lastBracket = '>';
  594. break;
  595. case '{':
  596. int o = t.Item2 - 1;
  597. if (!didAppendSemicolon) {
  598. didAppendSemicolon = true;
  599. wrapper.Append (';');
  600. }
  601. bool didAppendCatch = false;
  602. while (o >= "try".Length) {
  603. char ch = memberText [o];
  604. if (!char.IsWhiteSpace (ch)) {
  605. if (ch == 'y' && memberText [o - 1] == 'r' && memberText [o - 2] == 't') {
  606. wrapper.Append ("} catch {}");
  607. didAppendCatch = true;
  608. }
  609. break;
  610. }
  611. o--;
  612. }
  613. if (!didAppendCatch)
  614. wrapper.Append ('}');
  615. break;
  616. }
  617. }
  618. if (!didAppendSemicolon)
  619. wrapper.Append (';');
  620. }
  621. protected SyntaxTree ParseStub(string continuation, bool appendSemicolon = true, string afterContinuation = null)
  622. {
  623. var mt = GetMemberTextToCaret();
  624. if (mt == null) {
  625. return null;
  626. }
  627. string memberText = mt.Item1;
  628. var memberLocation = mt.Item2;
  629. int closingBrackets = 1;
  630. int generatedLines = 0;
  631. var wrapper = new StringBuilder();
  632. bool wrapInClass = memberLocation != new TextLocation(1, 1);
  633. if (wrapInClass) {
  634. wrapper.Append("class Stub {");
  635. wrapper.AppendLine();
  636. closingBrackets++;
  637. generatedLines++;
  638. }
  639. wrapper.Append(memberText);
  640. wrapper.Append(continuation);
  641. AppendMissingClosingBrackets(wrapper, memberText, appendSemicolon);
  642. wrapper.Append(afterContinuation);
  643. if (closingBrackets > 0) {
  644. wrapper.Append(new string('}', closingBrackets));
  645. }
  646. var parser = new CSharpParser ();
  647. foreach (var sym in CompletionContextProvider.ConditionalSymbols)
  648. parser.CompilerSettings.ConditionalSymbols.Add (sym);
  649. parser.InitialLocation = new TextLocation(memberLocation.Line - generatedLines, 1);
  650. var result = parser.Parse(wrapper.ToString ());
  651. return result;
  652. }
  653. // string cachedText = null;
  654. protected virtual void Reset ()
  655. {
  656. // cachedText = null;
  657. }
  658. protected Tuple<string, TextLocation> GetMemberTextToCaret()
  659. {
  660. return CompletionContextProvider.GetMemberTextToCaret(offset, currentType, currentMember);
  661. }
  662. protected ExpressionResult GetInvocationBeforeCursor(bool afterBracket)
  663. {
  664. SyntaxTree baseUnit;
  665. baseUnit = ParseStub("a", false);
  666. var section = baseUnit.GetNodeAt<AttributeSection>(location.Line, location.Column - 2);
  667. var attr = section != null ? section.Attributes.LastOrDefault() : null;
  668. if (attr != null) {
  669. return new ExpressionResult((AstNode)attr, baseUnit);
  670. }
  671. //var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin;
  672. var mref = baseUnit.GetNodeAt(location.Line, location.Column - 1, n => n is InvocationExpression || n is ObjectCreateExpression);
  673. AstNode expr = null;
  674. if (mref is InvocationExpression) {
  675. expr = ((InvocationExpression)mref).Target;
  676. } else if (mref is ObjectCreateExpression) {
  677. expr = mref;
  678. } else {
  679. baseUnit = ParseStub(")};", false);
  680. mref = baseUnit.GetNodeAt(location.Line, location.Column - 1, n => n is InvocationExpression || n is ObjectCreateExpression);
  681. if (mref is InvocationExpression) {
  682. expr = ((InvocationExpression)mref).Target;
  683. } else if (mref is ObjectCreateExpression) {
  684. expr = mref;
  685. }
  686. }
  687. if (expr == null) {
  688. // work around for missing ';' bug in mcs:
  689. baseUnit = ParseStub("a", true);
  690. section = baseUnit.GetNodeAt<AttributeSection>(location.Line, location.Column - 2);
  691. attr = section != null ? section.Attributes.LastOrDefault() : null;
  692. if (attr != null) {
  693. return new ExpressionResult((AstNode)attr, baseUnit);
  694. }
  695. //var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin;
  696. mref = baseUnit.GetNodeAt(location.Line, location.Column - 1, n => n is InvocationExpression || n is ObjectCreateExpression);
  697. expr = null;
  698. if (mref is InvocationExpression) {
  699. expr = ((InvocationExpression)mref).Target;
  700. } else if (mref is ObjectCreateExpression) {
  701. expr = mref;
  702. }
  703. }
  704. if (expr == null) {
  705. return null;
  706. }
  707. return new ExpressionResult ((AstNode)expr, baseUnit);
  708. }
  709. public class ExpressionResult
  710. {
  711. public AstNode Node { get; private set; }
  712. public SyntaxTree Unit { get; private set; }
  713. public ExpressionResult (AstNode item2, SyntaxTree item3)
  714. {
  715. this.Node = item2;
  716. this.Unit = item3;
  717. }
  718. public override string ToString ()
  719. {
  720. return string.Format ("[ExpressionResult: Node={0}, Unit={1}]", Node, Unit);
  721. }
  722. }
  723. protected Tuple<ResolveResult, CSharpResolver> ResolveExpression (ExpressionResult tuple)
  724. {
  725. return ResolveExpression (tuple.Node);
  726. }
  727. protected Tuple<ResolveResult, CSharpResolver> ResolveExpression(AstNode expr)
  728. {
  729. if (expr == null) {
  730. return null;
  731. }
  732. AstNode resolveNode;
  733. if (expr is Expression || expr is AstType) {
  734. resolveNode = expr;
  735. } else if (expr is VariableDeclarationStatement) {
  736. resolveNode = ((VariableDeclarationStatement)expr).Type;
  737. } else {
  738. resolveNode = expr;
  739. }
  740. try {
  741. var root = expr.AncestorsAndSelf.FirstOrDefault(n => n is EntityDeclaration || n is SyntaxTree);
  742. if (root == null) {
  743. return null;
  744. }
  745. if (root is Accessor)
  746. root = root.Parent;
  747. var csResolver = CompletionContextProvider.GetResolver (GetState(), root);
  748. var result = csResolver.Resolve(resolveNode);
  749. var state = csResolver.GetResolverStateBefore(resolveNode);
  750. return Tuple.Create(result, state);
  751. } catch (Exception e) {
  752. Console.WriteLine(e);
  753. return null;
  754. }
  755. }
  756. #endregion
  757. }
  758. }