From 99b856a5ee9a2956063698308121e0ba80900948 Mon Sep 17 00:00:00 2001 From: Nieve Date: Fri, 11 May 2012 21:35:18 +0100 Subject: [PATCH 01/24] added extract field code action --- .../ICSharpCode.NRefactory.CSharp.csproj | 3 +- .../CodeActions/ExtractFieldAction.cs | 93 +++++++++++ .../CSharp/CodeActions/ExtractFieldTests.cs | 149 ++++++++++++++++++ .../ICSharpCode.NRefactory.Tests.csproj | 3 +- 4 files changed, 246 insertions(+), 2 deletions(-) create mode 100755 ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractFieldAction.cs create mode 100644 ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ExtractFieldTests.cs diff --git a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj index 407c641280..c83f2160ce 100644 --- a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj +++ b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj @@ -1,4 +1,4 @@ - + {53DCA265-3C3C-42F9-B647-F72BA678122B} @@ -372,6 +372,7 @@ + diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractFieldAction.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractFieldAction.cs new file mode 100755 index 0000000000..7585386f04 --- /dev/null +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractFieldAction.cs @@ -0,0 +1,93 @@ +// +// ExtractFieldAction.cs +// +// Author: +// Nieve <> +// +// Copyright (c) 2012 Nieve +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Collections.Generic; +using System.Linq; +using ICSharpCode.NRefactory.PatternMatching; +using Mono.CSharp; + +namespace ICSharpCode.NRefactory.CSharp.Refactoring +{ + [ContextAction("Extract field", Description = "Extracts a field from a local variable declaration.")] + public class ExtractFieldAction : ICodeActionProvider + { + public IEnumerable GetActions(RefactoringContext context) + { + //TODO: implement variable assignment & ctor param + var varInit = context.GetNode(); + if (varInit != null) { + AstType type = varInit.GetPrevNode() as AstType; + if (type == null) yield break; + if (varInit.Parent is FieldDeclaration) yield break; + if (CannotExtractField(varInit)) yield break; + + yield return new CodeAction("Extract field", s=>{ + var name = varInit.Name; + FieldDeclaration field = new FieldDeclaration(){ + ReturnType = type.Clone(), + Variables = { new VariableInitializer(name) } + }; + AstNode nodeToRemove = RemoveDeclaration(varInit) ? varInit.Parent : type; + s.Remove(nodeToRemove, true); + s.InsertWithCursor(context.TranslateString("Extract field"),Script.InsertPosition.Before,field); + s.FormatText(varInit.Parent); + }); + } + + var idntf = context.GetNode(); + if (idntf == null) yield break; + var paramDec = idntf.Parent as ParameterDeclaration; + if (paramDec != null) { + var ctor = paramDec.Parent as ConstructorDeclaration; + if (ctor == null) yield break; + MemberReferenceExpression thisField = new MemberReferenceExpression(new ThisReferenceExpression(), idntf.Name, new AstType[]{}); + var assign = new AssignmentExpression(thisField, AssignmentOperatorType.Assign, new IdentifierExpression(idntf.Name)); + var statement = new ExpressionStatement(assign); + var type = (idntf.GetPrevNode() as AstType).Clone(); + FieldDeclaration field = new FieldDeclaration(){ + ReturnType = type.Clone(), + Variables = { new VariableInitializer(idntf.Name) } + }; + yield return new CodeAction("Extract field", s=>{ + s.InsertWithCursor(context.TranslateString("Extract field"),Script.InsertPosition.Before,field); + s.AddTo(ctor.Body, statement); + }); + } + } + + static bool RemoveDeclaration (VariableInitializer varInit){ + var result = varInit.Parent as VariableDeclarationStatement; + return result.Variables.First ().Initializer.IsNull; + } + + static bool CannotExtractField (VariableInitializer varInit) + { + var result = varInit.Parent as VariableDeclarationStatement; + return result == null || result.Variables.Count != 1; + } + } +} + diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ExtractFieldTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ExtractFieldTests.cs new file mode 100644 index 0000000000..40082ea51f --- /dev/null +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ExtractFieldTests.cs @@ -0,0 +1,149 @@ +// +// CreateFieldTests.cs +// +// Author: +// Nieve Goor +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using NUnit.Framework; +using ICSharpCode.NRefactory.CSharp.Refactoring; + +namespace ICSharpCode.NRefactory.CSharp.CodeActions +{ + [TestFixture] + public class ExtractFieldTests : ContextActionTestBase + { + [Test] + public void TestWrongContext1 () + { + TestWrongContext ( + "using System;" + Environment.NewLine + + "class TestClass" + Environment.NewLine + + "{" + Environment.NewLine + + " void Test ()" + Environment.NewLine + + " {" + Environment.NewLine + + " $foo = 2;" + Environment.NewLine + + " }" + Environment.NewLine + + "}" + ); + } + + [Test] + public void TestWrongContext2 () + { + TestWrongContext ( + "using System;" + Environment.NewLine + + "class TestClass" + Environment.NewLine + + "{" + Environment.NewLine + + " int foo;" + Environment.NewLine + + " void Test ()" + Environment.NewLine + + " {" + Environment.NewLine + + " $foo = 2;" + Environment.NewLine + + " }" + Environment.NewLine + + "}" + ); + } + + [Test] + public void TestLocalInitializer() + { + string result = RunContextAction ( + new ExtractFieldAction (), + "using System;" + Environment.NewLine + + "class TestClass" + Environment.NewLine + + "{" + Environment.NewLine + + " void Test ()" + Environment.NewLine + + " {" + Environment.NewLine + + " int $foo = 5;" + Environment.NewLine + + " }" + Environment.NewLine + + "}" + ); + Console.WriteLine (result); + Assert.AreEqual ( + "using System;" + Environment.NewLine + + "class TestClass" + Environment.NewLine + + "{" + Environment.NewLine + + " int foo;" + Environment.NewLine + + "" + Environment.NewLine + + " void Test ()" + Environment.NewLine + + " {" + Environment.NewLine + + " foo = 5;" + Environment.NewLine + + " }" + Environment.NewLine + + "}", result); + } + + [Test] + public void TestLocalDeclaration() + { + string result = RunContextAction ( + new ExtractFieldAction (), + "using System;" + Environment.NewLine + + "class TestClass" + Environment.NewLine + + "{" + Environment.NewLine + + " void Test ()" + Environment.NewLine + + " {" + Environment.NewLine + + " int $foo;" + Environment.NewLine + + " }" + Environment.NewLine + + "}" + ); + Console.WriteLine (result); + Assert.AreEqual ( + "using System;" + Environment.NewLine + + "class TestClass" + Environment.NewLine + + "{" + Environment.NewLine + + " int foo;" + Environment.NewLine + + "" + Environment.NewLine + + " void Test ()" + Environment.NewLine + + " {" + Environment.NewLine + + " }" + Environment.NewLine + + "}", result); + } + + [Test] + public void TestCtorParam () + { + string result = RunContextAction ( + new ExtractFieldAction (), + "using System;" + Environment.NewLine + + "class TestClass" + Environment.NewLine + + "{" + Environment.NewLine + + " TestClass (int $foo)" + Environment.NewLine + + " {" + Environment.NewLine + + " " + Environment.NewLine + + " }" + Environment.NewLine + + "}" + ); + + Assert.AreEqual ( + "using System;" + Environment.NewLine + + "class TestClass" + Environment.NewLine + + "{" + Environment.NewLine + + " int foo;" + Environment.NewLine + + "" + Environment.NewLine + + " TestClass (int foo)" + Environment.NewLine + + " {" + Environment.NewLine + + " this.foo = foo;" + Environment.NewLine + + " " + Environment.NewLine + + " }" + Environment.NewLine + + "}", result); + } + } +} + diff --git a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj index fcba04c29c..4d21a8c105 100644 --- a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj +++ b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj @@ -1,4 +1,4 @@ - + {63D3B27A-D966-4902-90B3-30290E1692F1} @@ -269,6 +269,7 @@ + From 8d46989d47e42153deaa7b008402da054528c579 Mon Sep 17 00:00:00 2001 From: Simon Lindgren Date: Tue, 5 Jun 2012 19:49:15 +0200 Subject: [PATCH 02/24] [Formatter] Avoid newlines between multiline arguments and the ending parenthesis in function calls. --- .../Formatter/AstFormattingVisitor.cs | 2 +- .../FormattingTests/TestWrapping.cs | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs b/ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs index 26ce5e4622..5d91a97ca5 100644 --- a/ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs @@ -1822,7 +1822,7 @@ namespace ICSharpCode.NRefactory.CSharp if (methodCallArgumentWrapping == Wrapping.DoNotWrap) { ForceSpacesBeforeRemoveNewLines(rParToken, spaceWithinMethodCallParentheses); } else { - bool sameLine = rParToken.GetPrevNode().StartLocation.Line == rParToken.StartLocation.Line; + bool sameLine = rParToken.GetPrevNode().EndLocation.Line == rParToken.StartLocation.Line; if (sameLine) { ForceSpacesBeforeRemoveNewLines(rParToken, spaceWithinMethodCallParentheses); } else { diff --git a/ICSharpCode.NRefactory.Tests/FormattingTests/TestWrapping.cs b/ICSharpCode.NRefactory.Tests/FormattingTests/TestWrapping.cs index 9dea96c6fe..baeb467a17 100644 --- a/ICSharpCode.NRefactory.Tests/FormattingTests/TestWrapping.cs +++ b/ICSharpCode.NRefactory.Tests/FormattingTests/TestWrapping.cs @@ -579,6 +579,40 @@ namespace ICSharpCode.NRefactory.CSharp.FormattingTests } }"); } + + [Test()] + public void TestNoBlankLinesBetweenEndBraceAndEndParenthesis () + { + CSharpFormattingOptions policy = FormattingOptionsFactory.CreateMono (); + policy.BlankLinesBetweenMembers = 1; + + var adapter = Test (policy, @"class Test +{ + int Foo (int i, double d, Action a) + { + a (); + } + + void Bar () + { + Foo (1, 2, () => { + }); + } +}", +@"class Test +{ + int Foo (int i, double d, Action a) + { + a (); + } + + void Bar () + { + Foo (1, 2, () => { + }); + } +}", FormattingMode.Intrusive); + } } } From 75f65dac64a513a9d7cd2deace28fdae0adeb053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Wed, 6 Jun 2012 10:18:49 +0200 Subject: [PATCH 03/24] Fixed typo. --- .../Refactoring/CodeActions/UseExplicitTypeAction.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/UseExplicitTypeAction.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/UseExplicitTypeAction.cs index 96cd3a10ca..c1b0aecb53 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/UseExplicitTypeAction.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/UseExplicitTypeAction.cs @@ -52,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring if (!(!type.Equals(SpecialType.NullType) && !type.Equals(SpecialType.UnknownType))) { yield break; } - yield return new CodeAction (context.TranslateString("Use expcicit type"), script => { + yield return new CodeAction (context.TranslateString("Use explicit type"), script => { if (varDecl != null) { script.Replace (varDecl.Type, context.CreateShortType (type)); } else { From 050035186c9cb5c6413c6af0103493b1e1fbd266 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 26 May 2012 11:16:27 +0200 Subject: [PATCH 04/24] Simplify API for retrieving compiler errors/warnings. --- .../Parser/CSharpParser.cs | 77 +++++++++++-------- .../CSharpProject.cs | 2 +- ICSharpCode.NRefactory.Demo/CSDemo.cs | 2 +- .../CodeActions/TestRefactoringContext.cs | 6 +- .../CSharp/Parser/ParseUtil.cs | 20 ++--- 5 files changed, 62 insertions(+), 45 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs b/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs index 1964c3bbea..8d750b714c 100644 --- a/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs +++ b/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs @@ -177,7 +177,7 @@ namespace ICSharpCode.NRefactory.CSharp } return result; } - + AstType ConvertToType (Mono.CSharp.Expression typeName) { if (typeName == null) // may happen in typeof(Generic<,,,,>) @@ -190,7 +190,7 @@ namespace ICSharpCode.NRefactory.CSharp if (typeName is Mono.CSharp.QualifiedAliasMember) { var qam = (Mono.CSharp.QualifiedAliasMember)typeName; - var memberType = new MemberType (); + var memberType = new MemberType (); memberType.Target = new SimpleType (qam.alias, Convert (qam.Location)); memberType.IsDoubleColon = true; memberType.MemberName = qam.Name; @@ -267,7 +267,7 @@ namespace ICSharpCode.NRefactory.CSharp int pos = 0; if (loc != null) result.AddChild (new CSharpTokenNode (Convert (loc [pos++])), Roles.LPar); - + if (attr.PositionalArguments != null) { foreach (var arg in attr.PositionalArguments) { var na = arg as NamedArgument; @@ -289,7 +289,7 @@ namespace ICSharpCode.NRefactory.CSharp result.AddChild (new CSharpTokenNode (Convert (loc [pos++])), Roles.Comma); } } - if (attr.NamedArguments != null) { + if (attr.NamedArguments != null) { foreach (NamedArgument na in attr.NamedArguments) { var newArg = new NamedExpression (); newArg.AddChild (Identifier.Create (na.Name, Convert (na.Location)), Roles.Identifier); @@ -387,13 +387,13 @@ namespace ICSharpCode.NRefactory.CSharp } // public override void Visit (UsingsBag.Namespace nspace) // { -// -// +// +// // VisitNamespaceUsings (nspace); // VisitNamespaceBody (nspace); -// +// // } -// +// void ConvertNamespaceName (MemberName memberName, NamespaceDeclaration namespaceDecl) { AstNode insertPos = null; @@ -439,7 +439,7 @@ namespace ICSharpCode.NRefactory.CSharp ud.AddChild (new CSharpTokenNode (Convert (loc [1])), Roles.Semicolon); AddToNamespace (ud); } - + public override void Visit (UsingExternAlias uea) { var ud = new ExternAliasDeclaration (); @@ -755,7 +755,7 @@ namespace ICSharpCode.NRefactory.CSharp var bracketLocations = LocationsBag.GetLocations (f.Initializer); if (bracketLocations != null && bracketLocations.Count > 1) variable.AddChild (new CSharpTokenNode (Convert (bracketLocations [0])), Roles.LBracket); - + variable.AddChild ((Expression)f.Initializer.Accept (this), Roles.Expression); if (bracketLocations != null && bracketLocations.Count > 1) variable.AddChild (new CSharpTokenNode (Convert (bracketLocations [0])), Roles.RBracket); @@ -1062,7 +1062,7 @@ namespace ICSharpCode.NRefactory.CSharp modifierTable [Mono.CSharp.Modifiers.ASYNC] = ICSharpCode.NRefactory.CSharp.Modifiers.Async; keywordTable = new string[255]; - for (int i = 0; i< keywordTable.Length; i++) + for (int i = 0; i< keywordTable.Length; i++) keywordTable [i] = "unknown"; keywordTable [(int)BuiltinTypeSpec.Type.Other] = "void"; @@ -2118,7 +2118,7 @@ namespace ICSharpCode.NRefactory.CSharp result.AddChild (new CSharpTokenNode (Convert (memberAccess.DotLocation)), Roles.Dot); } } - + result.AddChild (Identifier.Create (memberAccess.Name, Convert (memberAccess.Location)), Roles.Identifier); AddTypeArguments (result, memberAccess); @@ -2137,7 +2137,7 @@ namespace ICSharpCode.NRefactory.CSharp public override object Visit (Constant constant) { - if (constant.GetValue () == null) + if (constant.GetValue () == null) return new NullReferenceExpression (Convert (constant.Location)); string literalValue; if (constant is ILiteralConstant) { @@ -2699,7 +2699,7 @@ namespace ICSharpCode.NRefactory.CSharp if (par == null) continue; var parLocation = LocationsBag.GetLocations (par); - + if (parLocation == null) { if (par.Expr != null) result.AddChild ((Expression)par.Expr.Accept (this), Roles.Expression); @@ -2718,16 +2718,16 @@ namespace ICSharpCode.NRefactory.CSharp return result; } - ArrayInitializerExpression ConvertCollectionOrObjectInitializers(CollectionOrObjectInitializers minit) - { - if (minit == null) - return null; - var init = new ArrayInitializerExpression(); - AddConvertCollectionOrObjectInitializers(init, minit); - return init; - } + ArrayInitializerExpression ConvertCollectionOrObjectInitializers(CollectionOrObjectInitializers minit) + { + if (minit == null) + return null; + var init = new ArrayInitializerExpression(); + AddConvertCollectionOrObjectInitializers(init, minit); + return init; + } - void AddConvertCollectionOrObjectInitializers(Expression init, CollectionOrObjectInitializers minit) + void AddConvertCollectionOrObjectInitializers(Expression init, CollectionOrObjectInitializers minit) { var initLoc = LocationsBag.GetLocations(minit); var commaLoc = LocationsBag.GetLocations(minit.Initializers); @@ -2738,12 +2738,12 @@ namespace ICSharpCode.NRefactory.CSharp var collectionInit = expr as CollectionElementInitializer; if (collectionInit != null) { AstNode parent; - // For ease of use purposes in the resolver the ast representation + // For ease of use purposes in the resolver the ast representation // of { a, b, c } is { {a}, {b}, {c} } - but the generated ArrayInitializerExpression // can be identified by expr.IsSingleElement. if (!collectionInit.IsSingle) { parent = new ArrayInitializerExpression(); - parent.AddChild(new CSharpTokenNode(Convert(collectionInit.Location)), Roles.LBrace); + parent.AddChild(new CSharpTokenNode(Convert(collectionInit.Location)), Roles.LBrace); } else { parent = ArrayInitializerExpression.CreateSingleElementInitializer (); } @@ -2832,7 +2832,7 @@ namespace ICSharpCode.NRefactory.CSharp result.AddChild (new CSharpTokenNode (Convert (arrayCreationExpression.Location)), ArrayCreateExpression.NewKeywordRole); if (arrayCreationExpression.TypeExpression != null) result.AddChild (ConvertToType (arrayCreationExpression.TypeExpression), Roles.Type); - + var next = arrayCreationExpression.Rank; if (arrayCreationExpression.Arguments != null) { // skip first array rank. @@ -3518,8 +3518,8 @@ namespace ICSharpCode.NRefactory.CSharp var start = new TextLocation (comment.Line, comment.Col); var end = new TextLocation (comment.EndLine, comment.EndCol); newLeaf = new Comment (type, start, end) { - StartsLine = comment.StartsLine, - Content = isMultilineDocumentationComment ? comment.Content.Substring(1) : comment.Content + StartsLine = comment.StartsLine, + Content = isMultilineDocumentationComment ? comment.Content.Substring(1) : comment.Content }; } else { var directive = special as SpecialsBag.PreProcessorDirective; @@ -3598,6 +3598,7 @@ namespace ICSharpCode.NRefactory.CSharp } ErrorReportPrinter errorReportPrinter = new ErrorReportPrinter (null); + [Obsolete("Use the Errors/Warnings/ErrorsAndWarnings properties instead")] public ErrorReportPrinter ErrorPrinter { get { return errorReportPrinter; @@ -3616,6 +3617,22 @@ namespace ICSharpCode.NRefactory.CSharp } } + public IEnumerable Errors { + get { + return errorReportPrinter.Errors.Where(e => e.ErrorType == ErrorType.Error); + } + } + + public IEnumerable Warnings { + get { + return errorReportPrinter.Errors.Where(e => e.ErrorType == ErrorType.Warning); + } + } + + public IEnumerable ErrorsAndWarnings { + get { return errorReportPrinter.Errors; } + } + public CompilationUnit Parse (ITextSource textSource, string fileName, int lineModifier = 0) { return Parse (textSource.CreateReader (), fileName, lineModifier); @@ -3689,12 +3706,12 @@ namespace ICSharpCode.NRefactory.CSharp var module = new ModuleContainer (ctx); var parser = Driver.Parse (reader, file, module, lineModifier); - var top = new CompilerCompilationUnit () { + var top = new CompilerCompilationUnit () { ModuleCompiled = module, LocationsBag = parser.LocationsBag, SpecialsBag = parser.Lexer.sbag }; - var unit = Parse (top, fileName, lineModifier); + var unit = Parse (top, fileName, lineModifier); unit.Errors.AddRange (errorReportPrinter.Errors); CompilerCallableEntryPoint.Reset (); return unit; diff --git a/ICSharpCode.NRefactory.ConsistencyCheck/CSharpProject.cs b/ICSharpCode.NRefactory.ConsistencyCheck/CSharpProject.cs index 2d8c2dc3a6..cb689e527f 100644 --- a/ICSharpCode.NRefactory.ConsistencyCheck/CSharpProject.cs +++ b/ICSharpCode.NRefactory.ConsistencyCheck/CSharpProject.cs @@ -180,7 +180,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck this.CompilationUnit = p.Parse(Content.CreateReader(), fileName); if (p.HasErrors) { Console.WriteLine("Error parsing " + fileName + ":"); - foreach (var error in p.ErrorPrinter.Errors) { + foreach (var error in p.ErrorsAndWarnings) { Console.WriteLine(" " + error.Region + " " + error.Message); } } diff --git a/ICSharpCode.NRefactory.Demo/CSDemo.cs b/ICSharpCode.NRefactory.Demo/CSDemo.cs index c0a8d622b4..a7bc38b461 100644 --- a/ICSharpCode.NRefactory.Demo/CSDemo.cs +++ b/ICSharpCode.NRefactory.Demo/CSDemo.cs @@ -94,7 +94,7 @@ namespace ICSharpCode.NRefactory.Demo b.Append(node.GetType().Name); bool hasProperties = false; foreach (PropertyInfo p in node.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { - if (p.Name == "NodeType" || p.Name == "IsNull") + if (p.Name == "NodeType" || p.Name == "IsNull" || p.Name == "IsFrozen" || p.Name == "HasChildren") continue; if (p.PropertyType == typeof(string) || p.PropertyType.IsEnum || p.PropertyType == typeof(bool)) { if (!hasProperties) { diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs index 9335b63a58..50d2221d48 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs @@ -1,4 +1,4 @@ -// +// // TestRefactoringContext.cs // // Author: @@ -246,8 +246,8 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions var doc = new StringBuilderDocument (content); var parser = new CSharpParser (); var unit = parser.Parse (content, "program.cs"); - if (parser.HasErrors) - parser.ErrorPrinter.Errors.ForEach (e => Console.WriteLine (e.Message)); + foreach (var error in parser.Errors) + Console.WriteLine (error.Message); Assert.IsFalse (parser.HasErrors, "File contains parsing errors."); unit.Freeze (); var parsedFile = unit.ToTypeSystem (); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseUtil.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseUtil.cs index 2b409ba649..33fa90ccf4 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseUtil.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseUtil.cs @@ -35,8 +35,8 @@ namespace ICSharpCode.NRefactory.CSharp.Parser CSharpParser parser = new CSharpParser(); CompilationUnit cu = parser.Parse(new StringReader(code), "parsed.cs"); - if (parser.HasErrors) - parser.ErrorPrinter.Errors.ForEach (err => Console.WriteLine (err.Message)); + foreach (var error in parser.Errors) + Console.WriteLine (error.Message); Assert.AreEqual(expectErrors, parser.HasErrors, "HasErrors"); AstNode node = cu.Children.Single(); @@ -58,8 +58,8 @@ namespace ICSharpCode.NRefactory.CSharp.Parser CSharpParser parser = new CSharpParser(); var statements = parser.ParseStatements(new StringReader(stmt)); - if (parser.HasErrors) - parser.ErrorPrinter.Errors.ForEach (err => Console.WriteLine (err.Message)); + foreach (var error in parser.Errors) + Console.WriteLine (error.Message); Assert.AreEqual(expectErrors, parser.HasErrors, "HasErrors"); AstNode statement = statements.Single(); @@ -81,8 +81,8 @@ namespace ICSharpCode.NRefactory.CSharp.Parser CSharpParser parser = new CSharpParser(); AstNode parsedExpression = parser.ParseExpression(new StringReader(expr)); - if (parser.HasErrors) - parser.ErrorPrinter.Errors.ForEach (err => Console.WriteLine (err.Message)); + foreach (var error in parser.Errors) + Console.WriteLine (error.Message); Assert.AreEqual(expectErrors, parser.HasErrors, "HasErrors"); if (expectErrors && parsedExpression == null) return default (T); @@ -103,8 +103,8 @@ namespace ICSharpCode.NRefactory.CSharp.Parser { CSharpParser parser = new CSharpParser(); var members = parser.ParseTypeMembers(new StringReader(expr)); - if (parser.HasErrors) - parser.ErrorPrinter.Errors.ForEach (err => Console.WriteLine (err.Message)); + foreach (var error in parser.Errors) + Console.WriteLine (error.Message); Assert.AreEqual(expectErrors, parser.HasErrors, "HasErrors"); EntityDeclaration m = members.Single(); Type type = typeof(T); @@ -125,8 +125,8 @@ namespace ICSharpCode.NRefactory.CSharp.Parser CSharpParser parser = new CSharpParser(); var parsedExpression = parser.ParseDocumentationReference(cref); - if (parser.HasErrors) - parser.ErrorPrinter.Errors.ForEach (err => Console.WriteLine (err.Message)); + foreach (var error in parser.Errors) + Console.WriteLine (error.Message); Assert.AreEqual(expectErrors, parser.HasErrors, "HasErrors"); if (expectErrors && parsedExpression == null) return null; From eb41192c49f909d0264292856618b6e5231b6cc3 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 6 Jun 2012 17:51:36 +0200 Subject: [PATCH 05/24] Fix unit test failing on .NET 4.5 RC. --- ICSharpCode.NRefactory.Tests/TypeSystem/CecilLoaderTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/CecilLoaderTests.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/CecilLoaderTests.cs index e2ac3972b6..fbb9540539 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/CecilLoaderTests.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/CecilLoaderTests.cs @@ -145,7 +145,6 @@ namespace ICSharpCode.NRefactory.TypeSystem Assert.AreEqual(0, c.GetProperties().Count()); Assert.AreEqual(0, c.GetEvents().Count()); Assert.AreEqual(0, c.GetFields().Count()); - Assert.AreEqual(3, c.Attributes.Count); } [Test] From b0c73cc6a8eac15c172d1a8c34b1367c95a20e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 7 Jun 2012 08:45:52 +0200 Subject: [PATCH 06/24] [CodeIssues] Fixed fdg naming rules. --- .../InconsistentNamingIssue/DefaultRules.cs | 24 ++--------- .../CodeIssues/InconsistentNamingTests.cs | 42 +++++++++---------- 2 files changed, 25 insertions(+), 41 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/DefaultRules.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/DefaultRules.cs index 658a17e502..5271719ee6 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/DefaultRules.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/DefaultRules.cs @@ -79,26 +79,18 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring }; yield return new NamingRule(AffectedEntity.Field) { - Name = "Fields (Non Private)", + Name = "Fields (Public & Protected)", NamingStyle = NamingStyle.PascalCase, - VisibilityMask = Modifiers.Public | Modifiers.Protected | Modifiers.Internal + VisibilityMask = Modifiers.Public | Modifiers.Protected }; yield return new NamingRule(AffectedEntity.ReadonlyField) { - Name = "ReadOnly Fields (Non Private)", + Name = "ReadOnly Fields (Public & Protected)", NamingStyle = NamingStyle.PascalCase, - VisibilityMask = Modifiers.Public | Modifiers.Protected | Modifiers.Internal, + VisibilityMask = Modifiers.Public | Modifiers.Protected, IncludeStaticEntities = false }; - yield return new NamingRule(AffectedEntity.Field | AffectedEntity.ReadonlyField) { - Name = "Fields (Private)", - NamingStyle = NamingStyle.CamelCase, - AllowedPrefixes = new [] { "_", "m_" }, - VisibilityMask = Modifiers.Private, - IncludeStaticEntities = false - }; - yield return new NamingRule(AffectedEntity.Field) { Name = "Static Fields (Private)", NamingStyle = NamingStyle.CamelCase, @@ -107,14 +99,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring IncludeInstanceMembers = false }; - yield return new NamingRule(AffectedEntity.ReadonlyField) { - Name = "ReadOnly Fields (Private)", - NamingStyle = NamingStyle.CamelCase, - VisibilityMask = Modifiers.Private, - AllowedPrefixes = new [] { "_", "m_" }, - IncludeStaticEntities = false - }; - yield return new NamingRule(AffectedEntity.ConstantField) { Name = "Constant Fields", NamingStyle = NamingStyle.PascalCase, diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/InconsistentNamingTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/InconsistentNamingTests.cs index fb7f53e71e..7047704bc3 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/InconsistentNamingTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/InconsistentNamingTests.cs @@ -118,21 +118,21 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues CheckNaming (input, output); } - [Test] - public void TestPrivateFieldName () - { - var input = @"class AClass { int Field; }"; - var output = @"class AClass { int field; }"; - CheckNaming (input, output); - } +// [Test] +// public void TestPrivateFieldName () +// { +// var input = @"class AClass { int Field; }"; +// var output = @"class AClass { int field; }"; +// CheckNaming (input, output); +// } - [Test] - public void TestUnderscoreFieldName () - { - var input = @"class AClass { int _Field; }"; - var output = @"class AClass { int _field; }"; - CheckNaming (input, output); - } +// [Test] +// public void TestUnderscoreFieldName () +// { +// var input = @"class AClass { int _Field; }"; +// var output = @"class AClass { int _field; }"; +// CheckNaming (input, output); +// } [Test] public void TestPublicFieldName () @@ -190,13 +190,13 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues CheckNaming (input, output); } - [Test] - public void TestPrivateReadOnlyFieldName () - { - var input = @"class AClass { readonly int Field; }"; - var output = @"class AClass { readonly int field; }"; - CheckNaming (input, output); - } +// [Test] +// public void TestPrivateReadOnlyFieldName () +// { +// var input = @"class AClass { readonly int Field; }"; +// var output = @"class AClass { readonly int field; }"; +// CheckNaming (input, output); +// } [Test] public void TestPublicConstantFieldName () From 4e443698548226aaff9c62a0997b51b8b6fd7372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 7 Jun 2012 08:54:08 +0200 Subject: [PATCH 07/24] [CodeIssues] Fdg rules now apply only to public & protected entities. (The Fdg rules only apply to that, we were more restrictive). --- .../InconsistentNamingIssue/DefaultRules.cs | 23 ++++--- .../CodeIssues/InconsistentNamingTests.cs | 64 +++++++++---------- 2 files changed, 43 insertions(+), 44 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/DefaultRules.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/DefaultRules.cs index 5271719ee6..7a30d73510 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/DefaultRules.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/DefaultRules.cs @@ -39,24 +39,28 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring yield return new NamingRule(AffectedEntity.Class | AffectedEntity.Struct | AffectedEntity.Enum | AffectedEntity.Delegate) { Name = "Types", + VisibilityMask = Modifiers.Public, NamingStyle = NamingStyle.PascalCase }; yield return new NamingRule(AffectedEntity.Interface) { Name = "Interfaces", NamingStyle = NamingStyle.PascalCase, + VisibilityMask = Modifiers.Public, RequiredPrefixes = new [] { "I" } }; yield return new NamingRule(AffectedEntity.CustomAttributes) { Name = "Attributes", NamingStyle = NamingStyle.PascalCase, + VisibilityMask = Modifiers.Public, RequiredSuffixes = new [] { "Attribute" } }; yield return new NamingRule(AffectedEntity.CustomEventArgs) { Name = "Event Arguments", NamingStyle = NamingStyle.PascalCase, + VisibilityMask = Modifiers.Public, RequiredSuffixes = new [] { "EventArgs" } }; @@ -68,50 +72,45 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring yield return new NamingRule(AffectedEntity.Methods) { Name = "Methods", + VisibilityMask = Modifiers.Public | Modifiers.Protected, NamingStyle = NamingStyle.PascalCase }; yield return new NamingRule(AffectedEntity.ReadonlyField) { Name = "Static Readonly Fields", - VisibilityMask = Modifiers.Public | Modifiers.Protected | Modifiers.Internal, + VisibilityMask = Modifiers.Public | Modifiers.Protected, NamingStyle = NamingStyle.PascalCase, IncludeInstanceMembers = false }; yield return new NamingRule(AffectedEntity.Field) { - Name = "Fields (Public & Protected)", + Name = "Fields", NamingStyle = NamingStyle.PascalCase, VisibilityMask = Modifiers.Public | Modifiers.Protected }; yield return new NamingRule(AffectedEntity.ReadonlyField) { - Name = "ReadOnly Fields (Public & Protected)", + Name = "ReadOnly Fields", NamingStyle = NamingStyle.PascalCase, VisibilityMask = Modifiers.Public | Modifiers.Protected, IncludeStaticEntities = false }; - yield return new NamingRule(AffectedEntity.Field) { - Name = "Static Fields (Private)", - NamingStyle = NamingStyle.CamelCase, - VisibilityMask = Modifiers.Private, - IncludeStaticEntities = true, - IncludeInstanceMembers = false - }; - yield return new NamingRule(AffectedEntity.ConstantField) { Name = "Constant Fields", NamingStyle = NamingStyle.PascalCase, - VisibilityMask = Modifiers.Public | Modifiers.Protected | Modifiers.Internal | Modifiers.Private + VisibilityMask = Modifiers.Public | Modifiers.Protected }; yield return new NamingRule(AffectedEntity.Property) { Name = "Properties", + VisibilityMask = Modifiers.Public | Modifiers.Protected, NamingStyle = NamingStyle.PascalCase }; yield return new NamingRule(AffectedEntity.Event) { Name = "Events", + VisibilityMask = Modifiers.Public | Modifiers.Protected, NamingStyle = NamingStyle.PascalCase }; diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/InconsistentNamingTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/InconsistentNamingTests.cs index 7047704bc3..f75e4bb35e 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/InconsistentNamingTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/InconsistentNamingTests.cs @@ -57,24 +57,24 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues [Test] public void TestClassName () { - var input = @"class anIssue {}"; - var output = @"class AnIssue {}"; + var input = @"public class anIssue {}"; + var output = @"public class AnIssue {}"; CheckNaming (input, output); } [Test] public void TestAttributeName () { - var input = @"class test : System.Attribute {}"; - var output = @"class TestAttribute : System.Attribute {}"; + var input = @"public class test : System.Attribute {}"; + var output = @"public class TestAttribute : System.Attribute {}"; CheckNaming (input, output); } [Test] public void TestEventArgsName () { - var input = @"class test : System.EventArgs {}"; - var output = @"class TestEventArgs : System.EventArgs {}"; + var input = @"public class test : System.EventArgs {}"; + var output = @"public class TestEventArgs : System.EventArgs {}"; CheckNaming (input, output); } @@ -89,32 +89,32 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues [Test] public void TestStructName () { - var input = @"struct anIssue {}"; - var output = @"struct AnIssue {}"; + var input = @"public struct anIssue {}"; + var output = @"public struct AnIssue {}"; CheckNaming (input, output); } [Test] public void TestInterfaceName () { - var input = @"interface anIssue {}"; - var output = @"interface IAnIssue {}"; + var input = @"public interface anIssue {}"; + var output = @"public interface IAnIssue {}"; CheckNaming (input, output); } [Test] public void TestEnumName () { - var input = @"enum anIssue {}"; - var output = @"enum AnIssue {}"; + var input = @"public enum anIssue {}"; + var output = @"public enum AnIssue {}"; CheckNaming (input, output); } [Test] public void TestDelegateName () { - var input = @"delegate void anIssue ();"; - var output = @"delegate void AnIssue ();"; + var input = @"public delegate void anIssue ();"; + var output = @"public delegate void AnIssue ();"; CheckNaming (input, output); } @@ -142,13 +142,13 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues CheckNaming (input, output); } - [Test] - public void TestPrivateConstantFieldName () - { - var input = @"class AClass { const int field = 5; }"; - var output = @"class AClass { const int Field = 5; }"; - CheckNaming (input, output); - } +// [Test] +// public void TestPrivateConstantFieldName () +// { +// var input = @"class AClass { const int field = 5; }"; +// var output = @"class AClass { const int Field = 5; }"; +// CheckNaming (input, output); +// } [Test] public void TestPublicReadOnlyFieldName () @@ -174,13 +174,13 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues CheckNaming (input, output, true); } - [Test] - public void TestPrivateStaticFieldName () - { - var input = @"class AClass { static int Field; }"; - var output = @"class AClass { static int field; }"; - CheckNaming (input, output); - } +// [Test] +// public void TestPrivateStaticFieldName () +// { +// var input = @"class AClass { static int Field; }"; +// var output = @"class AClass { static int field; }"; +// CheckNaming (input, output); +// } [Test] public void TestPublicStaticReadOnlyFieldName () @@ -209,16 +209,16 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues [Test] public void TestMethodName () { - var input = @"class AClass { int method () {} }"; - var output = @"class AClass { int Method () {} }"; + var input = @"class AClass { public int method () {} }"; + var output = @"class AClass { public int Method () {} }"; CheckNaming (input, output); } [Test] public void TestPropertyName () { - var input = @"class AClass { int property { get; set; } }"; - var output = @"class AClass { int Property { get; set; } }"; + var input = @"class AClass { public int property { get; set; } }"; + var output = @"class AClass { public int Property { get; set; } }"; CheckNaming (input, output); } From f198d68a79dd9550a4e12bd9fce5496df5e946cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 7 Jun 2012 09:06:32 +0200 Subject: [PATCH 08/24] [CodeAction] Fixed bug in create property action. --- .../Refactoring/CodeActions/CreatePropertyAction.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreatePropertyAction.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreatePropertyAction.cs index 6b948eb8bb..f86a6cee10 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreatePropertyAction.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreatePropertyAction.cs @@ -63,6 +63,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring ResolveResult targetResolveResult = null; if (identifier is MemberReferenceExpression) { targetResolveResult = context.Resolve(((MemberReferenceExpression)identifier).Target); + if (targetResolveResult.Type.GetDefinition() == null || targetResolveResult.Type.GetDefinition().Region.IsEmpty) + yield break; createInOtherType = !state.CurrentTypeDefinition.Equals(targetResolveResult.Type.GetDefinition()); } From d60aaebc8a4e66e548a5c9890fd271e82e1d6d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Fri, 8 Jun 2012 13:06:36 +0200 Subject: [PATCH 09/24] [Completion] Member provider now needs to be given in the constructor. --- .../Completion/CSharpCompletionEngine.cs | 2 +- .../Completion/CSharpCompletionEngineBase.cs | 141 ++---------------- .../CSharpParameterCompletionEngine.cs | 2 +- .../Completion/IMemberProvider.cs | 124 +++++++++++++++ .../CodeCompletion/CodeCompletionBugTests.cs | 67 +++++---- .../ParameterCompletionTests.cs | 52 +++---- 6 files changed, 198 insertions(+), 190 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs index 270a308a36..e1d15d76e5 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs @@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion public bool CloseOnSquareBrackets; #endregion - public CSharpCompletionEngine(IDocument document, ICompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx, CompilationUnit unit, CSharpParsedFile parsedFile) : base (content, ctx, unit, parsedFile) + public CSharpCompletionEngine(IDocument document, IMemberProvider memberProvider, ICompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx, CompilationUnit unit, CSharpParsedFile parsedFile) : base (content, memberProvider, ctx, unit, parsedFile) { if (document == null) { throw new ArgumentNullException("document"); diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs index 7ec124b5cb..b0f08e2197 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs @@ -68,18 +68,21 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } #endregion - protected CSharpCompletionEngineBase (IProjectContent content, CSharpTypeResolveContext ctx, CompilationUnit unit, CSharpParsedFile parsedFile) + protected CSharpCompletionEngineBase(IProjectContent content, IMemberProvider memberProvider, CSharpTypeResolveContext ctx, CompilationUnit unit, CSharpParsedFile parsedFile) { if (content == null) - throw new ArgumentNullException ("content"); + throw new ArgumentNullException("content"); if (ctx == null) - throw new ArgumentNullException ("ctx"); + throw new ArgumentNullException("ctx"); if (unit == null) - throw new ArgumentNullException ("unit"); + throw new ArgumentNullException("unit"); if (parsedFile == null) - throw new ArgumentNullException ("parsedFile"); + throw new ArgumentNullException("parsedFile"); + if (memberProvider == null) + throw new ArgumentNullException("memberProvider"); this.ProjectContent = content; + this.MemberProvider = memberProvider; this.ctx = ctx; this.Unit = unit; this.CSharpParsedFile = parsedFile; @@ -88,7 +91,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion public IMemberProvider MemberProvider { get; - set; + private set; } public void SetOffset (int offset) @@ -97,8 +100,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion this.offset = offset; this.location = document.GetLocation (offset); - var provider = MemberProvider ?? new DefaultMemberProvider (this); - provider.GetCurrentMembers (offset, out currentType, out currentMember); + MemberProvider.GetCurrentMembers (offset, out currentType, out currentMember); } public bool GetParameterCompletionCommandOffset (out int cpos) @@ -839,128 +841,5 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } #endregion - - class DefaultMemberProvider : IMemberProvider - { - CSharpCompletionEngineBase engine; - - - public DefaultMemberProvider (CSharpCompletionEngineBase engine) - { - this.engine = engine; - } - - public void GetCurrentMembers (int offset, out IUnresolvedTypeDefinition currentType, out IUnresolvedMember currentMember) - { - //var document = engine.document; - var location = engine.location; - - currentType = null; - - foreach (var type in engine.CSharpParsedFile.TopLevelTypeDefinitions) { - if (type.Region.Begin < location) - currentType = type; - } - currentType = FindInnerType (currentType, location); - - // location is beyond last reported end region, now we need to check, if the end region changed - if (currentType != null && currentType.Region.End < location) { - if (!IsInsideType (currentType, location)) - currentType = null; - } - currentMember = null; - if (currentType != null) { - foreach (var member in currentType.Members) { - if (member.Region.Begin < location && (currentMember == null || currentMember.Region.Begin < member.Region.Begin)) - currentMember = member; - } - } - - // location is beyond last reported end region, now we need to check, if the end region changed - // NOTE: Enums are a special case, there the "last" field needs to be treated as current member - if (currentMember != null && currentMember.Region.End < location && currentType.Kind != TypeKind.Enum) { - if (!IsInsideType (currentMember, location)) - currentMember = null; - } - var stack = GetBracketStack (engine.GetMemberTextToCaret ().Item1); - if (stack.Count == 0) - currentMember = null; - } - - IUnresolvedTypeDefinition FindInnerType (IUnresolvedTypeDefinition parent, TextLocation location) - { - if (parent == null) - return null; - var currentType = parent; - foreach (var type in parent.NestedTypes) { - if (type.Region.Begin < location && location < type.Region.End) - currentType = FindInnerType (type, location); - } - - return currentType; - } - - bool IsInsideType (IUnresolvedEntity currentType, TextLocation location) - { - var document = engine.document; - - int startOffset = document.GetOffset (currentType.Region.Begin); - int endOffset = document.GetOffset (location); - //bool foundEndBracket = false; - - var bracketStack = new Stack (); - - bool isInString = false, isInChar = false; - bool isInLineComment = false, isInBlockComment = false; - - for (int i = startOffset; i < endOffset; i++) { - char ch = document.GetCharAt (i); - switch (ch) { - case '(': - case '[': - case '{': - if (!isInString && !isInChar && !isInLineComment && !isInBlockComment) - bracketStack.Push (ch); - break; - case ')': - case ']': - case '}': - if (!isInString && !isInChar && !isInLineComment && !isInBlockComment) - if (bracketStack.Count > 0) - bracketStack.Pop (); - break; - case '\r': - case '\n': - isInLineComment = false; - break; - case '/': - if (isInBlockComment) { - if (i > 0 && document.GetCharAt (i - 1) == '*') - isInBlockComment = false; - } else if (!isInString && !isInChar && i + 1 < document.TextLength) { - char nextChar = document.GetCharAt (i + 1); - if (nextChar == '/') - isInLineComment = true; - if (!isInLineComment && nextChar == '*') - isInBlockComment = true; - } - break; - case '"': - if (!(isInChar || isInLineComment || isInBlockComment)) - isInString = !isInString; - break; - case '\'': - if (!(isInString || isInLineComment || isInBlockComment)) - isInChar = !isInChar; - break; - default : - break; - } - } - return bracketStack.Any (t => t == '{'); - } - } - - } } \ No newline at end of file diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs index 5ba4e01ce4..a1ccdd1cf1 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs @@ -39,7 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion { internal IParameterCompletionDataFactory factory; - public CSharpParameterCompletionEngine(IDocument document, IParameterCompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx, CompilationUnit unit, CSharpParsedFile parsedFile) : base (content, ctx, unit, parsedFile) + public CSharpParameterCompletionEngine(IDocument document, IMemberProvider memberProvider, IParameterCompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx, CompilationUnit unit, CSharpParsedFile parsedFile) : base (content, memberProvider, ctx, unit, parsedFile) { if (document == null) { throw new ArgumentNullException("document"); diff --git a/ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs b/ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs index 689fe96148..e41a006695 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs @@ -36,5 +36,129 @@ namespace ICSharpCode.NRefactory.CSharp.Completion { void GetCurrentMembers (int offset, out IUnresolvedTypeDefinition currentType, out IUnresolvedMember currentMember); } + + public class DefaultMemberProvider : IMemberProvider + { + readonly IDocument document; + readonly CSharpParsedFile parsedFile; + + public DefaultMemberProvider (IDocument document, CSharpParsedFile parsedFile) + { + if (document == null) + throw new ArgumentNullException("document"); + if (parsedFile == null) + throw new ArgumentNullException("parsedFile"); + this.document = document; + this.parsedFile = parsedFile; + } + + public void GetCurrentMembers(int offset, out IUnresolvedTypeDefinition currentType, out IUnresolvedMember currentMember) + { + //var document = engine.document; + var location = document.GetLocation(offset); + + currentType = null; + + foreach (var type in parsedFile.TopLevelTypeDefinitions) { + if (type.Region.Begin < location) + currentType = type; + } + currentType = FindInnerType (currentType, location); + + // location is beyond last reported end region, now we need to check, if the end region changed + if (currentType != null && currentType.Region.End < location) { + if (!IsInsideType (currentType, location)) + currentType = null; + } + currentMember = null; + if (currentType != null) { + foreach (var member in currentType.Members) { + if (member.Region.Begin < location && (currentMember == null || currentMember.Region.Begin < member.Region.Begin)) + currentMember = member; + } + } + + // location is beyond last reported end region, now we need to check, if the end region changed + // NOTE: Enums are a special case, there the "last" field needs to be treated as current member + if (currentMember != null && currentMember.Region.End < location && currentType.Kind != TypeKind.Enum) { + if (!IsInsideType (currentMember, location)) + currentMember = null; + }/* + var stack = GetBracketStack (engine.GetMemberTextToCaret ().Item1); + if (stack.Count == 0) + currentMember = null;*/ + } + + IUnresolvedTypeDefinition FindInnerType (IUnresolvedTypeDefinition parent, TextLocation location) + { + if (parent == null) + return null; + var currentType = parent; + foreach (var type in parent.NestedTypes) { + if (type.Region.Begin < location && location < type.Region.End) + currentType = FindInnerType (type, location); + } + + return currentType; + } + + bool IsInsideType (IUnresolvedEntity currentType, TextLocation location) + { + int startOffset = document.GetOffset (currentType.Region.Begin); + int endOffset = document.GetOffset (location); + //bool foundEndBracket = false; + + var bracketStack = new Stack (); + + bool isInString = false, isInChar = false; + bool isInLineComment = false, isInBlockComment = false; + + for (int i = startOffset; i < endOffset; i++) { + char ch = document.GetCharAt (i); + switch (ch) { + case '(': + case '[': + case '{': + if (!isInString && !isInChar && !isInLineComment && !isInBlockComment) + bracketStack.Push (ch); + break; + case ')': + case ']': + case '}': + if (!isInString && !isInChar && !isInLineComment && !isInBlockComment) + if (bracketStack.Count > 0) + bracketStack.Pop (); + break; + case '\r': + case '\n': + isInLineComment = false; + break; + case '/': + if (isInBlockComment) { + if (i > 0 && document.GetCharAt (i - 1) == '*') + isInBlockComment = false; + } else if (!isInString && !isInChar && i + 1 < document.TextLength) { + char nextChar = document.GetCharAt (i + 1); + if (nextChar == '/') + isInLineComment = true; + if (!isInLineComment && nextChar == '*') + isInBlockComment = true; + } + break; + case '"': + if (!(isInChar || isInLineComment || isInBlockComment)) + isInString = !isInString; + break; + case '\'': + if (!(isInString || isInLineComment || isInBlockComment)) + isInChar = !isInChar; + break; + default : + break; + } + } + return bracketStack.Any (t => t == '{'); + } + } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs index 206aeae030..d8309e6b61 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs @@ -199,46 +199,48 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion #endregion } - static CompletionDataList CreateProvider (string text, bool isCtrlSpace) + static CompletionDataList CreateProvider(string text, bool isCtrlSpace) { string parsedText; string editorText; - int cursorPosition = text.IndexOf ('$'); - int endPos = text.IndexOf ('$', cursorPosition + 1); + int cursorPosition = text.IndexOf('$'); + int endPos = text.IndexOf('$', cursorPosition + 1); if (endPos == -1) { - parsedText = editorText = text.Substring (0, cursorPosition) + text.Substring (cursorPosition + 1); + parsedText = editorText = text.Substring(0, cursorPosition) + text.Substring(cursorPosition + 1); } else { - parsedText = text.Substring (0, cursorPosition) + new string (' ', endPos - cursorPosition) + text.Substring (endPos + 1); - editorText = text.Substring (0, cursorPosition) + text.Substring (cursorPosition + 1, endPos - cursorPosition - 1) + text.Substring (endPos + 1); + parsedText = text.Substring(0, cursorPosition) + new string(' ', endPos - cursorPosition) + text.Substring(endPos + 1); + editorText = text.Substring(0, cursorPosition) + text.Substring(cursorPosition + 1, endPos - cursorPosition - 1) + text.Substring(endPos + 1); cursorPosition = endPos - 1; } - var doc = new ReadOnlyDocument (editorText); + var doc = new ReadOnlyDocument(editorText); - IProjectContent pctx = new CSharpProjectContent (); - pctx = pctx.AddAssemblyReferences (new [] { CecilLoaderTests.Mscorlib, CecilLoaderTests.SystemCore }); + IProjectContent pctx = new CSharpProjectContent(); + pctx = pctx.AddAssemblyReferences(new [] { CecilLoaderTests.Mscorlib, CecilLoaderTests.SystemCore }); - var compilationUnit = new CSharpParser ().Parse (parsedText, "program.cs"); - compilationUnit.Freeze (); + var compilationUnit = new CSharpParser().Parse(parsedText, "program.cs"); + compilationUnit.Freeze(); - var parsedFile = compilationUnit.ToTypeSystem (); - pctx = pctx.UpdateProjectContent (null, parsedFile); + var parsedFile = compilationUnit.ToTypeSystem(); + pctx = pctx.UpdateProjectContent(null, parsedFile); - var cmp = pctx.CreateCompilation (); - var loc = doc.GetLocation (cursorPosition); + var cmp = pctx.CreateCompilation(); + var loc = doc.GetLocation(cursorPosition); - var rctx = new CSharpTypeResolveContext (cmp.MainAssembly); - rctx = rctx.WithUsingScope (parsedFile.GetUsingScope (loc).Resolve (cmp)); + var rctx = new CSharpTypeResolveContext(cmp.MainAssembly); + rctx = rctx.WithUsingScope(parsedFile.GetUsingScope(loc).Resolve(cmp)); - var curDef = parsedFile.GetInnermostTypeDefinition (loc); + var curDef = parsedFile.GetInnermostTypeDefinition(loc); if (curDef != null) { - var resolvedDef = curDef.Resolve (rctx).GetDefinition (); - rctx = rctx.WithCurrentTypeDefinition (resolvedDef); - var curMember = resolvedDef.Members.FirstOrDefault (m => m.Region.Begin <= loc && loc < m.BodyRegion.End); - if (curMember != null) - rctx = rctx.WithCurrentMember (curMember); + var resolvedDef = curDef.Resolve(rctx).GetDefinition(); + rctx = rctx.WithCurrentTypeDefinition(resolvedDef); + var curMember = resolvedDef.Members.FirstOrDefault(m => m.Region.Begin <= loc && loc < m.BodyRegion.End); + if (curMember != null) { + rctx = rctx.WithCurrentMember(curMember); + } } - var engine = new CSharpCompletionEngine (doc, new TestFactory (), pctx, rctx, compilationUnit, parsedFile); + var mb = new DefaultMemberProvider(doc, parsedFile); + var engine = new CSharpCompletionEngine (doc, mb, new TestFactory (), pctx, rctx, compilationUnit, parsedFile); engine.EolMarker = Environment.NewLine; engine.FormattingPolicy = FormattingOptionsFactory.CreateMono (); @@ -253,17 +255,18 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion }; } - Tuple GetContent (string text, CompilationUnit compilationUnit) + Tuple GetContent(string text, CompilationUnit compilationUnit) { - var doc = new ReadOnlyDocument (text); - IProjectContent pctx = new CSharpProjectContent (); - pctx = pctx.AddAssemblyReferences (new [] { CecilLoaderTests.Mscorlib, CecilLoaderTests.SystemCore }); - var parsedFile = compilationUnit.ToTypeSystem (); + var doc = new ReadOnlyDocument(text); + IProjectContent pctx = new CSharpProjectContent(); + pctx = pctx.AddAssemblyReferences(new [] { CecilLoaderTests.Mscorlib, CecilLoaderTests.SystemCore }); + var parsedFile = compilationUnit.ToTypeSystem(); - pctx = pctx.UpdateProjectContent (null, parsedFile); - var cmp = pctx.CreateCompilation (); + pctx = pctx.UpdateProjectContent(null, parsedFile); + var cmp = pctx.CreateCompilation(); - var engine = new CSharpCompletionEngine (doc, new TestFactory (), pctx, new CSharpTypeResolveContext (cmp.MainAssembly), compilationUnit, parsedFile); + var mb = new DefaultMemberProvider(doc, parsedFile); + var engine = new CSharpCompletionEngine (doc, mb, new TestFactory (), pctx, new CSharpTypeResolveContext (cmp.MainAssembly), compilationUnit, parsedFile); engine.EolMarker = Environment.NewLine; engine.FormattingPolicy = FormattingOptionsFactory.CreateMono (); return Tuple.Create (doc, engine); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs index 82ec44c466..58532ee35b 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs @@ -254,43 +254,45 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion #endregion } - internal static IParameterDataProvider CreateProvider (string text) + internal static IParameterDataProvider CreateProvider(string text) { string parsedText; string editorText; - int cursorPosition = text.IndexOf ('$'); - int endPos = text.IndexOf ('$', cursorPosition + 1); - if (endPos == -1) - parsedText = editorText = text.Substring (0, cursorPosition) + text.Substring (cursorPosition + 1); - else { - parsedText = text.Substring (0, cursorPosition) + new string (' ', endPos - cursorPosition) + text.Substring (endPos + 1); - editorText = text.Substring (0, cursorPosition) + text.Substring (cursorPosition + 1, endPos - cursorPosition - 1) + text.Substring (endPos + 1); + int cursorPosition = text.IndexOf('$'); + int endPos = text.IndexOf('$', cursorPosition + 1); + if (endPos == -1) { + parsedText = editorText = text.Substring(0, cursorPosition) + text.Substring(cursorPosition + 1); + } else { + parsedText = text.Substring(0, cursorPosition) + new string(' ', endPos - cursorPosition) + text.Substring(endPos + 1); + editorText = text.Substring(0, cursorPosition) + text.Substring(cursorPosition + 1, endPos - cursorPosition - 1) + text.Substring(endPos + 1); cursorPosition = endPos - 1; } - var doc = new ReadOnlyDocument (editorText); + var doc = new ReadOnlyDocument(editorText); - IProjectContent pctx = new CSharpProjectContent (); - pctx = pctx.AddAssemblyReferences (new [] { CecilLoaderTests.Mscorlib, CecilLoaderTests.SystemCore }); + IProjectContent pctx = new CSharpProjectContent(); + pctx = pctx.AddAssemblyReferences(new [] { CecilLoaderTests.Mscorlib, CecilLoaderTests.SystemCore }); - var compilationUnit = new CSharpParser ().Parse (parsedText, "program.cs"); - compilationUnit.Freeze (); + var compilationUnit = new CSharpParser().Parse(parsedText, "program.cs"); + compilationUnit.Freeze(); - var parsedFile = compilationUnit.ToTypeSystem (); - pctx = pctx.UpdateProjectContent (null, parsedFile); - var cmp = pctx.CreateCompilation (); - var loc = doc.GetLocation (cursorPosition); + var parsedFile = compilationUnit.ToTypeSystem(); + pctx = pctx.UpdateProjectContent(null, parsedFile); + var cmp = pctx.CreateCompilation(); + var loc = doc.GetLocation(cursorPosition); - var rctx = new CSharpTypeResolveContext (cmp.MainAssembly); - rctx = rctx.WithUsingScope (parsedFile.GetUsingScope (loc).Resolve (cmp)); - var curDef = parsedFile.GetInnermostTypeDefinition (loc); + var rctx = new CSharpTypeResolveContext(cmp.MainAssembly); + rctx = rctx.WithUsingScope(parsedFile.GetUsingScope(loc).Resolve(cmp)); + var curDef = parsedFile.GetInnermostTypeDefinition(loc); if (curDef != null) { - rctx = rctx.WithCurrentTypeDefinition (curDef.Resolve (rctx).GetDefinition ()); - var curMember = parsedFile.GetMember (loc); - if (curMember != null) - rctx = rctx.WithCurrentMember (curMember.CreateResolved (rctx)); + rctx = rctx.WithCurrentTypeDefinition(curDef.Resolve(rctx).GetDefinition()); + var curMember = parsedFile.GetMember(loc); + if (curMember != null) { + rctx = rctx.WithCurrentMember(curMember.CreateResolved(rctx)); + } } - var engine = new CSharpParameterCompletionEngine (doc, new TestFactory (pctx), pctx, rctx, compilationUnit, parsedFile); + var mb = new DefaultMemberProvider(doc, parsedFile); + var engine = new CSharpParameterCompletionEngine (doc, mb, new TestFactory (pctx), pctx, rctx, compilationUnit, parsedFile); return engine.GetParameterDataProvider (cursorPosition, doc.GetCharAt (cursorPosition - 1)); } From 39ac51cf09cbaeae795ed0bdca49b648daf30fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Fri, 8 Jun 2012 13:16:53 +0200 Subject: [PATCH 10/24] [Completion] Made API a bit simpler. --- .../Completion/CSharpCompletionEngine.cs | 55 +++++++++---------- .../Completion/CSharpCompletionEngineBase.cs | 11 +--- .../CSharpParameterCompletionEngine.cs | 15 +---- .../CodeCompletion/CodeCompletionBugTests.cs | 4 +- .../ParameterCompletionTests.cs | 2 +- 5 files changed, 35 insertions(+), 52 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs index e1d15d76e5..e6fabac394 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs @@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion public bool CloseOnSquareBrackets; #endregion - public CSharpCompletionEngine(IDocument document, IMemberProvider memberProvider, ICompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx, CompilationUnit unit, CSharpParsedFile parsedFile) : base (content, memberProvider, ctx, unit, parsedFile) + public CSharpCompletionEngine(IDocument document, IMemberProvider memberProvider, ICompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx, CSharpParsedFile parsedFile) : base (content, memberProvider, ctx, parsedFile) { if (document == null) { throw new ArgumentNullException("document"); @@ -239,7 +239,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion parent = (ArrayInitializerExpression)parent.Parent; if (p != null) { var contextList = new CompletionDataWrapper(this); - var initializerResult = ResolveExpression(p, unit); + var initializerResult = ResolveExpression(p); if (initializerResult != null && initializerResult.Item1.Type.Kind != TypeKind.Unknown) { // check 3 cases: // 1) New initalizer { xpr @@ -255,7 +255,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } if (prev != null && !(prev is NamedExpression)) { - AddContextCompletion(contextList, GetState(), n, unit); + AddContextCompletion(contextList, GetState(), n); // case 3) return contextList.Result; } @@ -279,7 +279,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion return contextList.Result; } - AddContextCompletion(contextList, GetState(), n, unit); + AddContextCompletion(contextList, GetState(), n); return contextList.Result; } } @@ -480,8 +480,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion AddContextCompletion( wrapper, resolveResult.Item2, - expressionOrVariableDeclaration.Node, - expressionOrVariableDeclaration.Unit); + expressionOrVariableDeclaration.Node); AddEnumMembers(wrapper, resolveResult.Item1.Type, resolveResult.Item2); AutoCompleteEmptyMatch = false; return wrapper.Result; @@ -742,8 +741,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion if (n != null && n.Parent is InvocationExpression) { var invokeParent = (InvocationExpression)n.Parent; var invokeResult = ResolveExpression( - invokeParent.Target, - identifierStart.Unit + invokeParent.Target ); var mgr = invokeResult != null ? invokeResult.Item1 as MethodGroupResolveResult : null; if (mgr != null) { @@ -777,7 +775,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } if (n != null && n.Parent is ObjectCreateExpression) { - var invokeResult = ResolveExpression(n.Parent, identifierStart.Unit); + var invokeResult = ResolveExpression(n.Parent); var mgr = invokeResult != null ? invokeResult.Item1 as ResolveResult : null; if (mgr != null) { foreach (var constructor in mgr.Type.GetConstructors ()) { @@ -797,14 +795,13 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } // check for compare to enum case if (evaluationExpr != null) { - resolveResult = ResolveExpression(evaluationExpr, identifierStart.Unit); + resolveResult = ResolveExpression(evaluationExpr); if (resolveResult != null && resolveResult.Item1.Type.Kind == TypeKind.Enum) { var wrapper = new CompletionDataWrapper(this); AddContextCompletion( wrapper, resolveResult.Item2, - evaluationExpr, - identifierStart.Unit + evaluationExpr ); AddEnumMembers(wrapper, resolveResult.Item1.Type, resolveResult.Item2); AutoCompleteEmptyMatch = false; @@ -827,7 +824,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion return DefaultControlSpaceItems(); } - var initalizerResult = ResolveExpression(n.Parent, identifierStart.Unit); + var initalizerResult = ResolveExpression(n.Parent); var concreteNode = identifierStart.Unit.GetNodeAt(location); // check if we're on the right side of an initializer expression @@ -869,8 +866,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } if (n is MemberType) { resolveResult = ResolveExpression( - ((MemberType)n).Target, - identifierStart.Unit + ((MemberType)n).Target ); return CreateTypeAndNamespaceCompletionData( location, @@ -917,8 +913,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion AddContextCompletion( contextList, csResolver, - identifierStart.Node, - identifierStart.Unit + identifierStart.Node ); return contextList.Result; // if (stub.Parent is BlockStatement) @@ -1111,7 +1106,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion Tuple rr; if (xp != null) { node = xp.Node; - rr = ResolveExpression(node, xp.Unit); + rr = ResolveExpression(node); unit = xp.Unit; } else { unit = ParseStub("foo", false); @@ -1120,7 +1115,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion location.Column + 2, n => n is Expression || n is AstType ); - rr = ResolveExpression(node, unit); + rr = ResolveExpression(node); } if (node is Identifier && node.Parent is ForeachStatement) { var foreachStmt = (ForeachStatement)node.Parent; @@ -1152,7 +1147,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion return wrapper.Result; } } - if (Unit != null && (node == null || node is TypeDeclaration)) { +/* if (Unit != null && (node == null || node is TypeDeclaration)) { var constructor = Unit.GetNodeAt( location.Line, location.Column - 3 @@ -1162,7 +1157,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion wrapper.AddCustom("base"); return wrapper.Result; } - } + }*/ var initializer = node != null ? node.Parent as ArrayInitializerExpression : null; if (initializer != null) { @@ -1190,12 +1185,12 @@ namespace ICSharpCode.NRefactory.CSharp.Completion csResolver = GetState(); } } - AddContextCompletion(wrapper, csResolver, node, unit); + AddContextCompletion(wrapper, csResolver, node); return wrapper.Result; } - void AddContextCompletion(CompletionDataWrapper wrapper, CSharpResolver state, AstNode node, CompilationUnit unit) + void AddContextCompletion(CompletionDataWrapper wrapper, CSharpResolver state, AstNode node) { if (state != null && !(node is AstType)) { foreach (var variable in state.LocalVariables) { @@ -1266,7 +1261,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion wrapper.Result.AddRange(factory.CreateCodeTemplateCompletionData()); if (node != null && node.Role == Roles.Argument) { - var resolved = ResolveExpression(node.Parent, unit); + var resolved = ResolveExpression(node.Parent); var invokeResult = resolved != null ? resolved.Item1 as CSharpInvocationResolveResult : null; if (invokeResult != null) { int argNum = 0; @@ -1284,7 +1279,10 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } if (node is Expression) { - var astResolver = new CSharpAstResolver(state, unit, CSharpParsedFile); + var root = node; + while (root.Parent != null) + root = root.Parent; + var astResolver = new CSharpAstResolver(state, root, CSharpParsedFile); foreach (var type in CreateFieldAction.GetValidTypes(astResolver, (Expression)node)) { if (type.Kind == TypeKind.Enum) { AddEnumMembers(wrapper, type, state); @@ -1523,7 +1521,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion parent = parent.Parent; } if (parent is VariableDeclarationStatement) { - var resolved = ResolveExpression(parent, isAsExpression.Unit); + var resolved = ResolveExpression(parent); if (resolved != null) { isAsType = resolved.Item1.Type; } @@ -1689,8 +1687,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion AddContextCompletion( inList, rr != null ? rr.Item2 : GetState(), - expr.Node, - Unit + expr.Node ); return inList.Result; } @@ -2238,7 +2235,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion AutoCompleteEmptyMatch = false; AutoSelect = false; } - AddContextCompletion(result, state, invocation, unit); + AddContextCompletion(result, state, invocation); // resolver.AddAccessibleCodeCompletionData (ExpressionContext.MethodBody, cdc); // if (addedDelegates.Count > 0) { diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs index b0f08e2197..05d86d4d5d 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs @@ -51,8 +51,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion #region Input properties public CSharpTypeResolveContext ctx { get; private set; } - public CompilationUnit Unit { get; private set; } - public CSharpParsedFile CSharpParsedFile { get; private set; } public IProjectContent ProjectContent { get; private set; } @@ -68,14 +66,12 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } #endregion - protected CSharpCompletionEngineBase(IProjectContent content, IMemberProvider memberProvider, CSharpTypeResolveContext ctx, CompilationUnit unit, CSharpParsedFile parsedFile) + protected CSharpCompletionEngineBase(IProjectContent content, IMemberProvider memberProvider, CSharpTypeResolveContext ctx, CSharpParsedFile parsedFile) { if (content == null) throw new ArgumentNullException("content"); if (ctx == null) throw new ArgumentNullException("ctx"); - if (unit == null) - throw new ArgumentNullException("unit"); if (parsedFile == null) throw new ArgumentNullException("parsedFile"); if (memberProvider == null) @@ -84,7 +80,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion this.ProjectContent = content; this.MemberProvider = memberProvider; this.ctx = ctx; - this.Unit = unit; this.CSharpParsedFile = parsedFile; } @@ -808,10 +803,10 @@ namespace ICSharpCode.NRefactory.CSharp.Completion protected Tuple ResolveExpression (ExpressionResult tuple) { - return ResolveExpression (tuple.Node, tuple.Unit); + return ResolveExpression (tuple.Node); } - protected Tuple ResolveExpression(AstNode expr, CompilationUnit unit) + protected Tuple ResolveExpression(AstNode expr) { if (expr == null) { return null; diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs index a1ccdd1cf1..306ccaa4df 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs @@ -39,7 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion { internal IParameterCompletionDataFactory factory; - public CSharpParameterCompletionEngine(IDocument document, IMemberProvider memberProvider, IParameterCompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx, CompilationUnit unit, CSharpParsedFile parsedFile) : base (content, memberProvider, ctx, unit, parsedFile) + public CSharpParameterCompletionEngine(IDocument document, IMemberProvider memberProvider, IParameterCompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx, CSharpParsedFile parsedFile) : base (content, memberProvider, ctx, parsedFile) { if (document == null) { throw new ArgumentNullException("document"); @@ -57,9 +57,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion if (currentMember == null && currentType == null) { return null; } - if (Unit == null) { - return null; - } baseUnit = ParseStub("x] = a[1"); //var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin; @@ -80,9 +77,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion if (currentMember == null && currentType == null) { return null; } - if (Unit == null) { - return null; - } baseUnit = ParseStub("a) {}", false); var expr = baseUnit.GetNodeAt (location); @@ -98,9 +92,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion if (currentMember == null && currentType == null) { return null; } - if (Unit == null) { - return null; - } baseUnit = ParseStub("x> a"); //var memberLocation = currentMember != null ? currentMember.Region.Begin : currentType.Region.Begin; @@ -171,7 +162,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } } if (invoke.Node is ObjectCreateExpression) { - var createType = ResolveExpression(((ObjectCreateExpression)invoke.Node).Type, invoke.Unit); + var createType = ResolveExpression(((ObjectCreateExpression)invoke.Node).Type); if (createType.Item1.Type.Kind == TypeKind.Unknown) return null; return factory.CreateConstructorProvider(document.GetOffset(invoke.Node.StartLocation), createType.Item1.Type); @@ -234,7 +225,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion if (GetCurrentParameterIndex(document.GetOffset(invoke.Node.StartLocation), offset) < 0) return null; if (invoke.Node is ObjectCreateExpression) { - var createType = ResolveExpression(((ObjectCreateExpression)invoke.Node).Type, invoke.Unit); + var createType = ResolveExpression(((ObjectCreateExpression)invoke.Node).Type); return factory.CreateConstructorProvider(document.GetOffset(invoke.Node.StartLocation), createType.Item1.Type); } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs index d8309e6b61..f8a2525475 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs @@ -240,7 +240,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion } } var mb = new DefaultMemberProvider(doc, parsedFile); - var engine = new CSharpCompletionEngine (doc, mb, new TestFactory (), pctx, rctx, compilationUnit, parsedFile); + var engine = new CSharpCompletionEngine (doc, mb, new TestFactory (), pctx, rctx, parsedFile); engine.EolMarker = Environment.NewLine; engine.FormattingPolicy = FormattingOptionsFactory.CreateMono (); @@ -266,7 +266,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion var cmp = pctx.CreateCompilation(); var mb = new DefaultMemberProvider(doc, parsedFile); - var engine = new CSharpCompletionEngine (doc, mb, new TestFactory (), pctx, new CSharpTypeResolveContext (cmp.MainAssembly), compilationUnit, parsedFile); + var engine = new CSharpCompletionEngine (doc, mb, new TestFactory (), pctx, new CSharpTypeResolveContext (cmp.MainAssembly), parsedFile); engine.EolMarker = Environment.NewLine; engine.FormattingPolicy = FormattingOptionsFactory.CreateMono (); return Tuple.Create (doc, engine); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs index 58532ee35b..d88185624e 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs @@ -292,7 +292,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion } } var mb = new DefaultMemberProvider(doc, parsedFile); - var engine = new CSharpParameterCompletionEngine (doc, mb, new TestFactory (pctx), pctx, rctx, compilationUnit, parsedFile); + var engine = new CSharpParameterCompletionEngine (doc, mb, new TestFactory (pctx), pctx, rctx, parsedFile); return engine.GetParameterDataProvider (cursorPosition, doc.GetCharAt (cursorPosition - 1)); } From a8e702be8c6529de2d31fd2051e12354206c370f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Fri, 8 Jun 2012 13:41:48 +0200 Subject: [PATCH 11/24] [Completion] Lowered parsed file usages. --- .../Completion/CSharpCompletionEngine.cs | 15 ++++++--------- .../Completion/CSharpParameterCompletionEngine.cs | 11 +++-------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs index e6fabac394..3ba578c4ae 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs @@ -1318,10 +1318,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion void AddTypesAndNamespaces(CompletionDataWrapper wrapper, CSharpResolver state, AstNode node, Func typePred = null, Predicate memberPred = null, Action callback = null) { - var lookup = new MemberLookup( - ctx.CurrentTypeDefinition, - Compilation.MainAssembly - ); + var lookup = new MemberLookup(ctx.CurrentTypeDefinition, Compilation.MainAssembly); if (currentType != null) { for (var ct = currentType; ct != null; ct = ct.DeclaringTypeDefinition) { foreach (var nestedType in ct.NestedTypes) { @@ -1382,7 +1379,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion wrapper.AddTypeParameter(p); } } - var scope = CSharpParsedFile.GetUsingScope(location).Resolve(Compilation); + var scope = ctx.CurrentUsingScope; for (var n = scope; n != null; n = n.Parent) { foreach (var pair in n.UsingAliases) { @@ -2369,7 +2366,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } } // ADD Aliases - var scope = CSharpParsedFile.GetUsingScope(location).Resolve(Compilation); + var scope = ctx.CurrentUsingScope; for (var n = scope; n != null; n = n.Parent) { foreach (var pair in n.UsingAliases) { @@ -2749,7 +2746,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion sb.Append("a;"); AppendMissingClosingBrackets(sb, text, false); var stream = new System.IO.StringReader(sb.ToString()); - var completionUnit = parser.Parse(stream, CSharpParsedFile.FileName, 0); + var completionUnit = parser.Parse(stream, "a.cs", 0); stream.Close(); var loc = document.GetLocation(offset); @@ -2772,7 +2769,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion AppendMissingClosingBrackets(sb, text, false); var stream = new System.IO.StringReader(sb.ToString()); - var completionUnit = parser.Parse(stream, CSharpParsedFile.FileName, 0); + var completionUnit = parser.Parse(stream, "a.cs", 0); stream.Close(); var loc = document.GetLocation(offset); @@ -2783,7 +2780,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion sb.Append("a ()"); AppendMissingClosingBrackets(sb, text, false); stream = new System.IO.StringReader(sb.ToString()); - completionUnit = parser.Parse(stream, CSharpParsedFile.FileName, 0); + completionUnit = parser.Parse(stream, "a.cs", 0); stream.Close(); loc = document.GetLocation(offset); diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs index 306ccaa4df..129ad12992 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs @@ -307,17 +307,12 @@ namespace ICSharpCode.NRefactory.CSharp.Completion List GetUsedNamespaces() { - var scope = CSharpParsedFile.GetUsingScope(location); + var scope = ctx.CurrentUsingScope; var result = new List(); - var resolver = new CSharpResolver(ctx); while (scope != null) { - result.Add(scope.NamespaceName); + result.Add(scope.Namespace.FullName); - foreach (var u in scope.Usings) { - var ns = u.ResolveNamespace(resolver); - if (ns == null) { - continue; - } + foreach (var ns in scope.Usings) { result.Add(ns.FullName); } scope = scope.Parent; From 1a3303968c4019b045b7b97deb88e0b92633f99d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Fri, 8 Jun 2012 13:55:26 +0200 Subject: [PATCH 12/24] [Completion] Use getstate to get the current resolver state. --- .../Completion/CSharpCompletionEngineBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs index 05d86d4d5d..4f3357baa7 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs @@ -820,7 +820,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion resolveNode = expr; } try { - var ctx = CSharpParsedFile.GetResolver(Compilation, location); + var ctx = GetState (); var root = expr.AncestorsAndSelf.FirstOrDefault(n => n is EntityDeclaration || n is CompilationUnit); if (root == null) { return null; From c9d2776522461c1ac932880ee58c519dd9ffdd26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Fri, 8 Jun 2012 14:38:45 +0200 Subject: [PATCH 13/24] [Completion] Added GetMemberTextToCaret interface method. --- .../Completion/CSharpCompletionEngineBase.cs | 24 +++--------------- .../Completion/IMemberProvider.cs | 25 +++++++++++++++++++ 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs index 4f3357baa7..eb46e309ef 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs @@ -699,34 +699,16 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } } - string cachedText = null; +// string cachedText = null; protected virtual void Reset () { - cachedText = null; +// cachedText = null; } protected Tuple GetMemberTextToCaret() { - int startOffset; - if (currentMember != null && currentType != null && currentType.Kind != TypeKind.Enum) { - startOffset = document.GetOffset(currentMember.Region.Begin); - } else if (currentType != null) { - startOffset = document.GetOffset(currentType.Region.Begin); - } else { - startOffset = 0; - } - while (startOffset > 0) { - char ch = document.GetCharAt(startOffset - 1); - if (ch != ' ' && ch != '\t') { - break; - } - --startOffset; - } - if (cachedText == null) - cachedText = document.GetText (startOffset, offset - startOffset); - - return Tuple.Create (cachedText, document.GetLocation (startOffset)); + return MemberProvider.GetMemberTextToCaret(offset, currentType, currentMember); } protected ExpressionResult GetInvocationBeforeCursor(bool afterBracket) diff --git a/ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs b/ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs index e41a006695..fddc43846e 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs @@ -35,6 +35,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion public interface IMemberProvider { void GetCurrentMembers (int offset, out IUnresolvedTypeDefinition currentType, out IUnresolvedMember currentMember); + + Tuple GetMemberTextToCaret(int caretOffset, IUnresolvedTypeDefinition currentType, IUnresolvedMember currentMember); } public class DefaultMemberProvider : IMemberProvider @@ -159,6 +161,29 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } return bracketStack.Any (t => t == '{'); } + + public Tuple GetMemberTextToCaret(int caretOffset, IUnresolvedTypeDefinition currentType, IUnresolvedMember currentMember) + { + int startOffset; + if (currentMember != null && currentType != null && currentType.Kind != TypeKind.Enum) { + startOffset = document.GetOffset(currentMember.Region.Begin); + } else if (currentType != null) { + startOffset = document.GetOffset(currentType.Region.Begin); + } else { + startOffset = 0; + } + while (startOffset > 0) { + char ch = document.GetCharAt(startOffset - 1); + if (ch != ' ' && ch != '\t') { + break; + } + --startOffset; + } + + return Tuple.Create (document.GetText (startOffset, caretOffset - startOffset), document.GetLocation (startOffset)); + } + + } } From 33efe343d633030aa02f2614b3cc8e9c4c880367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Sat, 9 Jun 2012 09:46:59 +0200 Subject: [PATCH 14/24] [Documentation] Added support for relative redirection targets. --- .../Documentation/XmlDocumentationProvider.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs b/ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs index de2105211e..e16b6c0f03 100644 --- a/ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs +++ b/ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs @@ -121,7 +121,7 @@ namespace ICSharpCode.NRefactory.Documentation this.fileName = fileName; ReadXmlDoc(xmlReader); } else { - string redirectionTarget = GetRedirectionTarget(xmlReader.GetAttribute("redirect")); + string redirectionTarget = GetRedirectionTarget(fileName, xmlReader.GetAttribute("redirect")); if (redirectionTarget != null) { Debug.WriteLine("XmlDoc " + fileName + " is redirecting to " + redirectionTarget); using (FileStream redirectedFs = new FileStream(redirectionTarget, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)) { @@ -138,7 +138,7 @@ namespace ICSharpCode.NRefactory.Documentation } } - static string GetRedirectionTarget(string target) + static string GetRedirectionTarget(string xmlFileName, string target) { string programFilesDir = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86); programFilesDir = AppendDirectorySeparator(programFilesDir); @@ -146,8 +146,11 @@ namespace ICSharpCode.NRefactory.Documentation string corSysDir = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(); corSysDir = AppendDirectorySeparator(corSysDir); - return LookupLocalizedXmlDoc(target.Replace("%PROGRAMFILESDIR%", programFilesDir) - .Replace("%CORSYSDIR%", corSysDir)); + var fileName = target.Replace ("%PROGRAMFILESDIR%", programFilesDir) + .Replace ("%CORSYSDIR%", corSysDir); + if (!Path.IsPathRooted (fileName)) + fileName = Path.Combine (Path.GetDirectoryName (xmlFileName), fileName); + return LookupLocalizedXmlDoc(fileName); } static string AppendDirectorySeparator(string dir) From 6cbda4656343cd7fe5b23ef9bd900430f6357e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Sat, 9 Jun 2012 12:29:53 +0200 Subject: [PATCH 15/24] [Completion] It's no longer needed to specify a parsed file for the completion engine. --- .../Completion/CSharpCompletionEngine.cs | 22 +++++-------------- .../Completion/CSharpCompletionEngineBase.cs | 10 ++------- .../CSharpParameterCompletionEngine.cs | 2 +- .../Completion/IMemberProvider.cs | 11 +++++++++- .../CodeCompletion/CodeCompletionBugTests.cs | 4 ++-- .../ParameterCompletionTests.cs | 2 +- 6 files changed, 21 insertions(+), 30 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs index 3ba578c4ae..641c2fa95c 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs @@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion public bool CloseOnSquareBrackets; #endregion - public CSharpCompletionEngine(IDocument document, IMemberProvider memberProvider, ICompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx, CSharpParsedFile parsedFile) : base (content, memberProvider, ctx, parsedFile) + public CSharpCompletionEngine(IDocument document, IMemberProvider memberProvider, ICompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx) : base (content, memberProvider, ctx) { if (document == null) { throw new ArgumentNullException("document"); @@ -882,11 +882,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion if (n.Parent is ICSharpCode.NRefactory.CSharp.Attribute) { nodes.Add(n.Parent); } - var astResolver = new CSharpAstResolver( - csResolver, - identifierStart.Unit, - CSharpParsedFile - ); + var astResolver = MemberProvider.GetResolver (csResolver, identifierStart.Unit); astResolver.ApplyNavigator(new NodeListResolveVisitorNavigator(nodes)); try { csResolver = astResolver.GetResolverStateBefore(n); @@ -1282,7 +1278,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion var root = node; while (root.Parent != null) root = root.Parent; - var astResolver = new CSharpAstResolver(state, root, CSharpParsedFile); + var astResolver = MemberProvider.GetResolver (state, root); foreach (var type in CreateFieldAction.GetValidTypes(astResolver, (Expression)node)) { if (type.Kind == TypeKind.Enum) { AddEnumMembers(wrapper, type, state); @@ -1657,11 +1653,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion var expressionOrVariableDeclaration = GetNewExpressionAt(j); if (expressionOrVariableDeclaration == null) return null; - var astResolver = new CSharpAstResolver( - GetState(), - expressionOrVariableDeclaration.Unit, - CSharpParsedFile - ); + var astResolver = MemberProvider.GetResolver(GetState(), expressionOrVariableDeclaration.Unit); hintType = CreateFieldAction.GetValidTypes( astResolver, expressionOrVariableDeclaration.Node as Expression @@ -2143,11 +2135,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion var exprParent = resolvedNode.GetParent(); var unit = exprParent != null ? exprParent.GetParent() : null; - var astResolver = unit != null ? new CSharpAstResolver( - state, - unit, - CSharpParsedFile - ) : null; + var astResolver = unit != null ? MemberProvider.GetResolver(state, unit) : null; IType hintType = exprParent != null && astResolver != null ? CreateFieldAction.GetValidTypes(astResolver, exprParent) .FirstOrDefault() : null; diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs index eb46e309ef..c3f84c210a 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs @@ -51,8 +51,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion #region Input properties public CSharpTypeResolveContext ctx { get; private set; } - public CSharpParsedFile CSharpParsedFile { get; private set; } - public IProjectContent ProjectContent { get; private set; } ICompilation compilation; @@ -66,21 +64,18 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } #endregion - protected CSharpCompletionEngineBase(IProjectContent content, IMemberProvider memberProvider, CSharpTypeResolveContext ctx, CSharpParsedFile parsedFile) + protected CSharpCompletionEngineBase(IProjectContent content, IMemberProvider memberProvider, CSharpTypeResolveContext ctx) { if (content == null) throw new ArgumentNullException("content"); if (ctx == null) throw new ArgumentNullException("ctx"); - if (parsedFile == null) - throw new ArgumentNullException("parsedFile"); if (memberProvider == null) throw new ArgumentNullException("memberProvider"); this.ProjectContent = content; this.MemberProvider = memberProvider; this.ctx = ctx; - this.CSharpParsedFile = parsedFile; } @@ -802,12 +797,11 @@ namespace ICSharpCode.NRefactory.CSharp.Completion resolveNode = expr; } try { - var ctx = GetState (); var root = expr.AncestorsAndSelf.FirstOrDefault(n => n is EntityDeclaration || n is CompilationUnit); if (root == null) { return null; } - var csResolver = new CSharpAstResolver (ctx, root, CSharpParsedFile); + var csResolver = MemberProvider.GetResolver (GetState(), root); var result = csResolver.Resolve(resolveNode); var state = csResolver.GetResolverStateBefore(resolveNode); return Tuple.Create(result, state); diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs index 129ad12992..67a014eac5 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs @@ -39,7 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion { internal IParameterCompletionDataFactory factory; - public CSharpParameterCompletionEngine(IDocument document, IMemberProvider memberProvider, IParameterCompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx, CSharpParsedFile parsedFile) : base (content, memberProvider, ctx, parsedFile) + public CSharpParameterCompletionEngine(IDocument document, IMemberProvider memberProvider, IParameterCompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx) : base (content, memberProvider, ctx) { if (document == null) { throw new ArgumentNullException("document"); diff --git a/ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs b/ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs index fddc43846e..5001f3d22c 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs @@ -29,6 +29,7 @@ using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.Editor; using ICSharpCode.NRefactory.CSharp.TypeSystem; using System.Linq; +using ICSharpCode.NRefactory.CSharp.Resolver; namespace ICSharpCode.NRefactory.CSharp.Completion { @@ -37,6 +38,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion void GetCurrentMembers (int offset, out IUnresolvedTypeDefinition currentType, out IUnresolvedMember currentMember); Tuple GetMemberTextToCaret(int caretOffset, IUnresolvedTypeDefinition currentType, IUnresolvedMember currentMember); + + CSharpAstResolver GetResolver (CSharpResolver resolver, AstNode rootNode); } public class DefaultMemberProvider : IMemberProvider @@ -182,7 +185,13 @@ namespace ICSharpCode.NRefactory.CSharp.Completion return Tuple.Create (document.GetText (startOffset, caretOffset - startOffset), document.GetLocation (startOffset)); } - + + + public CSharpAstResolver GetResolver (CSharpResolver resolver, AstNode rootNode) + { + return new CSharpAstResolver (resolver, rootNode, parsedFile); + } + } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs index f8a2525475..d93d1b582b 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs @@ -240,7 +240,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion } } var mb = new DefaultMemberProvider(doc, parsedFile); - var engine = new CSharpCompletionEngine (doc, mb, new TestFactory (), pctx, rctx, parsedFile); + var engine = new CSharpCompletionEngine (doc, mb, new TestFactory (), pctx, rctx); engine.EolMarker = Environment.NewLine; engine.FormattingPolicy = FormattingOptionsFactory.CreateMono (); @@ -266,7 +266,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion var cmp = pctx.CreateCompilation(); var mb = new DefaultMemberProvider(doc, parsedFile); - var engine = new CSharpCompletionEngine (doc, mb, new TestFactory (), pctx, new CSharpTypeResolveContext (cmp.MainAssembly), parsedFile); + var engine = new CSharpCompletionEngine (doc, mb, new TestFactory (), pctx, new CSharpTypeResolveContext (cmp.MainAssembly)); engine.EolMarker = Environment.NewLine; engine.FormattingPolicy = FormattingOptionsFactory.CreateMono (); return Tuple.Create (doc, engine); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs index d88185624e..bc04a31ff7 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs @@ -292,7 +292,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion } } var mb = new DefaultMemberProvider(doc, parsedFile); - var engine = new CSharpParameterCompletionEngine (doc, mb, new TestFactory (pctx), pctx, rctx, parsedFile); + var engine = new CSharpParameterCompletionEngine (doc, mb, new TestFactory (pctx), pctx, rctx); return engine.GetParameterDataProvider (cursorPosition, doc.GetCharAt (cursorPosition - 1)); } From 81c7daa56306fdef7aa49714a84401f1a228e7e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Sat, 9 Jun 2012 12:39:54 +0200 Subject: [PATCH 16/24] [Completion] Renamed IMemberProvider -> ICompletionContextProvider. --- .../Completion/CSharpCompletionEngine.cs | 10 +++++----- .../Completion/CSharpCompletionEngineBase.cs | 18 +++++++++--------- .../CSharpParameterCompletionEngine.cs | 2 +- ...ovider.cs => ICompletionContextProvider.cs} | 6 +++--- .../ICSharpCode.NRefactory.CSharp.csproj | 5 ++--- .../CodeCompletion/CodeCompletionBugTests.cs | 4 ++-- .../CodeCompletion/ParameterCompletionTests.cs | 2 +- 7 files changed, 23 insertions(+), 24 deletions(-) rename ICSharpCode.NRefactory.CSharp/Completion/{IMemberProvider.cs => ICompletionContextProvider.cs} (96%) diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs index 641c2fa95c..fcb8af2bba 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs @@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion public bool CloseOnSquareBrackets; #endregion - public CSharpCompletionEngine(IDocument document, IMemberProvider memberProvider, ICompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx) : base (content, memberProvider, ctx) + public CSharpCompletionEngine(IDocument document, ICompletionContextProvider completionContextProvider, ICompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx) : base (content, completionContextProvider, ctx) { if (document == null) { throw new ArgumentNullException("document"); @@ -882,7 +882,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion if (n.Parent is ICSharpCode.NRefactory.CSharp.Attribute) { nodes.Add(n.Parent); } - var astResolver = MemberProvider.GetResolver (csResolver, identifierStart.Unit); + var astResolver = CompletionContextProvider.GetResolver (csResolver, identifierStart.Unit); astResolver.ApplyNavigator(new NodeListResolveVisitorNavigator(nodes)); try { csResolver = astResolver.GetResolverStateBefore(n); @@ -1278,7 +1278,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion var root = node; while (root.Parent != null) root = root.Parent; - var astResolver = MemberProvider.GetResolver (state, root); + var astResolver = CompletionContextProvider.GetResolver (state, root); foreach (var type in CreateFieldAction.GetValidTypes(astResolver, (Expression)node)) { if (type.Kind == TypeKind.Enum) { AddEnumMembers(wrapper, type, state); @@ -1653,7 +1653,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion var expressionOrVariableDeclaration = GetNewExpressionAt(j); if (expressionOrVariableDeclaration == null) return null; - var astResolver = MemberProvider.GetResolver(GetState(), expressionOrVariableDeclaration.Unit); + var astResolver = CompletionContextProvider.GetResolver(GetState(), expressionOrVariableDeclaration.Unit); hintType = CreateFieldAction.GetValidTypes( astResolver, expressionOrVariableDeclaration.Node as Expression @@ -2135,7 +2135,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion var exprParent = resolvedNode.GetParent(); var unit = exprParent != null ? exprParent.GetParent() : null; - var astResolver = unit != null ? MemberProvider.GetResolver(state, unit) : null; + var astResolver = unit != null ? CompletionContextProvider.GetResolver(state, unit) : null; IType hintType = exprParent != null && astResolver != null ? CreateFieldAction.GetValidTypes(astResolver, exprParent) .FirstOrDefault() : null; diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs index c3f84c210a..a2ec8ec116 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs @@ -1,4 +1,4 @@ -// +// // CSharpCompletionEngineBase.cs // // Author: @@ -64,22 +64,22 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } #endregion - protected CSharpCompletionEngineBase(IProjectContent content, IMemberProvider memberProvider, CSharpTypeResolveContext ctx) + protected CSharpCompletionEngineBase(IProjectContent content, ICompletionContextProvider completionContextProvider, CSharpTypeResolveContext ctx) { if (content == null) throw new ArgumentNullException("content"); if (ctx == null) throw new ArgumentNullException("ctx"); - if (memberProvider == null) - throw new ArgumentNullException("memberProvider"); + if (completionContextProvider == null) + throw new ArgumentNullException("completionContextProvider"); this.ProjectContent = content; - this.MemberProvider = memberProvider; + this.CompletionContextProvider = completionContextProvider; this.ctx = ctx; } - public IMemberProvider MemberProvider { + public ICompletionContextProvider CompletionContextProvider { get; private set; } @@ -90,7 +90,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion this.offset = offset; this.location = document.GetLocation (offset); - MemberProvider.GetCurrentMembers (offset, out currentType, out currentMember); + CompletionContextProvider.GetCurrentMembers (offset, out currentType, out currentMember); } public bool GetParameterCompletionCommandOffset (out int cpos) @@ -703,7 +703,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion protected Tuple GetMemberTextToCaret() { - return MemberProvider.GetMemberTextToCaret(offset, currentType, currentMember); + return CompletionContextProvider.GetMemberTextToCaret(offset, currentType, currentMember); } protected ExpressionResult GetInvocationBeforeCursor(bool afterBracket) @@ -801,7 +801,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion if (root == null) { return null; } - var csResolver = MemberProvider.GetResolver (GetState(), root); + var csResolver = CompletionContextProvider.GetResolver (GetState(), root); var result = csResolver.Resolve(resolveNode); var state = csResolver.GetResolverStateBefore(resolveNode); return Tuple.Create(result, state); diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs index 67a014eac5..229016533c 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs @@ -39,7 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion { internal IParameterCompletionDataFactory factory; - public CSharpParameterCompletionEngine(IDocument document, IMemberProvider memberProvider, IParameterCompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx) : base (content, memberProvider, ctx) + public CSharpParameterCompletionEngine(IDocument document, ICompletionContextProvider completionContextProvider, IParameterCompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx) : base (content, completionContextProvider, ctx) { if (document == null) { throw new ArgumentNullException("document"); diff --git a/ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs b/ICSharpCode.NRefactory.CSharp/Completion/ICompletionContextProvider.cs similarity index 96% rename from ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs rename to ICSharpCode.NRefactory.CSharp/Completion/ICompletionContextProvider.cs index 5001f3d22c..b477dc1bbf 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/ICompletionContextProvider.cs @@ -33,7 +33,7 @@ using ICSharpCode.NRefactory.CSharp.Resolver; namespace ICSharpCode.NRefactory.CSharp.Completion { - public interface IMemberProvider + public interface ICompletionContextProvider { void GetCurrentMembers (int offset, out IUnresolvedTypeDefinition currentType, out IUnresolvedMember currentMember); @@ -42,12 +42,12 @@ namespace ICSharpCode.NRefactory.CSharp.Completion CSharpAstResolver GetResolver (CSharpResolver resolver, AstNode rootNode); } - public class DefaultMemberProvider : IMemberProvider + public class DefaultCompletionContextProvider : ICompletionContextProvider { readonly IDocument document; readonly CSharpParsedFile parsedFile; - public DefaultMemberProvider (IDocument document, CSharpParsedFile parsedFile) + public DefaultCompletionContextProvider (IDocument document, CSharpParsedFile parsedFile) { if (document == null) throw new ArgumentNullException("document"); diff --git a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj index 696c10d510..7f4015306f 100644 --- a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj +++ b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj @@ -41,8 +41,7 @@ TRACE;FULL_AST - PdbOnly - false + none full @@ -294,7 +293,6 @@ - @@ -374,6 +372,7 @@ + diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs index d93d1b582b..80cae089e7 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs @@ -239,7 +239,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion rctx = rctx.WithCurrentMember(curMember); } } - var mb = new DefaultMemberProvider(doc, parsedFile); + var mb = new DefaultCompletionContextProvider(doc, parsedFile); var engine = new CSharpCompletionEngine (doc, mb, new TestFactory (), pctx, rctx); engine.EolMarker = Environment.NewLine; @@ -265,7 +265,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion pctx = pctx.UpdateProjectContent(null, parsedFile); var cmp = pctx.CreateCompilation(); - var mb = new DefaultMemberProvider(doc, parsedFile); + var mb = new DefaultCompletionContextProvider(doc, parsedFile); var engine = new CSharpCompletionEngine (doc, mb, new TestFactory (), pctx, new CSharpTypeResolveContext (cmp.MainAssembly)); engine.EolMarker = Environment.NewLine; engine.FormattingPolicy = FormattingOptionsFactory.CreateMono (); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs index bc04a31ff7..aef48a5e15 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs @@ -291,7 +291,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion rctx = rctx.WithCurrentMember(curMember.CreateResolved(rctx)); } } - var mb = new DefaultMemberProvider(doc, parsedFile); + var mb = new DefaultCompletionContextProvider(doc, parsedFile); var engine = new CSharpParameterCompletionEngine (doc, mb, new TestFactory (pctx), pctx, rctx); return engine.GetParameterDataProvider (cursorPosition, doc.GetCharAt (cursorPosition - 1)); } From 00d5de8b18ad8d1bd7f01caab8d8ca974883cb5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Sat, 9 Jun 2012 14:06:26 +0200 Subject: [PATCH 17/24] [CodeIssues] Optimized word break algorithm. --- .../InconsistentNamingIssue/WordParser.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/WordParser.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/WordParser.cs index 98ac57d6cd..9cbbcff0a3 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/WordParser.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/WordParser.cs @@ -37,26 +37,28 @@ namespace ICSharpCode.NRefactory.CSharp bool lastWasLower = false, lastWasUpper = false; for (int i = 0; i < identifier.Length; i++) { char c = identifier[i]; - if (c == '_') { - if ((i - wordStart) > 0) { - words.Add (identifier.Substring (wordStart, i - wordStart)); - } - wordStart = i + 1; - lastWasLower = lastWasUpper = false; - } else if (Char.IsLower (c)) { + var category = char.GetUnicodeCategory (c); + if (category == System.Globalization.UnicodeCategory.LowercaseLetter) { if (lastWasUpper && (i - wordStart) > 2) { words.Add (identifier.Substring (wordStart, i - wordStart - 1)); wordStart = i - 1; } lastWasLower = true; lastWasUpper = false; - } else if (Char.IsUpper (c)) { + } else if (category == System.Globalization.UnicodeCategory.UppercaseLetter) { if (lastWasLower) { words.Add (identifier.Substring (wordStart, i - wordStart)); wordStart = i; } lastWasLower = false; lastWasUpper = true; + } else { + if (c == '_') { + if ((i - wordStart) > 0) + words.Add(identifier.Substring(wordStart, i - wordStart)); + wordStart = i + 1; + lastWasLower = lastWasUpper = false; + } } } if (wordStart < identifier.Length) From 79f634cc407fcc98217060b42ce9009c213e34e9 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 7 Jun 2012 13:57:37 +0200 Subject: [PATCH 18/24] Change TextChangeEventArgs.InsertedText and RemovedText from string to ITextSource. --- ICSharpCode.NRefactory/Editor/IDocument.cs | 32 +++++++++++++++++++ .../Editor/ReadOnlyDocument.cs | 15 +++++++++ .../Editor/StringBuilderDocument.cs | 28 +++++++++++++++- .../Editor/StringTextSource.cs | 7 +++- .../Editor/TextChangeEventArgs.cs | 30 ++++++++++++----- 5 files changed, 102 insertions(+), 10 deletions(-) diff --git a/ICSharpCode.NRefactory/Editor/IDocument.cs b/ICSharpCode.NRefactory/Editor/IDocument.cs index 4201ce4484..f9a793b911 100644 --- a/ICSharpCode.NRefactory/Editor/IDocument.cs +++ b/ICSharpCode.NRefactory/Editor/IDocument.cs @@ -109,6 +109,18 @@ namespace ICSharpCode.NRefactory.Editor /// void Insert(int offset, string text); + /// + /// Inserts text. + /// + /// The offset at which the text is inserted. + /// The new text. + /// + /// Anchors positioned exactly at the insertion offset will move according to their movement type. + /// For AnchorMovementType.Default, they will move behind the inserted text. + /// The caret will also move behind the inserted text. + /// + void Insert(int offset, ITextSource text); + /// /// Inserts text. /// @@ -121,6 +133,18 @@ namespace ICSharpCode.NRefactory.Editor /// void Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType); + /// + /// Inserts text. + /// + /// The offset at which the text is inserted. + /// The new text. + /// + /// Anchors positioned exactly at the insertion offset will move according to the anchor's movement type. + /// For AnchorMovementType.Default, they will move according to the movement type specified by this parameter. + /// The caret will also move according to the parameter. + /// + void Insert(int offset, ITextSource text, AnchorMovementType defaultAnchorMovementType); + /// /// Removes text. /// @@ -136,6 +160,14 @@ namespace ICSharpCode.NRefactory.Editor /// The new text. void Replace(int offset, int length, string newText); + /// + /// Replaces text. + /// + /// The starting offset of the text to be replaced. + /// The length of the text to be replaced. + /// The new text. + void Replace(int offset, int length, ITextSource newText); + /// /// Make the document combine the following actions into a single /// action for undo purposes. diff --git a/ICSharpCode.NRefactory/Editor/ReadOnlyDocument.cs b/ICSharpCode.NRefactory/Editor/ReadOnlyDocument.cs index a4d76a8394..2a36ccda33 100644 --- a/ICSharpCode.NRefactory/Editor/ReadOnlyDocument.cs +++ b/ICSharpCode.NRefactory/Editor/ReadOnlyDocument.cs @@ -257,6 +257,21 @@ namespace ICSharpCode.NRefactory.Editor throw new NotSupportedException(); } + void IDocument.Insert(int offset, ITextSource text) + { + throw new NotImplementedException(); + } + + void IDocument.Insert(int offset, ITextSource text, AnchorMovementType defaultAnchorMovementType) + { + throw new NotImplementedException(); + } + + void IDocument.Replace(int offset, int length, ITextSource newText) + { + throw new NotImplementedException(); + } + void IDocument.StartUndoableAction() { } diff --git a/ICSharpCode.NRefactory/Editor/StringBuilderDocument.cs b/ICSharpCode.NRefactory/Editor/StringBuilderDocument.cs index 79553a4136..f69070a196 100644 --- a/ICSharpCode.NRefactory/Editor/StringBuilderDocument.cs +++ b/ICSharpCode.NRefactory/Editor/StringBuilderDocument.cs @@ -104,17 +104,35 @@ namespace ICSharpCode.NRefactory.Editor Replace(offset, 0, text); } + /// + public void Insert(int offset, ITextSource text) + { + if (text == null) + throw new ArgumentNullException("text"); + Replace(offset, 0, text.Text); + } + /// public void Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType) { if (offset < 0 || offset > this.TextLength) throw new ArgumentOutOfRangeException("offset"); + if (text == null) + throw new ArgumentNullException("text"); if (defaultAnchorMovementType == AnchorMovementType.BeforeInsertion) PerformChange(new InsertionWithMovementBefore(offset, text)); else Replace(offset, 0, text); } + /// + public void Insert(int offset, ITextSource text, AnchorMovementType defaultAnchorMovementType) + { + if (text == null) + throw new ArgumentNullException("text"); + Insert(offset, text.Text, defaultAnchorMovementType); + } + [Serializable] sealed class InsertionWithMovementBefore : TextChangeEventArgs { @@ -149,6 +167,14 @@ namespace ICSharpCode.NRefactory.Editor PerformChange(new TextChangeEventArgs(offset, b.ToString(offset, length), newText)); } + /// + public void Replace(int offset, int length, ITextSource newText) + { + if (newText == null) + throw new ArgumentNullException("newText"); + Replace(offset, length, newText.Text); + } + bool isInChange; void PerformChange(TextChangeEventArgs change) @@ -166,7 +192,7 @@ namespace ICSharpCode.NRefactory.Editor documentSnapshot = null; cachedText = null; b.Remove(change.Offset, change.RemovalLength); - b.Insert(change.Offset, change.InsertedText); + b.Insert(change.Offset, change.InsertedText.Text); versionProvider.AppendChange(change); // Update anchors and fire Deleted events diff --git a/ICSharpCode.NRefactory/Editor/StringTextSource.cs b/ICSharpCode.NRefactory/Editor/StringTextSource.cs index 3a24db3646..36780954bd 100644 --- a/ICSharpCode.NRefactory/Editor/StringTextSource.cs +++ b/ICSharpCode.NRefactory/Editor/StringTextSource.cs @@ -27,6 +27,11 @@ namespace ICSharpCode.NRefactory.Editor [Serializable] public class StringTextSource : ITextSource { + /// + /// Gets a text source containing the empty string. + /// + public static readonly StringTextSource Empty = new StringTextSource(string.Empty); + readonly string text; readonly ITextSourceVersion version; @@ -69,7 +74,7 @@ namespace ICSharpCode.NRefactory.Editor /// public ITextSource CreateSnapshot() { - return this; // StringTextBuffer is immutable + return this; // StringTextSource is immutable } /// diff --git a/ICSharpCode.NRefactory/Editor/TextChangeEventArgs.cs b/ICSharpCode.NRefactory/Editor/TextChangeEventArgs.cs index 936de37aa4..f1eeb4d27f 100644 --- a/ICSharpCode.NRefactory/Editor/TextChangeEventArgs.cs +++ b/ICSharpCode.NRefactory/Editor/TextChangeEventArgs.cs @@ -28,8 +28,8 @@ namespace ICSharpCode.NRefactory.Editor public class TextChangeEventArgs : EventArgs { readonly int offset; - readonly string removedText; - readonly string insertedText; + readonly ITextSource removedText; + readonly ITextSource insertedText; /// /// The offset at which the change occurs. @@ -41,7 +41,7 @@ namespace ICSharpCode.NRefactory.Editor /// /// The text that was removed. /// - public string RemovedText { + public ITextSource RemovedText { get { return removedText; } } @@ -49,13 +49,13 @@ namespace ICSharpCode.NRefactory.Editor /// The number of characters removed. /// public int RemovalLength { - get { return removedText.Length; } + get { return removedText.TextLength; } } /// /// The text that was inserted. /// - public string InsertedText { + public ITextSource InsertedText { get { return insertedText; } } @@ -63,7 +63,7 @@ namespace ICSharpCode.NRefactory.Editor /// The number of characters inserted. /// public int InsertionLength { - get { return insertedText.Length; } + get { return insertedText.TextLength; } } /// @@ -71,9 +71,23 @@ namespace ICSharpCode.NRefactory.Editor /// public TextChangeEventArgs(int offset, string removedText, string insertedText) { + if (offset < 0) + throw new ArgumentOutOfRangeException("offset", offset, "offset must not be negative"); this.offset = offset; - this.removedText = removedText ?? string.Empty; - this.insertedText = insertedText ?? string.Empty; + this.removedText = removedText != null ? new StringTextSource(removedText) : StringTextSource.Empty; + this.insertedText = insertedText != null ? new StringTextSource(insertedText) : StringTextSource.Empty; + } + + /// + /// Creates a new TextChangeEventArgs object. + /// + public TextChangeEventArgs(int offset, ITextSource removedText, ITextSource insertedText) + { + if (offset < 0) + throw new ArgumentOutOfRangeException("offset", offset, "offset must not be negative"); + this.offset = offset; + this.removedText = removedText ?? StringTextSource.Empty; + this.insertedText = insertedText ?? StringTextSource.Empty; } /// From 731ddf7c3931942c26d3f2639ba2b1824c0f4405 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 9 Jun 2012 12:59:04 +0200 Subject: [PATCH 19/24] Add ConversionResolveResult.CheckForOverflow --- .../Resolver/CSharpResolver.cs | 27 ++++++++++++------- .../Resolver/MethodGroupResolveResult.cs | 4 ++- .../Resolver/OverloadResolution.cs | 11 ++++++-- .../Resolver/ResolveVisitor.cs | 8 +++--- .../Semantics/ConversionResolveResult.cs | 11 ++++++++ 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs index 6c3574b5d6..08dc75394c 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs @@ -390,7 +390,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver bool isNullable = NullableType.IsNullable(expression.Type); // the operator is overloadable: - OverloadResolution userDefinedOperatorOR = new OverloadResolution(compilation, new[] { expression }, conversions: conversions); + OverloadResolution userDefinedOperatorOR = CreateOverloadResolution(new[] { expression }); foreach (var candidate in GetUserDefinedOperatorCandidates(type, overloadableOperatorName)) { userDefinedOperatorOR.AddCandidate(candidate); } @@ -439,7 +439,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver default: throw new InvalidOperationException(); } - OverloadResolution builtinOperatorOR = new OverloadResolution(compilation, new[] { expression }, conversions: conversions); + OverloadResolution builtinOperatorOR = CreateOverloadResolution(new[] { expression }); foreach (var candidate in methodGroup) { builtinOperatorOR.AddCandidate(candidate); } @@ -569,7 +569,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver IType rhsType = NullableType.GetUnderlyingType(rhs.Type); // the operator is overloadable: - OverloadResolution userDefinedOperatorOR = new OverloadResolution(compilation, new[] { lhs, rhs }, conversions: conversions); + OverloadResolution userDefinedOperatorOR = CreateOverloadResolution(new[] { lhs, rhs }); HashSet userOperatorCandidates = new HashSet(); userOperatorCandidates.UnionWith(GetUserDefinedOperatorCandidates(lhsType, overloadableOperatorName)); userOperatorCandidates.UnionWith(GetUserDefinedOperatorCandidates(rhsType, overloadableOperatorName)); @@ -800,7 +800,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver default: throw new InvalidOperationException(); } - OverloadResolution builtinOperatorOR = new OverloadResolution(compilation, new[] { lhs, rhs }, conversions: conversions); + OverloadResolution builtinOperatorOR = CreateOverloadResolution(new[] { lhs, rhs }); foreach (var candidate in methodGroup) { builtinOperatorOR.AddCandidate(candidate); } @@ -1260,7 +1260,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver else if (rr.IsCompileTimeConstant && c != Conversion.None) return ResolveCast(targetType, rr); else - return new ConversionResolveResult(targetType, rr, c); + return new ConversionResolveResult(targetType, rr, c, checkForOverflow); } public ResolveResult ResolveCast(IType targetType, ResolveResult expression) @@ -1291,7 +1291,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } Conversion c = conversions.ExplicitConversion(expression, targetType); - return new ConversionResolveResult(targetType, expression, c); + return new ConversionResolveResult(targetType, expression, c, checkForOverflow); } internal object CSharpPrimitiveCast(TypeCode targetType, object input) @@ -1891,7 +1891,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver MethodGroupResolveResult mgrr = target as MethodGroupResolveResult; if (mgrr != null) { - OverloadResolution or = mgrr.PerformOverloadResolution(compilation, arguments, argumentNames, conversions: conversions); + OverloadResolution or = mgrr.PerformOverloadResolution(compilation, arguments, argumentNames, checkForOverflow: checkForOverflow, conversions: conversions); if (or.BestCandidate != null) { if (or.BestCandidate.IsStatic && !or.IsExtensionMethodInvocation && !(mgrr.TargetResult is TypeResolveResult)) return or.CreateResolveResult(new TypeResolveResult(mgrr.TargetResult.Type)); @@ -1914,7 +1914,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } IMethod invokeMethod = target.Type.GetDelegateInvokeMethod(); if (invokeMethod != null) { - OverloadResolution or = new OverloadResolution(compilation, arguments, argumentNames, conversions: conversions); + OverloadResolution or = CreateOverloadResolution(arguments, argumentNames); or.AddCandidate(invokeMethod); return new CSharpInvocationResolveResult( target, invokeMethod, //invokeMethod.ReturnType.Resolve(context), @@ -2003,6 +2003,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver variableName = variableName.Substring(1); return char.ToLower(variableName[0]) + variableName.Substring(1); } + + OverloadResolution CreateOverloadResolution(ResolveResult[] arguments, string[] argumentNames = null, IType[] typeArguments = null) + { + var or = new OverloadResolution(compilation, arguments, argumentNames, typeArguments, conversions); + or.CheckForOverflow = checkForOverflow; + return or; + } #endregion #region ResolveIndexer @@ -2035,7 +2042,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } // §7.6.6.2 Indexer access - OverloadResolution or = new OverloadResolution(compilation, arguments, argumentNames, conversions: conversions); + OverloadResolution or = CreateOverloadResolution(arguments, argumentNames); MemberLookup lookup = CreateMemberLookup(); var indexers = lookup.LookupIndexers(target.Type); or.AddMethodLists(indexers); @@ -2090,7 +2097,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (type.Kind == TypeKind.Delegate && arguments.Length == 1) { return Convert(arguments[0], type); } - OverloadResolution or = new OverloadResolution(compilation, arguments, argumentNames, conversions: conversions); + OverloadResolution or = CreateOverloadResolution(arguments, argumentNames); MemberLookup lookup = CreateMemberLookup(); foreach (IMethod ctor in type.GetConstructors()) { if (lookup.IsAccessible(ctor, allowProtectedAccess)) diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs b/ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs index 3d319ecfcf..87e9f46129 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs @@ -178,7 +178,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return string.Format("[{0} with {1} method(s)]", GetType().Name, this.Methods.Count()); } - public OverloadResolution PerformOverloadResolution(ICompilation compilation, ResolveResult[] arguments, string[] argumentNames = null, bool allowExtensionMethods = true, bool allowExpandingParams = true, CSharpConversions conversions = null) + public OverloadResolution PerformOverloadResolution(ICompilation compilation, ResolveResult[] arguments, string[] argumentNames = null, bool allowExtensionMethods = true, bool allowExpandingParams = true, bool checkForOverflow = false, CSharpConversions conversions = null) { Log.WriteLine("Performing overload resolution for " + this); Log.WriteCollection(" Arguments: ", arguments); @@ -186,6 +186,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver var typeArgumentArray = this.TypeArguments.ToArray(); OverloadResolution or = new OverloadResolution(compilation, arguments, argumentNames, typeArgumentArray, conversions); or.AllowExpandingParams = allowExpandingParams; + or.CheckForOverflow = checkForOverflow; or.AddMethodLists(methodLists); @@ -207,6 +208,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver var extOr = new OverloadResolution(compilation, extArguments, extArgumentNames, typeArgumentArray, conversions); extOr.AllowExpandingParams = allowExpandingParams; extOr.IsExtensionMethodInvocation = true; + extOr.CheckForOverflow = checkForOverflow; foreach (var g in extensionMethods) { foreach (var method in g) { diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs b/ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs index 63c880bf81..d7f8da21a9 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs @@ -170,6 +170,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// public bool AllowExpandingParams { get; set; } + /// + /// Gets/Sets whether ConversionResolveResults created by this OverloadResolution + /// instance apply overflow checking. + /// The default value is false. + /// + public bool CheckForOverflow { get; set; } + /// /// Gets the arguments for which this OverloadResolution instance was created. /// @@ -801,9 +808,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver parameterType = SpecialType.UnknownType; } if (arguments[i].IsCompileTimeConstant && conversions[i] != Conversion.None) { - args[i] = new CSharpResolver(compilation).ResolveCast(parameterType, argument); + args[i] = new CSharpResolver(compilation).WithCheckForOverflow(CheckForOverflow).ResolveCast(parameterType, argument); } else { - args[i] = new ConversionResolveResult(parameterType, argument, conversions[i]); + args[i] = new ConversionResolveResult(parameterType, argument, conversions[i], CheckForOverflow); } } } diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs index 86300a0ab7..f4823ea7ae 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs @@ -1236,7 +1236,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (resolverEnabled) { ResolveResult input = Resolve(asExpression.Expression); var targetType = ResolveType(asExpression.Type); - return new ConversionResolveResult(targetType, input, Conversion.TryCast); + return new ConversionResolveResult(targetType, input, Conversion.TryCast, resolver.CheckForOverflow); } else { ScanChildren(asExpression); return null; @@ -1498,7 +1498,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver var addRR = memberLookup.Lookup(initializedObject, "Add", EmptyList.Instance, true); var mgrr = addRR as MethodGroupResolveResult; if (mgrr != null) { - OverloadResolution or = mgrr.PerformOverloadResolution(resolver.Compilation, addArguments, null, false, false, resolver.conversions); + OverloadResolution or = mgrr.PerformOverloadResolution(resolver.Compilation, addArguments, null, false, false, resolver.CheckForOverflow, resolver.conversions); var invocationRR = or.CreateResolveResult(initializedObject); StoreResult(aie, invocationRR); ProcessConversionsInInvocation(null, aie.Elements, invocationRR); @@ -3415,7 +3415,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// ResolveResult WrapResult(ResolveResult result) { - return new ConversionResolveResult(result.Type, result, Conversion.IdentityConversion); + return new ConversionResolveResult(result.Type, result, Conversion.IdentityConversion, resolver.CheckForOverflow); } ResolveResult IAstVisitor.VisitQueryContinuationClause(QueryContinuationClause queryContinuationClause) @@ -3603,7 +3603,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver ProcessConversion(queryWhereClause.Condition, condition, conversionToBool, boolType); if (currentQueryResult != null) { if (conversionToBool != Conversion.IdentityConversion && conversionToBool != Conversion.None) { - condition = new ConversionResolveResult(boolType, condition, conversionToBool); + condition = new ConversionResolveResult(boolType, condition, conversionToBool, resolver.CheckForOverflow); } var methodGroup = resolver.ResolveMemberAccess(currentQueryResult, "Where", EmptyList.Instance); diff --git a/ICSharpCode.NRefactory/Semantics/ConversionResolveResult.cs b/ICSharpCode.NRefactory/Semantics/ConversionResolveResult.cs index d015ddd3d4..303118bf00 100644 --- a/ICSharpCode.NRefactory/Semantics/ConversionResolveResult.cs +++ b/ICSharpCode.NRefactory/Semantics/ConversionResolveResult.cs @@ -27,6 +27,11 @@ namespace ICSharpCode.NRefactory.Semantics public readonly ResolveResult Input; public readonly Conversion Conversion; + /// + /// For numeric conversions, specifies whether overflow checking is enabled. + /// + public readonly bool CheckForOverflow; + public ConversionResolveResult(IType targetType, ResolveResult input, Conversion conversion) : base(targetType) { @@ -38,6 +43,12 @@ namespace ICSharpCode.NRefactory.Semantics this.Conversion = conversion; } + public ConversionResolveResult(IType targetType, ResolveResult input, Conversion conversion, bool checkForOverflow) + : this(targetType, input, conversion) + { + this.CheckForOverflow = checkForOverflow; + } + public override bool IsError { get { return !Conversion.IsValid; } } From a77fa3103acabd5152aed6f943b36832587d85b0 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 9 Jun 2012 19:07:02 +0200 Subject: [PATCH 20/24] Add IMethod.AccessorOwner. --- .../TypeSystem/TypeSystemConvertVisitor.cs | 1 + .../TypeSystem/TypeSystemTests.TestCase.cs | 2 ++ .../TypeSystem/TypeSystemTests.cs | 11 +++++++++ .../TypeSystem/CecilLoader.cs | 16 +++++++++---- ICSharpCode.NRefactory/TypeSystem/IMethod.cs | 17 ++++++++++++++ .../Implementation/DefaultResolvedMethod.cs | 14 +++++++++++ .../Implementation/DefaultUnresolvedMethod.cs | 9 ++++++++ .../Implementation/SpecializedMember.cs | 9 +++++--- .../Implementation/SpecializedMethod.cs | 23 ++++++++++++++++++- 9 files changed, 93 insertions(+), 9 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs index 55c80e9c9a..d2a273dcc0 100644 --- a/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs @@ -677,6 +677,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem if (accessor.IsNull) return null; var a = new DefaultUnresolvedMethod(currentTypeDefinition, prefix + p.Name); + a.AccessorOwner = p; a.Accessibility = GetAccessibility(accessor.Modifiers) ?? p.Accessibility; a.IsAbstract = p.IsAbstract; a.IsOverride = p.IsOverridable; diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs index d130b6b4f6..580138eae6 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs @@ -72,6 +72,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase public NestedEnum EnumField; + public A Property { get; set; } + public enum NestedEnum { EnumMember } diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs index 4586652ff8..6f76812ac4 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs @@ -351,6 +351,7 @@ namespace ICSharpCode.NRefactory.TypeSystem Assert.AreEqual(Accessibility.Public, p.Getter.Accessibility); Assert.AreEqual(new[] { "index" }, p.Getter.Parameters.Select(x => x.Name).ToArray()); Assert.AreEqual("System.String", p.Getter.ReturnType.ReflectionName); + Assert.AreEqual(p, p.Getter.AccessorOwner); } [Test] @@ -365,6 +366,16 @@ namespace ICSharpCode.NRefactory.TypeSystem Assert.AreEqual(TypeKind.Void, p.Setter.ReturnType.Kind); } + [Test] + public void GenericPropertyGetter() + { + var type = compilation.FindType(typeof(GenericClass)); + var prop = type.GetProperties(p => p.Name == "Property").Single(); + Assert.AreEqual("System.String", prop.Getter.ReturnType.ReflectionName); + Assert.IsTrue(prop.Getter.IsAccessor); + Assert.AreEqual(prop, prop.Getter.AccessorOwner); + } + [Test] public void EnumTest() { diff --git a/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs b/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs index 7bc866c501..15530707a5 100644 --- a/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs +++ b/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs @@ -1646,11 +1646,17 @@ namespace ICSharpCode.NRefactory.TypeSystem #region Read Method [CLSCompliant(false)] public IUnresolvedMethod ReadMethod(MethodDefinition method, IUnresolvedTypeDefinition parentType, EntityType methodType = EntityType.Method) + { + return ReadMethod(method, parentType, null, methodType); + } + + IUnresolvedMethod ReadMethod(MethodDefinition method, IUnresolvedTypeDefinition parentType, IUnresolvedMember accessorOwner, EntityType methodType = EntityType.Method) { if (method == null) return null; DefaultUnresolvedMethod m = new DefaultUnresolvedMethod(parentType, method.Name); m.EntityType = methodType; + m.AccessorOwner = accessorOwner; if (method.HasGenericParameters) { for (int i = 0; i < method.GenericParameters.Count; i++) { if (method.GenericParameters[i].Position != i) @@ -1876,8 +1882,8 @@ namespace ICSharpCode.NRefactory.TypeSystem TranslateModifiers(property.GetMethod ?? property.SetMethod, p); p.ReturnType = ReadTypeReference(property.PropertyType, typeAttributes: property); - p.Getter = ReadMethod(property.GetMethod, parentType); - p.Setter = ReadMethod(property.SetMethod, parentType); + p.Getter = ReadMethod(property.GetMethod, parentType, p); + p.Setter = ReadMethod(property.SetMethod, parentType, p); if (property.HasParameters) { foreach (ParameterDefinition par in property.Parameters) { @@ -1904,9 +1910,9 @@ namespace ICSharpCode.NRefactory.TypeSystem TranslateModifiers(ev.AddMethod, e); e.ReturnType = ReadTypeReference(ev.EventType, typeAttributes: ev); - e.AddAccessor = ReadMethod(ev.AddMethod, parentType); - e.RemoveAccessor = ReadMethod(ev.RemoveMethod, parentType); - e.InvokeAccessor = ReadMethod(ev.InvokeMethod, parentType); + e.AddAccessor = ReadMethod(ev.AddMethod, parentType, e); + e.RemoveAccessor = ReadMethod(ev.RemoveMethod, parentType, e); + e.InvokeAccessor = ReadMethod(ev.InvokeMethod, parentType, e); AddAttributes(ev, e); diff --git a/ICSharpCode.NRefactory/TypeSystem/IMethod.cs b/ICSharpCode.NRefactory/TypeSystem/IMethod.cs index c3fd1b7720..844c810ecc 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IMethod.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IMethod.cs @@ -39,6 +39,12 @@ namespace ICSharpCode.NRefactory.TypeSystem bool IsPartialMethodDeclaration { get; } bool IsPartialMethodImplementation { get; } + /// + /// If this method is an accessor, returns a reference to the corresponding property/event. + /// Otherwise, returns null. + /// + IMemberReference AccessorOwner { get; } + /// /// Resolves the member. /// @@ -75,5 +81,16 @@ namespace ICSharpCode.NRefactory.TypeSystem bool IsConstructor { get; } bool IsDestructor { get; } bool IsOperator { get; } + + /// + /// Gets whether the method is a property/event accessor. + /// + bool IsAccessor { get; } + + /// + /// If this method is an accessor, returns the corresponding property/event. + /// Otherwise, returns null. + /// + IMember AccessorOwner { get; } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs index 57ddbbfa48..6a20f62c21 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs @@ -190,6 +190,20 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public bool IsOperator { get { return ((IUnresolvedMethod)unresolved).IsOperator; } } + + public bool IsAccessor { + get { return ((IUnresolvedMethod)unresolved).AccessorOwner != null; } + } + + public IMember AccessorOwner { + get { + var reference = ((IUnresolvedMethod)unresolved).AccessorOwner; + if (reference != null) + return reference.Resolve(context); + else + return null; + } + } public override IMemberReference ToMemberReference() { diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedMethod.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedMethod.cs index f06815297a..8ec9e65727 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedMethod.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedMethod.cs @@ -32,6 +32,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation IList returnTypeAttributes; IList typeParameters; IList parameters; + IMemberReference accessorOwner; protected override void FreezeInternal() { @@ -125,6 +126,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } } + public IMemberReference AccessorOwner { + get { return accessorOwner; } + set { + ThrowIfFrozen(); + accessorOwner = value; + } + } + public override string ToString() { StringBuilder b = new StringBuilder("["); diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs index 53fd6d350c..f9ba5382f5 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs @@ -101,10 +101,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation if (accessorDefinition == null) return null; var result = LazyInit.VolatileRead(ref cachingField); - if (result != null) + if (result != null) { return result; - else - return LazyInit.GetOrSet(ref cachingField, new SpecializedMethod(accessorDefinition, substitution)); + } else { + var sm = new SpecializedMethod(accessorDefinition, substitution); + //sm.AccessorOwner = this; + return LazyInit.GetOrSet(ref cachingField, sm); + } } /// diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs index ac3fdb3d8c..79b5d10fa7 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs @@ -21,7 +21,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; - +using System.Threading; using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -121,6 +121,27 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation get { return methodDefinition.IsOperator; } } + public bool IsAccessor { + get { return methodDefinition.IsAccessor; } + } + + IMember accessorOwner; + + public IMember AccessorOwner { + get { + var result = LazyInit.VolatileRead(ref accessorOwner); + if (result != null) { + return result; + } else { + result = SpecializedMember.Create(methodDefinition.AccessorOwner, this.Substitution); + return LazyInit.GetOrSet(ref accessorOwner, result); + } + } + internal set { + accessorOwner = value; + } + } + public override IMemberReference ToMemberReference() { // Pass the MethodTypeArguments to the SpecializingMemberReference only if From a9d876904bca02b2e0504cf1fcaf0cc9804c145b Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 9 Jun 2012 20:11:18 +0200 Subject: [PATCH 21/24] Implemented CSharpResolver.ResolveConditionFalse() for resolving operator false() calls. Add message to ErrorResolveResult. Expose CSharpOutputVisitor.PrintPrimitiveValue and CSharpConversions.IsImplicitReferenceConversion/IsBoxingConversion. --- .../OutputVisitor/CSharpOutputVisitor.cs | 8 +++++++ .../Resolver/CSharpConversions.cs | 11 +++++++--- .../Resolver/CSharpResolver.cs | 21 +++++++++++++++++++ .../Semantics/ErrorResolveResult.cs | 10 +++++++++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs b/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs index 40876d2bfb..23932e802c 100644 --- a/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs @@ -1007,6 +1007,14 @@ namespace ICSharpCode.NRefactory.CSharp EndNode(primitiveExpression); } + public static string PrintPrimitiveValue(object val) + { + StringWriter writer = new StringWriter(); + CSharpOutputVisitor visitor = new CSharpOutputVisitor(writer, new CSharpFormattingOptions()); + visitor.WritePrimitiveValue(val); + return writer.ToString(); + } + void WritePrimitiveValue(object val) { if (val == null) { diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs index e818b6a5a0..9b5ec92a64 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs @@ -155,7 +155,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return Conversion.NullLiteralConversion; if (ImplicitReferenceConversion(fromType, toType, 0)) return Conversion.ImplicitReferenceConversion; - if (BoxingConversion(fromType, toType)) + if (IsBoxingConversion(fromType, toType)) return Conversion.BoxingConversion; if (fromType.Kind == TypeKind.Dynamic) return Conversion.ImplicitDynamicConversion; @@ -184,7 +184,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return true; if (ImplicitReferenceConversion(fromType, toType, 0)) return true; - if (BoxingConversion(fromType, toType) && !NullableType.IsNullable(fromType)) + if (IsBoxingConversion(fromType, toType) && !NullableType.IsNullable(fromType)) return true; if (ImplicitTypeParameterConversion(fromType, toType)) return true; @@ -398,6 +398,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver #endregion #region Implicit Reference Conversion + public bool IsImplicitReferenceConversion(IType fromType, IType toType) + { + return ImplicitReferenceConversion(fromType, toType, 0); + } + bool ImplicitReferenceConversion(IType fromType, IType toType, int subtypeCheckNestingDepth) { // C# 4.0 spec: §6.1.6 @@ -510,7 +515,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver #endregion #region Boxing Conversions - bool BoxingConversion(IType fromType, IType toType) + public bool IsBoxingConversion(IType fromType, IType toType) { // C# 4.0 spec: §6.1.7 fromType = NullableType.GetUnderlyingType(fromType); diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs index 08dc75394c..168bebca6b 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs @@ -2204,6 +2204,27 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return Convert(input, boolean, c); } + /// + /// Converts the negated input to bool using the rules for boolean expressions. + /// Computes !(bool)input if the implicit cast to bool is valid; otherwise + /// computes input.operator false(). + /// + public ResolveResult ResolveConditionFalse(ResolveResult input) + { + if (input == null) + throw new ArgumentNullException("input"); + IType boolean = compilation.FindType(KnownTypeCode.Boolean); + Conversion c = conversions.ImplicitConversion(input, boolean); + if (!c.IsValid) { + var opFalse = input.Type.GetMethods(m => m.IsOperator && m.Name == "op_False").FirstOrDefault(); + if (opFalse != null) { + c = Conversion.UserDefinedImplicitConversion(opFalse, false); + return Convert(input, boolean, c); + } + } + return ResolveUnaryOperator(UnaryOperatorType.Not, Convert(input, boolean, c)); + } + public ResolveResult ResolveConditional(ResolveResult condition, ResolveResult trueExpression, ResolveResult falseExpression) { // C# 4.0 spec §7.14: Conditional operator diff --git a/ICSharpCode.NRefactory/Semantics/ErrorResolveResult.cs b/ICSharpCode.NRefactory/Semantics/ErrorResolveResult.cs index 15942f7a8a..da68da167a 100644 --- a/ICSharpCode.NRefactory/Semantics/ErrorResolveResult.cs +++ b/ICSharpCode.NRefactory/Semantics/ErrorResolveResult.cs @@ -35,8 +35,18 @@ namespace ICSharpCode.NRefactory.Semantics { } + public ErrorResolveResult(IType type, string message, TextLocation location) : base(type) + { + this.Message = message; + this.Location = location; + } + public override bool IsError { get { return true; } } + + public string Message { get; private set; } + + public TextLocation Location { get; private set; } } } From cd9c9483753a8c043b39d410e765aebffba5ee8a Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 9 Jun 2012 21:01:58 +0200 Subject: [PATCH 22/24] Add ICollection, ICollection and IList to KnownTypeReference. --- .../TypeSystem/KnownTypeReference.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ICSharpCode.NRefactory/TypeSystem/KnownTypeReference.cs b/ICSharpCode.NRefactory/TypeSystem/KnownTypeReference.cs index 53277ee713..8abb14a7a5 100644 --- a/ICSharpCode.NRefactory/TypeSystem/KnownTypeReference.cs +++ b/ICSharpCode.NRefactory/TypeSystem/KnownTypeReference.cs @@ -101,6 +101,12 @@ namespace ICSharpCode.NRefactory.TypeSystem IEnumerableOfT, /// System.Collections.Generic.IEnumerator{T} IEnumeratorOfT, + /// System.Collections.Generic.ICollection + ICollection, + /// System.Collections.Generic.ICollection{T} + ICollectionOfT, + /// System.Collections.Generic.IList + IList, /// System.Collections.Generic.IList{T} IListOfT, /// System.Collections.Generic.IReadOnlyList{T} @@ -158,7 +164,11 @@ namespace ICSharpCode.NRefactory.TypeSystem new KnownTypeReference(KnownTypeCode.IEnumerator, "System.Collections", "IEnumerator"), new KnownTypeReference(KnownTypeCode.IEnumerableOfT, "System.Collections.Generic", "IEnumerable", 1), new KnownTypeReference(KnownTypeCode.IEnumeratorOfT, "System.Collections.Generic", "IEnumerator", 1), + new KnownTypeReference(KnownTypeCode.ICollection, "System.Collections", "ICollection"), + new KnownTypeReference(KnownTypeCode.ICollectionOfT, "System.Collections.Generic", "ICollection", 1), + new KnownTypeReference(KnownTypeCode.IList, "System.Collections", "IList"), new KnownTypeReference(KnownTypeCode.IListOfT, "System.Collections.Generic", "IList", 1), + new KnownTypeReference(KnownTypeCode.IReadOnlyListOfT, "System.Collections.Generic", "IReadOnlyList", 1), new KnownTypeReference(KnownTypeCode.Task, "System.Threading.Tasks", "Task"), new KnownTypeReference(KnownTypeCode.TaskOfT, "System.Threading.Tasks", "Task", 1, baseType: KnownTypeCode.Task), From d6ed3b772618bd832b9d4e38e886a0707ee17045 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 10 Jun 2012 10:27:48 +0200 Subject: [PATCH 23/24] Fixed resolving accessors. --- ICSharpCode.NRefactory/TypeSystem/IMethod.cs | 2 +- .../Implementation/DefaultUnresolvedMethod.cs | 27 +++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/ICSharpCode.NRefactory/TypeSystem/IMethod.cs b/ICSharpCode.NRefactory/TypeSystem/IMethod.cs index 844c810ecc..74a7cc6b0b 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IMethod.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IMethod.cs @@ -43,7 +43,7 @@ namespace ICSharpCode.NRefactory.TypeSystem /// If this method is an accessor, returns a reference to the corresponding property/event. /// Otherwise, returns null. /// - IMemberReference AccessorOwner { get; } + IUnresolvedMember AccessorOwner { get; } /// /// Resolves the member. diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedMethod.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedMethod.cs index 8ec9e65727..8b0e16d345 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedMethod.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedMethod.cs @@ -32,7 +32,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation IList returnTypeAttributes; IList typeParameters; IList parameters; - IMemberReference accessorOwner; + IUnresolvedMember accessorOwner; protected override void FreezeInternal() { @@ -126,7 +126,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } } - public IMemberReference AccessorOwner { + public IUnresolvedMember AccessorOwner { get { return accessorOwner; } set { ThrowIfFrozen(); @@ -159,6 +159,29 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public override IMember Resolve(ITypeResolveContext context) { + if (accessorOwner != null) { + var owner = accessorOwner.Resolve(context); + if (owner != null) { + IProperty p = owner as IProperty; + if (p != null) { + if (p.CanGet && p.Getter.Name == this.Name) + return p.Getter; + if (p.CanSet && p.Setter.Name == this.Name) + return p.Setter; + } + IEvent e = owner as IEvent; + if (e != null) { + if (e.CanAdd && e.AddAccessor.Name == this.Name) + return e.AddAccessor; + if (e.CanRemove && e.RemoveAccessor.Name == this.Name) + return e.RemoveAccessor; + if (e.CanInvoke && e.InvokeAccessor.Name == this.Name) + return e.InvokeAccessor; + } + } + return null; + } + ITypeReference interfaceTypeReference = null; if (this.IsExplicitInterfaceImplementation && this.ExplicitInterfaceImplementations.Count == 1) interfaceTypeReference = this.ExplicitInterfaceImplementations[0].DeclaringTypeReference; From bf6217d038acde9535e315a65837163665a7959a Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 10 Jun 2012 17:06:26 +0200 Subject: [PATCH 24/24] Improved CodeDomConvertVisitor. --- .../OutputVisitor/CodeDomConvertVisitor.cs | 121 ++++-- .../Parser/CSharpParser.cs | 4 +- .../CSharp/CodeDomConvertVisitorTests.cs | 376 +++++++++++++++--- 3 files changed, 413 insertions(+), 88 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/OutputVisitor/CodeDomConvertVisitor.cs b/ICSharpCode.NRefactory.CSharp/OutputVisitor/CodeDomConvertVisitor.cs index 53584eef08..b8e94dcfb5 100644 --- a/ICSharpCode.NRefactory.CSharp/OutputVisitor/CodeDomConvertVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/OutputVisitor/CodeDomConvertVisitor.cs @@ -21,12 +21,12 @@ using System.CodeDom; using System.Collections.Generic; using System.IO; using System.Linq; +using ICSharpCode.NRefactory.CSharp.Refactoring; using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.CSharp.TypeSystem; using ICSharpCode.NRefactory.PatternMatching; using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.TypeSystem; -using ICSharpCode.NRefactory.TypeSystem.Implementation; namespace ICSharpCode.NRefactory.CSharp { @@ -40,14 +40,23 @@ namespace ICSharpCode.NRefactory.CSharp { //ICompilation compilation = MinimalResolveContext.Instance; CSharpAstResolver resolver; - bool useFullyQualifiedTypeNames; /// /// Gets/Sets whether the visitor should use fully-qualified type references. /// - public bool UseFullyQualifiedTypeNames { - get { return useFullyQualifiedTypeNames; } - set { useFullyQualifiedTypeNames = value; } + public bool UseFullyQualifiedTypeNames { get; set; } + + /// + /// Gets whether the visitor is allowed to produce snippet nodes for + /// code that cannot be converted. + /// The default is true. If this property is set to false, + /// unconvertible code will throw a NotSupportedException. + /// + public bool AllowSnippetNodes { get; set; } + + public CodeDomConvertVisitor() + { + this.AllowSnippetNodes = true; } /// @@ -136,7 +145,15 @@ namespace ICSharpCode.NRefactory.CSharp CodeTypeReference Convert(IType type) { - return new CodeTypeReference(type.ReflectionName); + if (type.Kind == TypeKind.Array) { + ArrayType a = (ArrayType)type; + return new CodeTypeReference(Convert(a.ElementType), a.Dimensions); + } else if (type is ParameterizedType) { + var pt = (ParameterizedType)type; + return new CodeTypeReference(pt.GetDefinition().ReflectionName, pt.TypeArguments.Select(Convert).ToArray()); + } else { + return new CodeTypeReference(type.ReflectionName); + } } CodeStatement Convert(Statement stmt) @@ -148,6 +165,8 @@ namespace ICSharpCode.NRefactory.CSharp { List result = new List(); foreach (Statement stmt in block.Statements) { + if (stmt is EmptyStatement) + continue; CodeStatement s = Convert(stmt); if (s != null) result.Add(s); @@ -160,6 +179,8 @@ namespace ICSharpCode.NRefactory.CSharp BlockStatement block = embeddedStatement as BlockStatement; if (block != null) { return ConvertBlock(block); + } else if (embeddedStatement is EmptyStatement) { + return new CodeStatement[0]; } CodeStatement s = Convert(embeddedStatement); if (s != null) @@ -170,6 +191,8 @@ namespace ICSharpCode.NRefactory.CSharp string MakeSnippet(AstNode node) { + if (!AllowSnippetNodes) + throw new NotSupportedException(); StringWriter w = new StringWriter(); CSharpOutputVisitor v = new CSharpOutputVisitor(w, FormattingOptionsFactory.CreateMono ()); node.AcceptVisitor(v); @@ -371,7 +394,7 @@ namespace ICSharpCode.NRefactory.CSharp TypeResolveResult trr = rr as TypeResolveResult; if (trr != null) { CodeTypeReference typeRef; - if (useFullyQualifiedTypeNames) { + if (UseFullyQualifiedTypeNames) { typeRef = Convert(trr.Type); } else { typeRef = new CodeTypeReference(identifierExpression.Identifier); @@ -380,7 +403,7 @@ namespace ICSharpCode.NRefactory.CSharp return new CodeTypeReferenceExpression(typeRef); } MethodGroupResolveResult mgrr = rr as MethodGroupResolveResult; - if (mgrr != null) { + if (mgrr != null || identifierExpression.TypeArguments.Any()) { return new CodeMethodReferenceExpression(new CodeThisReferenceExpression(), identifierExpression.Identifier, Convert(identifierExpression.TypeArguments)); } return new CodeVariableReferenceExpression(identifierExpression.Identifier); @@ -658,7 +681,7 @@ namespace ICSharpCode.NRefactory.CSharp CodeObject IAstVisitor.VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration) { CodeTypeDelegate d = new CodeTypeDelegate(delegateDeclaration.Name); - d.Attributes = ConvertMemberAttributes(delegateDeclaration.Modifiers); + d.Attributes = ConvertMemberAttributes(delegateDeclaration.Modifiers, EntityType.TypeDefinition); d.CustomAttributes.AddRange(Convert(delegateDeclaration.Attributes)); d.ReturnType = Convert(delegateDeclaration.ReturnType); d.Parameters.AddRange(Convert(delegateDeclaration.Parameters)); @@ -666,13 +689,15 @@ namespace ICSharpCode.NRefactory.CSharp return d; } - static MemberAttributes ConvertMemberAttributes(Modifiers modifiers) + MemberAttributes ConvertMemberAttributes(Modifiers modifiers, EntityType entityType) { MemberAttributes a = 0; if ((modifiers & Modifiers.Abstract) != 0) a |= MemberAttributes.Abstract; if ((modifiers & Modifiers.Sealed) != 0) a |= MemberAttributes.Final; + if (entityType != EntityType.TypeDefinition && (modifiers & (Modifiers.Abstract | Modifiers.Override | Modifiers.Virtual)) == 0) + a |= MemberAttributes.Final; if ((modifiers & Modifiers.Static) != 0) a |= MemberAttributes.Static; if ((modifiers & Modifiers.Override) != 0) @@ -719,7 +744,7 @@ namespace ICSharpCode.NRefactory.CSharp { //bool isNestedType = typeStack.Count > 0; CodeTypeDeclaration typeDecl = new CodeTypeDeclaration(typeDeclaration.Name); - typeDecl.Attributes = ConvertMemberAttributes(typeDeclaration.Modifiers); + typeDecl.Attributes = ConvertMemberAttributes(typeDeclaration.Modifiers, EntityType.TypeDefinition); typeDecl.CustomAttributes.AddRange(Convert(typeDeclaration.Attributes)); switch (typeDeclaration.ClassType) { @@ -809,7 +834,12 @@ namespace ICSharpCode.NRefactory.CSharp CodeObject IAstVisitor.VisitEmptyStatement(EmptyStatement emptyStatement) { - return null; + return EmptyStatement(); + } + + CodeStatement EmptyStatement() + { + return new CodeExpressionStatement(new CodeObjectCreateExpression(new CodeTypeReference(typeof(object)))); } CodeObject IAstVisitor.VisitExpressionStatement(ExpressionStatement expressionStatement) @@ -817,10 +847,55 @@ namespace ICSharpCode.NRefactory.CSharp AssignmentExpression assignment = expressionStatement.Expression as AssignmentExpression; if (assignment != null && assignment.Operator == AssignmentOperatorType.Assign) { return new CodeAssignStatement(Convert(assignment.Left), Convert(assignment.Right)); + } else if (assignment != null && CanBeDuplicatedForCompoundAssignment(assignment.Left)) { + CodeBinaryOperatorType op; + switch (assignment.Operator) { + case AssignmentOperatorType.Add: + op = CodeBinaryOperatorType.Add; + break; + case AssignmentOperatorType.Subtract: + op = CodeBinaryOperatorType.Subtract; + break; + case AssignmentOperatorType.Multiply: + op = CodeBinaryOperatorType.Multiply; + break; + case AssignmentOperatorType.Divide: + op = CodeBinaryOperatorType.Divide; + break; + case AssignmentOperatorType.Modulus: + op = CodeBinaryOperatorType.Modulus; + break; + case AssignmentOperatorType.BitwiseAnd: + op = CodeBinaryOperatorType.BitwiseAnd; + break; + case AssignmentOperatorType.BitwiseOr: + op = CodeBinaryOperatorType.BitwiseOr; + break; + default: + return MakeSnippetStatement(expressionStatement); + } + var cboe = new CodeBinaryOperatorExpression(Convert(assignment.Left), op, Convert(assignment.Right)); + return new CodeAssignStatement(Convert(assignment.Left), cboe); + } + UnaryOperatorExpression unary = expressionStatement.Expression as UnaryOperatorExpression; + if (unary != null && CanBeDuplicatedForCompoundAssignment(unary.Expression)) { + var op = unary.Operator; + if (op == UnaryOperatorType.Increment || op == UnaryOperatorType.PostIncrement) { + var cboe = new CodeBinaryOperatorExpression(Convert(unary.Expression), CodeBinaryOperatorType.Add, new CodePrimitiveExpression(1)); + return new CodeAssignStatement(Convert(unary.Expression), cboe); + } else if (op == UnaryOperatorType.Decrement || op == UnaryOperatorType.PostDecrement) { + var cboe = new CodeBinaryOperatorExpression(Convert(unary.Expression), CodeBinaryOperatorType.Subtract, new CodePrimitiveExpression(1)); + return new CodeAssignStatement(Convert(unary.Expression), cboe); + } } return new CodeExpressionStatement(Convert(expressionStatement.Expression)); } + bool CanBeDuplicatedForCompoundAssignment(Expression expr) + { + return expr is IdentifierExpression; + } + CodeObject IAstVisitor.VisitFixedStatement(FixedStatement fixedStatement) { return MakeSnippetStatement(fixedStatement); @@ -956,7 +1031,7 @@ namespace ICSharpCode.NRefactory.CSharp CodeObject IAstVisitor.VisitWhileStatement(WhileStatement whileStatement) { - return new CodeIterationStatement(null, Convert(whileStatement.Condition), null, ConvertEmbeddedStatement(whileStatement.EmbeddedStatement)); + return new CodeIterationStatement(EmptyStatement(), Convert(whileStatement.Condition), EmptyStatement(), ConvertEmbeddedStatement(whileStatement.EmbeddedStatement)); } CodeObject IAstVisitor.VisitYieldBreakStatement(YieldBreakStatement yieldBreakStatement) @@ -977,7 +1052,7 @@ namespace ICSharpCode.NRefactory.CSharp CodeObject IAstVisitor.VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration) { CodeConstructor ctor = new CodeConstructor(); - ctor.Attributes = ConvertMemberAttributes(constructorDeclaration.Modifiers); + ctor.Attributes = ConvertMemberAttributes(constructorDeclaration.Modifiers, EntityType.Constructor); ctor.CustomAttributes.AddRange(Convert(constructorDeclaration.Attributes)); if (constructorDeclaration.Initializer.ConstructorInitializerType == ConstructorInitializerType.This) { ctor.ChainedConstructorArgs.AddRange(Convert(constructorDeclaration.Initializer.Arguments)); @@ -1019,7 +1094,7 @@ namespace ICSharpCode.NRefactory.CSharp } CodeMemberEvent e = new CodeMemberEvent(); - e.Attributes = ConvertMemberAttributes(eventDeclaration.Modifiers); + e.Attributes = ConvertMemberAttributes(eventDeclaration.Modifiers, EntityType.Event); e.CustomAttributes.AddRange(Convert(eventDeclaration.Attributes)); e.Name = vi.Name; e.Type = Convert(eventDeclaration.ReturnType); @@ -1037,7 +1112,7 @@ namespace ICSharpCode.NRefactory.CSharp { foreach (VariableInitializer vi in fieldDeclaration.Variables) { CodeMemberField f = new CodeMemberField(Convert(fieldDeclaration.ReturnType), vi.Name); - f.Attributes = ConvertMemberAttributes(fieldDeclaration.Modifiers); + f.Attributes = ConvertMemberAttributes(fieldDeclaration.Modifiers, EntityType.Field); f.CustomAttributes.AddRange(Convert(fieldDeclaration.Attributes)); f.InitExpression = ConvertVariableInitializer(vi.Initializer, fieldDeclaration.ReturnType); AddTypeMember(f); @@ -1048,7 +1123,7 @@ namespace ICSharpCode.NRefactory.CSharp CodeObject IAstVisitor.VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration) { CodeMemberProperty p = new CodeMemberProperty(); - p.Attributes = ConvertMemberAttributes(indexerDeclaration.Modifiers); + p.Attributes = ConvertMemberAttributes(indexerDeclaration.Modifiers, EntityType.Indexer); p.CustomAttributes.AddRange(Convert(indexerDeclaration.Attributes)); p.Name = "Items"; p.PrivateImplementationType = Convert(indexerDeclaration.PrivateImplementationType); @@ -1069,7 +1144,7 @@ namespace ICSharpCode.NRefactory.CSharp CodeObject IAstVisitor.VisitMethodDeclaration(MethodDeclaration methodDeclaration) { CodeMemberMethod m = new CodeMemberMethod(); - m.Attributes = ConvertMemberAttributes(methodDeclaration.Modifiers); + m.Attributes = ConvertMemberAttributes(methodDeclaration.Modifiers, EntityType.Method); m.CustomAttributes.AddRange(Convert(methodDeclaration.Attributes.Where(a => a.AttributeTarget != "return"))); m.ReturnTypeCustomAttributes.AddRange(Convert(methodDeclaration.Attributes.Where(a => a.AttributeTarget == "return"))); @@ -1087,7 +1162,7 @@ namespace ICSharpCode.NRefactory.CSharp CodeObject IAstVisitor.VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration) { CodeMemberMethod m = new CodeMemberMethod(); - m.Attributes = ConvertMemberAttributes(operatorDeclaration.Modifiers); + m.Attributes = ConvertMemberAttributes(operatorDeclaration.Modifiers, EntityType.Method); m.CustomAttributes.AddRange(Convert(operatorDeclaration.Attributes.Where(a => a.AttributeTarget != "return"))); m.ReturnTypeCustomAttributes.AddRange(Convert(operatorDeclaration.Attributes.Where(a => a.AttributeTarget == "return"))); @@ -1129,7 +1204,7 @@ namespace ICSharpCode.NRefactory.CSharp CodeObject IAstVisitor.VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration) { CodeMemberProperty p = new CodeMemberProperty(); - p.Attributes = ConvertMemberAttributes(propertyDeclaration.Modifiers); + p.Attributes = ConvertMemberAttributes(propertyDeclaration.Modifiers, EntityType.Property); p.CustomAttributes.AddRange(Convert(propertyDeclaration.Attributes)); p.Name = propertyDeclaration.Name; p.PrivateImplementationType = Convert(propertyDeclaration.PrivateImplementationType); @@ -1181,7 +1256,7 @@ namespace ICSharpCode.NRefactory.CSharp CodeObject IAstVisitor.VisitSimpleType(SimpleType simpleType) { - if (useFullyQualifiedTypeNames) { + if (UseFullyQualifiedTypeNames) { IType type = Resolve(simpleType).Type; if (type.Kind != TypeKind.Unknown) return Convert(type); @@ -1198,7 +1273,7 @@ namespace ICSharpCode.NRefactory.CSharp tr.TypeArguments.AddRange(Convert(memberType.TypeArguments)); return tr; } - if (useFullyQualifiedTypeNames || memberType.IsDoubleColon) { + if (UseFullyQualifiedTypeNames || memberType.IsDoubleColon) { IType type = Resolve(memberType).Type; if (type.Kind != TypeKind.Unknown) return Convert(type); @@ -1309,7 +1384,7 @@ namespace ICSharpCode.NRefactory.CSharp return null; } - CodeObject IAstVisitor.VisitPatternPlaceholder(AstNode placeholder, ICSharpCode.NRefactory.PatternMatching.Pattern pattern) + CodeObject IAstVisitor.VisitPatternPlaceholder(AstNode placeholder, Pattern pattern) { return null; } diff --git a/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs b/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs index 8d750b714c..3f2c274438 100644 --- a/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs +++ b/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs @@ -3750,7 +3750,7 @@ namespace ICSharpCode.NRefactory.CSharp return AstType.Null; } - public AstNode ParseExpression (TextReader reader) + public Expression ParseExpression (TextReader reader) { var es = ParseStatements (new StringReader ("tmp = " + Environment.NewLine + reader.ReadToEnd () + ";"), -1).FirstOrDefault () as ExpressionStatement; if (es != null) { @@ -3758,7 +3758,7 @@ namespace ICSharpCode.NRefactory.CSharp if (ae != null) return ae.Right; } - return null; + return Expression.Null; } /// diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeDomConvertVisitorTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeDomConvertVisitorTests.cs index 92efb0f156..52d55315bd 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeDomConvertVisitorTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeDomConvertVisitorTests.cs @@ -20,11 +20,11 @@ using System; using System.CodeDom; using System.CodeDom.Compiler; using System.IO; +using System.Linq; using System.Text.RegularExpressions; using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.CSharp.TypeSystem; using ICSharpCode.NRefactory.TypeSystem; -using ICSharpCode.NRefactory.TypeSystem.Implementation; using Microsoft.CSharp; using NUnit.Framework; @@ -45,138 +45,388 @@ namespace ICSharpCode.NRefactory.CSharp parsedFile.RootUsingScope.Usings.Add(MakeReference("System.Linq")); convertVisitor = new CodeDomConvertVisitor(); + convertVisitor.AllowSnippetNodes = false; convertVisitor.UseFullyQualifiedTypeNames = true; } - string Convert(Expression expr) + #region Helper methods + string ConvertHelper(AstNode node, Action action) { CSharpResolver resolver = new CSharpResolver(compilation); resolver = resolver.WithCurrentUsingScope(parsedFile.RootUsingScope.Resolve(compilation)); resolver = resolver.WithCurrentTypeDefinition(compilation.FindType(KnownTypeCode.Object).GetDefinition()); - var codeExpr = (CodeExpression)convertVisitor.Convert(expr, new CSharpAstResolver(resolver, expr, parsedFile)); + var codeObj = convertVisitor.Convert(node, new CSharpAstResolver(resolver, node)); StringWriter writer = new StringWriter(); writer.NewLine = " "; - new CSharpCodeProvider().GenerateCodeFromExpression(codeExpr, writer, new CodeGeneratorOptions { IndentString = " " }); - return Regex.Replace(writer.ToString(), @"\s+", " "); + action(new CSharpCodeProvider(), codeObj, writer, new CodeGeneratorOptions { IndentString = " " }); + return Regex.Replace(writer.ToString(), @"\s+", " ").Trim(); } + string ConvertExpression(Expression expr) + { + return ConvertHelper(expr, (p,obj,w,opt) => p.GenerateCodeFromExpression((CodeExpression)obj, w, opt)); + } + + string ConvertExpression(string code) + { + CSharpParser parser = new CSharpParser(); + var expr = parser.ParseExpression(new StringReader(code)); + Assert.IsFalse(parser.HasErrors); + return ConvertExpression(expr); + } + + string ConvertStatement(Statement statement) + { + return ConvertHelper(statement, (p,obj,w,opt) => p.GenerateCodeFromStatement((CodeStatement)obj, w, opt)); + } + + string ConvertStatement(string code) + { + CSharpParser parser = new CSharpParser(); + var expr = parser.ParseStatements(new StringReader(code)).Single(); + Assert.IsFalse(parser.HasErrors); + return ConvertStatement(expr); + } + + string ConvertMember(EntityDeclaration entity) + { + return ConvertHelper(entity, (p,obj,w,opt) => p.GenerateCodeFromMember((CodeTypeMember)obj, w, opt)); + } + + string ConvertMember(string code) + { + CSharpParser parser = new CSharpParser(); + var expr = parser.ParseTypeMembers(new StringReader(code)).Single(); + Assert.IsFalse(parser.HasErrors); + return ConvertMember(expr); + } + + string ConvertTypeDeclaration(EntityDeclaration decl) + { + return ConvertHelper(decl, (p,obj,w,opt) => p.GenerateCodeFromType((CodeTypeDeclaration)obj, w, opt)); + } + + string ConvertTypeDeclaration(string code) + { + CSharpParser parser = new CSharpParser(); + var cu = parser.Parse(new StringReader(code), "program.cs"); + Assert.IsFalse(parser.HasErrors); + return ConvertTypeDeclaration((EntityDeclaration)cu.Children.Single()); + } + #endregion + + #region Type References [Test] - public void CreateArray() + public void MultidimensionalArrayTypeReference() { - Assert.AreEqual("new int[10]", Convert( - new ArrayCreateExpression { - Type = new PrimitiveType("int"), - Arguments = { new PrimitiveExpression(10) } - })); + Assert.AreEqual("default(int[,][])", ConvertExpression("default(int[,][])")); } [Test] - public void CreateJaggedArray() + public void NestedTypeInGenericType() { - Assert.AreEqual("new int[10][]", Convert( - new ArrayCreateExpression { - Type = new PrimitiveType("int"), - Arguments = { new PrimitiveExpression(10) }, - AdditionalArraySpecifiers = { new ArraySpecifier() } - })); + Assert.AreEqual("default(System.Collections.Generic.List.Enumerator)", + ConvertExpression("default(List.Enumerator)")); + convertVisitor.UseFullyQualifiedTypeNames = false; + Assert.AreEqual("default(List.Enumerator)", + ConvertExpression("default(List.Enumerator)")); } + #endregion + #region Arrays [Test] + public void CreateArray() + { + Assert.AreEqual("new int[10]", ConvertExpression("new int[10]")); + } + + [Test, ExpectedException(typeof(NotSupportedException))] + public void CreateJaggedArray() + { + ConvertExpression("new int[10][]"); + } + + [Test, ExpectedException(typeof(NotSupportedException))] public void Create2DArray() { - Assert.AreEqual("new int[10, 20]", Convert( - new ArrayCreateExpression { - Type = new PrimitiveType("int"), - Arguments = { new PrimitiveExpression(10), new PrimitiveExpression(20) } - })); + ConvertExpression("new int[10, 20]"); } [Test] public void CreateImplicitlyTypedArray() { // implicitly-typed array not supported in CodeDom, so the conversion should infer the type - Assert.AreEqual("new int[] { 1, 2, 3}", Convert( - new ArrayCreateExpression { - AdditionalArraySpecifiers = { new ArraySpecifier() }, - Initializer = new ArrayInitializerExpression { - Elements = { - new PrimitiveExpression(1), - new PrimitiveExpression(2), - new PrimitiveExpression(3) - } - } - })); + Assert.AreEqual("new int[] { 1, 2, 3}", ConvertExpression("new [] { 1, 2, 3 }")); + Assert.AreEqual("new System.Collections.Generic.List[] { new System.Collections.Generic.List()}", + ConvertExpression("new [] { new List() }")); } - [Test] + [Test, ExpectedException(typeof(NotSupportedException))] public void Create2DImplicitlyTypedArray() { - Assert.AreEqual("new int[,] { { 1, 2 }, { 3, 4 }}", Convert( - new ArrayCreateExpression { - AdditionalArraySpecifiers = { new ArraySpecifier(2) }, - Initializer = new ArrayInitializerExpression { - Elements = { - new ArrayInitializerExpression(new PrimitiveExpression(1), new PrimitiveExpression(2)), - new ArrayInitializerExpression(new PrimitiveExpression(3), new PrimitiveExpression(4)) - } - } - })); + ConvertExpression("new [,] { { 1, 2 }, { 3, 4 }}"); } + #endregion + #region Operators [Test] - public void AdditionOperator() + public void ArithmeticOperators() { - Assert.AreEqual("(0 + 1)", Convert( - new BinaryOperatorExpression(new PrimitiveExpression(0), BinaryOperatorType.Add, new PrimitiveExpression(1)))); + Assert.AreEqual("(0 + 1)", ConvertExpression("0 + 1")); + Assert.AreEqual("(0 - 1)", ConvertExpression("0 - 1")); + Assert.AreEqual("(0 * 1)", ConvertExpression("0 * 1")); + Assert.AreEqual("(0 / 1)", ConvertExpression("0 / 1")); + Assert.AreEqual("(0 % 1)", ConvertExpression("0 % 1")); + Assert.AreEqual("(0 & 1)", ConvertExpression("0 & 1")); + Assert.AreEqual("(0 | 1)", ConvertExpression("0 | 1")); + Assert.AreEqual("(0 < 1)", ConvertExpression("0 < 1")); + Assert.AreEqual("(0 > 1)", ConvertExpression("0 > 1")); + Assert.AreEqual("(0 <= 1)", ConvertExpression("0 <= 1")); + Assert.AreEqual("(0 >= 1)", ConvertExpression("0 >= 1")); + Assert.AreEqual("(true && false)", ConvertExpression("true && false")); + Assert.AreEqual("(true || false)", ConvertExpression("true || false")); } [Test] public void EqualityOperator() { - Assert.AreEqual("(0 == 1)", Convert( - new BinaryOperatorExpression(new PrimitiveExpression(0), BinaryOperatorType.Equality, new PrimitiveExpression(1)))); + Assert.AreEqual("(0 == 1)", ConvertExpression("0 == 1")); + Assert.AreEqual("(default(object) == null)", ConvertExpression("default(object) == null")); } [Test] public void InEqualityOperator() { - Assert.AreEqual("((0 == 1) == false)", Convert( - new BinaryOperatorExpression(new PrimitiveExpression(0), BinaryOperatorType.InEquality, new PrimitiveExpression(1)))); + Assert.AreEqual("((0 == 1) == false)", ConvertExpression("0 != 1")); + Assert.AreEqual("(default(object) != null)", ConvertExpression("default(object) != null")); } [Test] - public void ReferenceInEqualityOperator() + public void UnaryOperators() { - Assert.AreEqual("(default(object) != null)", Convert( - new BinaryOperatorExpression(new DefaultValueExpression(new PrimitiveType("object")), BinaryOperatorType.InEquality, new NullReferenceExpression()))); + Assert.AreEqual("(a == false)", ConvertExpression("!a")); + Assert.AreEqual("(0 - a)", ConvertExpression("-a")); + Assert.AreEqual("a", ConvertExpression("+a")); } + [Test] + public void Cast() + { + Assert.AreEqual("((double)(0))", ConvertExpression("(double)0")); + } + #endregion + + #region Member Access [Test] public void StaticProperty() { - Assert.AreEqual("System.Environment.TickCount", Convert( - new IdentifierExpression("Environment").Member("TickCount"))); + Assert.AreEqual("System.Environment.TickCount", ConvertExpression("Environment.TickCount")); } [Test] public void InstanceMethodInvocation() { - Assert.AreEqual("this.Equals(null)", - Convert(new IdentifierExpression("Equals").Invoke(new NullReferenceExpression()))); + Assert.AreEqual("this.Equals(null)", ConvertExpression("Equals(null)")); } [Test] public void StaticMethodInvocation() { - Assert.AreEqual("object.Equals(null, null)", - Convert(new IdentifierExpression("Equals").Invoke(new NullReferenceExpression(), new NullReferenceExpression()))); + Assert.AreEqual("object.Equals(null, null)", ConvertExpression("Equals(null, null)")); + } + + [Test] + public void BaseMemberAccess() + { + Assert.AreEqual("base.X", ConvertExpression("base.X")); + Assert.AreEqual("base[i]", ConvertExpression("base[i]")); + } + + [Test] + public void GenericMethodReference() + { + Assert.AreEqual("this.Stuff", ConvertExpression("this.Stuff")); + Assert.AreEqual("this.Stuff", ConvertExpression("Stuff")); + } + + [Test] + public void ByReferenceCall() + { + Assert.AreEqual("a.Call(ref x, out y, z)", ConvertExpression("a.Call(ref x, out y, z)")); + } + + [Test] + public void MemberAccessOnType() + { + Assert.AreEqual("string.Empty", ConvertExpression("string.Empty")); + } + #endregion + + #region Statements + [Test] + public void MethodInvocationStatement() + { + Assert.AreEqual("a.SomeMethod();", ConvertStatement("a.SomeMethod();")); + } + + [Test] + public void Assignment() + { + Assert.AreEqual("a = 1;", ConvertStatement("a = 1;")); + } + + [Test, ExpectedException(typeof(NotSupportedException))] + public void AssignmentNotSupportedInExpression() + { + ConvertStatement("a = b = 1;"); + } + + [Test] + public void BlockStatement() + { + Assert.AreEqual("if (true) { a = 1; b = 2; }", + ConvertStatement("{ a = 1; b = 2; }")); + } + + [Test] + public void CompoundAssign() + { + Assert.AreEqual("a = (a + 1);", ConvertStatement("a += 1;")); + Assert.AreEqual("a = (a - 1);", ConvertStatement("a -= 1;")); + Assert.AreEqual("a = (a * 1);", ConvertStatement("a *= 1;")); + Assert.AreEqual("a = (a / 1);", ConvertStatement("a /= 1;")); + Assert.AreEqual("a = (a % 1);", ConvertStatement("a %= 1;")); + Assert.AreEqual("a = (a & 1);", ConvertStatement("a &= 1;")); + Assert.AreEqual("a = (a | 1);", ConvertStatement("a |= 1;")); + } + + [Test] + public void Increment() + { + Assert.AreEqual("a = (a + 1);", ConvertStatement("a++;")); + Assert.AreEqual("a = (a + 1);", ConvertStatement("++a;")); + Assert.AreEqual("a = (a - 1);", ConvertStatement("a--;")); + Assert.AreEqual("a = (a - 1);", ConvertStatement("--a;")); + } + + [Test] + public void ForLoop() + { + Assert.AreEqual("for (int i = 0; (i < 10); i = (i + 1)) { }", + ConvertStatement("for (int i = 0; i < 10; i++) {}")); + } + + [Test] + public void WhileLoop() + { + Assert.AreEqual("for (new object(); (i < 10); new object()) { }", + ConvertStatement("while (i < 10);")); + } + + [Test] + public void VariableDeclarationWithArrayInitializer() + { + Assert.AreEqual("int[] nums = new int[] { 1, 2};", + ConvertStatement("int[] nums = { 1, 2 };")); + } + + [Test] + public void TryCatch() + { + Assert.AreEqual("try { a = 1; } catch (System.Exception ex) { ex.ToString(); }", + ConvertStatement("try { a = 1; } catch (Exception ex) { ex.ToString(); }")); + } + + [Test] + public void TryEmptyCatch() + { + Assert.AreEqual("try { a = 1; } catch (System.Exception ) { }", + ConvertStatement("try { a = 1; } catch (Exception) { }")); + } + + [Test] + public void TryFinally() + { + Assert.AreEqual("try { a = 1; } finally { a = 0; }", + ConvertStatement("try { a = 1; } finally { a = 0; }")); + } + #endregion + + #region Type Members + [Test] + public void MethodParameterNamedValue() + { + Assert.AreEqual("void M(string value) { System.Console.WriteLine(value); }", + ConvertMember("void M(string value) { Console.WriteLine(value); }")); + } + + [Test] + public void ValueInProperty() + { + Assert.AreEqual("string P { set { System.Console.WriteLine(value); } }", + ConvertMember("string P { set { Console.WriteLine(value); } }")); + } + + [Test] + public void MethodWithAttribute() + { + Assert.AreEqual("[Test()] void MethodWithAttribute() { }", + ConvertMember("[Test] void MethodWithAttribute() { }")); + } + + [Test] + public void PublicNonVirtualMethod() + { + Assert.AreEqual("public void Method() { }", + ConvertMember("public void Method() { }")); + } + + [Test] + public void PublicVirtualMethod() + { + Assert.AreEqual("public virtual void Method() { }", + ConvertMember("public virtual void Method() { }")); + } + + [Test] + public void NestedClass() + { + Assert.AreEqual("public class Outer { public class Inner { } }", + ConvertTypeDeclaration("class Outer { class Inner { } }")); + } + + [Test] + public void Constructor() + { + string code = "public class Test : Base { public Test(string x) : base(x) { } }"; + Assert.AreEqual(code, ConvertTypeDeclaration(code)); + } + + [Test] + public void Enum() + { + string code = "public enum E { [Description(\"Text\")] None, B = 2, }"; + Assert.AreEqual(code, ConvertTypeDeclaration(code)); + } + + [Test] + public void Field() + { + Assert.AreEqual("public class X {" + + " int A;" + + " int B; }", + ConvertMember("public class X { int A, B; }")); } [Test] - public void NotOperator() + public void Event() { - Assert.AreEqual("(a == false)", Convert(new UnaryOperatorExpression(UnaryOperatorType.Not, new IdentifierExpression("a")))); + Assert.AreEqual("public class X {" + + " protected event System.EventHandler A;" + + " protected event System.EventHandler B; }", + ConvertMember("public class X { protected event EventHandler A, B; }")); } + #endregion } }