Browse Source

Update NRefactory to v5.2.0-554-g755e37e

newNRvisualizers
Daniel Grunwald 13 years ago
parent
commit
7f2f6dc332
  1. 15
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstType.cs
  2. 9
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Comment.cs
  3. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/UsingDeclaration.cs
  4. 1
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs
  5. 14
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Formatter/CSharpFormattingOptions.cs
  6. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Formatter/FormattingOptionsFactory.cs
  7. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  8. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-parser.cs
  9. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-parser.jay
  10. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-tokenizer.cs
  11. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/statement.cs
  12. 156
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/AddUsingAction.cs
  13. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateFieldAction.cs
  14. 75
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/SortUsingsAction.cs
  15. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssue.cs
  16. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExceptionRethrowIssue.cs
  17. 17
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/GatherVisitorBase.cs
  18. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/InconsistentNamingIssue.cs
  19. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/IncorrectExceptionParameterOrderingIssue.cs
  20. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceToStaticMemberViaDerivedTypeIssue.cs
  21. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ResultOfAsyncCallShouldNotBeIgnoredIssue.cs
  22. 22
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs
  23. 180
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/UsingHelper.cs
  24. 3
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/AwaitResolveResult.cs
  25. 52
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  26. 1
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs
  27. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs
  28. 229
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/AddUsing/AddUsingActionAlphabeticalTests.cs
  29. 203
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/AddUsing/AddUsingActionInsideNamespaceTests.cs
  30. 320
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/AddUsing/AddUsingActionTests.cs
  31. 248
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/AddUsing/AddUsingRunActionTests.cs
  32. 40
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ContextActionTestBase.cs
  33. 17
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/SortUsingsTests.cs
  34. 5
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs
  35. 33
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs
  36. 374
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnaryOperatorTests.cs
  37. 23
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/FormattingTests/TestStatementIndentation.cs
  38. 5
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
  39. 16
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs
  40. 24
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs
  41. 46
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs
  42. 22
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/KnownTypeReference.cs

15
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstType.cs

@ -251,5 +251,20 @@ namespace ICSharpCode.NRefactory.CSharp @@ -251,5 +251,20 @@ namespace ICSharpCode.NRefactory.CSharp
{
return new TypeReferenceExpression { Type = this }.Invoke(methodName, typeArguments, arguments);
}
/// <summary>
/// Creates a simple AstType from a dotted name.
/// Does not support generics, arrays, etc. - just simple dotted names,
/// e.g. namespace names.
/// </summary>
public static AstType Create(string dottedName)
{
string[] parts = dottedName.Split('.');
AstType type = new SimpleType(parts[0]);
for (int i = 1; i < parts.Length; i++) {
type = new MemberType(type, parts[i]);
}
return type;
}
}
}

9
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Comment.cs

