From c989cbc19e0c8c056e49822992b1be75f60fc453 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Mon, 25 Jun 2007 12:54:52 +0000 Subject: [PATCH] Support right-click > add using on type names when the "using" is missing. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2586 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../CSharpBinding/Project/CSharpBinding.addin | 8 + .../Project/CSharpBinding.csproj | 1 + .../Project/Src/CSharpAdvancedHighlighter.cs | 154 +++++ .../Project/Src/Parser/ExpressionFinder.cs | 525 ------------------ .../VBNetBinding/Project/Src/Parser/Parser.cs | 4 +- .../VBNetBinding/Project/VBNetBinding.csproj | 1 - .../ClassEditor/ClassEditor.csproj | 1 + .../Project/FormsDesigner.csproj | 6 +- .../WpfDesign.AddIn/WpfDesign.AddIn.csproj | 1 + .../Project/WpfDesign.Designer.csproj | 2 + .../Project/Debugger.AddIn.csproj | 1 + .../Project/Resources/CSharp-Mode.xshd | 226 ++++---- .../NamespaceRefactoringService.cs | 39 +- .../RefactoringMenuBuilder.cs | 54 +- .../RefactoringService/RefactoringService.cs | 5 + .../SharpDevelopTextEditorProperties.cs | 11 +- .../Base/Test/CSharpExpressionFinderTests.cs | 16 +- .../Project/Src/CSharp/ExpressionFinder.cs | 41 +- .../Project/Src/ExpressionContext.cs | 9 + .../NRefactoryResolver/NRefactoryResolver.cs | 3 + .../Src/ProjectContent/IProjectContent.cs | 8 + .../Src/Refactoring/RefactoringProvider.cs | 3 +- .../Project/Src/ResolveResult.cs | 26 + 23 files changed, 487 insertions(+), 658 deletions(-) create mode 100644 src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpAdvancedHighlighter.cs delete mode 100644 src/AddIns/BackendBindings/VBNetBinding/Project/Src/Parser/ExpressionFinder.cs diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin index 8e25a81583..fa36bc2777 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin @@ -57,6 +57,12 @@ + + + + diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj index a44216f0ad..9431b180c6 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj @@ -45,6 +45,7 @@ + diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpAdvancedHighlighter.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpAdvancedHighlighter.cs new file mode 100644 index 0000000000..6a0e9a2f61 --- /dev/null +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpAdvancedHighlighter.cs @@ -0,0 +1,154 @@ +/* + * Created by SharpDevelop. + * User: Daniel + * Date: 24.06.2007 + * Time: 15:29 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Diagnostics; +using ICSharpCode.SharpDevelop.Dom.CSharp; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.TextEditor; +using ICSharpCode.TextEditor.Document; + +namespace CSharpBinding +{ + public class CSharpAdvancedHighlighter : AsynchronousAdvancedHighlighter + { + public override void Initialize(TextEditorControl textEditor) + { + base.Initialize(textEditor); + ParserService.ParserUpdateStepFinished += OnUpdateStep; + } + + public override void Dispose() + { + ParserService.ParserUpdateStepFinished -= OnUpdateStep; + base.Dispose(); + } + + void OnUpdateStep(object sender, ParserUpdateStepEventArgs e) + { + if (FileUtility.IsEqualFileName(e.FileName, this.TextEditor.FileName)) { + ParseInformation parseInfo = e.ParseInformation; +// if (parseInfo == null && this.storedParseInformation) +// parseInfo = ParserService.GetParseInformation(this.TextEditor.FileName); +// if (parseInfo != null) { +// ICompilationUnit cu = parseInfo.MostRecentCompilationUnit; +// } + WorkbenchSingleton.SafeThreadAsyncCall(MarkOutstanding); + } + } + + static bool IsInMultilineCommentOrStringLiteral(LineSegment line) + { + if (line.HighlightSpanStack == null || line.HighlightSpanStack.IsEmpty) { + return false; + } + return !line.HighlightSpanStack.Peek().StopEOL; + } + + protected override void MarkWords(int lineNumber, LineSegment currentLine, List words) + { + if (IsInMultilineCommentOrStringLiteral(currentLine)) { + return; + } + ParseInformation parseInfo = ParserService.GetParseInformation(this.TextEditor.FileName); + if (parseInfo == null) return; + + CSharpExpressionFinder finder = new CSharpExpressionFinder(parseInfo); + Func findExpressionMethod; + IClass callingClass = parseInfo.MostRecentCompilationUnit.GetInnermostClass(lineNumber, 0); + if (callingClass != null) { + if (GetCurrentMember(callingClass, lineNumber, 0) != null) { + findExpressionMethod = finder.FindFullExpressionInMethod; + } else { + findExpressionMethod = finder.FindFullExpressionInTypeDeclaration; + } + } else { + findExpressionMethod = finder.FindFullExpression; + } + + string lineText = this.Document.GetText(currentLine.Offset, currentLine.Length); + bool changedLine = false; + // now go through the word list: + foreach (TextWord word in words) { + if (word.IsWhiteSpace) continue; + if (char.IsLetter(lineText[word.Offset]) || lineText[word.Offset] == '_') { + ExpressionResult result = findExpressionMethod(lineText, word.Offset); + if (result.Expression != null) { + // result.Expression + if (ICSharpCode.NRefactory.Parser.CSharp.Keywords.GetToken(result.Expression) >= 0) + continue; + // convert text editor to DOM coordinates: + resolveCount++; + ResolveResult rr = ParserService.Resolve(result, lineNumber + 1, word.Offset + 1, this.TextEditor.FileName, this.TextEditor.Text); + if (rr is MixedResolveResult || rr is TypeResolveResult) { + changedLine = true; + word.SyntaxColor = this.Document.HighlightingStrategy.GetColorFor("TypeReference"); + } else if (rr == null) { + changedLine = true; + word.SyntaxColor = this.Document.HighlightingStrategy.GetColorFor("UnknownEntity"); + } + } + } + } + + if (markingOutstanding && changedLine) { + this.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, lineNumber)); + } + } + + static IMember GetCurrentMember(IClass callingClass, int caretLine, int caretColumn) + { + if (callingClass == null) + return null; + foreach (IMethod method in callingClass.Methods) { + if (method.Region.IsInside(caretLine, caretColumn) || method.BodyRegion.IsInside(caretLine, caretColumn)) { + return method; + } + } + foreach (IProperty property in callingClass.Properties) { + if (property.Region.IsInside(caretLine, caretColumn) || property.BodyRegion.IsInside(caretLine, caretColumn)) { + return property; + } + } + return null; + } + + bool markingOutstanding; + int resolveCount; + + protected override void MarkOutstanding() + { + #if DEBUG + int time = Environment.TickCount; + #endif + markingOutstanding = true; + resolveCount = 0; + base.MarkOutstanding(); + markingOutstanding = false; + #if DEBUG + time = Environment.TickCount - time; + if (time > 0) { + LoggingService.Info("CSharpHighlighter took " + time + "ms for " + resolveCount + " resolves"); + } + #endif + this.Document.CommitUpdate(); + } + } +} + + + + + diff --git a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/Parser/ExpressionFinder.cs b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/Parser/ExpressionFinder.cs deleted file mode 100644 index 5d50490251..0000000000 --- a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/Parser/ExpressionFinder.cs +++ /dev/null @@ -1,525 +0,0 @@ -// -// -// -// -// $Revision$ -// - -using System; -using System.Text; -using ICSharpCode.SharpDevelop.Dom; - -namespace VBNetBinding.Parser -{ - /// - /// Description of ExpressionFinder. - /// - public class ExpressionFinder : IExpressionFinder - { - ExpressionResult CreateResult(string expression) - { - if (expression == null) - return ExpressionResult.Empty; - if (expression.Length > 8 && expression.Substring(0, 8).Equals("Imports ", StringComparison.InvariantCultureIgnoreCase)) - return new ExpressionResult(expression.Substring(8).TrimStart(), ExpressionContext.Type, null); - if (expression.Length > 4 && expression.Substring(0, 4).Equals("New ", StringComparison.InvariantCultureIgnoreCase)) - return new ExpressionResult(expression.Substring(4).TrimStart(), ExpressionContext.ObjectCreation, null); - if (curTokenType == Ident && lastIdentifier.Equals("as", StringComparison.InvariantCultureIgnoreCase)) - return new ExpressionResult(expression, ExpressionContext.Type); - return new ExpressionResult(expression); - } - - public ExpressionResult FindExpression(string inText, int offset) - { - return CreateResult(FindExpressionInternal(inText, offset)); - } - - public string FindExpressionInternal(string inText, int offset) - { - this.text = FilterComments(inText, ref offset); - this.offset = this.lastAccept = offset; - this.state = START; - if (this.text == null) - { - return null; - } - //Console.WriteLine("---------------"); - while (state != ERROR) - { - ReadNextToken(); - //Console.WriteLine("cur state {0} got token {1}/{3} going to {2}", GetStateName(state), GetTokenName(curTokenType), GetStateName(stateTable[state, curTokenType]), curTokenType); - state = stateTable[state, curTokenType]; - - if (state == ACCEPT || state == ACCEPT2 || state == DOT) - { - lastAccept = this.offset; - } - if (state == ACCEPTNOMORE) - { - return this.text.Substring(this.offset + 1, offset - this.offset); - } - } - return this.text.Substring(this.lastAccept + 1, offset - this.lastAccept); - } - - internal int LastExpressionStartPosition { - get { - return ((state == ACCEPTNOMORE) ? offset : lastAccept) + 1; - } - } - - public ExpressionResult FindFullExpression(string inText, int offset) - { - string expressionBeforeOffset = FindExpressionInternal(inText, offset); - if (expressionBeforeOffset == null || expressionBeforeOffset.Length == 0) - return CreateResult(null); - StringBuilder b = new StringBuilder(expressionBeforeOffset); - // append characters after expression - for (int i = offset + 1; i < inText.Length; ++i) { - char c = inText[i]; - if (Char.IsLetterOrDigit(c)) { - if (Char.IsWhiteSpace(inText, i - 1)) - break; - b.Append(c); - } else if (c == ' ') { - b.Append(c); - } else if (c == '(') { - int otherBracket = SearchBracketForward(inText, i + 1, '(', ')'); - if (otherBracket < 0) - break; - b.Append(inText, i, otherBracket - i + 1); - break; - } else { - break; - } - } - return CreateResult(b.ToString()); - } - - // Like VBNetFormattingStrategy.SearchBracketForward, but operates on a string. - private int SearchBracketForward(string text, int offset, char openBracket, char closingBracket) - { - bool inString = false; - bool inComment = false; - int brackets = 1; - for (int i = offset; i < text.Length; ++i) { - char ch = text[i]; - if (ch == '\n') { - inString = false; - inComment = false; - } - if (inComment) continue; - if (ch == '"') inString = !inString; - if (inString) continue; - if (ch == '\'') { - inComment = true; - } else if (ch == openBracket) { - ++brackets; - } else if (ch == closingBracket) { - --brackets; - if (brackets == 0) return i; - } - } - return -1; - } - - /// - /// Removed the last part of the expression. - /// - /// - /// "obj.Field" => "obj" - /// "obj.Method(args,...)" => "obj.Method" - /// - public string RemoveLastPart(string expression) - { - text = expression; - offset = text.Length - 1; - ReadNextToken(); - if (curTokenType == Ident && Peek() == '.') - GetNext(); - return text.Substring(0, offset + 1); - } - - #region Comment Filter and 'inside string watcher' - int initialOffset; - public string FilterComments(string text, ref int offset) - { - if (text.Length <= offset) - return null; - this.initialOffset = offset; - StringBuilder outText = new StringBuilder(); - int curOffset = 0; - while (curOffset <= initialOffset) - { - char ch = text[curOffset]; - - switch (ch) - { - case '@': - if (curOffset + 1 < text.Length && text[curOffset + 1] == '"') - { - outText.Append(text[curOffset++]); // @ - outText.Append(text[curOffset++]); // " - if (!ReadVerbatimString(outText, text, ref curOffset)) - { - return null; - } - } - else - { - outText.Append(ch); - ++curOffset; - } - break; - case '"': - outText.Append(ch); - curOffset++; - if (!ReadString(outText, text, ref curOffset)) - { - return null; - } - break; - case '\'': - offset -= 1; - curOffset += 1; - if (!ReadToEOL(text, ref curOffset, ref offset)) - { - return null; - } - break; - default: - outText.Append(ch); - ++curOffset; - break; - } - } - - return outText.ToString(); - } - - bool ReadToEOL(string text, ref int curOffset, ref int offset) - { - while (curOffset <= initialOffset) - { - char ch = text[curOffset++]; - --offset; - if (ch == '\n') - { - return true; - } - } - return false; - } - - bool ReadString(StringBuilder outText, string text, ref int curOffset) - { - while (curOffset <= initialOffset) - { - char ch = text[curOffset++]; - outText.Append(ch); - if (ch == '"') - { - return true; - } - } - return false; - } - - bool ReadVerbatimString(StringBuilder outText, string text, ref int curOffset) - { - while (curOffset <= initialOffset) - { - char ch = text[curOffset++]; - outText.Append(ch); - if (ch == '"') - { - if (curOffset < text.Length && text[curOffset] == '"') - { - outText.Append(text[curOffset++]); - } - else - { - return true; - } - } - } - return false; - } - - bool ReadMultiLineComment(string text, ref int curOffset, ref int offset) - { - while (curOffset <= initialOffset) - { - char ch = text[curOffset++]; - --offset; - if (ch == '*') - { - if (curOffset < text.Length && text[curOffset] == '/') - { - ++curOffset; - --offset; - return true; - } - } - } - return false; - } - #endregion - - #region mini backward lexer - string text; - int offset; - - char GetNext() - { - if (offset >= 0) - { - return text[offset--]; - } - return '\0'; - } - - char Peek() - { - if (offset >= 0) - { - return text[offset]; - } - return '\0'; - } - - void UnGet() - { - ++offset; - } - - // tokens for our lexer - static int Err = 0; - static int Dot = 1; - static int StrLit = 2; - static int Ident = 3; - static int New = 4; - // static int Bracket = 5; - static int Parent = 6; - static int Curly = 7; - static int Using = 8; - int curTokenType; - - readonly static string[] tokenStateName = new string[] { - "Err", "Dot", "StrLit", "Ident", "New", "Bracket", "Paren", "Curly", "Using" - }; - string GetTokenName(int state) - { - return tokenStateName[state]; - } - - string lastIdentifier; - - void ReadNextToken() - { - char ch = GetNext(); - - curTokenType = Err; - if (ch == '\0' || ch == '\n' || ch == '\r') - { - return; - } - while (Char.IsWhiteSpace(ch)) - { - ch = GetNext(); - if (ch == '\n' || ch == '\r') - { - return; - } - } - - switch (ch) - { - case '}': - if (ReadBracket('{', '}')) - { - curTokenType = Curly; - } - break; - case ')': - if (ReadBracket('(', ')')) - { - curTokenType = Parent; - } - break; - case ']': - if (ReadBracket('[', ']')) - { - curTokenType = Ident; - } - break; - case '.': - curTokenType = Dot; - break; - case '\'': - case '"': - if (ReadStringLiteral(ch)) - { - curTokenType = StrLit; - } - break; - default: - if (IsIdentifierPart(ch)) - { - string ident = ReadIdentifier(ch); - if (ident != null) - { - switch (ident.ToLowerInvariant()) - { - case "new": - curTokenType = New; - break; - case "imports": - curTokenType = Using; - break; - default: - lastIdentifier = ident; - curTokenType = Ident; - break; - } - } - } - break; - } - } - - bool ReadStringLiteral(char litStart) - { - while (true) - { - char ch = GetNext(); - if (ch == '\0') - { - return false; - } - if (ch == litStart) - { - if (Peek() == '@' && litStart == '"') - { - GetNext(); - } - return true; - } - } - } - - bool ReadBracket(char openBracket, char closingBracket) - { - int curlyBraceLevel = 0; - int squareBracketLevel = 0; - int parenthesisLevel = 0; - switch (openBracket) - { - case '(': - parenthesisLevel++; - break; - case '[': - squareBracketLevel++; - break; - case '{': - curlyBraceLevel++; - break; - } - - while (parenthesisLevel != 0 || squareBracketLevel != 0 || curlyBraceLevel != 0) - { - char ch = GetNext(); - if (ch == '\0') - { - return false; - } - switch (ch) - { - case '(': - parenthesisLevel--; - break; - case '[': - squareBracketLevel--; - break; - case '{': - curlyBraceLevel--; - break; - case ')': - parenthesisLevel++; - break; - case ']': - squareBracketLevel++; - break; - case '}': - curlyBraceLevel++; - break; - } - } - return true; - } - - string ReadIdentifier(char ch) - { - string identifier = ch.ToString(); - while (IsIdentifierPart(Peek())) - { - identifier = GetNext() + identifier; - } - return identifier; - } - - bool IsIdentifierPart(char ch) - { - return Char.IsLetterOrDigit(ch) || ch == '_'; - } - #endregion - - #region finite state machine - readonly static int ERROR = 0; - readonly static int START = 1; - readonly static int DOT = 2; - readonly static int MORE = 3; - readonly static int CURLY = 4; - readonly static int CURLY2 = 5; - readonly static int CURLY3 = 6; - - readonly static int ACCEPT = 7; - readonly static int ACCEPTNOMORE = 8; - readonly static int ACCEPT2 = 9; - - readonly static string[] stateName = new string[] { - "ERROR", - "START", - "DOT", - "MORE", - "CURLY", - "CURLY2", - "CURLY3", - "ACCEPT", - "ACCEPTNOMORE", - "ACCEPT2" - }; - - string GetStateName(int state) - { - return stateName[state]; - } - - int state = 0; - int lastAccept = 0; - static int[,] stateTable = new int[,] { - // Err, Dot, Str, ID, New, Brk, Par, Cur, Using - /*ERROR*/ { ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR}, - /*START*/ { ERROR, ERROR, ACCEPT, ACCEPT, ERROR, MORE, ACCEPT2, CURLY, ACCEPTNOMORE}, - /*DOT*/ { ERROR, ERROR, ACCEPT, ACCEPT, ERROR, MORE, ACCEPT2, CURLY, ERROR}, - /*MORE*/ { ERROR, ERROR, ACCEPT, ACCEPT, ERROR, MORE, ACCEPT2, CURLY, ERROR}, - /*CURLY*/ { ERROR, ERROR, ERROR, ERROR, ERROR, CURLY2, ERROR, ERROR, ERROR}, - /*CURLY2*/ { ERROR, ERROR, ERROR, CURLY3, ERROR, ERROR, ERROR, ERROR, ERROR}, - /*CURLY3*/ { ERROR, ERROR, ERROR, ERROR, ACCEPTNOMORE, ERROR, ERROR, ERROR, ERROR}, - /*ACCEPT*/ { ERROR, DOT, ERROR, ERROR, ACCEPT, ERROR, ERROR, ERROR, ACCEPTNOMORE}, - /*ACCEPTNOMORE*/ { ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR}, - /*ACCEPT2*/ { ERROR, DOT, ERROR, ACCEPT, ACCEPT, ERROR, ERROR, ERROR, ERROR}, - }; - #endregion - } -} diff --git a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/Parser/Parser.cs b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/Parser/Parser.cs index ef7d3d2df8..098caf9f41 100644 --- a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/Parser/Parser.cs +++ b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/Parser/Parser.cs @@ -9,6 +9,7 @@ using System; using System.IO; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.VBNet; using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver; using ICSharpCode.SharpDevelop.Project; @@ -36,7 +37,7 @@ namespace VBNetBinding.Parser public IExpressionFinder CreateExpressionFinder(string fileName) { - return new ExpressionFinder(); + return new VBExpressionFinder(); } public bool CanParse(string fileName) @@ -139,3 +140,4 @@ namespace VBNetBinding.Parser ///////// IParser Interface END } } + diff --git a/src/AddIns/BackendBindings/VBNetBinding/Project/VBNetBinding.csproj b/src/AddIns/BackendBindings/VBNetBinding/Project/VBNetBinding.csproj index fe4ec7fa0d..75f5644473 100644 --- a/src/AddIns/BackendBindings/VBNetBinding/Project/VBNetBinding.csproj +++ b/src/AddIns/BackendBindings/VBNetBinding/Project/VBNetBinding.csproj @@ -51,7 +51,6 @@ Form - diff --git a/src/AddIns/DisplayBindings/ClassDiagram/ClassEditor/ClassEditor.csproj b/src/AddIns/DisplayBindings/ClassDiagram/ClassEditor/ClassEditor.csproj index e708ab5106..fef701e776 100644 --- a/src/AddIns/DisplayBindings/ClassDiagram/ClassEditor/ClassEditor.csproj +++ b/src/AddIns/DisplayBindings/ClassDiagram/ClassEditor/ClassEditor.csproj @@ -60,6 +60,7 @@ {E73BB233-D88B-44A7-A98F-D71EE158381D} Aga.Controls + False {2748AD25-9C63-4E12-877B-4DCE96FBED54} diff --git a/src/AddIns/DisplayBindings/FormsDesigner/Project/FormsDesigner.csproj b/src/AddIns/DisplayBindings/FormsDesigner/Project/FormsDesigner.csproj index 3eea0a50c2..3f011c7b15 100644 --- a/src/AddIns/DisplayBindings/FormsDesigner/Project/FormsDesigner.csproj +++ b/src/AddIns/DisplayBindings/FormsDesigner/Project/FormsDesigner.csproj @@ -13,25 +13,27 @@ OnSuccessfulBuild Library ICSharpCode.FormsDesigner - Full False Auto AnyCPU false False ..\..\..\..\..\AddIns\AddIns\DisplayBindings\FormsDesigner\ - true 108003328 4096 True False + None + false False True DEBUG + Full + true diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/WpfDesign.AddIn.csproj b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/WpfDesign.AddIn.csproj index 1ff733ead9..0485cf8262 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/WpfDesign.AddIn.csproj +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/WpfDesign.AddIn.csproj @@ -90,6 +90,7 @@ {7D7E92DF-ACEB-4B69-92C8-8AC7A703CD57} FormsDesigner + False {78CC29AC-CC79-4355-B1F2-97936DF198AC} diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj index f69f314bcb..ff05875e02 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj @@ -121,11 +121,13 @@ {88DA149F-21B2-48AB-82C4-28FB6BDFD783} WpfDesign.XamlDom + False {66A378A1-E9F4-4AD5-8946-D0EC06C2902F} WpfDesign False + False PropertyEditor.cs diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.csproj b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.csproj index b00fb63f24..b20e788f47 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.csproj +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.csproj @@ -121,6 +121,7 @@ {E73BB233-D88B-44A7-A98F-D71EE158381D} Aga.Controls + False diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Resources/CSharp-Mode.xshd b/src/Libraries/ICSharpCode.TextEditor/Project/Resources/CSharp-Mode.xshd index baa31082ae..683515d1f0 100644 --- a/src/Libraries/ICSharpCode.TextEditor/Project/Resources/CSharp-Mode.xshd +++ b/src/Libraries/ICSharpCode.TextEditor/Project/Resources/CSharp-Mode.xshd @@ -3,12 +3,17 @@ + + + + + - + &<>~!%^*()-+=|\#/{}[]:;"' , .? @@ -20,19 +25,19 @@ ///@!/@ - - - //@!/@ - - - //// - - + + + //@!/@ + + + //// + + /* */ - + " " @@ -73,9 +78,9 @@ - - - + + + @@ -91,8 +96,8 @@ - - + + @@ -100,7 +105,7 @@ - + @@ -108,7 +113,7 @@ - + @@ -129,12 +134,12 @@ - + - + @@ -156,88 +161,88 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - + + + - - + + - - + + - + - - - + + + - - - - + + + + - + - - + + - <>~!@%^*()-+=|\#/{}[]:;"' , .? + <>~!@%^*()-+=|\#/{}[]:;"' , .? - + - + - <>~!@%^*()-+=|\#/{}[]:;"' , .? + <>~!@%^*()-+=|\#/{}[]:;"' , .? < @@ -245,13 +250,13 @@ - - + + - - + + @@ -275,45 +280,46 @@ - <>~!@%^*()-+=|\#/{}[]:;"' , .? - + <>~!@%^*()-+=|\#/{}[]:;"' , .? + " " - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/NamespaceRefactoringService.cs b/src/Main/Base/Project/Src/Services/RefactoringService/NamespaceRefactoringService.cs index 20ed3c9669..5040be299c 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/NamespaceRefactoringService.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/NamespaceRefactoringService.cs @@ -67,7 +67,16 @@ namespace ICSharpCode.SharpDevelop.Refactoring } // put empty line after last System namespace - if (sort && newUsings.Count > 1 && newUsings[0].Usings.Count > 0) { + if (sort) { + PutEmptyLineAfterLastSystemNamespace(newUsings); + } + + cu.ProjectContent.Language.CodeGenerator.ReplaceUsings(new TextEditorDocument(document), cu.Usings, newUsings); + } + + static void PutEmptyLineAfterLastSystemNamespace(List newUsings) + { + if (newUsings.Count > 1 && newUsings[0].Usings.Count > 0) { bool inSystem = IsSystemNamespace(newUsings[0].Usings[0]); int inSystemCount = 1; for (int i = 1; inSystem && i < newUsings.Count; i++) { @@ -81,8 +90,36 @@ namespace ICSharpCode.SharpDevelop.Refactoring } } } + } + + public static void AddUsingDeclaration(ICompilationUnit cu, IDocument document, string newNamespace, bool sortExistingUsings) + { + IUsing newUsingDecl = new DefaultUsing(cu.ProjectContent); + newUsingDecl.Usings.Add(newNamespace); + List newUsings = new List(cu.Usings); + if (sortExistingUsings) { + newUsings.Sort(CompareUsings); + } + bool inserted = false; + for (int i = 0; i < newUsings.Count; i++) { + if (newUsings[i].Usings.Count >= 1 + && cu.ProjectContent.Language.NameComparer.Compare(newNamespace, newUsings[i].Usings[0]) <= 0) + { + newUsings.Insert(i, newUsingDecl); + inserted = true; + break; + } + } + if (!inserted) { + newUsings.Add(newUsingDecl); + } + if (sortExistingUsings) { + PutEmptyLineAfterLastSystemNamespace(newUsings); + } cu.ProjectContent.Language.CodeGenerator.ReplaceUsings(new TextEditorDocument(document), cu.Usings, newUsings); } } } + + diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringMenuBuilder.cs b/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringMenuBuilder.cs index 7deba91818..856165b7c1 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringMenuBuilder.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringMenuBuilder.cs @@ -94,19 +94,24 @@ namespace ICSharpCode.SharpDevelop.Refactoring } else if (rr is LocalResolveResult) { item = MakeItem((LocalResolveResult)rr, caretLine + 1 == ((LocalResolveResult)rr).Field.Region.BeginLine); insertIndex = 0; // Insert local variable menu item at the topmost position. + } else if (rr is UnknownIdentifierResolveResult) { + item = MakeItemForResolveError((UnknownIdentifierResolveResult)rr, expressionResult.Context, textArea); + insertIndex = 0; // Insert menu item at the topmost position. } if (item != null) { resultItems.Insert(insertIndex, item); } // Include menu for current class and method + ICompilationUnit cu = null; IMember callingMember = null; if (rr != null) { callingMember = rr.CallingMember; + cu = callingMember.DeclaringType.CompilationUnit; } else { ParseInformation parseInfo = ParserService.GetParseInformation(textEditorControl.FileName); if (parseInfo != null) { - ICompilationUnit cu = parseInfo.MostRecentCompilationUnit; + cu = parseInfo.MostRecentCompilationUnit; if (cu != null) { IClass callingClass = cu.GetInnermostClass(caretLine + 1, textArea.Caret.Column + 1); callingMember = GetCallingMember(callingClass, caretLine + 1, textArea.Caret.Column + 1); @@ -129,6 +134,48 @@ namespace ICSharpCode.SharpDevelop.Refactoring } } + ToolStripMenuItem MakeItemForResolveError(UnknownIdentifierResolveResult rr, ExpressionContext context, TextArea textArea) + { + if (context != null && context.IsTypeContext) { + return MakeItemForUnknownClass(rr.CallingClass, rr.Identifier, textArea); + } + return null; + } + + ToolStripMenuItem MakeItemForUnknownClass(IClass callingClass, string unknownClassName, TextArea textArea) + { + if (callingClass == null) + return null; + IProjectContent pc = callingClass.ProjectContent; + if (!pc.Language.RefactoringProvider.IsEnabledForFile(callingClass.CompilationUnit.FileName)) + return null; + ToolStripMenuItem item = MakeItemInternal(unknownClassName, ClassBrowserIconService.GotoArrowIndex, callingClass.CompilationUnit, DomRegion.Empty); + List searchResults = new List(); + SearchAllClassesWithName(searchResults, pc, unknownClassName, pc.Language); + foreach (IProjectContent rpc in pc.ReferencedContents) { + SearchAllClassesWithName(searchResults, rpc, unknownClassName, pc.Language); + } + foreach (IClass c in searchResults) { + string newNamespace = c.Namespace; + ToolStripMenuItem subItem = new ToolStripMenuItem("using " + newNamespace, ClassBrowserIconService.ImageList.Images[ClassBrowserIconService.NamespaceIndex]); + item.DropDownItems.Add(subItem); + subItem.Click += delegate { + NamespaceRefactoringService.AddUsingDeclaration(callingClass.CompilationUnit, textArea.Document, newNamespace, true); + textArea.MotherTextEditorControl.Refresh(); + }; + } + return item; + } + + void SearchAllClassesWithName(List searchResults, IProjectContent pc, string name, LanguageProperties language) + { + foreach (string ns in pc.NamespaceNames) { + IClass c = pc.GetClass(ns + "." + name, 0, language, false); + if (c != null) + searchResults.Add(c); + } + } + IMember GetCallingMember(IClass callingClass, int caretLine, int caretColumn) { if (callingClass == null) { @@ -194,7 +241,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring //item.DropDown.Items.Add(titleItem); //item.DropDown.Items.Add(new ToolStripSeparator()); - if (cu.FileName != null && !region.IsEmpty) { + if (cu != null && cu.FileName != null && !region.IsEmpty) { ToolStripMenuItem gotoDefinitionItem = new ToolStripMenuItem(StringParser.Parse("${res:ICSharpCode.NAntAddIn.GotoDefinitionMenuLabel}"), ClassBrowserIconService.ImageList.Images[ClassBrowserIconService.GotoArrowIndex]); gotoDefinitionItem.ShortcutKeys = Keys.Control | Keys.Enter; @@ -232,3 +279,6 @@ namespace ICSharpCode.SharpDevelop.Refactoring } } } + + + diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs b/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs index f5743e6b0f..c2969f4559 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs @@ -205,6 +205,10 @@ namespace ICSharpCode.SharpDevelop.Refactoring if (expressionFinder == null) { expressionFinder = ParserService.GetExpressionFinder(fileName); + if (expressionFinder == null) { + // ignore file if we cannot get an expression finder + return; + } } ExpressionResult expr = expressionFinder.FindFullExpression(fileContent, match.ResolvePosition); if (expr.Expression != null) { @@ -523,3 +527,4 @@ namespace ICSharpCode.SharpDevelop.Refactoring #endregion } } + diff --git a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextEditorProperties.cs b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextEditorProperties.cs index e4faaf23e2..216f5aa7d3 100644 --- a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextEditorProperties.cs +++ b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextEditorProperties.cs @@ -62,7 +62,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor } public IndentStyle IndentStyle { get { - return (IndentStyle)properties.Get("IndentStyle", IndentStyle.Smart); + return properties.Get("IndentStyle", IndentStyle.Smart); } set { properties.Set("IndentStyle", value); @@ -71,7 +71,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor public DocumentSelectionMode DocumentSelectionMode { get { - return (DocumentSelectionMode)properties.Get("DocumentSelectionMode", DocumentSelectionMode.Normal); + return properties.Get("DocumentSelectionMode", DocumentSelectionMode.Normal); } set { properties.Set("DocumentSelectionMode", value); @@ -132,7 +132,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor return properties.Get("ShowTabs", false); } set { - properties.Get("ShowTabs", value); + properties.Set("ShowTabs", value); } } public bool ShowEOLMarker { @@ -250,7 +250,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor } public LineViewerStyle LineViewerStyle { get { - return (LineViewerStyle)properties.Get("LineViewerStyle", LineViewerStyle.None); + return properties.Get("LineViewerStyle", LineViewerStyle.None); } set { properties.Set("LineViewerStyle", value); @@ -258,7 +258,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor } public string LineTerminator { get { - LineTerminatorStyle lineTerminatorStyle = (LineTerminatorStyle)PropertyService.Get("SharpDevelop.LineTerminatorStyle", LineTerminatorStyle.Windows); + LineTerminatorStyle lineTerminatorStyle = PropertyService.Get("SharpDevelop.LineTerminatorStyle", LineTerminatorStyle.Windows); switch (lineTerminatorStyle) { case LineTerminatorStyle.Windows: return "\r\n"; @@ -332,3 +332,4 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor } } } + diff --git a/src/Main/Base/Test/CSharpExpressionFinderTests.cs b/src/Main/Base/Test/CSharpExpressionFinderTests.cs index 99c322b8d0..af7171e986 100644 --- a/src/Main/Base/Test/CSharpExpressionFinderTests.cs +++ b/src/Main/Base/Test/CSharpExpressionFinderTests.cs @@ -26,7 +26,7 @@ class Main : BaseType void Method() { simple += 1; int a = 0; - ((CastTo)castTarget).MethodOnCastExpression(parameter); + ((CastTo)castTarget).MethodOnCastExpression(par.a, par.b); int b = 0; return ((CastTo)castTarget).PropertyOnCastExpression; } @@ -61,7 +61,9 @@ class Main { if (pos < 0) Assert.Fail("location not found in program"); ExpressionResult er = ef.FindFullExpression(program, pos); Assert.AreEqual(expectedExpression, er.Expression); - Assert.AreEqual(expectedContext.ToString(), er.Context.ToString()); + if (expectedContext != null) { + Assert.AreEqual(expectedContext.ToString(), er.Context.ToString()); + } } void FindExpr(string program, string location, string expectedExpression, ExpressionContext expectedContext) @@ -110,24 +112,21 @@ class Main { } [Test] - [Ignore("Context inside methods not yet implemented")] public void MethodOnCast() { - FindFull(document, "thodOnCastExpression(para", "((CastTo)castTarget).MethodOnCastExpression(parameter)", ExpressionContext.Default); + FindFull(document, "thodOnCastExpression(pa", "((CastTo)castTarget).MethodOnCastExpression(par.a, par.b)", null); } [Test] - [Ignore("Context inside methods not yet implemented")] public void PropertyOnCast() { - FindFull(document, "pertyOnCastExpression", "((CastTo)castTarget).PropertyOnCastExpression", ExpressionContext.Default); + FindFull(document, "pertyOnCastExpression", "((CastTo)castTarget).PropertyOnCastExpression", null); } [Test] - [Ignore("Context inside methods not yet implemented")] public void PropertyOnCastInForeachLoop() { - FindFull(program2, "pertyOnCastExpression", "((CastTo)castTarget).PropertyOnCastExpression", ExpressionContext.Default); + FindFull(program2, "pertyOnCastExpression", "((CastTo)castTarget).PropertyOnCastExpression", null); } [Test] @@ -204,3 +203,4 @@ class Main { } } } + diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CSharp/ExpressionFinder.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CSharp/ExpressionFinder.cs index d5d9715e83..c100ca2daf 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CSharp/ExpressionFinder.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CSharp/ExpressionFinder.cs @@ -434,9 +434,43 @@ namespace ICSharpCode.SharpDevelop.Dom.CSharp } public ExpressionResult FindFullExpression(string text, int offset) + { + return FindFullExpression(text, offset, null); + } + + /// + /// Like FindFullExpression, but text is a code snippet inside a type declaration. + /// + public ExpressionResult FindFullExpressionInTypeDeclaration(string text, int offset) + { + Frame root = new Frame(null); + root.childType = FrameType.TypeDecl; + Frame typeDecl = new Frame(root); + return FindFullExpression(text, offset, typeDecl); + } + + + /// + /// Like FindFullExpression, but text is a code snippet inside a method body. + /// + public ExpressionResult FindFullExpressionInMethod(string text, int offset) + { + Frame root = new Frame(null); + root.childType = FrameType.TypeDecl; + Frame typeDecl = new Frame(root); + typeDecl.childType = FrameType.Statements; + Frame methodBody = new Frame(typeDecl); + return FindFullExpression(text, offset, methodBody); + } + + ExpressionResult FindFullExpression(string text, int offset, Frame initialFrame) { Init(text, offset); + if (initialFrame != null) { + frame = initialFrame; + } + const int SEARCHING_OFFSET = 0; const int SEARCHING_END = 1; int state = SEARCHING_OFFSET; @@ -486,9 +520,11 @@ namespace ICSharpCode.SharpDevelop.Dom.CSharp } else if (resultFrame.bracketType == '<' && token.kind == Tokens.GreaterThan) { // expression was a type argument resultContext = ExpressionContext.Type; + return new ExpressionResult(text.Substring(resultStartOffset, resultEndOffset - resultStartOffset), resultContext); + } + if (frame == resultFrame || resultFrame.type == FrameType.Popped) { + return new ExpressionResult(text.Substring(resultStartOffset, resultEndOffset - resultStartOffset), resultContext); } - - return new ExpressionResult(text.Substring(resultStartOffset, resultEndOffset - resultStartOffset), resultContext); } else { resultEndOffset = LocationToOffset(token.EndLocation); } @@ -689,3 +725,4 @@ namespace ICSharpCode.SharpDevelop.Dom.CSharp #endregion } } + diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ExpressionContext.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ExpressionContext.cs index e17adbbf98..9981143f62 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ExpressionContext.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ExpressionContext.cs @@ -62,6 +62,10 @@ namespace ICSharpCode.SharpDevelop.Dom return false; } } + + public virtual bool IsTypeContext { + get { return false; } + } #endregion #region C# specific contexts (public static fields) * MOVE TO ANOTHER CLASS * @@ -277,6 +281,10 @@ namespace ICSharpCode.SharpDevelop.Dom } } + public override bool IsTypeContext { + get { return true; } + } + public override string ToString() { if (baseClass != null) @@ -461,3 +469,4 @@ namespace ICSharpCode.SharpDevelop.Dom #endregion } } + diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs index 0b8ce03796..8e98e4516e 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs @@ -417,6 +417,8 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver ResolveResult result = ResolveIdentifier(((IdentifierExpression)expr).Identifier, expr.StartLocation, context); if (result != null) return result; + else + return new UnknownIdentifierResolveResult(callingClass, callingMember, ((IdentifierExpression)expr).Identifier); } else if (expr is TypeReferenceExpression) { type = TypeVisitor.CreateReturnType(((TypeReferenceExpression)expr).TypeReference, this); if (type != null) { @@ -1185,3 +1187,4 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver } } } + diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/IProjectContent.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/IProjectContent.cs index 3eb0698302..a4e4670078 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/IProjectContent.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/IProjectContent.cs @@ -30,10 +30,17 @@ namespace ICSharpCode.SharpDevelop.Dom get; } + /// + /// Gets the list of namespaces defined in this project content. Does not include namespaces from + /// referenced project contents. + /// ICollection NamespaceNames { get; } + /// + /// Gets the list of referenced project contents. + /// ICollection ReferencedContents { get; } @@ -167,3 +174,4 @@ namespace ICSharpCode.SharpDevelop.Dom } } } + diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/RefactoringProvider.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/RefactoringProvider.cs index 15ca100ff9..44f40bdd87 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/RefactoringProvider.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/RefactoringProvider.cs @@ -40,7 +40,6 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring throw new NotSupportedException(); } - public virtual bool SupportsCreateNewFileLikeExisting { get { return false; @@ -72,3 +71,5 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring } } } + + diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs index 695740db35..2ce6180f99 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs @@ -32,6 +32,10 @@ namespace ICSharpCode.SharpDevelop.Dom this.resolvedType = resolvedType; } + public virtual bool IsValid { + get { return true; } + } + /// /// Gets the class that contained the expression used to get this ResolveResult. /// Can be null when the class is unknown. @@ -567,4 +571,26 @@ namespace ICSharpCode.SharpDevelop.Dom } } #endregion + + #region UnknownIdentifierResolveResult + public class UnknownIdentifierResolveResult : ResolveResult + { + string identifier; + + public UnknownIdentifierResolveResult(IClass callingClass, IMember callingMember, string identifier) + : base(callingClass, callingMember, null) + { + this.identifier = identifier; + } + + public string Identifier { + get { return identifier; } + } + + public override bool IsValid { + get { return false; } + } + } + #endregion } +