PageRenderTime 61ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs

https://github.com/shiftkey/SharpDevelop
C# | 890 lines | 801 code | 50 blank | 39 comment | 252 complexity | 2ebca4baabb25330f34031ce2463b9e1 MD5 | raw file
Possible License(s): BSD-3-Clause, 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. Version languageVersion = new Version (5, 0);
  60. public Version LanguageVersion {
  61. get {
  62. return languageVersion;
  63. }
  64. set {
  65. languageVersion = value;
  66. }
  67. }
  68. #endregion
  69. protected CSharpCompletionEngineBase(IProjectContent content, ICompletionContextProvider completionContextProvider, CSharpTypeResolveContext ctx)
  70. {
  71. if (content == null)
  72. throw new ArgumentNullException("content");
  73. if (ctx == null)
  74. throw new ArgumentNullException("ctx");
  75. if (completionContextProvider == null)
  76. throw new ArgumentNullException("completionContextProvider");
  77. this.ProjectContent = content;
  78. this.CompletionContextProvider = completionContextProvider;
  79. this.ctx = ctx;
  80. }
  81. public ICompletionContextProvider CompletionContextProvider {
  82. get;
  83. private set;
  84. }
  85. public void SetOffset (int offset)
  86. {
  87. Reset ();
  88. this.offset = offset;
  89. this.location = document.GetLocation (offset);
  90. CompletionContextProvider.GetCurrentMembers (offset, out currentType, out currentMember);
  91. }
  92. public bool GetParameterCompletionCommandOffset (out int cpos)
  93. {
  94. // Start calculating the parameter offset from the beginning of the
  95. // current member, instead of the beginning of the file.
  96. cpos = offset - 1;
  97. var mem = currentMember;
  98. if (mem == null || (mem is IType) || IsInsideCommentStringOrDirective ()) {
  99. return false;
  100. }
  101. int startPos = document.GetOffset (mem.Region.BeginLine, mem.Region.BeginColumn);
  102. int parenDepth = 0;
  103. int chevronDepth = 0;
  104. Stack<int> indexStack = new Stack<int> ();
  105. while (cpos > startPos) {
  106. char c = document.GetCharAt (cpos);
  107. if (c == ')') {
  108. parenDepth++;
  109. }
  110. if (c == '>') {
  111. chevronDepth++;
  112. }
  113. if (c == '}') {
  114. if (indexStack.Count > 0) {
  115. parenDepth = indexStack.Pop ();
  116. } else {
  117. parenDepth = 0;
  118. }
  119. chevronDepth = 0;
  120. }
  121. if (indexStack.Count == 0 && (parenDepth == 0 && c == '(' || chevronDepth == 0 && c == '<')) {
  122. int p = GetCurrentParameterIndex (startPos, cpos + 1);
  123. if (p != -1) {
  124. cpos++;
  125. return true;
  126. } else {
  127. return false;
  128. }
  129. }
  130. if (c == '(') {
  131. parenDepth--;
  132. }
  133. if (c == '<') {
  134. chevronDepth--;
  135. }
  136. if (c == '{') {
  137. indexStack.Push (parenDepth);
  138. chevronDepth = 0;
  139. }
  140. cpos--;
  141. }
  142. return false;
  143. }
  144. public int GetCurrentParameterIndex(int triggerOffset, int endOffset)
  145. {
  146. List<string> list;
  147. return GetCurrentParameterIndex (triggerOffset, endOffset, out list);
  148. }
  149. public int GetCurrentParameterIndex (int triggerOffset, int endOffset, out List<string> usedNamedParameters)
  150. {
  151. usedNamedParameters =new List<string> ();
  152. var parameter = new Stack<int> ();
  153. var bracketStack = new Stack<Stack<int>> ();
  154. bool inSingleComment = false, inString = false, inVerbatimString = false, inChar = false, inMultiLineComment = false;
  155. var word = new StringBuilder ();
  156. bool foundCharAfterOpenBracket = false;
  157. for (int i = triggerOffset; i < endOffset; i++) {
  158. char ch = document.GetCharAt (i);
  159. char nextCh = i + 1 < document.TextLength ? document.GetCharAt (i + 1) : '\0';
  160. if (ch == ':') {
  161. usedNamedParameters.Add (word.ToString ());
  162. word.Length = 0;
  163. } else if (char.IsLetterOrDigit (ch) || ch =='_') {
  164. word.Append (ch);
  165. } else if (char.IsWhiteSpace (ch)) {
  166. } else {
  167. word.Length = 0;
  168. }
  169. if (!char.IsWhiteSpace(ch) && parameter.Count > 0)
  170. foundCharAfterOpenBracket = true;
  171. switch (ch) {
  172. case '{':
  173. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
  174. break;
  175. }
  176. bracketStack.Push (parameter);
  177. parameter = new Stack<int> ();
  178. break;
  179. case '[':
  180. case '(':
  181. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
  182. break;
  183. }
  184. parameter.Push (0);
  185. break;
  186. case '}':
  187. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
  188. break;
  189. }
  190. if (bracketStack.Count > 0) {
  191. parameter = bracketStack.Pop ();
  192. } else {
  193. return -1;
  194. }
  195. break;
  196. case ']':
  197. case ')':
  198. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
  199. break;
  200. }
  201. if (parameter.Count > 0) {
  202. parameter.Pop ();
  203. } else {
  204. return -1;
  205. }
  206. break;
  207. case '<':
  208. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
  209. break;
  210. }
  211. parameter.Push (0);
  212. break;
  213. case '=':
  214. if (nextCh == '>') {
  215. i++;
  216. continue;
  217. }
  218. break;
  219. case '>':
  220. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
  221. break;
  222. }
  223. if (parameter.Count > 0) {
  224. parameter.Pop ();
  225. }
  226. break;
  227. case ',':
  228. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
  229. break;
  230. }
  231. if (parameter.Count > 0) {
  232. parameter.Push (parameter.Pop () + 1);
  233. }
  234. break;
  235. case '/':
  236. if (inString || inChar || inVerbatimString) {
  237. break;
  238. }
  239. if (nextCh == '/') {
  240. i++;
  241. inSingleComment = true;
  242. }
  243. if (nextCh == '*') {
  244. inMultiLineComment = true;
  245. }
  246. break;
  247. case '*':
  248. if (inString || inChar || inVerbatimString || inSingleComment) {
  249. break;
  250. }
  251. if (nextCh == '/') {
  252. i++;
  253. inMultiLineComment = false;
  254. }
  255. break;
  256. case '@':
  257. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
  258. break;
  259. }
  260. if (nextCh == '"') {
  261. i++;
  262. inVerbatimString = true;
  263. }
  264. break;
  265. case '\\':
  266. if (inString || inChar) {
  267. i++;
  268. }
  269. break;
  270. case '"':
  271. if (inSingleComment || inMultiLineComment || inChar) {
  272. break;
  273. }
  274. if (inVerbatimString) {
  275. if (nextCh == '"') {
  276. i++;
  277. break;
  278. }
  279. inVerbatimString = false;
  280. break;
  281. }
  282. inString = !inString;
  283. break;
  284. case '\'':
  285. if (inSingleComment || inMultiLineComment || inString || inVerbatimString) {
  286. break;
  287. }
  288. inChar = !inChar;
  289. break;
  290. default:
  291. if (NewLine.IsNewLine(ch)) {
  292. inSingleComment = false;
  293. inString = false;
  294. inChar = false;
  295. }
  296. break;
  297. }
  298. }
  299. if (parameter.Count != 1 || bracketStack.Count > 0) {
  300. return -1;
  301. }
  302. if (!foundCharAfterOpenBracket)
  303. return 0;
  304. return parameter.Pop() + 1;
  305. }
  306. #region Context helper methods
  307. public class MiniLexer
  308. {
  309. readonly string text;
  310. public bool IsFistNonWs = true;
  311. public bool IsInSingleComment = false;
  312. public bool IsInString = false;
  313. public bool IsInVerbatimString = false;
  314. public bool IsInChar = false;
  315. public bool IsInMultiLineComment = false;
  316. public bool IsInPreprocessorDirective = false;
  317. public MiniLexer(string text)
  318. {
  319. this.text = text;
  320. }
  321. public void Parse(Action<char> act = null)
  322. {
  323. Parse(0, text.Length, act);
  324. }
  325. public void Parse(int start, int length, Action<char> act = null)
  326. {
  327. for (int i = start; i < length; i++) {
  328. char ch = text [i];
  329. char nextCh = i + 1 < text.Length ? text [i + 1] : '\0';
  330. switch (ch) {
  331. case '#':
  332. if (IsFistNonWs)
  333. IsInPreprocessorDirective = true;
  334. break;
  335. case '/':
  336. if (IsInString || IsInChar || IsInVerbatimString || IsInSingleComment || IsInMultiLineComment)
  337. break;
  338. if (nextCh == '/') {
  339. i++;
  340. IsInSingleComment = true;
  341. IsInPreprocessorDirective = false;
  342. }
  343. if (nextCh == '*' && !IsInPreprocessorDirective) {
  344. IsInMultiLineComment = true;
  345. i++;
  346. }
  347. break;
  348. case '*':
  349. if (IsInString || IsInChar || IsInVerbatimString || IsInSingleComment)
  350. break;
  351. if (nextCh == '/') {
  352. i++;
  353. IsInMultiLineComment = false;
  354. }
  355. break;
  356. case '@':
  357. if (IsInString || IsInChar || IsInVerbatimString || IsInSingleComment || IsInMultiLineComment)
  358. break;
  359. if (nextCh == '"') {
  360. i++;
  361. IsInVerbatimString = true;
  362. }
  363. break;
  364. case '\n':
  365. case '\r':
  366. IsInSingleComment = false;
  367. IsInString = false;
  368. IsInChar = false;
  369. IsFistNonWs = true;
  370. IsInPreprocessorDirective = false;
  371. break;
  372. case '\\':
  373. if (IsInString || IsInChar)
  374. i++;
  375. break;
  376. case '"':
  377. if (IsInSingleComment || IsInMultiLineComment || IsInChar)
  378. break;
  379. if (IsInVerbatimString) {
  380. if (nextCh == '"') {
  381. i++;
  382. break;
  383. }
  384. IsInVerbatimString = false;
  385. break;
  386. }
  387. IsInString = !IsInString;
  388. break;
  389. case '\'':
  390. if (IsInSingleComment || IsInMultiLineComment || IsInString || IsInVerbatimString)
  391. break;
  392. IsInChar = !IsInChar;
  393. break;
  394. }
  395. if (act != null)
  396. act(ch);
  397. IsFistNonWs &= ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
  398. }
  399. }
  400. }
  401. protected bool IsInsideCommentStringOrDirective(int offset)
  402. {
  403. var lexer = new MiniLexer(document.Text);
  404. lexer.Parse(0, offset);
  405. return
  406. lexer.IsInSingleComment ||
  407. lexer.IsInString ||
  408. lexer.IsInVerbatimString ||
  409. lexer.IsInChar ||
  410. lexer.IsInMultiLineComment ||
  411. lexer.IsInPreprocessorDirective;
  412. }
  413. protected bool IsInsideCommentStringOrDirective()
  414. {
  415. var text = GetMemberTextToCaret();
  416. var lexer = new MiniLexer(text.Item1);
  417. lexer.Parse();
  418. return
  419. lexer.IsInSingleComment ||
  420. lexer.IsInString ||
  421. lexer.IsInVerbatimString ||
  422. lexer.IsInChar ||
  423. lexer.IsInMultiLineComment ||
  424. lexer.IsInPreprocessorDirective;
  425. }
  426. protected bool IsInsideDocComment ()
  427. {
  428. var text = GetMemberTextToCaret ();
  429. bool inSingleComment = false, inString = false, inVerbatimString = false, inChar = false, inMultiLineComment = false;
  430. bool singleLineIsDoc = false;
  431. for (int i = 0; i < text.Item1.Length - 1; i++) {
  432. char ch = text.Item1 [i];
  433. char nextCh = text.Item1 [i + 1];
  434. switch (ch) {
  435. case '/':
  436. if (inString || inChar || inVerbatimString)
  437. break;
  438. if (nextCh == '/') {
  439. i++;
  440. inSingleComment = true;
  441. singleLineIsDoc = i + 1 < text.Item1.Length && text.Item1 [i + 1] == '/';
  442. if (singleLineIsDoc) {
  443. i++;
  444. }
  445. }
  446. if (nextCh == '*')
  447. inMultiLineComment = true;
  448. break;
  449. case '*':
  450. if (inString || inChar || inVerbatimString || inSingleComment)
  451. break;
  452. if (nextCh == '/') {
  453. i++;
  454. inMultiLineComment = false;
  455. }
  456. break;
  457. case '@':
  458. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment)
  459. break;
  460. if (nextCh == '"') {
  461. i++;
  462. inVerbatimString = true;
  463. }
  464. break;
  465. case '\n':
  466. case '\r':
  467. inSingleComment = false;
  468. inString = false;
  469. inChar = false;
  470. break;
  471. case '\\':
  472. if (inString || inChar)
  473. i++;
  474. break;
  475. case '"':
  476. if (inSingleComment || inMultiLineComment || inChar)
  477. break;
  478. if (inVerbatimString) {
  479. if (nextCh == '"') {
  480. i++;
  481. break;
  482. }
  483. inVerbatimString = false;
  484. break;
  485. }
  486. inString = !inString;
  487. break;
  488. case '\'':
  489. if (inSingleComment || inMultiLineComment || inString || inVerbatimString)
  490. break;
  491. inChar = !inChar;
  492. break;
  493. }
  494. }
  495. return inSingleComment && singleLineIsDoc;
  496. }
  497. protected CSharpResolver GetState ()
  498. {
  499. return new CSharpResolver (ctx);
  500. /*var state = new CSharpResolver (ctx);
  501. state.CurrentMember = currentMember;
  502. state.CurrentTypeDefinition = currentType;
  503. state.CurrentUsingScope = CSharpUnresolvedFile.GetUsingScope (location);
  504. if (state.CurrentMember != null) {
  505. var node = Unit.GetNodeAt (location);
  506. if (node == null)
  507. return state;
  508. var navigator = new NodeListResolveVisitorNavigator (new[] { node });
  509. var visitor = new ResolveVisitor (state, CSharpUnresolvedFile, navigator);
  510. Unit.AcceptVisitor (visitor, null);
  511. try {
  512. var newState = visitor.GetResolverStateBefore (node);
  513. if (newState != null)
  514. state = newState;
  515. } catch (Exception) {
  516. }
  517. }
  518. return state;*/
  519. }
  520. #endregion
  521. #region Basic parsing/resolving functions
  522. static Stack<Tuple<char, int>> GetBracketStack (string memberText)
  523. {
  524. var bracketStack = new Stack<Tuple<char, int>> ();
  525. bool inSingleComment = false, inString = false, inVerbatimString = false, inChar = false, inMultiLineComment = false;
  526. for (int i = 0; i < memberText.Length; i++) {
  527. char ch = memberText [i];
  528. char nextCh = i + 1 < memberText.Length ? memberText [i + 1] : '\0';
  529. switch (ch) {
  530. case '(':
  531. case '[':
  532. case '{':
  533. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment)
  534. break;
  535. bracketStack.Push (Tuple.Create (ch, i));
  536. break;
  537. case ')':
  538. case ']':
  539. case '}':
  540. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment)
  541. break;
  542. if (bracketStack.Count > 0)
  543. bracketStack.Pop ();
  544. break;
  545. case '/':
  546. if (inString || inChar || inVerbatimString)
  547. break;
  548. if (nextCh == '/') {
  549. i++;
  550. inSingleComment = true;
  551. }
  552. if (nextCh == '*')
  553. inMultiLineComment = true;
  554. break;
  555. case '*':
  556. if (inString || inChar || inVerbatimString || inSingleComment)
  557. break;
  558. if (nextCh == '/') {
  559. i++;
  560. inMultiLineComment = false;
  561. }
  562. break;
  563. case '@':
  564. if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment)
  565. break;
  566. if (nextCh == '"') {
  567. i++;
  568. inVerbatimString = true;
  569. }
  570. break;
  571. case '\\':
  572. if (inString || inChar)
  573. i++;
  574. break;
  575. case '"':
  576. if (inSingleComment || inMultiLineComment || inChar)
  577. break;
  578. if (inVerbatimString) {
  579. if (nextCh == '"') {
  580. i++;
  581. break;
  582. }
  583. inVerbatimString = false;
  584. break;
  585. }
  586. inString = !inString;
  587. break;
  588. case '\'':
  589. if (inSingleComment || inMultiLineComment || inString || inVerbatimString)
  590. break;
  591. inChar = !inChar;
  592. break;
  593. default :
  594. if (NewLine.IsNewLine(ch)) {
  595. inSingleComment = false;
  596. inString = false;
  597. inChar = false;
  598. }
  599. break;
  600. }
  601. }
  602. return bracketStack;
  603. }
  604. public static void AppendMissingClosingBrackets (StringBuilder wrapper, bool appendSemicolon)
  605. {
  606. var memberText = wrapper.ToString();
  607. var bracketStack = GetBracketStack(memberText);
  608. bool didAppendSemicolon = !appendSemicolon;
  609. //char lastBracket = '\0';
  610. while (bracketStack.Count > 0) {
  611. var t = bracketStack.Pop ();
  612. switch (t.Item1) {
  613. case '(':
  614. wrapper.Append (')');
  615. if (appendSemicolon)
  616. didAppendSemicolon = false;
  617. //lastBracket = ')';
  618. break;
  619. case '[':
  620. wrapper.Append (']');
  621. if (appendSemicolon)
  622. didAppendSemicolon = false;
  623. //lastBracket = ']';
  624. break;
  625. case '<':
  626. wrapper.Append ('>');
  627. if (appendSemicolon)
  628. didAppendSemicolon = false;
  629. //lastBracket = '>';
  630. break;
  631. case '{':
  632. int o = t.Item2 - 1;
  633. if (!didAppendSemicolon) {
  634. didAppendSemicolon = true;
  635. wrapper.Append (';');
  636. }
  637. bool didAppendCatch = false;
  638. while (o >= "try".Length) {
  639. char ch = memberText [o];
  640. if (!char.IsWhiteSpace (ch)) {
  641. if (ch == 'y' && memberText [o - 1] == 'r' && memberText [o - 2] == 't') {
  642. wrapper.Append ("} catch {}");
  643. didAppendCatch = true;
  644. }
  645. break;
  646. }
  647. o--;
  648. }
  649. if (!didAppendCatch)
  650. wrapper.Append ('}');
  651. break;
  652. }
  653. }
  654. if (!didAppendSemicolon)
  655. wrapper.Append (';');
  656. }
  657. protected StringBuilder CreateWrapper(string continuation, bool appendSemicolon, string afterContinuation, string memberText, TextLocation memberLocation, ref int closingBrackets, ref int generatedLines)
  658. {
  659. var wrapper = new StringBuilder();
  660. bool wrapInClass = memberLocation != new TextLocation(1, 1);
  661. if (wrapInClass) {
  662. wrapper.Append("class Stub {");
  663. wrapper.AppendLine();
  664. closingBrackets++;
  665. generatedLines++;
  666. }
  667. wrapper.Append(memberText);
  668. wrapper.Append(continuation);
  669. AppendMissingClosingBrackets(wrapper, appendSemicolon);
  670. wrapper.Append(afterContinuation);
  671. if (closingBrackets > 0) {
  672. wrapper.Append(new string('}', closingBrackets));
  673. }
  674. return wrapper;
  675. }
  676. protected SyntaxTree ParseStub(string continuation, bool appendSemicolon = true, string afterContinuation = null)
  677. {
  678. var mt = GetMemberTextToCaret();
  679. if (mt == null) {
  680. return null;
  681. }
  682. string memberText = mt.Item1;
  683. var memberLocation = mt.Item2;
  684. int closingBrackets = 1;
  685. int generatedLines = 0;
  686. var wrapper = CreateWrapper(continuation, appendSemicolon, afterContinuation, memberText, memberLocation, ref closingBrackets, ref generatedLines);
  687. var parser = new CSharpParser ();
  688. foreach (var sym in CompletionContextProvider.ConditionalSymbols)
  689. parser.CompilerSettings.ConditionalSymbols.Add (sym);
  690. parser.InitialLocation = new TextLocation(memberLocation.Line - generatedLines, 1);
  691. var result = parser.Parse(wrapper.ToString ());
  692. return result;
  693. }
  694. protected virtual void Reset ()
  695. {
  696. memberText = null;
  697. }
  698. Tuple<string, TextLocation> memberText;
  699. protected Tuple<string, TextLocation> GetMemberTextToCaret()
  700. {
  701. if (memberText == null)
  702. memberText = CompletionContextProvider.GetMemberTextToCaret(offset, currentType, currentMember);
  703. return memberText;
  704. }
  705. protected ExpressionResult GetInvocationBeforeCursor(bool afterBracket)
  706. {
  707. SyntaxTree baseUnit;
  708. baseUnit = ParseStub("a", false);
  709. var section = baseUnit.GetNodeAt<AttributeSection>(location.Line, location.Column - 2);
  710. var attr = section != null ? section.Attributes.LastOrDefault() : null;
  711. if (attr != null) {
  712. return new ExpressionResult((AstNode)attr, baseUnit);
  713. }
  714. //var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin;
  715. var mref = baseUnit.GetNodeAt(location.Line, location.Column - 1, n => n is InvocationExpression || n is ObjectCreateExpression);
  716. AstNode expr = null;
  717. if (mref is InvocationExpression) {
  718. expr = ((InvocationExpression)mref).Target;
  719. } else if (mref is ObjectCreateExpression) {
  720. expr = mref;
  721. } else {
  722. baseUnit = ParseStub(")};", false);
  723. mref = baseUnit.GetNodeAt(location.Line, location.Column - 1, n => n is InvocationExpression || n is ObjectCreateExpression);
  724. if (mref is InvocationExpression) {
  725. expr = ((InvocationExpression)mref).Target;
  726. } else if (mref is ObjectCreateExpression) {
  727. expr = mref;
  728. }
  729. }
  730. if (expr == null) {
  731. // work around for missing ';' bug in mcs:
  732. baseUnit = ParseStub("a", true);
  733. section = baseUnit.GetNodeAt<AttributeSection>(location.Line, location.Column - 2);
  734. attr = section != null ? section.Attributes.LastOrDefault() : null;
  735. if (attr != null) {
  736. return new ExpressionResult((AstNode)attr, baseUnit);
  737. }
  738. //var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin;
  739. mref = baseUnit.GetNodeAt(location.Line, location.Column - 1, n => n is InvocationExpression || n is ObjectCreateExpression);
  740. expr = null;
  741. if (mref is InvocationExpression) {
  742. expr = ((InvocationExpression)mref).Target;
  743. } else if (mref is ObjectCreateExpression) {
  744. expr = mref;
  745. }
  746. }
  747. if (expr == null) {
  748. return null;
  749. }
  750. return new ExpressionResult ((AstNode)expr, baseUnit);
  751. }
  752. public class ExpressionResult
  753. {
  754. public AstNode Node { get; private set; }
  755. public SyntaxTree Unit { get; private set; }
  756. public ExpressionResult (AstNode item2, SyntaxTree item3)
  757. {
  758. this.Node = item2;
  759. this.Unit = item3;
  760. }
  761. public override string ToString ()
  762. {
  763. return string.Format ("[ExpressionResult: Node={0}, Unit={1}]", Node, Unit);
  764. }
  765. }
  766. protected ExpressionResolveResult ResolveExpression (ExpressionResult tuple)
  767. {
  768. return ResolveExpression (tuple.Node);
  769. }
  770. protected class ExpressionResolveResult
  771. {
  772. public ResolveResult Result { get; set; }
  773. public CSharpResolver Resolver { get; set; }
  774. public CSharpAstResolver AstResolver { get; set; }
  775. public ExpressionResolveResult(ResolveResult item1, CSharpResolver item2, CSharpAstResolver item3)
  776. {
  777. this.Result = item1;
  778. this.Resolver = item2;
  779. this.AstResolver = item3;
  780. }
  781. }
  782. protected ExpressionResolveResult ResolveExpression(AstNode expr)
  783. {
  784. if (expr == null) {
  785. return null;
  786. }
  787. AstNode resolveNode;
  788. if (expr is Expression || expr is AstType) {
  789. resolveNode = expr;
  790. } else if (expr is VariableDeclarationStatement) {
  791. resolveNode = ((VariableDeclarationStatement)expr).Type;
  792. } else {
  793. resolveNode = expr;
  794. }
  795. try {
  796. var root = expr.AncestorsAndSelf.FirstOrDefault(n => n is EntityDeclaration || n is SyntaxTree);
  797. if (root == null) {
  798. return null;
  799. }
  800. var curState = GetState();
  801. // current member needs to be in the setter because of the 'value' parameter
  802. if (root is Accessor) {
  803. var prop = curState.CurrentMember as IProperty;
  804. if (prop != null && prop.CanSet && (root.Role == IndexerDeclaration.SetterRole || root.Role == PropertyDeclaration.SetterRole))
  805. curState = curState.WithCurrentMember(prop.Setter);
  806. }
  807. // Rood should be the 'body' - otherwise the state -> current member isn't correct.
  808. var body = root.Children.FirstOrDefault(r => r.Role == Roles.Body);
  809. if (body != null && body.Contains(expr.StartLocation))
  810. root = body;
  811. var csResolver = CompletionContextProvider.GetResolver (curState, root);
  812. var result = csResolver.Resolve(resolveNode);
  813. var state = csResolver.GetResolverStateBefore(resolveNode);
  814. if (state.CurrentMember == null)
  815. state = state.WithCurrentMember(curState.CurrentMember);
  816. if (state.CurrentTypeDefinition == null)
  817. state = state.WithCurrentTypeDefinition(curState.CurrentTypeDefinition);
  818. if (state.CurrentUsingScope == null)
  819. state = state.WithCurrentUsingScope(curState.CurrentUsingScope);
  820. return new ExpressionResolveResult(result, state, csResolver);
  821. } catch (Exception e) {
  822. Console.WriteLine(e);
  823. return null;
  824. }
  825. }
  826. #endregion
  827. }
  828. }