@ -65,6 +65,15 @@ namespace ICSharpCode.NRefactory.CSharp @@ -65,6 +65,15 @@ namespace ICSharpCode.NRefactory.CSharp
set { ThrowIfFrozen(); commentType = value; }
}
/// <summary>
/// Returns true if the <see cref="CommentType"/> is Documentation or MultiLineDocumentation.
/// </summary>
public bool IsDocumentation {
get {
return commentType == CommentType.Documentation || commentType == CommentType.MultiLineDocumentation;
}
}
bool startsLine;
public bool StartsLine {

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/UsingDeclaration.cs

@ -67,7 +67,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -67,7 +67,7 @@ namespace ICSharpCode.NRefactory.CSharp
public UsingDeclaration (string nameSpace)
{
AddChild (new SimpleType (nameSpace), ImportRole);
AddChild (AstType.Create (nameSpace), ImportRole);
}
public UsingDeclaration (AstType import)

1
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs

@ -261,6 +261,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -261,6 +261,7 @@ namespace ICSharpCode.NRefactory.CSharp
public override void VisitUsingDeclaration(UsingDeclaration usingDeclaration)
{
if (usingDeclaration.PrevSibling != null && !(usingDeclaration.PrevSibling is UsingDeclaration || usingDeclaration.PrevSibling is UsingAliasDeclaration)) {
FixIndentationForceNewLine(usingDeclaration.StartLocation);
EnsureBlankLinesBefore(usingDeclaration, policy.BlankLinesBeforeUsings);
} else if (!(usingDeclaration.NextSibling is UsingDeclaration || usingDeclaration.NextSibling is UsingAliasDeclaration)) {
FixIndentationForceNewLine(usingDeclaration.StartLocation);

14
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Formatter/CSharpFormattingOptions.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// CSharpFormattingOptions.cs
//
// Author:
@ -68,6 +68,11 @@ namespace ICSharpCode.NRefactory.CSharp @@ -68,6 +68,11 @@ namespace ICSharpCode.NRefactory.CSharp
SameLine
}
public enum UsingPlacement {
TopOfFile,
InsideNamespace
}
public class CSharpFormattingOptions
{
public string Name {
@ -859,6 +864,13 @@ namespace ICSharpCode.NRefactory.CSharp @@ -859,6 +864,13 @@ namespace ICSharpCode.NRefactory.CSharp
}
#endregion
#region Using Declarations
public UsingPlacement UsingPlacement {
get;
set;
}
#endregion
internal CSharpFormattingOptions()
{
}

4
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Formatter/FormattingOptionsFactory.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// FormattingOptionsFactory.cs
//
// Author:
@ -168,7 +168,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -168,7 +168,7 @@ namespace ICSharpCode.NRefactory.CSharp
BlankLinesBeforeUsings = 0,
BlankLinesAfterUsings = 1,
UsingPlacement = UsingPlacement.TopOfFile,
BlankLinesBeforeFirstDeclaration = 0,
BlankLinesBetweenTypes = 1,

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj

@ -267,6 +267,7 @@ @@ -267,6 +267,7 @@
<Compile Include="Parser\mcs\visit.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="QueryExpressionExpander.cs" />
<Compile Include="Refactoring\CodeActions\AddUsingAction.cs" />
<Compile Include="Refactoring\CodeActions\ConvertAsToCastAction.cs" />
<Compile Include="Refactoring\CodeActions\ConvertCastToAsAction.cs" />
<Compile Include="Refactoring\CodeActions\ConvertConditionalToIfAction.cs" />
@ -329,6 +330,7 @@ @@ -329,6 +330,7 @@
<Compile Include="Refactoring\CodeIssues\VariableOnlyAssignedIssues\VariableOnlyAssignedIssue.cs" />
<Compile Include="Refactoring\DocumentScript.cs" />
<Compile Include="Refactoring\CodeActions\ExtractAnonymousMethodAction.cs" />
<Compile Include="Refactoring\UsingHelper.cs" />
<Compile Include="Refactoring\LambdaHelper.cs" />
<Compile Include="Refactoring\PatternHelper.cs" />
<Compile Include="Refactoring\RefactoringAstHelper.cs" />

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-parser.cs

@ -9056,7 +9056,7 @@ void case_903() @@ -9056,7 +9056,7 @@ void case_903()
void case_904()
#line 6041 "cs-parser.jay"
{
yyVal = new TryFinally (new TryCatch ((Block) yyVals[-3+yyTop], (List<Catch>) yyVals[-2+yyTop], Location.Null, true), (Block) yyVals[0+yyTop], GetLocation (yyVals[-4+yyTop]));
yyVal = new TryFinally (new TryCatch ((Block) yyVals[-3+yyTop], (List<Catch>) yyVals[-2+yyTop], GetLocation (yyVals[-4+yyTop]), true), (Block) yyVals[0+yyTop], GetLocation (yyVals[-4+yyTop]));
lbag.AddStatement (yyVal, GetLocation (yyVals[-1+yyTop]));
}

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-parser.jay

@ -6039,7 +6039,7 @@ try_statement @@ -6039,7 +6039,7 @@ try_statement
}
| TRY block catch_clauses FINALLY block
{
$$ = new TryFinally (new TryCatch ((Block) $2, (List<Catch>) $3, Location.Null, true), (Block) $5, GetLocation ($1));
$$ = new TryFinally (new TryCatch ((Block) $2, (List<Catch>) $3, GetLocation ($1), true), (Block) $5, GetLocation ($1));
lbag.AddStatement ($$, GetLocation ($4));
}
| TRY block error

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-tokenizer.cs

@ -1572,7 +1572,7 @@ namespace Mono.CSharp @@ -1572,7 +1572,7 @@ namespace Mono.CSharp
#endif
number_pos = 0;
var loc = Location;
// bool hasLeadingDot = c == '.';
bool hasLeadingDot = c == '.';
if (c >= '0' && c <= '9'){
if (c == '0'){

6
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/statement.cs

@ -2076,8 +2076,8 @@ namespace Mono.CSharp { @@ -2076,8 +2076,8 @@ namespace Mono.CSharp {
static int id;
public int ID = id++;
// static int clone_id_counter;
// int clone_id;
static int clone_id_counter;
int clone_id;
#endif
// int assignable_slots;
@ -2396,7 +2396,7 @@ namespace Mono.CSharp { @@ -2396,7 +2396,7 @@ namespace Mono.CSharp {
{
Block target = (Block) t;
#if DEBUG
// target.clone_id = clone_id_counter++;
target.clone_id = clone_id_counter++;
#endif
clonectx.AddBlockMap (this, target);

156
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/AddUsingAction.cs

@ -0,0 +1,156 @@ @@ -0,0 +1,156 @@
// Copyright (c) 2013 Daniel Grunwald
//
// 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.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// 1) When a type cannot be resolved, offers to add a using declaration
/// or to replace it with the fully qualified type name.
/// 2) When an extension method cannot be resolved, offers to add a using declaration.
/// 3) When the caret is on a namespace name, offers to add a using declaration
/// and simplify the type references to use the new shorter option.
/// </summary>
[ContextAction ("Add using", Description = "Add missing using declaration.")]
public class AddUsingAction : ICodeActionProvider
{
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
AstNode node = context.GetNode();
if (node is Identifier)
node = node.Parent;
if (node is SimpleType || node is IdentifierExpression) {
return GetActionsForType(context, node)
.Concat(GetActionsForAddNamespaceUsing(context, node));
} else if (node is MemberReferenceExpression && node.Parent is InvocationExpression) {
return GetActionsForExtensionMethodInvocation(context, (InvocationExpression)node.Parent);
} else if (node is MemberReferenceExpression) {
return GetActionsForAddNamespaceUsing(context, node);
} else {
return EmptyList<CodeAction>.Instance;
}
}
IEnumerable<CodeAction> GetActionsForType(RefactoringContext context, AstNode node)
{
var rr = context.Resolve(node) as UnknownIdentifierResolveResult;
if (rr == null)
return EmptyList<CodeAction>.Instance;
string identifier = rr.Identifier;
int tc = rr.TypeArgumentCount;
string attributeIdentifier = null;
if (node.Parent is Attribute)
attributeIdentifier = identifier + "Attribute";
var lookup = new MemberLookup(null, context.Compilation.MainAssembly);
List<CodeAction> actions = new List<CodeAction>();
foreach (var typeDefinition in context.Compilation.GetAllTypeDefinitions()) {
if ((typeDefinition.Name == identifier || typeDefinition.Name == attributeIdentifier)
&& typeDefinition.TypeParameterCount == tc
&& lookup.IsAccessible(typeDefinition, false))
{
if (typeDefinition.DeclaringTypeDefinition == null) {
actions.Add(NewUsingAction(context, node, typeDefinition.Namespace));
}
actions.Add(ReplaceWithFullTypeNameAction(context, node, typeDefinition));
}
}
return actions;
}
CodeAction NewUsingAction(RefactoringContext context, AstNode node, string ns)
{
return new CodeAction("using " + ns + ";", s => UsingHelper.InsertUsingAndRemoveRedundantNamespaceUsage(context, s, ns));
}
CodeAction ReplaceWithFullTypeNameAction(RefactoringContext context, AstNode node, ITypeDefinition typeDefinition)
{
AstType astType = context.CreateShortType(typeDefinition);
string textWithoutGenerics = astType.GetText();
foreach (var typeArg in node.GetChildrenByRole(Roles.TypeArgument)) {
astType.AddChild(typeArg.Clone(), Roles.TypeArgument);
}
return new CodeAction(textWithoutGenerics, s => s.Replace(node, astType));
}
IEnumerable<CodeAction> GetActionsForExtensionMethodInvocation(RefactoringContext context, InvocationExpression invocation)
{
var rr = context.Resolve(invocation) as UnknownMethodResolveResult;
if (rr == null)
return EmptyList<CodeAction>.Instance;
var lookup = new MemberLookup(null, context.Compilation.MainAssembly);
HashSet<string> namespaces = new HashSet<string>();
List<CodeAction> result = new List<CodeAction>();
foreach (var typeDefinition in context.Compilation.GetAllTypeDefinitions()) {
if (!(typeDefinition.HasExtensionMethods && lookup.IsAccessible(typeDefinition, false))) {
continue;
}
foreach (var method in typeDefinition.Methods.Where(m => m.IsExtensionMethod && m.Name == rr.MemberName)) {
IType[] inferredTypes;
if (CSharpResolver.IsEligibleExtensionMethod(rr.TargetType, method, true, out inferredTypes)) {
// avoid offering the same namespace twice
if (namespaces.Add(typeDefinition.Namespace)) {
result.Add(NewUsingAction(context, invocation, typeDefinition.Namespace));
}
break; // continue with the next type
}
}
}
return result;
}
IEnumerable<CodeAction> GetActionsForAddNamespaceUsing(RefactoringContext context, AstNode node)
{
var nrr = context.Resolve(node) as NamespaceResolveResult;
if (nrr == null)
return EmptyList<CodeAction>.Instance;
var trr = context.Resolve(node.Parent) as TypeResolveResult;
if (trr == null)
return EmptyList<CodeAction>.Instance;
ITypeDefinition typeDef = trr.Type.GetDefinition();
if (typeDef == null)
return EmptyList<CodeAction>.Instance;
IList<IType> typeArguments;
ParameterizedType parameterizedType = trr.Type as ParameterizedType;
if (parameterizedType != null)
typeArguments = parameterizedType.TypeArguments;
else
typeArguments = EmptyList<IType>.Instance;
var resolver = context.GetResolverStateBefore(node.Parent);
if (resolver.ResolveSimpleName(typeDef.Name, typeArguments) is UnknownIdentifierResolveResult) {
// It's possible to remove the explicit namespace usage and introduce a using instead
return new[] { NewUsingAction(context, node, typeDef.Namespace) };
}
return EmptyList<CodeAction>.Instance;
}
}
}

4
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateFieldAction.cs

@ -276,7 +276,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -276,7 +276,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
var type = GetValidTypes(context.Resolver, expr).ToArray();
var typeInference = new TypeInference(context.Compilation);
typeInference.Algorithm = TypeInferenceAlgorithm.ImprovedReturnAllResults;
typeInference.Algorithm = TypeInferenceAlgorithm.Improved;
var inferedType = typeInference.FindTypeInBounds(type, emptyTypes);
if (inferedType.Kind == TypeKind.Unknown)
return new PrimitiveType("object");
@ -287,7 +287,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -287,7 +287,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
var type = GetValidTypes(context.Resolver, expr).ToArray();
var typeInference = new TypeInference(context.Compilation);
typeInference.Algorithm = TypeInferenceAlgorithm.ImprovedReturnAllResults;
typeInference.Algorithm = TypeInferenceAlgorithm.Improved;
var inferedType = typeInference.FindTypeInBounds(type, emptyTypes);
return inferedType;
}

75
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/SortUsingsAction.cs

@ -23,7 +23,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -23,7 +23,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
foreach (var block in blocks)
{
var originalNodes = block.ToArray();
var sortedNodes = SortUsingBlock(originalNodes, context).ToArray();
var sortedNodes = UsingHelper.SortUsingBlock(originalNodes, context).ToArray();
for (var i = 0; i < originalNodes.Length; ++i)
script.Replace(originalNodes[i], sortedNodes[i].Clone());
@ -68,78 +68,5 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -68,78 +68,5 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
for (var node = firstNode; IsUsingDeclaration(node); node = node.NextSibling)
yield return node;
}
private static IEnumerable<AstNode> SortUsingBlock(IEnumerable<AstNode> nodes, RefactoringContext context)
{
var infos = nodes.Select(_ => new UsingInfo(_, context));
var orderedInfos = infos.OrderBy(_ => _, new UsingInfoComparer());
var orderedNodes = orderedInfos.Select(_ => _.Node);
return orderedNodes;
}
private sealed class UsingInfo
{
public AstNode Node { get; private set; }
public string Alias { get; private set; }
public string Name { get; private set; }
public bool IsAlias { get; private set; }
public bool IsAssembly { get; private set; }
public bool IsSystem { get; private set; }
public UsingInfo(AstNode node, RefactoringContext context)
{
var importAndAlias = GetImportAndAlias(node);
Node = node;
Alias = importAndAlias.Item2;
Name = importAndAlias.Item1.ToString();
IsAlias = Alias != null;
var result = context.Resolve(importAndAlias.Item1) as NamespaceResolveResult;
var mainSourceAssembly = result != null ? result.Namespace.ContributingAssemblies.First() : null;
var unresolvedAssembly = mainSourceAssembly != null ? mainSourceAssembly.UnresolvedAssembly : null;
IsAssembly = unresolvedAssembly is DefaultUnresolvedAssembly;
IsSystem = IsAssembly && Name.StartsWith("System");
}
private static Tuple<AstType, string> GetImportAndAlias(AstNode node)
{
var plainUsing = node as UsingDeclaration;
if (plainUsing != null)
return Tuple.Create(plainUsing.Import, (string)null);
var aliasUsing = node as UsingAliasDeclaration;
if (aliasUsing != null)
return Tuple.Create(aliasUsing.Import, aliasUsing.Alias);
throw new InvalidOperationException(string.Format("Invalid using node: {0}", node));
}
}
private sealed class UsingInfoComparer: IComparer<UsingInfo>
{
public int Compare(UsingInfo x, UsingInfo y)
{
if (x.IsAlias != y.IsAlias)
return x.IsAlias && !y.IsAlias ? 1 : -1;
else if (x.IsAssembly != y.IsAssembly)
return x.IsAssembly && !y.IsAssembly ? -1 : 1;
else if (x.IsSystem != y.IsSystem)
return x.IsSystem && !y.IsSystem ? -1 : 1;
else if (x.Alias != y.Alias)
return Comparer<string>.Default.Compare(x.Alias, y.Alias);
else if (x.Name != y.Name)
return Comparer<string>.Default.Compare(x.Name, y.Name);
else
return 0;
}
}
}
}

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssue.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// InspectionIssue.cs
//
// Author:

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExceptionRethrowIssue.cs

@ -63,7 +63,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -63,7 +63,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var action = new CodeAction(ctx.TranslateString("Change to 'throw;'"), script => {
script.Replace(localThrowStatement, new ThrowStatement());
});
AddIssue(localThrowStatement, title, new [] { action });
AddIssue(localThrowStatement, title, action);
}
}
}

17
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/GatherVisitorBase.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// GatherVisitorBase.cs
//
// Author:
@ -78,6 +78,16 @@ namespace ICSharpCode.NRefactory.CSharp @@ -78,6 +78,16 @@ namespace ICSharpCode.NRefactory.CSharp
FoundIssues.Add(new CodeIssue(title, start, end, fix != null ? new CodeAction(title, fix) : null));
}
protected void AddIssue(AstNode node, string title, CodeAction fix)
{
FoundIssues.Add(new CodeIssue(title, node.StartLocation, node.EndLocation, fix));
}
protected void AddIssue(TextLocation start, TextLocation end, string title, CodeAction fix)
{
FoundIssues.Add(new CodeIssue (title, start, end, fix));
}
protected void AddIssue(AstNode node, string title, IEnumerable<CodeAction> fixes)
{
FoundIssues.Add(new CodeIssue(title, node.StartLocation, node.EndLocation, fixes));
@ -87,10 +97,5 @@ namespace ICSharpCode.NRefactory.CSharp @@ -87,10 +97,5 @@ namespace ICSharpCode.NRefactory.CSharp
{
FoundIssues.Add(new CodeIssue (title, start, end, fixes));
}
}
}

6
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/InconsistentNamingIssue.cs

@ -55,8 +55,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -55,8 +55,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
void CheckName(TypeDeclaration node, AffectedEntity entity, Identifier identifier, Modifiers accessibilty)
{
ResolveResult resolveResult = ctx.Resolve(node);
var type = ((TypeResolveResult)resolveResult).Type;
TypeResolveResult resolveResult = ctx.Resolve(node) as TypeResolveResult;
if (resolveResult == null)
return;
var type = resolveResult.Type;
if (type.DirectBaseTypes.Any(t => t.FullName == "System.Attribute")) {
if (CheckNamedResolveResult(resolveResult, node, AffectedEntity.CustomAttributes, identifier, accessibilty)) {
return;

6
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/IncorrectExceptionParameterOrderingIssue.cs

@ -78,13 +78,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -78,13 +78,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (!func(leftLength, rightLength))
AddIssue(objectCreateExpression,
context.TranslateString("The parameters are in the wrong order"),
GetActions(objectCreateExpression, firstParam, secondParam));
GetAction(objectCreateExpression, firstParam, secondParam));
}
IEnumerable<CodeAction> GetActions(ObjectCreateExpression objectCreateExpression,
CodeAction GetAction(ObjectCreateExpression objectCreateExpression,
PrimitiveExpression firstParam, PrimitiveExpression secondParam)
{
yield return new CodeAction(context.TranslateString("Swap parameters"), script => {
return new CodeAction(context.TranslateString("Swap parameters"), script => {
var newOCE = objectCreateExpression.Clone() as ObjectCreateExpression;
newOCE.Arguments.Clear();
newOCE.Arguments.Add(secondParam.Clone());

6
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceToStaticMemberViaDerivedTypeIssue.cs

@ -96,16 +96,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -96,16 +96,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (v.IsContained)
return;
AddIssue(issueAnchor, context.TranslateString("Static method invoked via derived type"),
GetActions(context, targetExpression, member));
GetAction(context, targetExpression, member));
}
IEnumerable<CodeAction> GetActions(BaseRefactoringContext context, Expression targetExpression,
CodeAction GetAction(BaseRefactoringContext context, Expression targetExpression,
IMember member)
{
var builder = context.CreateTypeSytemAstBuilder(targetExpression);
var newType = builder.ConvertType(member.DeclaringType);
string description = string.Format("{0} '{1}'", context.TranslateString("Use base class"), newType.GetText());
yield return new CodeAction(description, script => {
return new CodeAction(description, script => {
script.Replace(targetExpression, newType);
});
}

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ResultOfAsyncCallShouldNotBeIgnoredIssue.cs

@ -50,7 +50,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -50,7 +50,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return;
var rr = ctx.Resolve(invocation) as InvocationResolveResult;
if (rr != null && (rr.Type.IsKnownType(KnownTypeCode.Task) || rr.Type.IsKnownType(KnownTypeCode.TaskOfT))) {
AddIssue(invocation, "Exceptions in async call will be silently ignored because the returned task is unused");
AddIssue(invocation, ctx.TranslateString("Exceptions in async call will be silently ignored because the returned task is unused"));
}
}
}

22
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs

@ -143,38 +143,38 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -143,38 +143,38 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
get { return options; }
}
public void InsertBefore(AstNode node, AstNode insertNode)
public void InsertBefore(AstNode node, AstNode newNode)
{
var startOffset = GetCurrentOffset(new TextLocation(node.StartLocation.Line, 1));
var output = OutputNode (GetIndentLevelAt (startOffset), insertNode);
var output = OutputNode (GetIndentLevelAt (startOffset), newNode);
string text = output.Text;
if (!(insertNode is Expression || insertNode is AstType))
if (!(newNode is Expression || newNode is AstType))
text += Options.EolMarker;
InsertText(startOffset, text);
output.RegisterTrackedSegments(this, startOffset);
CorrectFormatting (node, insertNode);
CorrectFormatting (node, newNode);
}
public void InsertAfter(AstNode node, AstNode insertNode)
public void InsertAfter(AstNode node, AstNode newNode)
{
var indentOffset = GetCurrentOffset(new TextLocation(node.StartLocation.Line, 1));
var output = OutputNode (GetIndentLevelAt (indentOffset), insertNode);
var output = OutputNode (GetIndentLevelAt (indentOffset), newNode);
string text = output.Text;
if (!(insertNode is Expression || insertNode is AstType))
if (!(newNode is Expression || newNode is AstType))
text = Options.EolMarker + text;
var insertOffset = GetCurrentOffset(node.EndLocation);
InsertText(insertOffset, text);
output.RegisterTrackedSegments(this, insertOffset);
CorrectFormatting (node, insertNode);
CorrectFormatting (node, newNode);
}
public void AddTo(BlockStatement bodyStatement, AstNode insertNode)
public void AddTo(BlockStatement bodyStatement, AstNode newNode)
{
var startOffset = GetCurrentOffset(bodyStatement.LBraceToken.EndLocation);
var output = OutputNode(1 + GetIndentLevelAt(startOffset), insertNode, true);
var output = OutputNode(1 + GetIndentLevelAt(startOffset), newNode, true);
InsertText(startOffset, output.Text);
output.RegisterTrackedSegments(this, startOffset);
CorrectFormatting (null, insertNode);
CorrectFormatting (null, newNode);
}
public virtual Task Link (params AstNode[] nodes)

180
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/UsingHelper.cs

@ -0,0 +1,180 @@ @@ -0,0 +1,180 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// 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.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Helper methods for managing using declarations.
/// </summary>
public class UsingHelper
{
/// <summary>
/// Inserts 'using ns;' in the current scope, and then removes all explicit
/// usages of ns that were made redundant by the new using.
/// </summary>
public static void InsertUsingAndRemoveRedundantNamespaceUsage(RefactoringContext context, Script script, string ns)
{
InsertUsing(context, script, new UsingDeclaration(ns));
// TODO: remove the usages that were made redundant
}
/// <summary>
/// Inserts 'newUsing' in the current scope.
/// This method will try to insert new usings in the correct position (depending on
/// where the existing usings are; and maintaining the sort order).
/// </summary>
public static void InsertUsing(RefactoringContext context, Script script, AstNode newUsing)
{
UsingInfo newUsingInfo = new UsingInfo(newUsing, context);
AstNode enclosingNamespace = context.GetNode<NamespaceDeclaration>() ?? context.RootNode;
// Find nearest enclosing parent that has usings:
AstNode usingParent = enclosingNamespace;
while (usingParent != null && !usingParent.Children.OfType<UsingDeclaration>().Any())
usingParent = usingParent.Parent;
if (usingParent == null) {
// No existing usings at all -> use the default location
if (script.FormattingOptions.UsingPlacement == UsingPlacement.TopOfFile) {
usingParent = context.RootNode;
} else {
usingParent = enclosingNamespace;
}
}
// Find the main block of using declarations in the chosen scope:
AstNode blockStart = usingParent.Children.FirstOrDefault(IsUsingDeclaration);
AstNode insertionPoint;
if (blockStart == null) {
// no using declarations in the file
Debug.Assert(SyntaxTree.MemberRole == NamespaceDeclaration.MemberRole);
insertionPoint = usingParent.GetChildrenByRole(SyntaxTree.MemberRole).SkipWhile(CanAppearBeforeUsings).FirstOrDefault();
} else {
insertionPoint = blockStart;
while (IsUsingDeclaration(insertionPoint) && newUsingInfo.CompareTo(new UsingInfo(insertionPoint, context)) > 0)
insertionPoint = insertionPoint.NextSibling;
}
if (insertionPoint != null) {
script.InsertBefore(insertionPoint, newUsing);
}
}
static bool IsUsingDeclaration(AstNode node)
{
return node is UsingDeclaration || node is UsingAliasDeclaration;
}
static bool CanAppearBeforeUsings(AstNode node)
{
if (node is ExternAliasDeclaration)
return true;
if (node is PreProcessorDirective)
return true;
Comment c = node as Comment;
if (c != null)
return !c.IsDocumentation;
return false;
}
/// <summary>
/// Sorts the specified usings.
/// </summary>
public static IEnumerable<AstNode> SortUsingBlock(IEnumerable<AstNode> nodes, BaseRefactoringContext context)
{
var infos = nodes.Select(_ => new UsingInfo(_, context));
var orderedInfos = infos.OrderBy(_ => _);
var orderedNodes = orderedInfos.Select(_ => _.Node);
return orderedNodes;
}
private sealed class UsingInfo : IComparable<UsingInfo>
{
public AstNode Node;
public string Alias;
public string Name;
public bool IsAlias;
public bool HasTypesFromOtherAssemblies;
public bool IsSystem;
public UsingInfo(AstNode node, BaseRefactoringContext context)
{
var importAndAlias = GetImportAndAlias(node);
Node = node;
Alias = importAndAlias.Item2;
Name = importAndAlias.Item1.ToString();
IsAlias = Alias != null;
ResolveResult rr;
if (node.Ancestors.Contains(context.RootNode)) {
rr = context.Resolve(importAndAlias.Item1);
} else {
// It's possible that we're looking at a new using that
// isn't part of the AST.
var resolver = new CSharpAstResolver(new CSharpResolver(context.Compilation), node);
rr = resolver.Resolve(importAndAlias.Item1);
}
var nrr = rr as NamespaceResolveResult;
HasTypesFromOtherAssemblies = nrr != null && nrr.Namespace.ContributingAssemblies.Any(a => !a.IsMainAssembly);
IsSystem = HasTypesFromOtherAssemblies && (Name == "System" || Name.StartsWith("System.", StringComparison.Ordinal));
}
private static Tuple<AstType, string> GetImportAndAlias(AstNode node)
{
var plainUsing = node as UsingDeclaration;
if (plainUsing != null)
return Tuple.Create(plainUsing.Import, (string)null);
var aliasUsing = node as UsingAliasDeclaration;
if (aliasUsing != null)
return Tuple.Create(aliasUsing.Import, aliasUsing.Alias);
throw new InvalidOperationException(string.Format("Invalid using node: {0}", node));
}
public int CompareTo(UsingInfo y)
{
UsingInfo x = this;
if (x.IsAlias != y.IsAlias)
return x.IsAlias ? 1 : -1;
else if (x.HasTypesFromOtherAssemblies != y.HasTypesFromOtherAssemblies)
return x.HasTypesFromOtherAssemblies ? -1 : 1;
else if (x.IsSystem != y.IsSystem)
return x.IsSystem ? -1 : 1;
else if (x.Alias != y.Alias)
return StringComparer.Ordinal.Compare(x.Alias, y.Alias);
else if (x.Name != y.Name)
return StringComparer.Ordinal.Compare(x.Name, y.Name);
else
return 0;
}
}
}
}

3
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/AwaitResolveResult.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -31,7 +31,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public class AwaitResolveResult : ResolveResult
{
/// <summary>
/// The method representing the GetAwaiter() call. Can be null if the GetAwaiter method was not found.
/// The method representing the GetAwaiter() call. Can be an <see cref="InvocationResolveResult"/> or a <see cref="DynamicInvocationResolveResult"/>.
/// </summary>
public readonly ResolveResult GetAwaiterInvocation;
@ -47,6 +47,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -47,6 +47,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// <summary>
/// Method representing the OnCompleted method on the awaiter type. Can be null if the awaiter type or the method was not found, or when awaiting a dynamic expression.
/// This can also refer to an UnsafeOnCompleted method, if the awaiter type implements <c>System.Runtime.CompilerServices.ICriticalNotifyCompletion</c>.
/// </summary>
public readonly IMethod OnCompletedMethod;

52
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs

@ -383,7 +383,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -383,7 +383,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return UnaryOperatorResolveResult(new PointerType(expression.Type), op, expression);
case UnaryOperatorType.Await: {
ResolveResult getAwaiterMethodGroup = ResolveMemberAccess(expression, "GetAwaiter", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget);
ResolveResult getAwaiterInvocation = ResolveInvocation(getAwaiterMethodGroup, new ResolveResult[0]);
ResolveResult getAwaiterInvocation = ResolveInvocation(getAwaiterMethodGroup, new ResolveResult[0], argumentNames: null, allowOptionalParameters: false);
var lookup = CreateMemberLookup();
IMethod getResultMethod;
@ -401,12 +401,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -401,12 +401,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
var isCompletedRR = lookup.Lookup(getAwaiterInvocation, "IsCompleted", EmptyList<IType>.Instance, false);
var isCompletedProperty = (isCompletedRR is MemberResolveResult ? ((MemberResolveResult)isCompletedRR).Member as IProperty : null);
if (isCompletedProperty != null && (!isCompletedProperty.ReturnType.IsKnownType(KnownTypeCode.Boolean) || !isCompletedProperty.CanGet))
isCompletedProperty = null;
var interfaceOnCompleted = compilation.FindType(KnownTypeCode.INotifyCompletion).GetMethods().FirstOrDefault(x => x.Name == "OnCompleted");
var interfaceUnsafeOnCompleted = compilation.FindType(KnownTypeCode.ICriticalNotifyCompletion).GetMethods().FirstOrDefault(x => x.Name == "UnsafeOnCompleted");
var onCompletedMethodGroup = lookup.Lookup(getAwaiterInvocation, "OnCompleted", EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
IMethod onCompletedMethod = null;
if (onCompletedMethodGroup != null) {
var onCompletedOR = onCompletedMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[] { new TypeResolveResult(compilation.FindType(new FullTypeName("System.Action"))) }, allowExtensionMethods: false, conversions: conversions);
onCompletedMethod = (onCompletedOR.FoundApplicableCandidate ? onCompletedOR.GetBestCandidateWithSubstitutedTypeArguments() as IMethod : null);
var candidates = getAwaiterInvocation.Type.GetMethods().Where(x => x.ImplementedInterfaceMembers.Select(y => y.MemberDefinition).Contains(interfaceUnsafeOnCompleted)).ToList();
if (candidates.Count == 0) {
candidates = getAwaiterInvocation.Type.GetMethods().Where(x => x.ImplementedInterfaceMembers.Select(y => y.MemberDefinition).Contains(interfaceOnCompleted)).ToList();
if (candidates.Count == 1)
onCompletedMethod = candidates[0];
}
else if (candidates.Count == 1) {
onCompletedMethod = candidates[0];
}
return new AwaitResolveResult(awaitResultType, getAwaiterInvocation, getAwaiterInvocation.Type, isCompletedProperty, onCompletedMethod, getResultMethod);
@ -1927,19 +1936,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1927,19 +1936,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
/// <summary>
/// Resolves an invocation.
/// </summary>
/// <param name="target">The target of the invocation. Usually a MethodGroupResolveResult.</param>
/// <param name="arguments">
/// Arguments passed to the method.
/// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
/// </param>
/// <param name="argumentNames">
/// The argument names. Pass the null string for positional arguments.
/// </param>
/// <returns>InvocationResolveResult or UnknownMethodResolveResult</returns>
public ResolveResult ResolveInvocation(ResolveResult target, ResolveResult[] arguments, string[] argumentNames = null)
private ResolveResult ResolveInvocation(ResolveResult target, ResolveResult[] arguments, string[] argumentNames, bool allowOptionalParameters)
{
// C# 4.0 spec: §7.6.5
@ -1971,7 +1968,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1971,7 +1968,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
OverloadResolution or = mgrr.PerformOverloadResolution(compilation, arguments, argumentNames, checkForOverflow: checkForOverflow, conversions: conversions);
OverloadResolution or = mgrr.PerformOverloadResolution(compilation, arguments, argumentNames, checkForOverflow: checkForOverflow, conversions: conversions, allowOptionalParameters: allowOptionalParameters);
if (or.BestCandidate != null) {
if (or.BestCandidate.IsStatic && !or.IsExtensionMethodInvocation && !(mgrr.TargetResult is TypeResolveResult))
return or.CreateResolveResult(new TypeResolveResult(mgrr.TargetType));
@ -2005,6 +2002,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2005,6 +2002,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
return ErrorResult;
}
/// <summary>
/// Resolves an invocation.
/// </summary>
/// <param name="target">The target of the invocation. Usually a MethodGroupResolveResult.</param>
/// <param name="arguments">
/// Arguments passed to the method.
/// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
/// </param>
/// <param name="argumentNames">
/// The argument names. Pass the null string for positional arguments.
/// </param>
/// <returns>InvocationResolveResult or UnknownMethodResolveResult</returns>
public ResolveResult ResolveInvocation(ResolveResult target, ResolveResult[] arguments, string[] argumentNames = null)
{
return ResolveInvocation(target, arguments, argumentNames, allowOptionalParameters: true);
}
List<IParameter> CreateParameters(ResolveResult[] arguments, string[] argumentNames)
{

1
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs

@ -759,6 +759,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -759,6 +759,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
case "GetAwaiter":
case "GetResult":
case "OnCompleted":
case "UnsafeOnCompleted":
specialNodeType = typeof(UnaryOperatorExpression);
break;
default:

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs

@ -1178,7 +1178,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -1178,7 +1178,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
// traverse AST backwards until the next non-whitespace node
for (AstNode node = entityDeclaration.PrevSibling; node != null && node.NodeType == NodeType.Whitespace; node = node.PrevSibling) {
Comment c = node as Comment;
if (c != null && (c.CommentType == CommentType.Documentation || c.CommentType == CommentType.MultiLineDocumentation)) {
if (c != null && c.IsDocumentation) {
if (documentation == null)
documentation = new List<string>();
if (c.CommentType == CommentType.MultiLineDocumentation) {

229
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/AddUsing/AddUsingActionAlphabeticalTests.cs

@ -0,0 +1,229 @@ @@ -0,0 +1,229 @@
using NUnit.Framework;
using ICSharpCode.NRefactory.CSharp.CodeIssues;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.CSharp.CodeActions;
using ICSharpCode.NRefactory.CSharp;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp.CodeIssues.UnresolvedType
{
[TestFixture]
public class UnresolvedTypeActionAlphabeticalTests : ContextActionTestBase
{
[Test]
public void ShouldAddUsingAtStartIfItIsTheFirstAlphabetically()
{
string testCode =
@"namespace OuterNamespace
{
using System.IO;
class TestClass
{
private $List<TextWriter> writerList;
}
}";
string expectedOutput =
@"namespace OuterNamespace
{
using System.Collections.Generic;
using System.IO;
class TestClass
{
private List<TextWriter> writerList;
}
}";
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
public void ShouldInsertUsingBetweenExistingUsings()
{
string testCode =
@"namespace OuterNamespace
{
using System;
using System.IO;
class TestClass
{
private $List<TextWriter> writerList;
}
}";
string expectedOutput =
@"namespace OuterNamespace
{
using System;
using System.Collections.Generic;
using System.IO;
class TestClass
{
private List<TextWriter> writerList;
}
}";
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
[Ignore("Add using does not honor the blank line setting yet")]
public void ShouldInsertUsingAfterExistingUsings()
{
string testCode =
@"namespace OuterNamespace
{
using System;
using System.Collections.Generic;
class TestClass
{
private List<$TextWriter> writerList;
}
}";
string expectedOutput =
@"namespace OuterNamespace
{
using System;
using System.Collections.Generic;
using System.IO;
class TestClass
{
private List<TextWriter> writerList;
}
}";
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
[Ignore("Add using does not honor the blank line setting yet")]
public void ShouldAddBlankLinesAfterUsingsWhenAddingAtEnd()
{
string testCode =
@"namespace OuterNamespace
{
using System;
using System.Collections.Generic;
class TestClass
{
private List<$TextWriter> writerList;
}
}";
string expectedOutput =
@"namespace OuterNamespace
{
using System;
using System.Collections.Generic;
using System.IO;
class TestClass
{
private List<TextWriter> writerList;
}
}";
Test(new AddUsingAction(), testCode, expectedOutput);
}
#region System Namespaces
[Test]
public void ShouldBeAbleToPlaceSystemNamespacesFirst()
{
string testCode =
@"namespace OuterNamespace
{
using ANamespace;
class TestClass
{
private $TextWriter writer;
}
}";
string expectedOutput =
@"namespace OuterNamespace
{
using System.IO;
using ANamespace;
class TestClass
{
private TextWriter writer;
}
}";
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
public void ShouldNotPlaceNonSystemNamespacesStartingWithSystemFirst()
{
string testCode =
@"namespace A { class B { } }
namespace OuterNamespace
{
using SystemA;
class TestClass
{
private $B b;
}
}";
string expectedOutput =
@"namespace A { class B { } }
namespace OuterNamespace
{
using A;
using SystemA;
class TestClass
{
private B b;
}
}";
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
public void ShouldPlaceSystemBeforeOtherNamespaces()
{
string testCode =
@"namespace OuterNamespace
{
using System.Collections.Generic;
class TestClass
{
private List<$DateTime> dates;
}
}";
string expectedOutput =
@"namespace OuterNamespace
{
using System;
using System.Collections.Generic;
class TestClass
{
private List<DateTime> dates;
}
}";
Test(new AddUsingAction(), testCode, expectedOutput);
}
#endregion
}
}

203
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/AddUsing/AddUsingActionInsideNamespaceTests.cs

@ -0,0 +1,203 @@ @@ -0,0 +1,203 @@
using NUnit.Framework;
using ICSharpCode.NRefactory.CSharp.CodeIssues;
using ICSharpCode.NRefactory.CSharp.CodeActions;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp.CodeIssues.UnresolvedType
{
[TestFixture]
public class UnresolvedTypeActionInsideNamespaceTests : ContextActionTestBase
{
[Test]
public void ShouldInsertUsingStatement()
{
string testCode =
@"namespace TestNamespace
{
class TestClass
{
private $List<string> stringList;
}
}";
string expectedOutput =
@"namespace TestNamespace
{
using System.Collections.Generic;
class TestClass
{
private List<string> stringList;
}
}";
formattingOptions.UsingPlacement = UsingPlacement.InsideNamespace;
formattingOptions.BlankLinesAfterUsings = 0;
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
[Ignore("Add using does not honor the blank line setting yet")]
public void ShouldAddBlankLinesBeforeUsingStatement()
{
string testCode =
@"namespace TestNamespace
{
class TestClass
{
private $List<string> stringList;
}
}";
string expectedOutput =
@"namespace TestNamespace
{
using System.Collections.Generic;
class TestClass
{
private List<string> stringList;
}
}";
formattingOptions.UsingPlacement = UsingPlacement.InsideNamespace;
formattingOptions.BlankLinesBeforeUsings = 2;
formattingOptions.BlankLinesAfterUsings = 0;
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
[Ignore("Add using does not honor the blank line setting yet")]
public void ShouldAddBlankLinesAfterUsingStatements()
{
string testCode =
@"namespace TestNamespace
{
class TestClass
{
private $List<string> stringList;
}
}";
string expectedOutput =
@"namespace TestNamespace
{
using System.Collections.Generic;
class TestClass
{
private List<string> stringList;
}
}";
formattingOptions.UsingPlacement = UsingPlacement.InsideNamespace;
formattingOptions.BlankLinesAfterUsings = 2;
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
[Ignore("Something is wrong with the blank lines")]
public void ShouldAddUsingAfterExistingUsings()
{
string testCode =
@"namespace TestNamespace
{
using System;
class TestClass
{
private $List<string> stringList;
}
}";
string expectedOutput =
@"namespace TestNamespace
{
using System;
using System.Collections.Generic;
class TestClass
{
private List<string> stringList;
}
}";
formattingOptions.UsingPlacement = UsingPlacement.InsideNamespace;
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
[Ignore("Add using does not honor the blank line setting yet")]
public void ShouldAddUsingInMostNestedNamespace()
{
string testCode =
@"namespace OuterNamespace
{
namespace InnerNamespace
{
class TestClass
{
private $List<string> stringList;
}
}
}";
string expectedOutput =
@"namespace OuterNamespace
{
namespace InnerNamespace
{
using System.Collections.Generic;
class TestClass
{
private List<string> stringList;
}
}
}";
formattingOptions.UsingPlacement = UsingPlacement.InsideNamespace;
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
[Ignore("Something is wrong with the blank lines")]
public void ShouldAddUsingAfterExistingUsingsInMostNestedNamespace()
{
string testCode =
@"namespace OuterNamespace
{
namespace InnerNamespace
{
using System;
class TestClass
{
private $List<string> stringList;
}
}
}";
string expectedOutput =
@"namespace OuterNamespace
{
namespace InnerNamespace
{
using System;
using System.Collections.Generic;
class TestClass
{
private List<string> stringList;
}
}
}";
formattingOptions.UsingPlacement = UsingPlacement.InsideNamespace;
Test(new AddUsingAction(), testCode, expectedOutput);
}
}
}

320
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/AddUsing/AddUsingActionTests.cs

@ -0,0 +1,320 @@ @@ -0,0 +1,320 @@
using ICSharpCode.NRefactory.CSharp.CodeIssues;
using NUnit.Framework;
using ICSharpCode.NRefactory.CSharp.CodeActions;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp.CodeIssues.UnresolvedType
{
[TestFixture]
public class UnresolvedTypeIssueTests : ContextActionTestBase
{
void UnresolvedTypeName(string code, string typeName, params string[] namespaces)
{
TestActionDescriptions(
new AddUsingAction(), code,
namespaces.SelectMany(ns => new[] {
"using " + ns + ";",
ns + "." + typeName
}).ToArray());
}
#region Field Declarations
[Test]
public void ShouldReturnAnIssueForUnresolvedFieldDeclarations()
{
UnresolvedTypeName(@"class Foo {
private $TextWriter textWriter;
}", "TextWriter", "System.IO");
}
[Test]
public void ShouldNotReturnAnyIssuesIfFieldTypeIsResolved()
{
TestWrongContext<AddUsingAction>(@"using System.IO;
class Foo {
private $TextWriter textWriter;
}");
}
[Test]
public void ShouldReturnAnIssueIfFieldTypeArgumentIsNotResolvable()
{
UnresolvedTypeName(
@"using System.Collections.Generic;
class Foo
{
private List<$AttributeTargets> targets;
}", "AttributeTargets", "System");
}
[Test]
public void ShouldNotReturnAnIssueIfFieldTypeArgumentIsResolvable()
{
TestWrongContext<AddUsingAction>(
@"using System;
using System.Collections.Generic;
class Foo
{
private List<$AttributeTargets> notifiers;
}");
}
[Test]
public void ShouldNotReturnAnIssueIfFieldTypeArgumentIsPrimitiveType()
{
TestWrongContext<AddUsingAction>(
@"using System.Collections.Generic;
class Foo
{
private List<$string> notifiers;
}");
}
#endregion
#region Method Return Types
[Test]
public void ShouldReturnIssueForUnresolvedReturnType()
{
UnresolvedTypeName(
@"class Foo
{
$TextWriter Bar ()
{
return null;
}
}", "TextWriter", "System.IO");
}
[Test]
public void ShouldNotReturnIssueForResolvedReturnType()
{
TestWrongContext<AddUsingAction>(
@"using System.IO;
class Foo
{
$TextWriter Bar ()
{
return null;
}
}");
}
#endregion
#region Local Variables
[Test]
public void ShouldReturnIssueForUnresolvedLocalVariableDeclaration()
{
UnresolvedTypeName(
@"class Foo
{
void Bar ()
{
$TextWriter writer;
}
}", "TextWriter", "System.IO");
}
[Test]
public void ShouldNotReturnIssueForResolvedLocalVariableDeclaration()
{
TestWrongContext<AddUsingAction>(
@"using System.IO;
class Foo
{
void Bar ()
{
$TextWriter writer;
}
}");
}
#endregion
#region Method Parameters
[Test]
public void ShouldReturnIssueIfMethodParameterIsNotResolvable()
{
UnresolvedTypeName(
@"class Foo
{
void Bar ($TextWriter writer)
{
}
}", "TextWriter", "System.IO");
}
[Test]
public void ShouldNotReturnAnIssueIfMethodParameterIsResolvable()
{
TestWrongContext<AddUsingAction>(
@"using System.IO;
class Foo
{
void Bar ($TextWriter writer)
{
}
}");
}
#endregion
#region Base Types
[Test]
public void ShouldReturnIssueIfBaseClassIsNotResolvable()
{
UnresolvedTypeName(
@"class Foo : $List<string>
{
}", "List<>", "System.Collections.Generic");
}
[Test]
public void ShouldNotReturnIssueIfBaseClassIsResolvable()
{
TestWrongContext<AddUsingAction>(
@"using System.Collections.Generic;
class Foo : $List<string>
{
}");
}
[Test]
public void ShouldReturnIssueIfGenericInterfaceIsMissingButNonGenericIsPresent()
{
UnresolvedTypeName(
@"using System.Collections;
class Foo : $IEnumerable<string>
{
}", "IEnumerable<>", "System.Collections.Generic");
}
[Test]
public void ShouldReturnIssueIfNonGenericInterfaceIsMissingButGenericIsPresent()
{
UnresolvedTypeName(
@"using System.Collections.Generic;
class Foo : $IEnumerable
{
}", "IEnumerable", "System.Collections");
}
#endregion
#region Member Access
[Test]
public void ShouldReturnIssueIfEnumValueIsNotResolvable()
{
UnresolvedTypeName(
@"class Foo
{
void Bar ()
{
var support = $AttributeTargets.Assembly;
}
}", "AttributeTargets", "System");
}
[Test]
public void ShouldNotReturnIssueIfEnumValueIsResolvable()
{
TestWrongContext<AddUsingAction>(
@"using System;
class Foo
{
void Bar ()
{
var support = $AttributeTargets.Assembly;
}
}");
}
#endregion
[Test]
public void ShouldReturnIssueIfAttributeIsNotResolvable()
{
UnresolvedTypeName(
@"[$Serializable]
class Foo
{
}", "SerializableAttribute", "System");
}
[Test]
public void ShouldNotReturnIssueIfAttributeIsResolvable()
{
TestWrongContext<AddUsingAction>(
@"using System;
[$Serializable]
class Foo
{
}");
}
[Test]
public void ShouldReturnIssueIfTypeArgumentIsNotResolvable()
{
UnresolvedTypeName(
@"using System.Collections.Generic;
class Test
{
void TestMethod()
{
var list = new List<$Stream>();
}
}", "Stream", "System.IO");
}
[Test]
public void ShouldReturnIssueForUnresolvedExtensionMethod()
{
TestActionDescriptions(
new AddUsingAction(),
@"using System.Collections.Generic;
class Test
{
void TestMethod()
{
var list = new List<string>();
var first = list.$First();
}
}", "using System.Linq;");
}
[Test]
public void ShouldReturnMultipleNamespaceSuggestions()
{
UnresolvedTypeName(
@"namespace A { public class TestClass { } }
namespace B { public class TestClass { } }
namespace C
{
public class Test
{
private $TestClass testClass;
}
}", "TestClass", "A", "B");
}
[Test]
public void InnerTypeCanOnlyBeReferredToByFullName()
{
TestActionDescriptions(
new AddUsingAction(),
@"class Outer { public class Inner {} }
public class Test
{
private $Inner t;
}
", "Outer.Inner");
}
}
}

248
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/AddUsing/AddUsingRunActionTests.cs

@ -0,0 +1,248 @@ @@ -0,0 +1,248 @@
using NUnit.Framework;
using ICSharpCode.NRefactory.CSharp.CodeIssues;
using ICSharpCode.NRefactory.CSharp.CodeActions;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp.CodeIssues.UnresolvedType
{
[TestFixture]
public class UnresolvedTypeActionTests : ContextActionTestBase
{
[Test]
[Ignore("Add using does not honor the blank line setting yet")]
public void ShouldInsertUsingStatement()
{
string testCode =
@"namespace TestNamespace
{
class TestClass
{
private $List<string> stringList;
}
}";
string expectedOutput =
@"using System.Collections.Generic;
namespace TestNamespace
{
class TestClass
{
private List<string> stringList;
}
}";
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
[Ignore("Add using does not honor the blank line setting yet")]
public void ShouldAddBlankLinesAfterUsings()
{
string testCode =
@"namespace TestNamespace
{
class TestClass
{
private $List<string> stringList;
}
}";
string expectedOutput =
@"using System.Collections.Generic;
namespace TestNamespace
{
class TestClass
{
private List<string> stringList;
}
}";
formattingOptions.BlankLinesAfterUsings = 2;
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
[Ignore("Add using does not honor the blank line setting yet")]
public void ShouldAddBlankLinesBeforeUsing()
{
string testCode =
@"namespace TestNamespace
{
class TestClass
{
private $List<string> stringList;
}
}";
string expectedOutput =
@"
using System.Collections.Generic;
namespace TestNamespace
{
class TestClass
{
private List<string> stringList;
}
}";
formattingOptions.BlankLinesBeforeUsings = 2;
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
[Ignore("Add using does not honor the blank line setting yet")]
public void ShouldAddAfterExistingUsingStatements()
{
string testCode =
@"using System;
namespace TestNamespace
{
class TestClass
{
private $List<string> stringList;
}
}";
string expectedOutput =
@"using System;
using System.Collections.Generic;
namespace TestNamespace
{
class TestClass
{
private List<string> stringList;
}
}";
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
[Ignore("Something else is broken regarding blank lines as well")]
public void ShouldNotAddBlankLinesAfterIfTheyAreAlreadyThere()
{
string testCode =
@"using System;
namespace TestNamespace
{
class TestClass
{
private $List<string> stringList;
}
}";
string expectedOutput =
@"using System;
using System.Collections.Generic;
namespace TestNamespace
{
class TestClass
{
private List<string> stringList;
}
}";
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
[Ignore("Something else is broken regarding blank lines as well")]
public void ShouldLeaveAdditionalBlankLinesThatAlreadyExist()
{
string testCode =
@"using System;
namespace TestNamespace
{
class TestClass
{
private $List<string> stringList;
}
}";
string expectedOutput =
@"using System;
using System.Collections.Generic;
namespace TestNamespace
{
class TestClass
{
private List<string> stringList;
}
}";
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
[Ignore("Add using does not honor the blank line setting yet")]
public void ShouldAddFirstUsingAfterComments()
{
string testCode =
@"// This is the file header.
// It contains any copyright information.
namespace TestNamespace
{
class TestClass
{
private $List<string> stringList;
}
}";
string expectedOutput =
@"// This is the file header.
// It contains any copyright information.
using System.Collections.Generic;
namespace TestNamespace
{
class TestClass
{
private List<string> stringList;
}
}";
Test(new AddUsingAction(), testCode, expectedOutput);
}
[Test]
[Ignore("Add using does not honor the blank line setting yet")]
public void ShouldBeAbleToFixAttributeWithShortName()
{
string testCode =
@"namespace TestNamespace
{
[$Serializable]
class TestClass
{
}
}";
string expectedOutput =
@"using System;
namespace TestNamespace
{
[Serializable]
class TestClass
{
}
}";
Test(new AddUsingAction(), testCode, expectedOutput);
}
}
}

40
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ContextActionTestBase.cs

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
//
// ContextActionTestBase.cs
//
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
@ -35,6 +35,14 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -35,6 +35,14 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
{
public abstract class ContextActionTestBase
{
protected CSharpFormattingOptions formattingOptions;
[SetUp]
public virtual void SetUp()
{
formattingOptions = FormattingOptionsFactory.CreateMono();
}
internal static string HomogenizeEol (string str)
{
var sb = new StringBuilder ();
@ -53,10 +61,15 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -53,10 +61,15 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
return sb.ToString ();
}
public void Test<T> (string input, string output, int action = 0, bool expectErrors = false)
public void Test<T> (string input, string output, int action = 0, bool expectErrors = false)
where T : ICodeActionProvider, new ()
{
string result = RunContextAction (new T (), HomogenizeEol (input), action, expectErrors);
Test(new T(), input, output, action, expectErrors);
}
public void Test (ICodeActionProvider provider, string input, string output, int action = 0, bool expectErrors = false)
{
string result = RunContextAction (provider, HomogenizeEol (input), action, expectErrors);
bool passed = result == output;
if (!passed) {
Console.WriteLine ("-----------Expected:");
@ -65,13 +78,13 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -65,13 +78,13 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
Console.WriteLine (result);
}
Assert.AreEqual (HomogenizeEol (output), result);
}
}
protected static string RunContextAction (ICodeActionProvider action, string input,
protected string RunContextAction (ICodeActionProvider action, string input,
int actionIndex = 0, bool expectErrors = false)
{
var context = TestRefactoringContext.Create (input, expectErrors);
context.FormattingOptions = formattingOptions;
bool isValid = action.GetActions (context).Any ();
if (!isValid)
@ -84,18 +97,29 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -84,18 +97,29 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
return context.doc.Text;
}
protected static void TestWrongContext<T> (string input) where T : ICodeActionProvider, new ()
protected void TestWrongContext<T> (string input) where T : ICodeActionProvider, new ()
{
TestWrongContext (new T(), input);
}
protected static void TestWrongContext (ICodeActionProvider action, string input)
protected void TestWrongContext (ICodeActionProvider action, string input)
{
var context = TestRefactoringContext.Create (input);
context.FormattingOptions = formattingOptions;
bool isValid = action.GetActions (context).Any ();
if (!isValid)
Console.WriteLine ("invalid node is:" + context.GetNode ());
Assert.IsTrue (!isValid, action.GetType () + " shouldn't be valid there.");
}
protected void TestActionDescriptions (ICodeActionProvider provider, string input, params string[] expected)
{
var ctx = TestRefactoringContext.Create(input);
ctx.FormattingOptions = formattingOptions;
var actions = provider.GetActions(ctx).ToList();
Assert.AreEqual(
expected,
actions.Select(a => a.Description).ToArray());
}
}
}

17
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/SortUsingsTests.cs

@ -105,5 +105,22 @@ using System;", @"using System; @@ -105,5 +105,22 @@ using System;", @"using System;
using System.Linq;");
}
[Test]
public void TestPreservesPreprocessorDirectives()
{
Test<SortUsingsAction>(@"$using D;
using A;
#if true
using C;
using B;
#endif", @"using A;
using D;
#if true
using B;
using C;
#endif");
}
}
}

5
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs

@ -55,6 +55,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -55,6 +55,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
this.doc = document;
this.location = location;
this.UseExplicitTypes = UseExplict;
this.FormattingOptions = FormattingOptionsFactory.CreateMono ();
UseExplict = false;
Services.AddService (typeof(NamingConventionService), new TestNameService ());
}
@ -77,6 +78,8 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -77,6 +78,8 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
get { return location; }
}
public CSharpFormattingOptions FormattingOptions { get; set; }
public Script StartScript ()
{
return new TestScript (this);
@ -85,7 +88,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -85,7 +88,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
sealed class TestScript : DocumentScript
{
readonly TestRefactoringContext context;
public TestScript(TestRefactoringContext context) : base(context.doc, FormattingOptionsFactory.CreateMono (), new TextEditorOptions ())
public TestScript(TestRefactoringContext context) : base(context.doc, context.FormattingOptions, new TextEditorOptions ())
{
this.context = context;
}

33
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs

@ -213,8 +213,11 @@ class Calls { @@ -213,8 +213,11 @@ class Calls {
#endregion
#region Await
#if NET_4_5
const string awaitTest = @"using System;
class MyAwaiter {
class MyAwaiter : System.Runtime.CompilerServices.INotifyCompletion {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
@ -268,6 +271,34 @@ public class C { @@ -268,6 +271,34 @@ public class C {
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 3 && r is PropertyDeclaration));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 13 && r is UnaryOperatorExpression));
}
[Test]
public void UnsafeOnCompletedReferenceInAwaitExpressionIsFound() {
Init(@"using System;
class MyAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public void UnsafeOnCompleted(Action continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
public MyAwaiter GetAwaiter() { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = await x;
}
}");
var test = compilation.MainAssembly.TopLevelTypeDefinitions.Single(t => t.Name == "MyAwaiter");
var method = test.Methods.Single(m => m.Name == "UnsafeOnCompleted");
var actual = FindReferences(method).ToList();
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 5 && r is MethodDeclaration));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 14 && r is UnaryOperatorExpression));
}
#endif // NET_4_5
#endregion
}
}

374
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnaryOperatorTests.cs

@ -275,11 +275,12 @@ class Test { @@ -275,11 +275,12 @@ class Test {
Assert.AreEqual(unchecked( (ushort)~3 ), rr.ConstantValue);
}
#if NET_4_5
[Test]
public void Await() {
string program = @"
using System;
class MyAwaiter {
class MyAwaiter : System.Runtime.CompilerServices.INotifyCompletion {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
@ -317,12 +318,97 @@ public class C { @@ -317,12 +318,97 @@ public class C {
Assert.AreEqual("MyAwaiter.GetResult", rr.GetResultMethod.FullName);
}
[Test]
public void AwaitWithGenericAwaiterType() {
string program = @"
using System;
class MyAwaiter<T> : System.Runtime.CompilerServices.INotifyCompletion {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public T GetResult() { return 0; }
}
class MyAwaitable {
public MyAwaiter<int> GetAwaiter() { return null; }
public MyAwaiter<int> GetAwaiter(int i) { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = $await x$;
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.IsTrue(rr.Type.IsKnownType(KnownTypeCode.Int32));
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
var getAwaiterInvocation = (CSharpInvocationResolveResult)rr.GetAwaiterInvocation;
Assert.IsFalse(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(0, getAwaiterInvocation.Arguments.Count);
Assert.AreEqual("MyAwaitable.GetAwaiter", getAwaiterInvocation.Member.FullName);
Assert.AreEqual(0, getAwaiterInvocation.Member.Parameters.Count);
Assert.AreEqual("MyAwaiter", rr.AwaiterType.FullName);
Assert.IsNotNull(rr.IsCompletedProperty);
Assert.AreEqual("MyAwaiter.IsCompleted", rr.IsCompletedProperty.FullName);
Assert.IsNotNull(rr.OnCompletedMethod);
Assert.AreEqual("MyAwaiter.OnCompleted", rr.OnCompletedMethod.FullName);
Assert.IsNotNull(rr.GetResultMethod);
Assert.AreEqual("MyAwaiter.GetResult", rr.GetResultMethod.FullName);
}
[Test]
public void AwaitWithCriticalGenericAwaiterType() {
string program = @"
using System;
class MyAwaiter<T> : System.Runtime.CompilerServices.ICriticalNotifyCompletion {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public void UnsafeOnCompleted(Action continuation) {}
public T GetResult() { return 0; }
}
class MyAwaitable {
public MyAwaiter<int> GetAwaiter() { return null; }
public MyAwaiter<int> GetAwaiter(int i) { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = $await x$;
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.IsTrue(rr.Type.IsKnownType(KnownTypeCode.Int32));
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
var getAwaiterInvocation = (CSharpInvocationResolveResult)rr.GetAwaiterInvocation;
Assert.IsFalse(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(0, getAwaiterInvocation.Arguments.Count);
Assert.AreEqual("MyAwaitable.GetAwaiter", getAwaiterInvocation.Member.FullName);
Assert.AreEqual(0, getAwaiterInvocation.Member.Parameters.Count);
Assert.AreEqual("MyAwaiter", rr.AwaiterType.FullName);
Assert.IsNotNull(rr.IsCompletedProperty);
Assert.AreEqual("MyAwaiter.IsCompleted", rr.IsCompletedProperty.FullName);
Assert.IsNotNull(rr.OnCompletedMethod);
Assert.AreEqual("MyAwaiter.UnsafeOnCompleted", rr.OnCompletedMethod.FullName);
Assert.IsNotNull(rr.GetResultMethod);
Assert.AreEqual("MyAwaiter.GetResult", rr.GetResultMethod.FullName);
}
[Test]
public void AwaitWhenGetAwaiterIsAnExtensionMethod() {
string program = @"
using System;
namespace N {
class MyAwaiter {
class MyAwaiter : System.Runtime.CompilerServices.INotifyCompletion {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
@ -363,11 +449,11 @@ namespace N { @@ -363,11 +449,11 @@ namespace N {
Assert.AreEqual("N.MyAwaiter.GetResult", rr.GetResultMethod.FullName);
}
[Test, Ignore("TODO: MS C# (at least the RC version) refuses to use default values in GetAwaiter(). I do not know, however, if this is by design, and I could not find a simple, nice way to do the implementation")]
[Test]
public void GetAwaiterMethodWithDefaultArgumentCannotBeUsed() {
string program = @"
using System;
class MyAwaiter {
class MyAwaiter : System.Runtime.CompilerServices.INotifyCompletion {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
@ -383,24 +469,16 @@ public class C { @@ -383,24 +469,16 @@ public class C {
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.AreEqual(SpecialType.UnknownType, rr.Type);
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
Assert.IsTrue(rr.IsError);
Assert.IsTrue(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(rr.AwaiterType, SpecialType.UnknownType);
Assert.IsNull(rr.IsCompletedProperty);
Assert.IsNull(rr.OnCompletedMethod);
Assert.IsNull(rr.GetResultMethod);
}
[Test, Ignore("TODO: MS C# (at least the RC version) refuses to use default values in GetAwaiter(). I do not know, however, if this is by design, and I could not find a simple, nice way to do the implementation")]
[Test, Ignore("TODO: MS C# refuses to use an extension method GetAwaiter() when there is an instance GetAwaiter() with only optional arguments. I do not know, however, if this is by design, and I could not find a simple, nice way to do the implementation")]
public void GetAwaiterMethodWithDefaultArgumentHidesExtensionMethodAndResultsInError() {
string program = @"
using System;
namespace N {
class MyAwaiter {
class MyAwaiter : System.Runtime.CompilerServices.INotifyCompletion {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
@ -420,7 +498,7 @@ namespace N { @@ -420,7 +498,7 @@ namespace N {
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.IsTrue(rr.IsError);
Assert.AreEqual(SpecialType.UnknownType, rr.Type);
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
Assert.IsTrue(rr.GetAwaiterInvocation.IsError);
@ -437,7 +515,7 @@ namespace N { @@ -437,7 +515,7 @@ namespace N {
string program = @"
using System;
namespace N {
class MyAwaiter {
class MyAwaiter : System.Runtime.CompilerServices.INotifyCompletion {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
@ -479,12 +557,35 @@ namespace N { @@ -479,12 +557,35 @@ namespace N {
Assert.AreEqual("N.MyAwaiter.GetResult", rr.GetResultMethod.FullName);
}
[Test]
public void GenericGetAwaiterResultsInError() {
string program = @"
using System;
class MyAwaiter : System.Runtime.CompilerServices.INotifyCompletion {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
public MyAwaiter GetAwaiter<T>() { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = $await x$;
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsTrue(rr.IsError);
}
[Test]
public void AwaiterWithNoSuitableGetResult() {
string program = @"
using System;
namespace N {
class MyAwaiter {
class MyAwaiter : System.Runtime.CompilerServices.INotifyCompletion {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult(int i) { return 0; }
@ -525,15 +626,61 @@ namespace N { @@ -525,15 +626,61 @@ namespace N {
Assert.IsNull(rr.GetResultMethod);
}
[Test]
public void AwaiterWithInaccessibleGetResult() {
string program = @"
using System;
namespace N {
class MyAwaiter : System.Runtime.CompilerServices.INotifyCompletion {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
private int GetResult() { return 0; }
}
class MyAwaitable {
public static MyAwaiter GetAwaiter(int i) { return null; }
}
static class MyAwaitableExtensions {
public static MyAwaiter GetAwaiter(this MyAwaitable x) { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = $await x$;
}
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsTrue(rr.IsError);
Assert.AreEqual(SpecialType.UnknownType, rr.Type);
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
var getAwaiterInvocation = (CSharpInvocationResolveResult)rr.GetAwaiterInvocation;
Assert.IsFalse(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(1, getAwaiterInvocation.Arguments.Count);
Assert.AreEqual("N.MyAwaitableExtensions.GetAwaiter", getAwaiterInvocation.Member.FullName);
Assert.AreEqual(1, getAwaiterInvocation.Member.Parameters.Count);
Assert.IsTrue(getAwaiterInvocation.Arguments[0] is LocalResolveResult && ((LocalResolveResult)getAwaiterInvocation.Arguments[0]).Variable.Name == "x");
Assert.AreEqual("N.MyAwaiter", rr.AwaiterType.FullName);
Assert.IsNotNull(rr.IsCompletedProperty);
Assert.AreEqual("N.MyAwaiter.IsCompleted", rr.IsCompletedProperty.FullName);
Assert.IsNotNull(rr.OnCompletedMethod);
Assert.AreEqual("N.MyAwaiter.OnCompleted", rr.OnCompletedMethod.FullName);
Assert.IsNull(rr.GetResultMethod);
}
[Test]
public void AwaiterWithNoIsCompletedProperty() {
string program = @"
using System;
namespace N {
class MyAwaiter {
class MyAwaiter : System.Runtime.CompilerServices.INotifyCompletion {
public bool IsCompleted() { return false; }
public void OnCompleted(Action continuation) {}
public int GetResult(int i) { return 0; }
public int GetResult() { return 0; }
}
class MyAwaitable {
public static MyAwaiter GetAwaiter(int i) { return null; }
@ -551,7 +698,7 @@ namespace N { @@ -551,7 +698,7 @@ namespace N {
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsTrue(rr.IsError);
Assert.AreEqual(SpecialType.UnknownType, rr.Type);
Assert.IsTrue(rr.Type.IsKnownType(KnownTypeCode.Int32));
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
var getAwaiterInvocation = (CSharpInvocationResolveResult)rr.GetAwaiterInvocation;
Assert.IsFalse(rr.GetAwaiterInvocation.IsError);
@ -567,16 +714,151 @@ namespace N { @@ -567,16 +714,151 @@ namespace N {
Assert.IsNotNull(rr.OnCompletedMethod);
Assert.AreEqual("N.MyAwaiter.OnCompleted", rr.OnCompletedMethod.FullName);
Assert.IsNull(rr.GetResultMethod);
Assert.IsNotNull(rr.GetResultMethod);
}
[Test]
public void AwaiterWithNoOnCompletedMethodWithSuitableSignature() {
public void AwaiterWithIsCompletedPropertyThatIsNotBoolean() {
string program = @"
using System;
namespace N {
class MyAwaiter : System.Runtime.CompilerServices.INotifyCompletion {
public string IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
public static MyAwaiter GetAwaiter(int i) { return null; }
}
static class MyAwaitableExtensions {
public static MyAwaiter GetAwaiter(this MyAwaitable x) { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = $await x$;
}
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsTrue(rr.IsError);
Assert.IsTrue(rr.Type.IsKnownType(KnownTypeCode.Int32));
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
var getAwaiterInvocation = (CSharpInvocationResolveResult)rr.GetAwaiterInvocation;
Assert.IsFalse(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(1, getAwaiterInvocation.Arguments.Count);
Assert.AreEqual("N.MyAwaitableExtensions.GetAwaiter", getAwaiterInvocation.Member.FullName);
Assert.AreEqual(1, getAwaiterInvocation.Member.Parameters.Count);
Assert.IsTrue(getAwaiterInvocation.Arguments[0] is LocalResolveResult && ((LocalResolveResult)getAwaiterInvocation.Arguments[0]).Variable.Name == "x");
Assert.AreEqual("N.MyAwaiter", rr.AwaiterType.FullName);
Assert.IsNull(rr.IsCompletedProperty);
Assert.IsNotNull(rr.OnCompletedMethod);
Assert.AreEqual("N.MyAwaiter.OnCompleted", rr.OnCompletedMethod.FullName);
Assert.IsNotNull(rr.GetResultMethod);
}
[Test]
public void AwaiterWithIsCompletedPropertyThatIsNotReadable() {
string program = @"
using System;
namespace N {
class MyAwaiter : System.Runtime.CompilerServices.INotifyCompletion {
public bool IsCompleted { set {} }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
public static MyAwaiter GetAwaiter(int i) { return null; }
}
static class MyAwaitableExtensions {
public static MyAwaiter GetAwaiter(this MyAwaitable x) { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = $await x$;
}
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsTrue(rr.IsError);
Assert.IsTrue(rr.Type.IsKnownType(KnownTypeCode.Int32));
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
var getAwaiterInvocation = (CSharpInvocationResolveResult)rr.GetAwaiterInvocation;
Assert.IsFalse(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(1, getAwaiterInvocation.Arguments.Count);
Assert.AreEqual("N.MyAwaitableExtensions.GetAwaiter", getAwaiterInvocation.Member.FullName);
Assert.AreEqual(1, getAwaiterInvocation.Member.Parameters.Count);
Assert.IsTrue(getAwaiterInvocation.Arguments[0] is LocalResolveResult && ((LocalResolveResult)getAwaiterInvocation.Arguments[0]).Variable.Name == "x");
Assert.AreEqual("N.MyAwaiter", rr.AwaiterType.FullName);
Assert.IsNull(rr.IsCompletedProperty);
Assert.IsNotNull(rr.OnCompletedMethod);
Assert.AreEqual("N.MyAwaiter.OnCompleted", rr.OnCompletedMethod.FullName);
Assert.IsNotNull(rr.GetResultMethod);
}
[Test]
public void AwaiterWithIsCompletedPropertyThatIsNotAccessible() {
string program = @"
using System;
namespace N {
class MyAwaiter : System.Runtime.CompilerServices.INotifyCompletion {
private bool IsCompleted { get; set; }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
public static MyAwaiter GetAwaiter(int i) { return null; }
}
static class MyAwaitableExtensions {
public static MyAwaiter GetAwaiter(this MyAwaitable x) { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = $await x$;
}
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsTrue(rr.IsError);
Assert.IsTrue(rr.Type.IsKnownType(KnownTypeCode.Int32));
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
var getAwaiterInvocation = (CSharpInvocationResolveResult)rr.GetAwaiterInvocation;
Assert.IsFalse(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(1, getAwaiterInvocation.Arguments.Count);
Assert.AreEqual("N.MyAwaitableExtensions.GetAwaiter", getAwaiterInvocation.Member.FullName);
Assert.AreEqual(1, getAwaiterInvocation.Member.Parameters.Count);
Assert.IsTrue(getAwaiterInvocation.Arguments[0] is LocalResolveResult && ((LocalResolveResult)getAwaiterInvocation.Arguments[0]).Variable.Name == "x");
Assert.AreEqual("N.MyAwaiter", rr.AwaiterType.FullName);
Assert.IsNull(rr.IsCompletedProperty);
Assert.IsNotNull(rr.OnCompletedMethod);
Assert.AreEqual("N.MyAwaiter.OnCompleted", rr.OnCompletedMethod.FullName);
Assert.IsNotNull(rr.GetResultMethod);
}
[Test]
public void AwaiterThatDoesNotImplementINotifyCompletion() {
string program = @"
using System;
class MyAwaiter {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Func<int> continuation) {}
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
@ -611,6 +893,49 @@ public class C { @@ -611,6 +893,49 @@ public class C {
Assert.AreEqual("MyAwaiter.GetResult", rr.GetResultMethod.FullName);
}
[Test]
public void AwaiterThatImplementsICriticalNotifyCompletion() {
string program = @"
using System;
class MyAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public void UnsafeOnCompleted(Action continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
public MyAwaiter GetAwaiter() { return null; }
public MyAwaiter GetAwaiter(int i) { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = $await x$;
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.IsTrue(rr.Type.IsKnownType(KnownTypeCode.Int32));
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
var getAwaiterInvocation = (CSharpInvocationResolveResult)rr.GetAwaiterInvocation;
Assert.IsFalse(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(0, getAwaiterInvocation.Arguments.Count);
Assert.AreEqual("MyAwaitable.GetAwaiter", getAwaiterInvocation.Member.FullName);
Assert.AreEqual(0, getAwaiterInvocation.Member.Parameters.Count);
Assert.AreEqual("MyAwaiter", rr.AwaiterType.FullName);
Assert.IsNotNull(rr.IsCompletedProperty);
Assert.AreEqual("MyAwaiter.IsCompleted", rr.IsCompletedProperty.FullName);
Assert.IsNotNull(rr.OnCompletedMethod);
Assert.AreEqual("MyAwaiter.UnsafeOnCompleted", rr.OnCompletedMethod.FullName);
Assert.IsNotNull(rr.GetResultMethod);
Assert.AreEqual("MyAwaiter.GetResult", rr.GetResultMethod.FullName);
}
[Test]
public void AwaitDynamic() {
string program = @"
@ -640,5 +965,6 @@ public class C { @@ -640,5 +965,6 @@ public class C {
Assert.IsNull(rr.OnCompletedMethod);
Assert.IsNull(rr.GetResultMethod);
}
#endif // NET_4_5
}
}

23
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/FormattingTests/TestStatementIndentation.cs

@ -2010,6 +2010,29 @@ if (b) { @@ -2010,6 +2010,29 @@ if (b) {
}
}");
}
[Test]
public void TestUsingInsideNamespace()
{
CSharpFormattingOptions policy = FormattingOptionsFactory.CreateMono();
policy.UsingPlacement = UsingPlacement.InsideNamespace;
Test(policy, @"namespace TestNamespace
{
using System;
class Test
{
}
}", @"namespace TestNamespace
{
using System;
class Test
{
}
}");
}
}
}

5
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

@ -75,6 +75,10 @@ @@ -75,6 +75,10 @@
</Compile>
<Compile Include="CSharp\Analysis\DefiniteAssignmentTests.cs" />
<Compile Include="CSharp\AstStructureTests.cs" />
<Compile Include="CSharp\CodeActions\AddUsing\AddUsingActionAlphabeticalTests.cs" />
<Compile Include="CSharp\CodeActions\AddUsing\AddUsingActionInsideNamespaceTests.cs" />
<Compile Include="CSharp\CodeActions\AddUsing\AddUsingRunActionTests.cs" />
<Compile Include="CSharp\CodeActions\AddUsing\AddUsingActionTests.cs" />
<Compile Include="CSharp\CodeActions\ConvertAsToCastTests.cs" />
<Compile Include="CSharp\CodeActions\ConvertCastToAsTests.cs" />
<Compile Include="CSharp\CodeActions\ConvertConditionalToIfTests.cs" />
@ -388,6 +392,7 @@ @@ -388,6 +392,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="CSharp\" />
<Folder Include="CSharp\CodeActions\AddUsing" />
<Folder Include="CSharp\Parser\" />
<Folder Include="CSharp\CodeIssues\" />
<Folder Include="CSharp\CodeActions\" />

16
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs

@ -342,4 +342,20 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase @@ -342,4 +342,20 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase
private void Private() {}
void None() {}
}
public class ConstantFieldTest
{
public const byte Cb = 42;
public const sbyte Csb = 42;
public const char Cc = '\x42';
public const short Cs = 42;
public const ushort Cus = 42;
public const int Ci = 42;
public const uint Cui = 42;
public const long Cl = 42;
public const ulong Cul = 42;
public const double Cd = 42;
public const float Cf = 42;
public const decimal Cm = 42;
}
}

24
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs

@ -1228,5 +1228,29 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -1228,5 +1228,29 @@ namespace ICSharpCode.NRefactory.TypeSystem
Assert.AreEqual(Accessibility.Private, type.Methods.Single(m => m.Name == "Private").Accessibility);
Assert.AreEqual(Accessibility.Private, type.Methods.Single(m => m.Name == "None").Accessibility);
}
private void AssertConstantField<T>(ITypeDefinition type, string name, T expected) {
var f = type.GetFields().Single(x => x.Name == name);
Assert.IsTrue(f.IsConst);
Assert.AreEqual(expected, f.ConstantValue);
}
[Test]
public void ConstantFields()
{
ITypeDefinition type = GetTypeDefinition(typeof(ConstantFieldTest));
AssertConstantField<byte>(type, "Cb", 42);
AssertConstantField<sbyte>(type, "Csb", 42);
AssertConstantField<char>(type, "Cc", '\x42');
AssertConstantField<short>(type, "Cs", 42);
AssertConstantField<ushort>(type, "Cus", 42);
AssertConstantField<int>(type, "Ci", 42);
AssertConstantField<uint>(type, "Cui", 42);
AssertConstantField<long>(type, "Cl", 42);
AssertConstantField<ulong>(type, "Cul", 42);
AssertConstantField<double>(type, "Cd", 42);
AssertConstantField<float>(type, "Cf", 42);
AssertConstantField<decimal>(type, "Cm", 42);
}
}
}

46
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs

@ -788,7 +788,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -788,7 +788,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
foreach (var cecilAttribute in attributes) {
TypeReference type = cecilAttribute.AttributeType;
if (type.Namespace == "System.Runtime.CompilerServices") {
if (type.Name == "DynamicAttribute" || type.Name == "ExtensionAttribute")
if (type.Name == "DynamicAttribute" || type.Name == "ExtensionAttribute" || type.Name == "DecimalConstantAttribute")
continue;
} else if (type.Name == "ParamArrayAttribute" && type.Namespace == "System") {
continue;
@ -2074,6 +2074,42 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -2074,6 +2074,42 @@ namespace ICSharpCode.NRefactory.TypeSystem
|| att == FieldAttributes.Family
|| att == FieldAttributes.FamORAssem;
}
decimal? TryDecodeDecimalConstantAttribute(CustomAttribute attribute)
{
if (attribute.ConstructorArguments.Count != 5)
return null;
BlobReader reader = new BlobReader(attribute.GetBlob(), null);
if (reader.ReadUInt16() != 0x0001) {
Debug.WriteLine("Unknown blob prolog");
return null;
}
// DecimalConstantAttribute has the arguments (byte scale, byte sign, uint hi, uint mid, uint low) or (byte scale, byte sign, int hi, int mid, int low)
// Both of these invoke the Decimal constructor (int lo, int mid, int hi, bool isNegative, byte scale) with explicit argument conversions if required.
var ctorArgs = new object[attribute.ConstructorArguments.Count];
for (int i = 0; i < ctorArgs.Length; i++) {
switch (attribute.ConstructorArguments[i].Type.FullName) {
case "System.Byte":
ctorArgs[i] = reader.ReadByte();
break;
case "System.Int32":
ctorArgs[i] = reader.ReadInt32();
break;
case "System.UInt32":
ctorArgs[i] = unchecked((int)reader.ReadUInt32());
break;
default:
return null;
}
}
if (!ctorArgs.Select(a => a.GetType()).SequenceEqual(new[] { typeof(byte), typeof(byte), typeof(int), typeof(int), typeof(int) }))
return null;
return new decimal((int)ctorArgs[4], (int)ctorArgs[3], (int)ctorArgs[2], (byte)ctorArgs[1] != 0, (byte)ctorArgs[0]);
}
[CLSCompliant(false)]
public IUnresolvedField ReadField(FieldDefinition field, IUnresolvedTypeDefinition parentType)
@ -2091,6 +2127,14 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -2091,6 +2127,14 @@ namespace ICSharpCode.NRefactory.TypeSystem
if (field.HasConstant) {
f.ConstantValue = CreateSimpleConstantValue(f.ReturnType, field.Constant);
}
else {
var decConstant = field.CustomAttributes.FirstOrDefault(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.DecimalConstantAttribute");
if (decConstant != null) {
var constValue = TryDecodeDecimalConstantAttribute(decConstant);
if (constValue != null)
f.ConstantValue = CreateSimpleConstantValue(f.ReturnType, constValue);
}
}
AddAttributes(field, f);
RequiredModifierType modreq = field.FieldType as RequiredModifierType;

22
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/KnownTypeReference.cs

@ -118,7 +118,11 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -118,7 +118,11 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// <summary><c>System.Nullable{T}</c></summary>
NullableOfT,
/// <summary><c>System.IDisposable</c></summary>
IDisposable
IDisposable,
/// <summary><c>System.Runtime.CompilerServices.INotifyCompletion</c></summary>
INotifyCompletion,
/// <summary><c>System.Runtime.CompilerServices.ICriticalNotifyCompletion</c></summary>
ICriticalNotifyCompletion,
}
/// <summary>
@ -127,7 +131,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -127,7 +131,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Serializable]
public sealed class KnownTypeReference : ITypeReference
{
internal const int KnownTypeCodeCount = (int)KnownTypeCode.IDisposable + 1;
internal const int KnownTypeCodeCount = (int)KnownTypeCode.ICriticalNotifyCompletion + 1;
static readonly KnownTypeReference[] knownTypeReferences = new KnownTypeReference[KnownTypeCodeCount] {
null, // None
@ -174,6 +178,8 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -174,6 +178,8 @@ namespace ICSharpCode.NRefactory.TypeSystem
new KnownTypeReference(KnownTypeCode.TaskOfT, "System.Threading.Tasks", "Task", 1, baseType: KnownTypeCode.Task),
new KnownTypeReference(KnownTypeCode.NullableOfT, "System", "Nullable", 1, baseType: KnownTypeCode.ValueType),
new KnownTypeReference(KnownTypeCode.IDisposable, "System", "IDisposable"),
new KnownTypeReference(KnownTypeCode.INotifyCompletion, "System.Runtime.CompilerServices", "INotifyCompletion"),
new KnownTypeReference(KnownTypeCode.ICriticalNotifyCompletion, "System.Runtime.CompilerServices", "ICriticalNotifyCompletion"),
};
/// <summary>
@ -389,7 +395,17 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -389,7 +395,17 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// Gets a type reference pointing to the <c>System.IDisposable</c> type.
/// </summary>
public static readonly KnownTypeReference IDisposable = Get(KnownTypeCode.IDisposable);
/// <summary>
/// Gets a type reference pointing to the <c>System.Runtime.CompilerServices.INotifyCompletion</c> type.
/// </summary>
public static readonly KnownTypeReference INotifyCompletion = Get(KnownTypeCode.INotifyCompletion);
/// <summary>
/// Gets a type reference pointing to the <c>System.Runtime.CompilerServices.ICriticalNotifyCompletion</c> type.
/// </summary>
public static readonly KnownTypeReference ICriticalNotifyCompletion = Get(KnownTypeCode.ICriticalNotifyCompletion);
readonly KnownTypeCode knownTypeCode;
readonly string namespaceName;
readonly string name;

Loading…
Cancel
Save