Browse Source

Merge NRefactory 5.2.0-435-gb500f46 into SharpDevelop newNR branch.

newNRvisualizers
Daniel Grunwald 13 years ago
parent
commit
5878b3a8bf
  1. 1
      src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin
  2. 13
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionDataFactory.cs
  3. 11
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs
  4. 96
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs
  5. 38
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstType.cs
  6. 55
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpModifierToken.cs
  7. 20
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpTokenNode.cs
  8. 8
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/ComposedType.cs
  9. 12
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/QueryExpression.cs
  10. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Constraint.cs
  11. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/MemberType.cs
  12. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/PrimitiveType.cs
  13. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/SimpleType.cs
  14. 32
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TokenRole.cs
  15. 17
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/EventDeclaration.cs
  16. 16
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/FieldDeclaration.cs
  17. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/IndexerDeclaration.cs
  18. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/OperatorDeclaration.cs
  19. 155
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs
  20. 8
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs
  21. 5
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs
  22. 34
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/CompletionDataWrapper.cs
  23. 9
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/ICompletionDataFactory.cs
  24. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  25. 12
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs
  26. 784
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs
  27. 8
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/cfold.cs
  28. 19
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/constant.cs
  29. 22
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/context.cs
  30. 35
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/convert.cs
  31. 6374
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-parser.cs
  32. 24
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-parser.jay
  33. 22
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-tokenizer.cs
  34. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/driver.cs
  35. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/expression.cs
  36. 49
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/statement.cs
  37. 152
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/support.cs
  38. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/QueryExpressionExpander.cs
  39. 10
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs
  40. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertToInitializer/AccessPath.cs
  41. 12
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateFieldAction.cs
  42. 145
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/SortUsingsAction.cs
  43. 23
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AccessToClosureIssues/AccessToClosureIssue.cs
  44. 48
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ForControlVariableNotModifiedIssue.cs
  45. 11
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/FormatStringIssues/FormatStringIssue.cs
  46. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/IncorrectExceptionParameterOrderingIssue.cs
  47. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MethodNeverReturnsIssue.cs
  48. 73
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MultipleEnumerationIssue.cs
  49. 24
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/OptionalParameterCouldBeSkippedIssue.cs
  50. 10
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ParameterCanBeDemotedIssue/ParameterCanBeDemotedIssue.cs
  51. 59
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantAssignmentIssue.cs
  52. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantNamespaceUsageIssue.cs
  53. 17
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantToStringIssue.cs
  54. 5
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceEqualsCalledWithValueTypeIssue.cs
  55. 19
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ValueParameterUnusedIssue.cs
  56. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableDeclaredInWideScopeIssue.cs
  57. 26
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/LocalVariableNotUsedIssue.cs
  58. 18
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/ParameterNotUsedIssue.cs
  59. 60
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/VariableNotUsedIssue.cs
  60. 11
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/LocalVariableOnlyAssignedIssue.cs
  61. 27
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/ParameterOnlyAssignedIssue.cs
  62. 69
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/VariableOnlyAssignedIssue.cs
  63. 154
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/LocalReferenceFinder.cs
  64. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/NamingHelper.cs
  65. 46
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/TypeSystemAstBuilder.cs
  66. 36
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/VariableReferenceGraph.cs
  67. 80
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/AwaitResolveResult.cs
  68. 59
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs
  69. 8
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpInvocationResolveResult.cs
  70. 90
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  71. 43
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs
  72. 8
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs
  73. 10
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs
  74. 7
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/ResolveAtLocation.cs
  75. 86
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
  76. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs
  77. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs
  78. 5
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/TypeSystem/ConstantValues.cs
  79. 15
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CSharpOutputVisitorTests.cs
  80. 109
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/SortUsingsTests.cs
  81. 178
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs
  82. 18
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/KeywordTests.cs
  83. 3
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/NameContextTests.cs
  84. 58
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ObjectInitializerTests.cs
  85. 53
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs
  86. 10
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/RedundantNamespaceUsageInspectorTests.cs
  87. 1
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PrimitiveExpressionTests.cs
  88. 29
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs
  89. 90
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Refactoring/TypeSystemAstBuilderTests.cs
  90. 100
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ArrayCreateTests.cs
  91. 14
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ComTests.cs
  92. 229
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs
  93. 58
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs
  94. 18
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/MethodTests.cs
  95. 28
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs
  96. 366
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnaryOperatorTests.cs
  97. 1
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
  98. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs
  99. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory/Semantics/ArrayCreateResolveResult.cs
  100. 17
      src/Libraries/NRefactory/ICSharpCode.NRefactory/Semantics/Conversion.cs
  101. Some files were not shown because too many files have changed in this diff Show More

1
src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin

@ -279,6 +279,7 @@
<CSharpCodeActionProvider class = "ICSharpCode.NRefactory.CSharp.Refactoring.RemoveRedundantCatchTypeAction" /> <CSharpCodeActionProvider class = "ICSharpCode.NRefactory.CSharp.Refactoring.RemoveRedundantCatchTypeAction" />
<CSharpCodeActionProvider class = "ICSharpCode.NRefactory.CSharp.Refactoring.RemoveRegionAction" /> <CSharpCodeActionProvider class = "ICSharpCode.NRefactory.CSharp.Refactoring.RemoveRegionAction" />
<CSharpCodeActionProvider class = "ICSharpCode.NRefactory.CSharp.Refactoring.ReplaceEmptyStringAction" /> <CSharpCodeActionProvider class = "ICSharpCode.NRefactory.CSharp.Refactoring.ReplaceEmptyStringAction" />
<CSharpCodeActionProvider class = "ICSharpCode.NRefactory.CSharp.Refactoring.SortUsingsAction" />
<CSharpCodeActionProvider class = "ICSharpCode.NRefactory.CSharp.Refactoring.SplitDeclarationAndAssignmentAction" /> <CSharpCodeActionProvider class = "ICSharpCode.NRefactory.CSharp.Refactoring.SplitDeclarationAndAssignmentAction" />
<CSharpCodeActionProvider class = "ICSharpCode.NRefactory.CSharp.Refactoring.SplitDeclarationListAction" /> <CSharpCodeActionProvider class = "ICSharpCode.NRefactory.CSharp.Refactoring.SplitDeclarationListAction" />
<CSharpCodeActionProvider class = "ICSharpCode.NRefactory.CSharp.Refactoring.SplitStringAction" /> <CSharpCodeActionProvider class = "ICSharpCode.NRefactory.CSharp.Refactoring.SplitStringAction" />

13
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionDataFactory.cs

@ -46,9 +46,18 @@ namespace CSharpBinding.Completion
}; };
} }
ICompletionData ICompletionDataFactory.CreateTypeCompletionData(IType type, string shortType) ICompletionData ICompletionDataFactory.CreateTypeCompletionData(IType type, bool showFullName, bool isInAttributeContext)
{ {
return new CompletionData(shortType); var typeDef = type.GetDefinition();
if (typeDef != null)
return new EntityCompletionData(typeDef);
else
return new CompletionData(type.Name);
}
ICompletionData ICompletionDataFactory.CreateMemberCompletionData(IType type, IEntity member)
{
return new CompletionData(type.Name + "." + member.Name);
} }
ICompletionData ICompletionDataFactory.CreateLiteralCompletionData(string title, string description, string insertText) ICompletionData ICompletionDataFactory.CreateLiteralCompletionData(string title, string description, string insertText)

11
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs

@ -408,10 +408,15 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
bool? cond = ifElseStatement.Condition.IsNull ? true : builder.EvaluateCondition(ifElseStatement.Condition); bool? cond = ifElseStatement.Condition.IsNull ? true : builder.EvaluateCondition(ifElseStatement.Condition);
if (ifElseStatement.TrueStatement.IsNull) if (ifElseStatement.TrueStatement.IsNull)
return data; return data;
ControlFlowNode trueBegin = builder.CreateStartNode(ifElseStatement.TrueStatement); ControlFlowNode trueBegin;
if (cond != false) if (ifElseStatement.TrueStatement.IsNull) {
trueBegin = null;
} else {
trueBegin = builder.CreateStartNode(ifElseStatement.TrueStatement);
}
if (cond != false && trueBegin != null)
Connect(data, trueBegin, ControlFlowEdgeType.ConditionTrue); Connect(data, trueBegin, ControlFlowEdgeType.ConditionTrue);
ControlFlowNode trueEnd = ifElseStatement.TrueStatement.AcceptVisitor(this, trueBegin); ControlFlowNode trueEnd = trueBegin != null ? ifElseStatement.TrueStatement.AcceptVisitor(this, trueBegin) : null;
ControlFlowNode falseEnd; ControlFlowNode falseEnd;
if (ifElseStatement.FalseStatement.IsNull) { if (ifElseStatement.FalseStatement.IsNull) {
falseEnd = null; falseEnd = null;

96
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs

@ -652,20 +652,18 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
AstNode result = null; AstNode result = null;
AstNode node = this; AstNode node = this;
while (node.FirstChild != null) { while (node.LastChild != null) {
var child = node.FirstChild; var child = node.LastChild;
while (child != null) { while (child != null && child.StartLocation > location)
if (child.StartLocation <= location && location < child.EndLocation) { child = child.prevSibling;
if (pred == null || pred (child)) if (child != null && location < child.EndLocation) {
result = child; if (pred == null || pred (child))
node = child; result = child;
break; node = child;
} } else {
child = child.NextSibling; // found no better child node - therefore the parent is the right one.
}
// found no better child node - therefore the parent is the right one.
if (child == null)
break; break;
}
} }
return result; return result;
} }
@ -689,20 +687,18 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
T result = null; T result = null;
AstNode node = this; AstNode node = this;
while (node.FirstChild != null) { while (node.LastChild != null) {
var child = node.FirstChild; var child = node.LastChild;
while (child != null) { while (child != null && child.StartLocation > location)
if (child.StartLocation <= location && location < child.EndLocation) { child = child.prevSibling;
if (child is T) if (child != null && location < child.EndLocation) {
result = (T)child; if (child is T)
node = child; result = (T)child;
break; node = child;
} } else {
child = child.NextSibling; // found no better child node - therefore the parent is the right one.
}
// found no better child node - therefore the parent is the right one.
if (child == null)
break; break;
}
} }
return result; return result;
} }
@ -729,20 +725,18 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
AstNode result = null; AstNode result = null;
AstNode node = this; AstNode node = this;
while (node.FirstChild != null) { while (node.LastChild != null) {
var child = node.FirstChild; var child = node.LastChild;
while (child != null) { while (child != null && child.StartLocation > location)
if (child.StartLocation <= location && location <= child.EndLocation) { child = child.prevSibling;
if (pred == null || pred (child)) if (child != null && location <= child.EndLocation) {
result = child; if (pred == null || pred (child))
node = child; result = child;
break; node = child;
} } else {
child = child.NextSibling; // found no better child node - therefore the parent is the right one.
}
// found no better child node - therefore the parent is the right one.
if (child == null)
break; break;
}
} }
return result; return result;
} }
@ -766,20 +760,18 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
T result = null; T result = null;
AstNode node = this; AstNode node = this;
while (node.FirstChild != null) { while (node.LastChild != null) {
var child = node.FirstChild; var child = node.LastChild;
while (child != null) { while (child != null && child.StartLocation > location)
if (child.StartLocation <= location && location < child.EndLocation) { child = child.prevSibling;
if (child is T) if (child != null && location <= child.EndLocation) {
result = (T)child; if (child is T)
node = child; result = (T)child;
break; node = child;
} } else {
child = child.NextSibling; // found no better child node - therefore the parent is the right one.
}
// found no better child node - therefore the parent is the right one.
if (child == null)
break; break;
}
} }
return result; return result;
} }

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

@ -127,6 +127,7 @@ namespace ICSharpCode.NRefactory.CSharp
/// <summary> /// <summary>
/// Create an ITypeReference for this AstType. /// Create an ITypeReference for this AstType.
/// Uses the context (ancestors of this node) to determine the correct <see cref="NameLookupMode"/>.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// The resulting type reference will read the context information from the /// The resulting type reference will read the context information from the
@ -135,7 +136,42 @@ namespace ICSharpCode.NRefactory.CSharp
/// For resolving simple names, the current namespace and usings from the CurrentUsingScope /// For resolving simple names, the current namespace and usings from the CurrentUsingScope
/// (on CSharpTypeResolveContext only) is used. /// (on CSharpTypeResolveContext only) is used.
/// </remarks> /// </remarks>
public abstract ITypeReference ToTypeReference(NameLookupMode lookupMode = NameLookupMode.Type, InterningProvider interningProvider = null); public ITypeReference ToTypeReference(InterningProvider interningProvider = null)
{
return ToTypeReference(GetNameLookupMode(), interningProvider);
}
/// <summary>
/// Create an ITypeReference for this AstType.
/// </summary>
/// <remarks>
/// The resulting type reference will read the context information from the
/// <see cref="ITypeResolveContext"/>:
/// For resolving type parameters, the CurrentTypeDefinition/CurrentMember is used.
/// For resolving simple names, the current namespace and usings from the CurrentUsingScope
/// (on CSharpTypeResolveContext only) is used.
/// </remarks>
public abstract ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null);
/// <summary>
/// Gets the name lookup mode from the context (looking at the ancestors of this <see cref="AstType"/>).
/// </summary>
public NameLookupMode GetNameLookupMode()
{
AstType outermostType = this;
while (outermostType.Parent is AstType)
outermostType = (AstType)outermostType.Parent;
if (outermostType.Parent is UsingDeclaration || outermostType.Parent is UsingAliasDeclaration) {
return NameLookupMode.TypeInUsingDeclaration;
} else if (outermostType.Role == Roles.BaseType) {
// Use BaseTypeReference for a type's base type, and for a constraint on a type.
// Do not use it for a constraint on a method.
if (outermostType.Parent is TypeDeclaration || (outermostType.Parent is Constraint && outermostType.Parent.Parent is TypeDeclaration))
return NameLookupMode.BaseTypeReference;
}
return NameLookupMode.Type;
}
/// <summary> /// <summary>
/// Creates a pointer type from this type by nesting it in a <see cref="ComposedType"/>. /// Creates a pointer type from this type by nesting it in a <see cref="ComposedType"/>.

55
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpModifierToken.cs

@ -40,13 +40,13 @@ namespace ICSharpCode.NRefactory.CSharp
this.modifier = value; this.modifier = value;
} }
} }
protected override int TokenLength { public override TextLocation EndLocation {
get { get {
return GetModifierName (modifier).Length; return new TextLocation (StartLocation.Line, StartLocation.Column + GetModifierLength (Modifier));
} }
} }
public override string GetText (CSharpFormattingOptions formattingOptions = null) public override string GetText (CSharpFormattingOptions formattingOptions = null)
{ {
return GetModifierName (Modifier); return GetModifierName (Modifier);
@ -75,7 +75,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return allModifiers; } get { return allModifiers; }
} }
public CSharpModifierToken (TextLocation location, Modifiers modifier) : base (location) public CSharpModifierToken (TextLocation location, Modifiers modifier) : base (location, null)
{ {
this.Modifier = modifier; this.Modifier = modifier;
} }
@ -124,5 +124,50 @@ namespace ICSharpCode.NRefactory.CSharp
throw new NotSupportedException("Invalid value for Modifiers"); throw new NotSupportedException("Invalid value for Modifiers");
} }
} }
public static int GetModifierLength(Modifiers modifier)
{
switch (modifier) {
case Modifiers.Private:
return "private".Length;
case Modifiers.Internal:
return "internal".Length;
case Modifiers.Protected:
return "protected".Length;
case Modifiers.Public:
return "public".Length;
case Modifiers.Abstract:
return "abstract".Length;
case Modifiers.Virtual:
return "virtual".Length;
case Modifiers.Sealed:
return "sealed".Length;
case Modifiers.Static:
return "static".Length;
case Modifiers.Override:
return "override".Length;
case Modifiers.Readonly:
return "readonly".Length;
case Modifiers.Const:
return "const".Length;
case Modifiers.New:
return "new".Length;
case Modifiers.Partial:
return "partial".Length;
case Modifiers.Extern:
return "extern".Length;
case Modifiers.Volatile:
return "volatile".Length;
case Modifiers.Unsafe:
return "unsafe".Length;
case Modifiers.Async:
return "async".Length;
case Modifiers.Any:
// even though it's used for pattern matching only, 'any' needs to be in this list to be usable in the AST
return "any".Length;
default:
throw new NotSupportedException("Invalid value for Modifiers");
}
}
} }
} }

20
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpTokenNode.cs

@ -44,7 +44,7 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public NullCSharpTokenNode () : base (TextLocation.Empty) public NullCSharpTokenNode () : base (TextLocation.Empty, null)
{ {
} }
@ -80,12 +80,10 @@ namespace ICSharpCode.NRefactory.CSharp
return startLocation; return startLocation;
} }
} }
protected virtual int TokenLength { int TokenLength {
get { get {
if (!(Role is TokenRole)) return TokenRole.TokenLengths [(int)(this.flags >> AstNodeFlagsUsedBits)];
return 0;
return ((TokenRole)Role).Length;
} }
} }
@ -94,17 +92,17 @@ namespace ICSharpCode.NRefactory.CSharp
return new TextLocation (StartLocation.Line, StartLocation.Column + TokenLength); return new TextLocation (StartLocation.Line, StartLocation.Column + TokenLength);
} }
} }
public CSharpTokenNode (TextLocation location) public CSharpTokenNode (TextLocation location, TokenRole role)
{ {
this.startLocation = location; this.startLocation = location;
if (role != null)
this.flags |= role.TokenIndex << AstNodeFlagsUsedBits;
} }
public override string GetText (CSharpFormattingOptions formattingOptions = null) public override string GetText (CSharpFormattingOptions formattingOptions = null)
{ {
if (!(Role is TokenRole)) return TokenRole.Tokens [(int)(this.flags >> AstNodeFlagsUsedBits)];
return null;
return ((TokenRole)Role).Token;
} }
public override void AcceptVisitor (IAstVisitor visitor) public override void AcceptVisitor (IAstVisitor visitor)

8
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/ComposedType.cs

@ -47,7 +47,7 @@ namespace ICSharpCode.NRefactory.CSharp
return !GetChildByRole(NullableRole).IsNull; return !GetChildByRole(NullableRole).IsNull;
} }
set { set {
SetChildByRole(NullableRole, value ? new CSharpTokenNode(TextLocation.Empty) : null); SetChildByRole(NullableRole, value ? new CSharpTokenNode(TextLocation.Empty, null) : null);
} }
} }
@ -64,7 +64,7 @@ namespace ICSharpCode.NRefactory.CSharp
d--; d--;
} }
while (d < value) { while (d < value) {
InsertChildBefore(GetChildByRole(PointerRole), new CSharpTokenNode(TextLocation.Empty), PointerRole); InsertChildBefore(GetChildByRole(PointerRole), new CSharpTokenNode(TextLocation.Empty, PointerRole), PointerRole);
d++; d++;
} }
} }
@ -126,7 +126,7 @@ namespace ICSharpCode.NRefactory.CSharp
return this; return this;
} }
public override ITypeReference ToTypeReference(NameLookupMode lookupMode = NameLookupMode.Type, InterningProvider interningProvider = null) public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null)
{ {
if (interningProvider == null) if (interningProvider == null)
interningProvider = InterningProvider.Dummy; interningProvider = InterningProvider.Dummy;
@ -178,7 +178,7 @@ namespace ICSharpCode.NRefactory.CSharp
d--; d--;
} }
while (d < value) { while (d < value) {
InsertChildBefore(GetChildByRole(Roles.Comma), new CSharpTokenNode(TextLocation.Empty), Roles.Comma); InsertChildBefore(GetChildByRole(Roles.Comma), new CSharpTokenNode(TextLocation.Empty, Roles.Comma), Roles.Comma);
d++; d++;
} }
} }

12
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/QueryExpression.cs

@ -118,6 +118,10 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole(PrecedingQueryRole, value); } set { SetChildByRole(PrecedingQueryRole, value); }
} }
public CSharpTokenNode IntoKeyword {
get { return GetChildByRole (IntoKeywordRole); }
}
public string Identifier { public string Identifier {
get { get {
return GetChildByRole (Roles.Identifier).Name; return GetChildByRole (Roles.Identifier).Name;
@ -158,6 +162,10 @@ namespace ICSharpCode.NRefactory.CSharp
public static readonly TokenRole FromKeywordRole = new TokenRole ("from"); public static readonly TokenRole FromKeywordRole = new TokenRole ("from");
public static readonly TokenRole InKeywordRole = new TokenRole ("in"); public static readonly TokenRole InKeywordRole = new TokenRole ("in");
public CSharpTokenNode FromKeyword {
get { return GetChildByRole (FromKeywordRole); }
}
public AstType Type { public AstType Type {
get { return GetChildByRole (Roles.Type); } get { return GetChildByRole (Roles.Type); }
set { SetChildByRole (Roles.Type, value); } set { SetChildByRole (Roles.Type, value); }
@ -176,6 +184,10 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole(Roles.Identifier); } get { return GetChildByRole(Roles.Identifier); }
} }
public CSharpTokenNode InKeyword {
get { return GetChildByRole (InKeywordRole); }
}
public Expression Expression { public Expression Expression {
get { return GetChildByRole (Roles.Expression); } get { return GetChildByRole (Roles.Expression); }
set { SetChildByRole (Roles.Expression, value); } set { SetChildByRole (Roles.Expression, value); }

6
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Constraint.cs

@ -41,7 +41,11 @@ namespace ICSharpCode.NRefactory.CSharp
return NodeType.Unknown; return NodeType.Unknown;
} }
} }
public CSharpTokenNode WhereKeyword {
get { return GetChildByRole (Roles.WhereKeyword); }
}
public SimpleType TypeParameter { public SimpleType TypeParameter {
get { get {
return GetChildByRole (Roles.ConstraintTypeParameter); return GetChildByRole (Roles.ConstraintTypeParameter);

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/MemberType.cs

@ -135,7 +135,7 @@ namespace ICSharpCode.NRefactory.CSharp
return b.ToString(); return b.ToString();
} }
public override ITypeReference ToTypeReference(NameLookupMode lookupMode = NameLookupMode.Type, InterningProvider interningProvider = null) public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null)
{ {
if (interningProvider == null) if (interningProvider == null)
interningProvider = InterningProvider.Dummy; interningProvider = InterningProvider.Dummy;

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/PrimitiveType.cs

@ -103,7 +103,7 @@ namespace ICSharpCode.NRefactory.CSharp
return Keyword; return Keyword;
} }
public override ITypeReference ToTypeReference(NameLookupMode lookupMode = NameLookupMode.Type, InterningProvider interningProvider = null) public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null)
{ {
KnownTypeCode typeCode = GetTypeCodeForPrimitiveType(this.Keyword); KnownTypeCode typeCode = GetTypeCodeForPrimitiveType(this.Keyword);
if (typeCode == KnownTypeCode.None) if (typeCode == KnownTypeCode.None)

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/SimpleType.cs

@ -158,7 +158,7 @@ namespace ICSharpCode.NRefactory.CSharp
return b.ToString(); return b.ToString();
} }
public override ITypeReference ToTypeReference(NameLookupMode lookupMode = NameLookupMode.Type, InterningProvider interningProvider = null) public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null)
{ {
if (interningProvider == null) if (interningProvider == null)
interningProvider = InterningProvider.Dummy; interningProvider = InterningProvider.Dummy;

32
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TokenRole.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp namespace ICSharpCode.NRefactory.CSharp
{ {
@ -7,6 +8,17 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary> /// </summary>
public sealed class TokenRole : Role<CSharpTokenNode> public sealed class TokenRole : Role<CSharpTokenNode>
{ {
internal readonly static List<string> Tokens = new List<string> ();
internal readonly static List<int> TokenLengths = new List<int> ();
internal readonly uint TokenIndex;
static TokenRole ()
{
// null token
Tokens.Add ("");
TokenLengths.Add (0);
}
/// <summary> /// <summary>
/// Gets the token as string. Note that the token Name and Token value may differ. /// Gets the token as string. Note that the token Name and Token value may differ.
/// </summary> /// </summary>
@ -22,11 +34,27 @@ namespace ICSharpCode.NRefactory.CSharp
get; get;
private set; private set;
} }
public TokenRole (string token) : base (token, CSharpTokenNode.Null)
public TokenRole(string token) : base (token, CSharpTokenNode.Null)
{ {
this.Token = token; this.Token = token;
this.Length = token.Length; this.Length = token.Length;
bool found = false;
for (int i = 0; i < Tokens.Count; i++) {
var existingToken = Tokens [i];
if (existingToken == token) {
TokenIndex = (uint)i;
found = true;
break;
}
}
if (!found) {
TokenIndex = (uint)Tokens.Count;
Tokens.Add (token);
TokenLengths.Add (this.Length);
}
} }
} }
} }

17
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/EventDeclaration.cs

@ -24,7 +24,10 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp namespace ICSharpCode.NRefactory.CSharp
@ -41,6 +44,20 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildrenByRole (Roles.Variable); } get { return GetChildrenByRole (Roles.Variable); }
} }
// Hide .Name and .NameToken from users; the actual field names
// are stored in the VariableInitializer.
[EditorBrowsable(EditorBrowsableState.Never)]
public override string Name {
get { return string.Empty; }
set { throw new NotSupportedException(); }
}
[EditorBrowsable(EditorBrowsableState.Never)]
public override Identifier NameToken {
get { return Identifier.Null; }
set { throw new NotSupportedException(); }
}
public override void AcceptVisitor (IAstVisitor visitor) public override void AcceptVisitor (IAstVisitor visitor)
{ {
visitor.VisitEventDeclaration (this); visitor.VisitEventDeclaration (this);

16
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/FieldDeclaration.cs

@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
using System;
using System.ComponentModel;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp namespace ICSharpCode.NRefactory.CSharp
@ -38,6 +40,20 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildrenByRole (Roles.Variable); } get { return GetChildrenByRole (Roles.Variable); }
} }
// Hide .Name and .NameToken from users; the actual field names
// are stored in the VariableInitializer.
[EditorBrowsable(EditorBrowsableState.Never)]
public override string Name {
get { return string.Empty; }
set { throw new NotSupportedException(); }
}
[EditorBrowsable(EditorBrowsableState.Never)]
public override Identifier NameToken {
get { return Identifier.Null; }
set { throw new NotSupportedException(); }
}
public override void AcceptVisitor (IAstVisitor visitor) public override void AcceptVisitor (IAstVisitor visitor)
{ {
visitor.VisitFieldDeclaration (this); visitor.VisitFieldDeclaration (this);

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/IndexerDeclaration.cs

@ -25,6 +25,7 @@
// THE SOFTWARE. // THE SOFTWARE.
using System; using System;
using System.ComponentModel;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp namespace ICSharpCode.NRefactory.CSharp
@ -53,6 +54,7 @@ namespace ICSharpCode.NRefactory.CSharp
set { throw new NotSupportedException(); } set { throw new NotSupportedException(); }
} }
[EditorBrowsable(EditorBrowsableState.Never)]
public override Identifier NameToken { public override Identifier NameToken {
get { return Identifier.Null; } get { return Identifier.Null; }
set { throw new NotSupportedException(); } set { throw new NotSupportedException(); }

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/OperatorDeclaration.cs

@ -25,6 +25,7 @@
// THE SOFTWARE. // THE SOFTWARE.
using System; using System;
using System.ComponentModel;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp namespace ICSharpCode.NRefactory.CSharp
@ -250,6 +251,7 @@ namespace ICSharpCode.NRefactory.CSharp
set { throw new NotSupportedException(); } set { throw new NotSupportedException(); }
} }
[EditorBrowsable(EditorBrowsableState.Never)]
public override Identifier NameToken { public override Identifier NameToken {
get { return Identifier.Null; } get { return Identifier.Null; }
set { throw new NotSupportedException(); } set { throw new NotSupportedException(); }

155
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs

@ -198,6 +198,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
} }
} }
var resolveResult = ResolveExpression(expr); var resolveResult = ResolveExpression(expr);
if (resolveResult == null) { if (resolveResult == null) {
return null; return null;
} }
@ -262,10 +263,20 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
return contextList.Result; return contextList.Result;
} }
foreach (var m in initializerResult.Item1.Type.GetMembers (m => m.IsPublic && (m.EntityType == EntityType.Property || m.EntityType == EntityType.Field))) { var lookup = new MemberLookup(ctx.CurrentTypeDefinition, Compilation.MainAssembly);
contextList.AddMember(m); bool isProtectedAllowed = ctx.CurrentTypeDefinition != null ?
ctx.CurrentTypeDefinition.IsDerivedFrom(initializerResult.Item1.Type.GetDefinition()) :
false;
foreach (var m in initializerResult.Item1.Type.GetMembers (m => m.EntityType == EntityType.Field)) {
if (lookup.IsAccessible (m, isProtectedAllowed))
contextList.AddMember(m);
} }
foreach (IProperty m in initializerResult.Item1.Type.GetMembers (m => m.EntityType == EntityType.Property)) {
if (m.CanSet && lookup.IsAccessible (m.Setter, isProtectedAllowed))
contextList.AddMember(m);
}
if (prev != null && (prev is NamedExpression)) { if (prev != null && (prev is NamedExpression)) {
// case 2) // case 2)
return contextList.Result; return contextList.Result;
@ -656,19 +667,11 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
return HandleCatchClauseType(identifierStart); return HandleCatchClauseType(identifierStart);
} }
} }
if (!(char.IsLetter(completionChar) || completionChar == '_') && (!controlSpace || identifierStart == null || !(identifierStart.Node.Parent is ArrayInitializerExpression))) { if (!(char.IsLetter(completionChar) || completionChar == '_') && (!controlSpace || identifierStart == null)) {
return controlSpace ? HandleAccessorContext() ?? DefaultControlSpaceItems(identifierStart) : null; return controlSpace ? HandleAccessorContext() ?? DefaultControlSpaceItems(identifierStart) : null;
} }
char prevCh = offset > 2 ? document.GetCharAt(offset - 2) : ';';
char nextCh = offset < document.TextLength ? document.GetCharAt(offset) : ' ';
const string allowedChars = ";,.[](){}+-*/%^?:&|~!<>=";
if (!Char.IsWhiteSpace(nextCh) && allowedChars.IndexOf(nextCh) < 0) {
return null;
}
if (!(Char.IsWhiteSpace(prevCh) || allowedChars.IndexOf(prevCh) >= 0)) {
return null;
}
// Do not pop up completion on identifier identifier (should be handled by keyword completion). // Do not pop up completion on identifier identifier (should be handled by keyword completion).
tokenIndex = offset - 1; tokenIndex = offset - 1;
token = GetPreviousToken(ref tokenIndex, false); token = GetPreviousToken(ref tokenIndex, false);
@ -680,6 +683,16 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (keywordresult != null) { if (keywordresult != null) {
return keywordresult; return keywordresult;
} }
char prevCh = offset > 2 ? document.GetCharAt(offset - 2) : ';';
char nextCh = offset < document.TextLength ? document.GetCharAt(offset) : ' ';
const string allowedChars = ";,.[](){}+-*/%^?:&|~!<>=";
if ((!Char.IsWhiteSpace(nextCh) && allowedChars.IndexOf(nextCh) < 0) || !(Char.IsWhiteSpace(prevCh) || allowedChars.IndexOf(prevCh) >= 0)) {
if (controlSpace)
return DefaultControlSpaceItems(identifierStart);
return null;
}
int prevTokenIndex = tokenIndex; int prevTokenIndex = tokenIndex;
var prevToken2 = GetPreviousToken(ref prevTokenIndex, false); var prevToken2 = GetPreviousToken(ref prevTokenIndex, false);
@ -1058,7 +1071,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
node = node.Parent; node = node.Parent;
} }
var contextList = new CompletionDataWrapper(this); var contextList = new CompletionDataWrapper(this);
if (node is PropertyDeclaration) { if (node is PropertyDeclaration || node is IndexerDeclaration) {
contextList.AddCustom("get"); contextList.AddCustom("get");
contextList.AddCustom("set"); contextList.AddCustom("set");
AddKeywords(contextList, accessorModifierKeywords); AddKeywords(contextList, accessorModifierKeywords);
@ -1098,10 +1111,13 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
node = unit.GetNodeAt( node = unit.GetNodeAt(
location.Line, location.Line,
location.Column + 2, location.Column + 2,
n => n is Expression || n is AstType n => n is Expression || n is AstType || n is NamespaceDeclaration
); );
rr = ResolveExpression(node); rr = ResolveExpression(node);
} }
// namespace name case
if (node is NamespaceDeclaration)
return null;
if (node is Identifier && node.Parent is ForeachStatement) { if (node is Identifier && node.Parent is ForeachStatement) {
var foreachStmt = (ForeachStatement)node.Parent; var foreachStmt = (ForeachStatement)node.Parent;
foreach (var possibleName in GenerateNameProposals (foreachStmt.VariableType)) { foreach (var possibleName in GenerateNameProposals (foreachStmt.VariableType)) {
@ -1308,26 +1324,25 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
} }
return false; return false;
} }
void AddTypesAndNamespaces(CompletionDataWrapper wrapper, CSharpResolver state, AstNode node, Func<IType, IType> typePred = null, Predicate<IMember> memberPred = null, Action<ICompletionData, IType> callback = null) void AddTypesAndNamespaces(CompletionDataWrapper wrapper, CSharpResolver state, AstNode node, Func<IType, IType> typePred = null, Predicate<IMember> memberPred = null, Action<ICompletionData, IType> callback = null)
{ {
var lookup = new MemberLookup(ctx.CurrentTypeDefinition, Compilation.MainAssembly); var lookup = new MemberLookup(ctx.CurrentTypeDefinition, Compilation.MainAssembly);
if (currentType != null) { if (currentType != null) {
for (var ct = ctx.CurrentTypeDefinition; ct != null; ct = ct.DeclaringTypeDefinition) { for (var ct = ctx.CurrentTypeDefinition; ct != null; ct = ct.DeclaringTypeDefinition) {
foreach (var nestedType in ct.NestedTypes) { foreach (var nestedType in ct.GetNestedTypes ()) {
string name = nestedType.Name; if (!lookup.IsAccessible (nestedType.GetDefinition (), true))
if (IsAttributeContext(node) && name.EndsWith("Attribute") && name.Length > "Attribute".Length) { continue;
name = name.Substring(0, name.Length - "Attribute".Length);
}
if (typePred == null) { if (typePred == null) {
wrapper.AddType(nestedType, name); wrapper.AddType(nestedType, false, IsAttributeContext(node));
continue; continue;
} }
var type = typePred(nestedType); var type = typePred(nestedType);
if (type != null) { if (type != null) {
var a2 = wrapper.AddType(type, name); var a2 = wrapper.AddType(type, false, IsAttributeContext(node));
if (a2 != null && callback != null) { if (a2 != null && callback != null) {
callback(a2, type); callback(a2, type);
} }
@ -1354,7 +1369,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (!lookup.IsAccessible(member, isProtectedAllowed)) { if (!lookup.IsAccessible(member, isProtectedAllowed)) {
continue; continue;
} }
if (memberPred == null || memberPred(member)) { if (memberPred == null || memberPred(member)) {
wrapper.AddMember(member); wrapper.AddMember(member);
} }
@ -1389,11 +1404,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
IType addType = typePred != null ? typePred(type) : type; IType addType = typePred != null ? typePred(type) : type;
if (addType != null) { if (addType != null) {
string name = type.Name; var a = wrapper.AddType(addType, false, IsAttributeContext(node));
if (IsAttributeContext(node) && name.EndsWith("Attribute") && name.Length > "Attribute".Length) {
name = name.Substring(0, name.Length - "Attribute".Length);
}
var a = wrapper.AddType(addType, name);
if (a != null && callback != null) { if (a != null && callback != null) {
callback(a, type); callback(a, type);
} }
@ -1406,7 +1417,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
continue; continue;
IType addType = typePred != null ? typePred(type) : type; IType addType = typePred != null ? typePred(type) : type;
if (addType != null) { if (addType != null) {
var a2 = wrapper.AddType(addType, addType.Name); var a2 = wrapper.AddType(addType, false);
if (a2 != null && callback != null) { if (a2 != null && callback != null) {
callback(a2, type); callback(a2, type);
} }
@ -1770,7 +1781,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
new [] { hintType } new [] { hintType }
); );
if (inferedType != SpecialType.UnknownType) { if (inferedType != SpecialType.UnknownType) {
var newType = wrapper.AddType(inferedType, amb.ConvertType(inferedType)); var newType = wrapper.AddType(inferedType, true);
if (newType != null) { if (newType != null) {
newType.CompletionCategory = inferredTypesCategory; newType.CompletionCategory = inferredTypesCategory;
} }
@ -1779,8 +1790,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
return t; return t;
}; };
if (!(hintType.Kind == TypeKind.Interface && hintType.Kind != TypeKind.Array)) { if (!(hintType.Kind == TypeKind.Interface && hintType.Kind != TypeKind.Array)) {
DefaultCompletionString = GetShortType(hintType, GetState()); var hint = wrapper.AddType(hintType, true);
var hint = wrapper.AddType(hintType, DefaultCompletionString); DefaultCompletionString = hint.DisplayText;
if (hint != null) { if (hint != null) {
hint.CompletionCategory = derivedTypesCategory; hint.CompletionCategory = derivedTypesCategory;
} }
@ -1789,11 +1800,11 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
var arg = ((ParameterizedType)hintType).TypeArguments.FirstOrDefault(); var arg = ((ParameterizedType)hintType).TypeArguments.FirstOrDefault();
if (arg.Kind != TypeKind.TypeParameter) { if (arg.Kind != TypeKind.TypeParameter) {
var array = new ArrayType (ctx.Compilation, arg, 1); var array = new ArrayType (ctx.Compilation, arg, 1);
wrapper.AddType(array, amb.ConvertType(array)); wrapper.AddType(array, true);
} }
} }
} else { } else {
var hint = wrapper.AddType(hintType, DefaultCompletionString); var hint = wrapper.AddType(hintType, true);
if (hint != null) { if (hint != null) {
DefaultCompletionString = hint.DisplayText; DefaultCompletionString = hint.DisplayText;
hint.CompletionCategory = derivedTypesCategory; hint.CompletionCategory = derivedTypesCategory;
@ -2159,15 +2170,18 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (resolveResult is NamespaceResolveResult) { if (resolveResult is NamespaceResolveResult) {
var nr = (NamespaceResolveResult)resolveResult; var nr = (NamespaceResolveResult)resolveResult;
if (!(resolvedNode.Parent is UsingDeclaration || resolvedNode.Parent != null && resolvedNode.Parent.Parent is UsingDeclaration)) { if (!(resolvedNode.Parent is UsingDeclaration || resolvedNode.Parent != null && resolvedNode.Parent.Parent is UsingDeclaration)) {
var lookup = new MemberLookup(
ctx.CurrentTypeDefinition,
Compilation.MainAssembly
);
foreach (var cl in nr.Namespace.Types) { foreach (var cl in nr.Namespace.Types) {
string name = cl.Name;
if (hintType != null && hintType.Kind != TypeKind.Array && cl.Kind == TypeKind.Interface) { if (hintType != null && hintType.Kind != TypeKind.Array && cl.Kind == TypeKind.Interface) {
continue; continue;
} }
if (IsAttributeContext(resolvedNode) && name.EndsWith("Attribute") && name.Length > "Attribute".Length) { if (!lookup.IsAccessible (cl, false))
name = name.Substring(0, name.Length - "Attribute".Length); continue;
} result.AddType(cl, false, IsAttributeContext(resolvedNode));
result.AddType(cl, name);
} }
} }
foreach (var ns in nr.Namespace.ChildNamespaces) { foreach (var ns in nr.Namespace.ChildNamespaces) {
@ -2179,7 +2193,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (hintType != null && hintType.Kind != TypeKind.Array && nested.Kind == TypeKind.Interface) { if (hintType != null && hintType.Kind != TypeKind.Array && nested.Kind == TypeKind.Interface) {
continue; continue;
} }
result.AddType(nested, nested.Name); result.AddType(nested, false);
} }
} }
return result.Result; return result.Result;
@ -2188,7 +2202,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
IEnumerable<ICompletionData> CreateTypeList() IEnumerable<ICompletionData> CreateTypeList()
{ {
foreach (var cl in Compilation.RootNamespace.Types) { foreach (var cl in Compilation.RootNamespace.Types) {
yield return factory.CreateTypeCompletionData(cl, cl.Name); yield return factory.CreateTypeCompletionData(cl, false, false);
} }
foreach (var ns in Compilation.RootNamespace.ChildNamespaces) { foreach (var ns in Compilation.RootNamespace.ChildNamespaces) {
@ -2258,33 +2272,14 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
// } // }
return result.Result; return result.Result;
} }
string GetShortType(IType type, CSharpResolver state)
{
var builder = new TypeSystemAstBuilder(state);
var dt = state.CurrentTypeDefinition;
var declaring = type.DeclaringType != null ? type.DeclaringType.GetDefinition() : null;
if (declaring != null) {
while (dt != null) {
if (dt.Equals(declaring)) {
builder.AlwaysUseShortTypeNames = true;
break;
}
dt = dt.DeclaringTypeDefinition;
}
}
var shortType = builder.ConvertType(type);
return shortType.GetText(FormattingPolicy);
}
void AddEnumMembers(CompletionDataWrapper completionList, IType resolvedType, CSharpResolver state) void AddEnumMembers(CompletionDataWrapper completionList, IType resolvedType, CSharpResolver state)
{ {
if (resolvedType.Kind != TypeKind.Enum) { if (resolvedType.Kind != TypeKind.Enum) {
return; return;
} }
string typeString = GetShortType(resolvedType, state); completionList.AddEnumMembers(resolvedType, state);
completionList.AddEnumMembers(resolvedType, state, typeString); DefaultCompletionString = resolvedType.Name;
DefaultCompletionString = typeString;
} }
IEnumerable<ICompletionData> CreateCompletionData(TextLocation location, ResolveResult resolveResult, AstNode resolvedNode, CSharpResolver state, Func<IType, IType> typePred = null) IEnumerable<ICompletionData> CreateCompletionData(TextLocation location, ResolveResult resolveResult, AstNode resolvedNode, CSharpResolver state, Func<IType, IType> typePred = null)
@ -2292,7 +2287,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (resolveResult == null /*|| resolveResult.IsError*/) { if (resolveResult == null /*|| resolveResult.IsError*/) {
return null; return null;
} }
var lookup = new MemberLookup( var lookup = new MemberLookup(
ctx.CurrentTypeDefinition, ctx.CurrentTypeDefinition,
Compilation.MainAssembly Compilation.MainAssembly
@ -2307,7 +2302,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
continue; continue;
IType addType = typePred != null ? typePred(cl) : cl; IType addType = typePred != null ? typePred(cl) : cl;
if (addType != null) if (addType != null)
namespaceContents.AddType(addType, addType.Name); namespaceContents.AddType(addType, false);
} }
foreach (var ns in nr.Namespace.ChildNamespaces) { foreach (var ns in nr.Namespace.ChildNamespaces) {
@ -2357,7 +2352,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (trr.Type.Kind == TypeKind.Enum) { if (trr.Type.Kind == TypeKind.Enum) {
foreach (var field in trr.Type.GetFields ()) { foreach (var field in trr.Type.GetFields ()) {
result.AddMember(field); if (lookup.IsAccessible (field, false))
result.AddMember(field);
} }
return result.Result; return result.Result;
} }
@ -2406,23 +2402,28 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
result.AddMember(member); result.AddMember(member);
}*/ }*/
foreach (var member in lookup.GetAccessibleMembers (resolveResult)) { foreach (var member in lookup.GetAccessibleMembers (resolveResult)) {
if (member.EntityType == EntityType.Indexer || member.EntityType == EntityType.Operator || member.EntityType == EntityType.Constructor || member.EntityType == EntityType.Destructor) { if (member.EntityType == EntityType.Indexer || member.EntityType == EntityType.Operator || member.EntityType == EntityType.Constructor || member.EntityType == EntityType.Destructor) {
continue; continue;
} }
if (resolvedNode is BaseReferenceExpression && member.IsAbstract) { if (resolvedNode is BaseReferenceExpression && member.IsAbstract) {
continue; continue;
} }
if (member is IType) {
if (resolveResult is TypeResolveResult || includeStaticMembers) {
result.AddType ((IType)member, false);
continue;
}
}
bool memberIsStatic = member.IsStatic; bool memberIsStatic = member.IsStatic;
if (!includeStaticMembers && memberIsStatic && !(resolveResult is TypeResolveResult)) { if (!includeStaticMembers && memberIsStatic && !(resolveResult is TypeResolveResult)) {
// Console.WriteLine ("skip static member: " + member.FullName); // Console.WriteLine ("skip static member: " + member.FullName);
continue; continue;
} }
var field = member as IField; var field = member as IField;
if (field != null) { if (field != null) {
memberIsStatic |= field.IsConst; memberIsStatic |= field.IsConst;
} }
if (!memberIsStatic && skipNonStaticMembers) { if (!memberIsStatic && skipNonStaticMembers) {
continue; continue;
} }
@ -2436,23 +2437,11 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (member is IMember) { if (member is IMember) {
result.AddMember ((IMember)member); result.AddMember ((IMember)member);
} else {
if (resolveResult is TypeResolveResult || includeStaticMembers)
result.AddType ((IType)member, member.Name);
} }
} }
} }
if (resolveResult is TypeResolveResult || includeStaticMembers) { if (!(resolveResult is TypeResolveResult || includeStaticMembers)) {
foreach (var nested in type.GetNestedTypes ()) {
if (!lookup.IsAccessible(nested.GetDefinition(), isProtectedAllowed))
continue;
IType addType = typePred != null ? typePred(nested) : nested;
if (addType != null)
result.AddType(addType, addType.Name);
}
} else {
foreach (var meths in state.GetExtensionMethods (type)) { foreach (var meths in state.GetExtensionMethods (type)) {
foreach (var m in meths) { foreach (var m in meths) {
if (!lookup.IsAccessible(m, isProtectedAllowed)) if (!lookup.IsAccessible(m, isProtectedAllowed))

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

@ -200,6 +200,12 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
} }
parameter.Push (0); parameter.Push (0);
break; break;
case '=':
if (nextCh == '>') {
i++;
continue;
}
break;
case '>': case '>':
if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) { if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
break; break;
@ -705,7 +711,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
{ {
SyntaxTree baseUnit; SyntaxTree baseUnit;
baseUnit = ParseStub("a", false); baseUnit = ParseStub("a", false);
var section = baseUnit.GetNodeAt<AttributeSection>(location.Line, location.Column - 2); var section = baseUnit.GetNodeAt<AttributeSection>(location.Line, location.Column - 2);
var attr = section != null ? section.Attributes.LastOrDefault() : null; var attr = section != null ? section.Attributes.LastOrDefault() : null;
if (attr != null) { if (attr != null) {

5
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs

@ -224,6 +224,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
} }
if (GetCurrentParameterIndex(document.GetOffset(invoke.Node.StartLocation), offset) < 0) if (GetCurrentParameterIndex(document.GetOffset(invoke.Node.StartLocation), offset) < 0)
return null; return null;
if (invoke.Node is ArrayCreateExpression)
return null;
if (invoke.Node is ObjectCreateExpression) { if (invoke.Node is ObjectCreateExpression) {
var createType = ResolveExpression(((ObjectCreateExpression)invoke.Node).Type); var createType = ResolveExpression(((ObjectCreateExpression)invoke.Node).Type);
return factory.CreateConstructorProvider(document.GetOffset(invoke.Node.StartLocation), createType.Item1.Type); return factory.CreateConstructorProvider(document.GetOffset(invoke.Node.StartLocation), createType.Item1.Type);
@ -276,6 +278,9 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (invoke == null) { if (invoke == null) {
return null; return null;
} }
if (invoke.Node is ArrayCreateExpression) {
return null;
}
var indexerExpression = ResolveExpression(invoke); var indexerExpression = ResolveExpression(invoke);
if (indexerExpression == null || indexerExpression.Item1 == null || indexerExpression.Item1.IsError) { if (indexerExpression == null || indexerExpression.Item1 == null || indexerExpression.Item1.IsError) {
return null; return null;

34
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/CompletionDataWrapper.cs

@ -82,25 +82,27 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
Dictionary<string, ICompletionData> usedTypes = new Dictionary<string, ICompletionData> (); Dictionary<string, ICompletionData> usedTypes = new Dictionary<string, ICompletionData> ();
public ICompletionData AddType(IType type, string shortType) public ICompletionData AddType(IType type, bool showFullName, bool isInAttributeContext = false)
{ {
if (type == null || string.IsNullOrEmpty(shortType)) if (type == null)
return null; throw new ArgumentNullException("type");
if (type.Name == "Void" && type.Namespace == "System") if (type.Name == "Void" && type.Namespace == "System" || type.Kind == TypeKind.Unknown)
return null; return null;
var def = type.GetDefinition(); var def = type.GetDefinition();
if (def != null && def.ParentAssembly != completion.ctx.CurrentAssembly && !def.IsBrowsable()) if (def != null && def.ParentAssembly != completion.ctx.CurrentAssembly && !def.IsBrowsable())
return null; return null;
ICompletionData usedType; ICompletionData usedType;
if (usedTypes.TryGetValue (shortType, out usedType)) { var data = Factory.CreateTypeCompletionData(type, showFullName, isInAttributeContext);
usedType.AddOverload (Factory.CreateTypeCompletionData(type, shortType)); var text = data.DisplayText;
if (usedTypes.TryGetValue(text, out usedType)) {
usedType.AddOverload(data);
return usedType; return usedType;
} }
var iCompletionData = Factory.CreateTypeCompletionData(type, shortType); usedTypes [text] = data;
usedTypes[shortType] = iCompletionData; result.Add(data);
result.Add(iCompletionData); return data;
return iCompletionData;
} }
Dictionary<string, List<ICompletionData>> data = new Dictionary<string, List<ICompletionData>> (); Dictionary<string, List<ICompletionData>> data = new Dictionary<string, List<ICompletionData>> ();
@ -214,21 +216,15 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
} }
} }
HashSet<IType> addedEnums = new HashSet<IType> (); HashSet<IType> addedEnums = new HashSet<IType> ();
public void AddEnumMembers (IType resolvedType, CSharpResolver state, string typeString) public void AddEnumMembers (IType resolvedType, CSharpResolver state)
{ {
if (addedEnums.Contains (resolvedType)) if (addedEnums.Contains (resolvedType))
return; return;
addedEnums.Add (resolvedType); addedEnums.Add (resolvedType);
if (typeString.Contains(".")) { AddType(resolvedType, true);
AddType(resolvedType, typeString);
}
foreach (var field in resolvedType.GetFields ()) { foreach (var field in resolvedType.GetFields ()) {
if (field.IsPublic && (field.IsConst || field.IsStatic)) { if (field.IsPublic && (field.IsConst || field.IsStatic)) {
Result.Add(Factory.CreateEntityCompletionData( Result.Add(Factory.CreateMemberCompletionData(resolvedType, field));
field,
typeString + "." + field.Name
)
);
} }
} }
} }

9
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/ICompletionDataFactory.cs

@ -35,7 +35,14 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
ICompletionData CreateEntityCompletionData (IEntity entity); ICompletionData CreateEntityCompletionData (IEntity entity);
ICompletionData CreateEntityCompletionData (IEntity entity, string text); ICompletionData CreateEntityCompletionData (IEntity entity, string text);
ICompletionData CreateTypeCompletionData (IType type, string shortType); ICompletionData CreateTypeCompletionData (IType type, bool showFullName, bool isInAttributeContext);
/// <summary>
/// Creates the member completion data.
/// Form: Type.Member
/// Used for generating enum members Foo.A, Foo.B where the enum 'Foo' is valid.
/// </summary>
ICompletionData CreateMemberCompletionData(IType type, IEntity member);
/// <summary> /// <summary>
/// Creates a generic completion data. /// Creates a generic completion data.

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

@ -324,7 +324,6 @@
<Compile Include="Refactoring\CodeIssues\VariableNotUsedIssues\LocalVariableNotUsedIssue.cs" /> <Compile Include="Refactoring\CodeIssues\VariableNotUsedIssues\LocalVariableNotUsedIssue.cs" />
<Compile Include="Refactoring\CodeIssues\VariableNotUsedIssues\ParameterNotUsedIssue.cs" /> <Compile Include="Refactoring\CodeIssues\VariableNotUsedIssues\ParameterNotUsedIssue.cs" />
<Compile Include="Refactoring\CodeIssues\TypeParameterNotUsedIssue.cs" /> <Compile Include="Refactoring\CodeIssues\TypeParameterNotUsedIssue.cs" />
<Compile Include="Refactoring\CodeIssues\VariableNotUsedIssues\VariableNotUsedIssue.cs" />
<Compile Include="Refactoring\CodeIssues\VariableOnlyAssignedIssues\ParameterOnlyAssignedIssue.cs" /> <Compile Include="Refactoring\CodeIssues\VariableOnlyAssignedIssues\ParameterOnlyAssignedIssue.cs" />
<Compile Include="Refactoring\CodeIssues\VariableOnlyAssignedIssues\VariableOnlyAssignedIssue.cs" /> <Compile Include="Refactoring\CodeIssues\VariableOnlyAssignedIssues\VariableOnlyAssignedIssue.cs" />
<Compile Include="Refactoring\DocumentScript.cs" /> <Compile Include="Refactoring\DocumentScript.cs" />
@ -338,6 +337,7 @@
<Compile Include="Refactoring\TypeSystemAstBuilder.cs" /> <Compile Include="Refactoring\TypeSystemAstBuilder.cs" />
<Compile Include="Refactoring\VariableReferenceGraph.cs" /> <Compile Include="Refactoring\VariableReferenceGraph.cs" />
<Compile Include="Resolver\CompositeResolveVisitorNavigator.cs" /> <Compile Include="Resolver\CompositeResolveVisitorNavigator.cs" />
<Compile Include="Resolver\AwaitResolveResult.cs" />
<Compile Include="Resolver\DynamicInvocationResolveResult.cs" /> <Compile Include="Resolver\DynamicInvocationResolveResult.cs" />
<Compile Include="Resolver\DynamicMemberResolveResult.cs" /> <Compile Include="Resolver\DynamicMemberResolveResult.cs" />
<Compile Include="Resolver\CSharpConversions.cs" /> <Compile Include="Resolver\CSharpConversions.cs" />
@ -503,6 +503,8 @@
<Compile Include="Refactoring\CodeIssues\ParameterCanBeDemotedIssue\SupportsIndexingCriterion.cs" /> <Compile Include="Refactoring\CodeIssues\ParameterCanBeDemotedIssue\SupportsIndexingCriterion.cs" />
<Compile Include="Refactoring\CodeIssues\RedundantWhereWithPredicateIssue.cs" /> <Compile Include="Refactoring\CodeIssues\RedundantWhereWithPredicateIssue.cs" />
<Compile Include="Refactoring\CodeActions\ConvertToInitializer\AccessPath.cs" /> <Compile Include="Refactoring\CodeActions\ConvertToInitializer\AccessPath.cs" />
<Compile Include="Refactoring\LocalReferenceFinder.cs" />
<Compile Include="Refactoring\CodeActions\SortUsingsAction.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj"> <ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
@ -534,4 +536,4 @@
<ItemGroup> <ItemGroup>
<None Include="Parser\mcs\cs-parser.jay" /> <None Include="Parser\mcs\cs-parser.jay" />
</ItemGroup> </ItemGroup>
</Project> </Project>

12
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -1057,6 +1057,12 @@ namespace ICSharpCode.NRefactory.CSharp
} }
return; return;
} }
if (f == 0 && 1 / f == float.NegativeInfinity) {
// negative zero is a special case
// (again, not a primitive expression, but it's better to handle
// the special case here than to do it in all code generators)
formatter.WriteToken("-");
}
formatter.WriteToken(f.ToString("R", NumberFormatInfo.InvariantInfo) + "f"); formatter.WriteToken(f.ToString("R", NumberFormatInfo.InvariantInfo) + "f");
lastWritten = LastWritten.Other; lastWritten = LastWritten.Other;
} else if (val is double) { } else if (val is double) {
@ -1075,6 +1081,12 @@ namespace ICSharpCode.NRefactory.CSharp
} }
return; return;
} }
if (f == 0 && 1 / f == double.NegativeInfinity) {
// negative zero is a special case
// (again, not a primitive expression, but it's better to handle
// the special case here than to do it in all code generators)
formatter.WriteToken("-");
}
string number = f.ToString("R", NumberFormatInfo.InvariantInfo); string number = f.ToString("R", NumberFormatInfo.InvariantInfo);
if (number.IndexOf('.') < 0 && number.IndexOf('E') < 0) { if (number.IndexOf('.') < 0 && number.IndexOf('E') < 0) {
number += ".0"; number += ".0";

784
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs

File diff suppressed because it is too large Load Diff

8
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/cfold.cs

@ -149,7 +149,7 @@ namespace Mono.CSharp {
case Binary.Operator.ExclusiveOr: case Binary.Operator.ExclusiveOr:
result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc); result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
if (result != null) if (result != null)
result = result.TryReduce (ec, lt); result = result.Reduce (ec, lt);
return result; return result;
/// ///
@ -158,7 +158,7 @@ namespace Mono.CSharp {
case Binary.Operator.Subtraction: case Binary.Operator.Subtraction:
result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc); result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
if (result != null) if (result != null)
result = result.TryReduce (ec, EnumSpec.GetUnderlyingType (lt)); result = result.Reduce (ec, EnumSpec.GetUnderlyingType (lt));
return result; return result;
/// ///
@ -340,7 +340,7 @@ namespace Mono.CSharp {
if (result == null) if (result == null)
return null; return null;
result = result.TryReduce (ec, lt); result = result.Reduce (ec, lt);
if (result == null) if (result == null)
return null; return null;
@ -459,7 +459,7 @@ namespace Mono.CSharp {
if (result == null) if (result == null)
return null; return null;
result = result.TryReduce (ec, lt); result = result.Reduce (ec, lt);
if (result == null) if (result == null)
return null; return null;

19
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/constant.cs

@ -251,10 +251,12 @@ namespace Mono.CSharp {
return this; return this;
} }
/// <summary> //
/// Attempts to do a compile-time folding of a constant cast. // Attempts to do a compile-time folding of a constant cast and handles
/// </summary> // error reporting for constant overlows only, on normal conversion
public Constant TryReduce (ResolveContext ec, TypeSpec target_type) // errors returns null
//
public Constant Reduce (ResolveContext ec, TypeSpec target_type)
{ {
try { try {
return TryReduceConstant (ec, target_type); return TryReduceConstant (ec, target_type);
@ -271,6 +273,15 @@ namespace Mono.CSharp {
} }
} }
public Constant TryReduce (ResolveContext rc, TypeSpec targetType)
{
try {
return TryReduceConstant (rc, targetType);
} catch (OverflowException) {
return null;
}
}
Constant TryReduceConstant (ResolveContext ec, TypeSpec target_type) Constant TryReduceConstant (ResolveContext ec, TypeSpec target_type)
{ {
if (Type == target_type) { if (Type == target_type) {

22
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/context.cs

@ -105,6 +105,24 @@ namespace Mono.CSharp
get { return return_type; } get { return return_type; }
} }
public bool IsUnreachable {
get {
return HasSet (Options.UnreachableScope);
}
set {
flags = value ? flags | Options.UnreachableScope : flags & ~Options.UnreachableScope;
}
}
public bool UnreachableReported {
get {
return HasSet (Options.UnreachableReported);
}
set {
flags = value ? flags | Options.UnreachableReported : flags & ~Options.UnreachableScope;
}
}
// <summary> // <summary>
// Starts a new code branching. This inherits the state of all local // Starts a new code branching. This inherits the state of all local
// variables and parameters from the current branching. // variables and parameters from the current branching.
@ -257,6 +275,10 @@ namespace Mono.CSharp
LockScope = 1 << 13, LockScope = 1 << 13,
UnreachableScope = 1 << 14,
UnreachableReported = 1 << 15,
/// <summary> /// <summary>
/// Whether control flow analysis is enabled /// Whether control flow analysis is enabled
/// </summary> /// </summary>

35
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/convert.cs

@ -1196,7 +1196,7 @@ namespace Mono.CSharp {
if (s_x != source_type) { if (s_x != source_type) {
var c = source as Constant; var c = source as Constant;
if (c != null) { if (c != null) {
source = c.TryReduce (ec, s_x); source = c.Reduce (ec, s_x);
if (source == null) if (source == null)
c = null; c = null;
} }
@ -1990,21 +1990,28 @@ namespace Mono.CSharp {
if (expr_type == real_target) if (expr_type == real_target)
return EmptyCast.Create (expr, target_type); return EmptyCast.Create (expr, target_type);
ne = ImplicitNumericConversion (expr, real_target); Constant c = expr as Constant;
if (ne != null) if (c != null) {
return EmptyCast.Create (ne, target_type); c = c.TryReduce (ec, real_target);
if (c != null)
ne = ExplicitNumericConversion (ec, expr, real_target); return c;
if (ne != null) } else {
return EmptyCast.Create (ne, target_type); ne = ImplicitNumericConversion (expr, real_target);
if (ne != null)
return EmptyCast.Create (ne, target_type);
// ne = ExplicitNumericConversion (ec, expr, real_target);
// LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed
//
if (expr_type.BuiltinType == BuiltinTypeSpec.Type.IntPtr || expr_type.BuiltinType == BuiltinTypeSpec.Type.UIntPtr) {
ne = ExplicitUserConversion (ec, expr, real_target, loc);
if (ne != null) if (ne != null)
return ExplicitConversionCore (ec, ne, target_type, loc); return EmptyCast.Create (ne, target_type);
//
// LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed
//
if (expr_type.BuiltinType == BuiltinTypeSpec.Type.IntPtr || expr_type.BuiltinType == BuiltinTypeSpec.Type.UIntPtr) {
ne = ExplicitUserConversion (ec, expr, real_target, loc);
if (ne != null)
return ExplicitConversionCore (ec, ne, target_type, loc);
}
} }
} else { } else {
ne = ExplicitNumericConversion (ec, expr, target_type); ne = ExplicitNumericConversion (ec, expr, target_type);

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

File diff suppressed because it is too large Load Diff

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

@ -538,6 +538,15 @@ namespace_declaration
current_container = current_namespace = current_namespace.Parent; current_container = current_namespace = current_namespace.Parent;
} }
| opt_attributes NAMESPACE namespace_name
{
report.Error (1514, lexer.Location, "Unexpected symbol `{0}', expecting `.' or `{{'", GetSymbolName (yyToken));
var name = (MemberName) $3;
var ns = new NamespaceContainer (name, current_namespace);
lbag.AddLocation (current_container, GetLocation ($2));
current_namespace.AddTypeContainer (ns);
}
; ;
namespace_name namespace_name
@ -1737,7 +1746,7 @@ indexer_declaration
{ {
valid_param_mod = ParameterModifierType.Params | ParameterModifierType.DefaultValue; valid_param_mod = ParameterModifierType.Params | ParameterModifierType.DefaultValue;
} }
opt_formal_parameter_list CLOSE_BRACKET OPEN_BRACE opt_formal_parameter_list CLOSE_BRACKET
{ {
valid_param_mod = 0; valid_param_mod = 0;
var type = (FullNamedExpression) $3; var type = (FullNamedExpression) $3;
@ -1746,7 +1755,7 @@ indexer_declaration
current_property = indexer; current_property = indexer;
current_type.AddIndexer (indexer); current_type.AddIndexer (indexer);
lbag.AddMember (current_property, GetModifierLocations (), GetLocation ($5), GetLocation ($8), GetLocation ($9)); lbag.AddMember (current_property, GetModifierLocations (), GetLocation ($5), GetLocation ($8));
if (type.Type != null && type.Type.Kind == MemberKind.Void) if (type.Type != null && type.Type.Kind == MemberKind.Void)
report.Error (620, GetLocation ($3), "`{0}': indexer return type cannot be `void'", indexer.GetSignatureForError ()); report.Error (620, GetLocation ($3), "`{0}': indexer return type cannot be `void'", indexer.GetSignatureForError ());
@ -1762,7 +1771,7 @@ indexer_declaration
lexer.PropertyParsing = true; lexer.PropertyParsing = true;
} }
accessor_declarations OPEN_BRACE accessor_declarations
{ {
lexer.PropertyParsing = false; lexer.PropertyParsing = false;
} }
@ -1774,7 +1783,7 @@ indexer_declaration
if (doc_support) if (doc_support)
current_property.DocComment = ConsumeStoredComment (); current_property.DocComment = ConsumeStoredComment ();
lbag.AppendToMember (current_property, GetLocation ($12)); lbag.AppendToMember (current_property, GetLocation ($10), GetLocation ($13));
current_property = null; current_property = null;
} }
; ;
@ -3348,7 +3357,8 @@ argument_list
} }
| argument_list COMMA error | argument_list COMMA error
{ {
lexer.putback (')'); // TODO: Wrong but what can I do if (lexer.putback_char == -1)
lexer.putback (')'); // TODO: Wrong but what can I do
Error_SyntaxError (yyToken); Error_SyntaxError (yyToken);
$$ = $1; $$ = $1;
} }
@ -6987,6 +6997,10 @@ void Error_SyntaxError (int error_code, int token, string msg)
// An error message has been reported by tokenizer // An error message has been reported by tokenizer
if (token == Token.ERROR) if (token == Token.ERROR)
return; return;
// Avoid duplicit error message after unterminated string literals
if (token == Token.LITERAL && lexer.Location.Column == 0)
return;
string symbol = GetSymbolName (token); string symbol = GetSymbolName (token);
string expecting = GetExpecting (); string expecting = GetExpecting ();

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

@ -1809,6 +1809,26 @@ namespace Mono.CSharp
return x; return x;
} }
int get_char_withwithoutskippingwindowseol ()
{
int x;
if (putback_char != -1) {
x = putback_char;
putback_char = -1;
} else {
x = reader.Read ();
}
if (x == '\r') {
} else if (x == '\n') {
advance_line ();
} else {
col++;
}
return x;
}
void advance_line () void advance_line ()
{ {
line++; line++;
@ -2901,7 +2921,7 @@ namespace Mono.CSharp
#endif #endif
while (true){ while (true){
c = get_char (); c = get_char_withwithoutskippingwindowseol ();
if (c == '"') { if (c == '"') {
if (quoted && peek_char () == '"') { if (quoted && peek_char () == '"') {
if (pos == value_builder.Length) if (pos == value_builder.Length)

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/driver.cs

@ -173,7 +173,7 @@ namespace Mono.CSharp
parser.parse (); parser.parse ();
return parser; return parser;
} }
public static int Main (string[] args) public static int Main (string[] args)
{ {
Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t"; Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";

4
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/expression.cs

@ -1702,7 +1702,7 @@ namespace Mono.CSharp
Constant c = expr as Constant; Constant c = expr as Constant;
if (c != null) { if (c != null) {
c = c.TryReduce (ec, type); c = c.Reduce (ec, type);
if (c != null) if (c != null)
return c; return c;
} }
@ -2661,7 +2661,7 @@ namespace Mono.CSharp
return left; return left;
if (left.IsZeroInteger) if (left.IsZeroInteger)
return left.TryReduce (ec, right.Type); return left.Reduce (ec, right.Type);
break; break;

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

@ -49,13 +49,21 @@ namespace Mono.CSharp {
// in unreachable code, for instance. // in unreachable code, for instance.
// //
if (warn) bool unreachable = false;
if (warn && !ec.UnreachableReported) {
ec.UnreachableReported = true;
unreachable = true;
ec.Report.Warning (162, 2, loc, "Unreachable code detected"); ec.Report.Warning (162, 2, loc, "Unreachable code detected");
}
ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc); ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
bool ok = Resolve (ec); bool ok = Resolve (ec);
ec.KillFlowBranching (); ec.KillFlowBranching ();
if (unreachable) {
ec.UnreachableReported = false;
}
return ok; return ok;
} }
@ -1225,7 +1233,7 @@ namespace Mono.CSharp {
res = c; res = c;
} else { } else {
TypeSpec type = ec.Switch.SwitchType; TypeSpec type = ec.Switch.SwitchType;
res = c.TryReduce (ec, type); res = c.Reduce (ec, type);
if (res == null) { if (res == null) {
c.Error_ValueCannotBeConverted (ec, type, true); c.Error_ValueCannotBeConverted (ec, type, true);
return false; return false;
@ -2073,9 +2081,7 @@ namespace Mono.CSharp {
#endif #endif
// int assignable_slots; // int assignable_slots;
bool unreachable_shown;
bool unreachable;
public Block (Block parent, Location start, Location end) public Block (Block parent, Location start, Location end)
: this (parent, 0, start, end) : this (parent, 0, start, end)
{ {
@ -2247,6 +2253,8 @@ namespace Mono.CSharp {
Block prev_block = ec.CurrentBlock; Block prev_block = ec.CurrentBlock;
bool ok = true; bool ok = true;
bool unreachable = ec.IsUnreachable;
bool prev_unreachable = unreachable;
ec.CurrentBlock = this; ec.CurrentBlock = this;
ec.StartFlowBranching (this); ec.StartFlowBranching (this);
@ -2279,14 +2287,10 @@ namespace Mono.CSharp {
if (s is EmptyStatement) if (s is EmptyStatement)
continue; continue;
if (!unreachable_shown && !(s is LabeledStatement)) { if (!ec.UnreachableReported && !(s is LabeledStatement)) {
ec.Report.Warning (162, 2, s.loc, "Unreachable code detected"); ec.Report.Warning (162, 2, s.loc, "Unreachable code detected");
unreachable_shown = true; ec.UnreachableReported = true;
} }
Block c_block = s as Block;
if (c_block != null)
c_block.unreachable = c_block.unreachable_shown = true;
} }
// //
@ -2310,8 +2314,15 @@ namespace Mono.CSharp {
statements [ix] = new EmptyStatement (s.loc); statements [ix] = new EmptyStatement (s.loc);
unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable; unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
if (unreachable && s is LabeledStatement) if (unreachable) {
throw new InternalErrorException ("should not happen"); ec.IsUnreachable = true;
} else if (ec.IsUnreachable)
ec.IsUnreachable = false;
}
if (unreachable != prev_unreachable) {
ec.IsUnreachable = prev_unreachable;
ec.UnreachableReported = false;
} }
while (ec.CurrentBranching is FlowBranchingLabeled) while (ec.CurrentBranching is FlowBranchingLabeled)
@ -2335,17 +2346,21 @@ namespace Mono.CSharp {
public override bool ResolveUnreachable (BlockContext ec, bool warn) public override bool ResolveUnreachable (BlockContext ec, bool warn)
{ {
unreachable_shown = true; bool unreachable = false;
unreachable = true; if (warn && !ec.UnreachableReported) {
ec.UnreachableReported = true;
if (warn) unreachable = true;
ec.Report.Warning (162, 2, loc, "Unreachable code detected"); ec.Report.Warning (162, 2, loc, "Unreachable code detected");
}
var fb = ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc); var fb = ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
fb.CurrentUsageVector.IsUnreachable = true; fb.CurrentUsageVector.IsUnreachable = true;
bool ok = Resolve (ec); bool ok = Resolve (ec);
ec.KillFlowBranching (); ec.KillFlowBranching ();
if (unreachable)
ec.UnreachableReported = false;
return ok; return ok;
} }

152
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/support.cs

@ -127,6 +127,158 @@ namespace Mono.CSharp {
return true; return true;
} }
} }
#if !FULL_AST
/// <summary>
/// This is an arbitrarily seekable StreamReader wrapper.
///
/// It uses a self-tuning buffer to cache the seekable data,
/// but if the seek is too far, it may read the underly
/// stream all over from the beginning.
/// </summary>
public class SeekableStreamReader : IDisposable
{
public const int DefaultReadAheadSize =
4096 / 2;
StreamReader reader;
Stream stream;
char[] buffer;
int read_ahead_length; // the length of read buffer
int buffer_start; // in chars
int char_count; // count of filled characters in buffer[]
int pos; // index into buffer[]
public SeekableStreamReader (Stream stream, Encoding encoding, char[] sharedBuffer = null)
{
this.stream = stream;
this.buffer = sharedBuffer;
InitializeStream (DefaultReadAheadSize);
reader = new StreamReader (stream, encoding, true);
}
public void Dispose ()
{
// Needed to release stream reader buffers
reader.Dispose ();
}
void InitializeStream (int read_length_inc)
{
read_ahead_length += read_length_inc;
int required_buffer_size = read_ahead_length * 2;
if (buffer == null || buffer.Length < required_buffer_size)
buffer = new char [required_buffer_size];
stream.Position = 0;
buffer_start = char_count = pos = 0;
}
/// <remarks>
/// This value corresponds to the current position in a stream of characters.
/// The StreamReader hides its manipulation of the underlying byte stream and all
/// character set/decoding issues. Thus, we cannot use this position to guess at
/// the corresponding position in the underlying byte stream even though there is
/// a correlation between them.
/// </remarks>
public int Position {
get {
return buffer_start + pos;
}
set {
//
// If the lookahead was too small, re-read from the beginning. Increase the buffer size while we're at it
// This should never happen until we are parsing some weird source code
//
if (value < buffer_start) {
InitializeStream (read_ahead_length);
//
// Discard buffer data after underlying stream changed position
// Cannot use handy reader.DiscardBufferedData () because it for
// some strange reason resets encoding as well
//
reader = new StreamReader (stream, reader.CurrentEncoding, true);
}
while (value > buffer_start + char_count) {
pos = char_count;
if (!ReadBuffer ())
throw new InternalErrorException ("Seek beyond end of file: " + (buffer_start + char_count - value));
}
pos = value - buffer_start;
}
}
bool ReadBuffer ()
{
int slack = buffer.Length - char_count;
//
// read_ahead_length is only half of the buffer to deal with
// reads ahead and moves back without re-reading whole buffer
//
if (slack <= read_ahead_length) {
//
// shift the buffer to make room for read_ahead_length number of characters
//
int shift = read_ahead_length - slack;
Array.Copy (buffer, shift, buffer, 0, char_count - shift);
// Update all counters
pos -= shift;
char_count -= shift;
buffer_start += shift;
slack += shift;
}
char_count += reader.Read (buffer, char_count, slack);
return pos < char_count;
}
public char GetChar (int position)
{
if (buffer_start <= position && position < buffer.Length)
return buffer[position];
return '\0';
}
public char[] ReadChars (int fromPosition, int toPosition)
{
char[] chars = new char[toPosition - fromPosition];
if (buffer_start <= fromPosition && toPosition <= buffer_start + buffer.Length) {
Array.Copy (buffer, fromPosition - buffer_start, chars, 0, chars.Length);
} else {
throw new NotImplementedException ();
}
return chars;
}
public int Peek ()
{
if ((pos >= char_count) && !ReadBuffer ())
return -1;
return buffer [pos];
}
public int Read ()
{
if ((pos >= char_count) && !ReadBuffer ())
return -1;
return buffer [pos++];
}
}
#endif
public class UnixUtils { public class UnixUtils {
[System.Runtime.InteropServices.DllImport ("libc", EntryPoint="isatty")] [System.Runtime.InteropServices.DllImport ("libc", EntryPoint="isatty")]
extern static int _isatty (int fd); extern static int _isatty (int fd);

6
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/QueryExpressionExpander.cs

@ -122,14 +122,14 @@ namespace ICSharpCode.NRefactory.CSharp {
LambdaExpression CreateLambda(IList<ParameterDeclaration> parameters, Expression body) { LambdaExpression CreateLambda(IList<ParameterDeclaration> parameters, Expression body) {
var result = new LambdaExpression(); var result = new LambdaExpression();
if (parameters.Count > 1) if (parameters.Count > 1)
result.AddChild(new CSharpTokenNode(TextLocation.Empty), Roles.LPar); result.AddChild(new CSharpTokenNode(TextLocation.Empty, Roles.LPar), Roles.LPar);
result.AddChild(parameters[0], Roles.Parameter); result.AddChild(parameters[0], Roles.Parameter);
for (int i = 1; i < parameters.Count; i++) { for (int i = 1; i < parameters.Count; i++) {
result.AddChild(new CSharpTokenNode(TextLocation.Empty), Roles.Comma); result.AddChild(new CSharpTokenNode(TextLocation.Empty, Roles.Comma), Roles.Comma);
result.AddChild(parameters[i], Roles.Parameter); result.AddChild(parameters[i], Roles.Parameter);
} }
if (parameters.Count > 1) if (parameters.Count > 1)
result.AddChild(new CSharpTokenNode(TextLocation.Empty), Roles.RPar); result.AddChild(new CSharpTokenNode(TextLocation.Empty, Roles.RPar), Roles.RPar);
result.AddChild(body, LambdaExpression.BodyRole); result.AddChild(body, LambdaExpression.BodyRole);
return result; return result;

10
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs

@ -36,6 +36,7 @@ using ICSharpCode.NRefactory.Editor;
using System.ComponentModel.Design; using System.ComponentModel.Design;
using ICSharpCode.NRefactory.CSharp.Analysis; using ICSharpCode.NRefactory.CSharp.Analysis;
using ICSharpCode.NRefactory.Utils; using ICSharpCode.NRefactory.Utils;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
@ -87,6 +88,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
this.resolver = resolver; this.resolver = resolver;
this.cancellationToken = cancellationToken; this.cancellationToken = cancellationToken;
this.referenceFinder = new LocalReferenceFinder(resolver);
} }
@ -161,6 +163,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
return new CompositeFormatStringParser().Parse(source); return new CompositeFormatStringParser().Parse(source);
} }
LocalReferenceFinder referenceFinder;
public IList<ReferenceResult> FindReferences(AstNode rootNode, IVariable variable)
{
return referenceFinder.FindReferences(rootNode, variable);
}
#endregion #endregion
/// <summary> /// <summary>

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertToInitializer/AccessPath.cs

@ -112,7 +112,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
if (obj.GetType() != typeof(AccessPath)) if (obj == null || obj.GetType() != typeof(AccessPath))
return false; return false;
var other = (AccessPath)obj; var other = (AccessPath)obj;

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

@ -148,10 +148,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return resolver.Compilation.FindType(KnownTypeCode.Object); return resolver.Compilation.FindType(KnownTypeCode.Object);
} }
foreach (var method in type.GetMethods (m => m.Name == "GetEnumerator")) { foreach (var method in type.GetMethods (m => m.Name == "GetEnumerator")) {
var pr = method.ReturnType.GetProperties(p => p.Name == "Current").FirstOrDefault(); IType returnType = null;
if (pr != null) foreach (var prop in method.ReturnType.GetProperties(p => p.Name == "Current")) {
return pr.ReturnType; if (returnType != null && prop.ReturnType.IsKnownType (KnownTypeCode.Object))
continue;
returnType = prop.ReturnType;
}
if (returnType != null)
return returnType;
} }
return resolver.Compilation.FindType(KnownTypeCode.Object); return resolver.Compilation.FindType(KnownTypeCode.Object);

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

@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
[ContextAction("Sort usings", Description = "Sorts usings by their origin and then alphabetically.")]
public class SortUsingsAction: ICodeActionProvider
{
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
var usingNode = FindUsingNodeAtCursor(context);
if (usingNode == null)
yield break;
yield return new CodeAction(context.TranslateString("Sort usings"), script =>
{
var blocks = EnumerateUsingBlocks(context.RootNode);
foreach (var block in blocks)
{
var originalNodes = block.ToArray();
var sortedNodes = SortUsingBlock(originalNodes, context).ToArray();
for (var i = 0; i < originalNodes.Length; ++i)
script.Replace(originalNodes[i], sortedNodes[i].Clone());
}
});
}
private static AstNode FindUsingNodeAtCursor(RefactoringContext context)
{
// If cursor is inside using declaration
var locationAsIs = context.Location;
// If cursor is at end of line with using declaration
var locationLeft = new TextLocation(locationAsIs.Line, locationAsIs.Column - 1);
var possibleNodes = new[] { locationAsIs, locationLeft }
.Select(_ => context.RootNode.GetNodeAt(_, IsUsingDeclaration));
var usingNode = possibleNodes.Where(_ => _ != null).Distinct().SingleOrDefault();
return usingNode;
}
private static bool IsUsingDeclaration(AstNode node)
{
return node is UsingDeclaration || node is UsingAliasDeclaration;
}
private static IEnumerable<IEnumerable<AstNode>> EnumerateUsingBlocks(AstNode root)
{
var alreadyAddedNodes = new HashSet<AstNode>();
foreach (var child in root.Descendants)
if (IsUsingDeclaration(child) && !alreadyAddedNodes.Contains(child)) {
var blockNodes = EnumerateUsingBlockNodes(child);
alreadyAddedNodes.UnionWith(blockNodes);
yield return blockNodes;
}
}
private static IEnumerable<AstNode> EnumerateUsingBlockNodes(AstNode firstNode)
{
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;
}
}
}
}

23
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AccessToClosureIssues/AccessToClosureIssue.cs

@ -27,7 +27,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using ICSharpCode.NRefactory.CSharp.Analysis; using ICSharpCode.NRefactory.CSharp.Analysis;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
@ -35,8 +34,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
public abstract class AccessToClosureIssue : ICodeIssueProvider public abstract class AccessToClosureIssue : ICodeIssueProvider
{ {
static FindReferences refFinder = new FindReferences (); ControlFlowGraphBuilder cfgBuilder = new ControlFlowGraphBuilder ();
static ControlFlowGraphBuilder cfgBuilder = new ControlFlowGraphBuilder ();
public string Title public string Title
{ get; private set; } { get; private set; }
@ -75,7 +73,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class GatherVisitor : GatherVisitorBase class GatherVisitor : GatherVisitorBase
{ {
SyntaxTree unit;
string title; string title;
AccessToClosureIssue issueProvider; AccessToClosureIssue issueProvider;
@ -84,7 +81,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
: base (context) : base (context)
{ {
this.title = context.TranslateString (issueProvider.Title); this.title = context.TranslateString (issueProvider.Title);
this.unit = unit;
this.issueProvider = issueProvider; this.issueProvider = issueProvider;
} }
@ -124,23 +120,18 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
base.VisitParameterDeclaration (parameterDeclaration); base.VisitParameterDeclaration (parameterDeclaration);
} }
void FindLocalReferences (IVariable variable, FoundReferenceCallback callback) void CheckVariable(IVariable variable, Statement env)
{ {
refFinder.FindLocalReferences (variable, ctx.UnresolvedFile, unit, ctx.Compilation, callback, if (!issueProvider.IsTargetVariable(variable))
ctx.CancellationToken);
}
void CheckVariable (IVariable variable, Statement env)
{
if (!issueProvider.IsTargetVariable (variable))
return; return;
var root = new Environment (env, env); var root = new Environment (env, env);
var envLookup = new Dictionary<AstNode, Environment> (); var envLookup = new Dictionary<AstNode, Environment> ();
envLookup [env] = root; envLookup [env] = root;
FindLocalReferences (variable, (astNode, resolveResult) => foreach (var result in ctx.FindReferences(env, variable)) {
AddNode (envLookup, new Node (astNode, issueProvider.GetNodeKind (astNode)))); AddNode(envLookup, new Node(result.Node, issueProvider.GetNodeKind(result.Node)));
}
root.SortChildren (); root.SortChildren ();
CollectIssues (root, variable.Name); CollectIssues (root, variable.Name);
@ -152,7 +143,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
IDictionary<Statement, IList<Node>> modifications = null; IDictionary<Statement, IList<Node>> modifications = null;
if (env.Body != null) { if (env.Body != null) {
cfg = cfgBuilder.BuildControlFlowGraph (env.Body); cfg = issueProvider.cfgBuilder.BuildControlFlowGraph (env.Body);
modifications = new Dictionary<Statement, IList<Node>> (); modifications = new Dictionary<Statement, IList<Node>> ();
foreach (var node in env.Children) { foreach (var node in env.Children) {
if (node.Kind == NodeKind.Modification || node.Kind == NodeKind.ReferenceAndModification) { if (node.Kind == NodeKind.Modification || node.Kind == NodeKind.ReferenceAndModification) {

48
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ForControlVariableNotModifiedIssue.cs

@ -26,7 +26,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.PatternMatching; using ICSharpCode.NRefactory.PatternMatching;
using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.Semantics;
@ -39,24 +38,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
IssueMarker = IssueMarker.Underline)] IssueMarker = IssueMarker.Underline)]
public class ForControlVariableNotModifiedIssue : ICodeIssueProvider public class ForControlVariableNotModifiedIssue : ICodeIssueProvider
{ {
static FindReferences refFinder = new FindReferences ();
public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context) public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context)
{ {
var unit = context.RootNode as SyntaxTree; return new GatherVisitor (context).GetIssues ();
if (unit == null)
return Enumerable.Empty<CodeIssue> ();
return new GatherVisitor (context, unit).GetIssues ();
} }
class GatherVisitor : GatherVisitorBase class GatherVisitor : GatherVisitorBase
{ {
SyntaxTree unit; public GatherVisitor (BaseRefactoringContext ctx)
public GatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit)
: base (ctx) : base (ctx)
{ {
this.unit = unit;
} }
static VariableInitializer GetControlVariable(VariableDeclarationStatement variableDecl, static VariableInitializer GetControlVariable(VariableDeclarationStatement variableDecl,
@ -111,25 +102,24 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (localResolveResult == null) if (localResolveResult == null)
return; return;
var results = ctx.FindReferences (forStatement, localResolveResult.Variable);
var modified = false; var modified = false;
refFinder.FindLocalReferences (localResolveResult.Variable, ctx.UnresolvedFile, unit, ctx.Compilation, foreach (var result in results) {
(node, resolveResult) => if (modified)
{ break;
if (modified) var node = result.Node;
return; var unary = node.Parent as UnaryOperatorExpression;
if (unary != null && unary.Expression == node) {
var unary = node.Parent as UnaryOperatorExpression; modified = unary.Operator == UnaryOperatorType.Decrement ||
if (unary != null && unary.Expression == node) { unary.Operator == UnaryOperatorType.PostDecrement ||
modified = unary.Operator == UnaryOperatorType.Decrement || unary.Operator == UnaryOperatorType.Increment ||
unary.Operator == UnaryOperatorType.PostDecrement || unary.Operator == UnaryOperatorType.PostIncrement;
unary.Operator == UnaryOperatorType.Increment || continue;
unary.Operator == UnaryOperatorType.PostIncrement; }
return;
} var assignment = node.Parent as AssignmentExpression;
modified = assignment != null && assignment.Left == node;
var assignment = node.Parent as AssignmentExpression; }
modified = assignment != null && assignment.Left == node;
}, ctx.CancellationToken);
if (!modified) if (!modified)
AddIssue (controlVariable.NameToken, AddIssue (controlVariable.NameToken,

11
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/FormatStringIssues/FormatStringIssue.cs

@ -54,6 +54,15 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
public override void VisitInvocationExpression(InvocationExpression invocationExpression) public override void VisitInvocationExpression(InvocationExpression invocationExpression)
{ {
base.VisitInvocationExpression(invocationExpression); base.VisitInvocationExpression(invocationExpression);
// Speed up the inspector by discarding some invocations early
var hasEligibleArgument = invocationExpression.Arguments.Any(argument => {
var primitiveArg = argument as PrimitiveExpression;
return primitiveArg != null && primitiveArg.Value is string;
});
if (!hasEligibleArgument)
return;
var invocationResolveResult = context.Resolve(invocationExpression) as CSharpInvocationResolveResult; var invocationResolveResult = context.Resolve(invocationExpression) as CSharpInvocationResolveResult;
if (invocationResolveResult == null) if (invocationResolveResult == null)
return; return;
@ -65,7 +74,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return; return;
} }
var primitiveArgument = formatArgument as PrimitiveExpression; var primitiveArgument = formatArgument as PrimitiveExpression;
if (primitiveArgument == null || !(primitiveArgument.Value is String)) if (primitiveArgument == null || !(primitiveArgument.Value is string))
return; return;
var format = (string)primitiveArgument.Value; var format = (string)primitiveArgument.Value;
var parsingResult = context.ParseFormatString(format); var parsingResult = context.ParseFormatString(format);

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

@ -58,9 +58,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
public override void VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression) public override void VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression)
{ {
var type = context.Resolve(objectCreateExpression.Type) as TypeResolveResult;
if (type == null)
return;
var parameters = objectCreateExpression.Arguments; var parameters = objectCreateExpression.Arguments;
if (parameters.Count != 2) if (parameters.Count != 2)
return; return;
@ -69,6 +66,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (firstParam == null || firstParam.Value.GetType() != typeof(string) || if (firstParam == null || firstParam.Value.GetType() != typeof(string) ||
secondParam == null || firstParam.Value.GetType() != typeof(string)) secondParam == null || firstParam.Value.GetType() != typeof(string))
return; return;
var type = context.Resolve(objectCreateExpression.Type) as TypeResolveResult;
if (type == null)
return;
var leftLength = (firstParam.Value as string).Length; var leftLength = (firstParam.Value as string).Length;
var rightLength = (secondParam.Value as string).Length; var rightLength = (secondParam.Value as string).Length;

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

@ -43,7 +43,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class GatherVisitor : GatherVisitorBase class GatherVisitor : GatherVisitorBase
{ {
static readonly ControlFlowGraphBuilder cfgBuilder = new ControlFlowGraphBuilder (); readonly ControlFlowGraphBuilder cfgBuilder = new ControlFlowGraphBuilder ();
public GatherVisitor(BaseRefactoringContext ctx) public GatherVisitor(BaseRefactoringContext ctx)
: base (ctx) : base (ctx)

73
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MultipleEnumerationIssue.cs

@ -42,11 +42,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context) public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context)
{ {
var unit = context.RootNode as SyntaxTree; return new GatherVisitor (context).GetIssues ();
if (unit == null)
return Enumerable.Empty<CodeIssue> ();
return new GatherVisitor (context, unit).GetIssues ();
} }
class AnalysisStatementCollector : DepthFirstAstVisitor class AnalysisStatementCollector : DepthFirstAstVisitor
@ -110,15 +106,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class GatherVisitor : GatherVisitorBase class GatherVisitor : GatherVisitorBase
{ {
static FindReferences refFinder = new FindReferences ();
SyntaxTree unit;
HashSet<AstNode> collectedAstNodes; HashSet<AstNode> collectedAstNodes;
public GatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit) public GatherVisitor (BaseRefactoringContext ctx)
: base (ctx) : base (ctx)
{ {
this.unit = unit;
this.collectedAstNodes = new HashSet<AstNode> (); this.collectedAstNodes = new HashSet<AstNode> ();
} }
@ -139,7 +131,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
base.VisitParameterDeclaration (parameterDeclaration); base.VisitParameterDeclaration (parameterDeclaration);
var resolveResult = ctx.Resolve (parameterDeclaration) as LocalResolveResult; var resolveResult = ctx.Resolve (parameterDeclaration) as LocalResolveResult;
CollectIssues (parameterDeclaration, resolveResult); CollectIssues (parameterDeclaration, parameterDeclaration.Parent, resolveResult);
} }
public override void VisitVariableInitializer (VariableInitializer variableInitializer) public override void VisitVariableInitializer (VariableInitializer variableInitializer)
@ -147,7 +139,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
base.VisitVariableInitializer (variableInitializer); base.VisitVariableInitializer (variableInitializer);
var resolveResult = ctx.Resolve (variableInitializer) as LocalResolveResult; var resolveResult = ctx.Resolve (variableInitializer) as LocalResolveResult;
CollectIssues (variableInitializer, resolveResult); CollectIssues (variableInitializer, variableInitializer.Parent.Parent, resolveResult);
} }
static bool IsAssignment (AstNode node) static bool IsAssignment (AstNode node)
@ -200,42 +192,42 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
HashSet<VariableReferenceNode> collectedNodes; HashSet<VariableReferenceNode> collectedNodes;
Dictionary<VariableReferenceNode, int> nodeDegree; // number of enumerations a node can reach Dictionary<VariableReferenceNode, int> nodeDegree; // number of enumerations a node can reach
void FindReferences (AstNode variableDecl, IVariable variable) void FindReferences (AstNode variableDecl, AstNode rootNode, IVariable variable)
{ {
references = new HashSet<AstNode> (); references = new HashSet<AstNode> ();
refStatements = new HashSet<Statement> (); refStatements = new HashSet<Statement> ();
lambdaExpressions = new HashSet<LambdaExpression> (); lambdaExpressions = new HashSet<LambdaExpression> ();
refFinder.FindLocalReferences (variable, ctx.UnresolvedFile, unit, ctx.Compilation, foreach (var result in ctx.FindReferences (rootNode, variable)) {
(astNode, resolveResult) => { var astNode = result.Node;
if (astNode == variableDecl) if (astNode == variableDecl)
return; continue;
var parent = astNode.Parent;
while (!(parent == null || parent is Statement || parent is LambdaExpression))
parent = parent.Parent;
if (parent == null)
return;
// lambda expression with expression body, should be analyzed separately
var expr = parent as LambdaExpression;
if (expr != null) {
if (IsAssignment (astNode) || IsEnumeration (astNode)) {
references.Add (astNode);
lambdaExpressions.Add (expr);
}
return;
}
var statement = (Statement)parent; var parent = astNode.Parent;
while (!(parent == null || parent is Statement || parent is LambdaExpression))
parent = parent.Parent;
if (parent == null)
continue;
// lambda expression with expression body, should be analyzed separately
var expr = parent as LambdaExpression;
if (expr != null) {
if (IsAssignment (astNode) || IsEnumeration (astNode)) { if (IsAssignment (astNode) || IsEnumeration (astNode)) {
references.Add (astNode); references.Add (astNode);
refStatements.Add (statement); lambdaExpressions.Add (expr);
} }
}, ctx.CancellationToken); continue;
}
if (IsAssignment (astNode) || IsEnumeration (astNode)) {
references.Add (astNode);
var statement = (Statement)parent;
refStatements.Add (statement);
}
}
} }
void CollectIssues (AstNode variableDecl, LocalResolveResult resolveResult) void CollectIssues (AstNode variableDecl, AstNode rootNode, LocalResolveResult resolveResult)
{ {
if (resolveResult == null) if (resolveResult == null)
return; return;
@ -246,15 +238,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
typeDef.KnownTypeCode != KnownTypeCode.IEnumerableOfT)) typeDef.KnownTypeCode != KnownTypeCode.IEnumerableOfT))
return; return;
FindReferences (variableDecl, resolveResult.Variable); FindReferences (variableDecl, rootNode, resolveResult.Variable);
var statements = AnalysisStatementCollector.Collect (variableDecl); var statements = AnalysisStatementCollector.Collect (variableDecl);
var builder = new VariableReferenceGraphBuilder (ctx);
foreach (var statement in statements) { foreach (var statement in statements) {
var vrNode = VariableReferenceGraphBuilder.Build (statement, references, refStatements, ctx); var vrNode = builder.Build (statement, references, refStatements, ctx);
FindMultipleEnumeration (vrNode); FindMultipleEnumeration (vrNode);
} }
foreach (var lambda in lambdaExpressions) { foreach (var lambda in lambdaExpressions) {
var vrNode = VariableReferenceGraphBuilder.Build (references, ctx.Resolver, (Expression)lambda.Body); var vrNode = builder.Build (references, ctx.Resolver, (Expression)lambda.Body);
FindMultipleEnumeration (vrNode); FindMultipleEnumeration (vrNode);
} }
} }

24
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/OptionalParameterCouldBeSkippedIssue.cs

@ -66,15 +66,24 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
(invocation, args) => new InvocationExpression(invocation.Target.Clone(), args)); (invocation, args) => new InvocationExpression(invocation.Target.Clone(), args));
} }
void CheckMethodCall<T> (T node, IEnumerable<Expression> arguments, Func<T, IEnumerable<Expression>, T> generateReplacement) where T: AstNode void CheckMethodCall<T> (T node, IEnumerable<Expression> args, Func<T, IEnumerable<Expression>, T> generateReplacement) where T: AstNode
{ {
// The first two checks are unnecessary, but eliminates the majority of calls early,
// improving performance.
var arguments = args.ToArray();
if (arguments.Length == 0)
return;
var lastArg = arguments[arguments.Length - 1];
if (!(lastArg is PrimitiveExpression || lastArg is NamedArgumentExpression))
return;
var invocationResolveResult = ctx.Resolve(node) as CSharpInvocationResolveResult; var invocationResolveResult = ctx.Resolve(node) as CSharpInvocationResolveResult;
if (invocationResolveResult == null) if (invocationResolveResult == null)
return; return;
string actionMessage = ctx.TranslateString("Remove redundant arguments"); string actionMessage = ctx.TranslateString("Remove redundant arguments");
var redundantArguments = GetRedundantArguments(arguments.ToArray(), invocationResolveResult); var redundantArguments = GetRedundantArguments(arguments, invocationResolveResult);
var action = new CodeAction(actionMessage, script => { var action = new CodeAction(actionMessage, script => {
var newArgumentList = arguments var newArgumentList = arguments
.Where(arg => !redundantArguments.Contains(arg)) .Where(arg => !redundantArguments.Contains(arg))
@ -84,7 +93,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
}); });
var issueMessage = ctx.TranslateString("Argument is identical to the default value"); var issueMessage = ctx.TranslateString("Argument is identical to the default value");
var lastPositionalArgument = redundantArguments.FirstOrDefault(expression => !(expression is NamedArgumentExpression)); var lastPositionalArgument = redundantArguments.FirstOrDefault(expression => !(expression is NamedArgumentExpression));
bool hasNamedArguments = false;
foreach (var argument in redundantArguments) { foreach (var argument in redundantArguments) {
var localArgument = argument; var localArgument = argument;
@ -100,7 +108,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var newInvocation = generateReplacement(node, newArgumentList); var newInvocation = generateReplacement(node, newArgumentList);
script.Replace(node, newInvocation); script.Replace(node, newInvocation);
})); }));
hasNamedArguments = true;
} else { } else {
var title = ctx.TranslateString("Remove this and the following positional arguments"); var title = ctx.TranslateString("Remove this and the following positional arguments");
actions.Add(new CodeAction(title, script => { actions.Add(new CodeAction(title, script => {
@ -116,11 +123,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
} }
} }
IEnumerable<Expression> GetRedundantArguments(Expression[] arguments, CSharpInvocationResolveResult invocationResolveResult) IList<Expression> GetRedundantArguments(Expression[] arguments, CSharpInvocationResolveResult invocationResolveResult)
{ {
var argumentToParameterMap = invocationResolveResult.GetArgumentToParameterMap(); var argumentToParameterMap = invocationResolveResult.GetArgumentToParameterMap();
var resolvedParameters = invocationResolveResult.Member.Parameters; var resolvedParameters = invocationResolveResult.Member.Parameters;
IList<Expression> redundantArguments = new List<Expression>();
for (int i = arguments.Length - 1; i >= 0; i--) { for (int i = arguments.Length - 1; i >= 0; i--) {
var parameterIndex = argumentToParameterMap[i]; var parameterIndex = argumentToParameterMap[i];
if (parameterIndex == -1) if (parameterIndex == -1)
@ -141,7 +150,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
// Stop here since any arguments before this one has to be there // Stop here since any arguments before this one has to be there
// to enable the passing of this argument // to enable the passing of this argument
break; break;
yield return argument; redundantArguments.Add(argument);
} else if (argument is NamedArgumentExpression) { } else if (argument is NamedArgumentExpression) {
var expression = ((NamedArgumentExpression)argument).Expression as PrimitiveExpression; var expression = ((NamedArgumentExpression)argument).Expression as PrimitiveExpression;
if (expression == null) if (expression == null)
@ -150,12 +159,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (expressionResolveResult == null || parameter.ConstantValue != expressionResolveResult.ConstantValue) if (expressionResolveResult == null || parameter.ConstantValue != expressionResolveResult.ConstantValue)
// continue, since there can still be more arguments that are redundant // continue, since there can still be more arguments that are redundant
continue; continue;
yield return argument; redundantArguments.Add(argument);
} else { } else {
// This is a non-constant positional argument => no more redundancies are possible // This is a non-constant positional argument => no more redundancies are possible
break; break;
} }
} }
return redundantArguments;
} }
} }
} }

10
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ParameterCanBeDemotedIssue/ParameterCanBeDemotedIssue.cs

@ -54,13 +54,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
#region ICodeIssueProvider implementation #region ICodeIssueProvider implementation
public IEnumerable<CodeIssue> GetIssues(BaseRefactoringContext context) public IEnumerable<CodeIssue> GetIssues(BaseRefactoringContext context)
{ {
var sw = new Stopwatch(); // var sw = new Stopwatch();
sw.Start(); // sw.Start();
var gatherer = new GatherVisitor(context, tryResolve); var gatherer = new GatherVisitor(context, tryResolve);
var issues = gatherer.GetIssues(); var issues = gatherer.GetIssues();
sw.Stop(); // sw.Stop();
Console.WriteLine("Elapsed time in ParameterCanBeDemotedIssue: {0} (Checked types: {3, 4} Qualified for resolution check: {5, 4} Members with issues: {4, 4} Method bodies resolved: {2, 4} File: '{1}')", // Console.WriteLine("Elapsed time in ParameterCanBeDemotedIssue: {0} (Checked types: {3, 4} Qualified for resolution check: {5, 4} Members with issues: {4, 4} Method bodies resolved: {2, 4} File: '{1}')",
sw.Elapsed, context.UnresolvedFile.FileName, gatherer.MethodResolveCount, gatherer.TypesChecked, gatherer.MembersWithIssues, gatherer.TypeResolveCount); // sw.Elapsed, context.UnresolvedFile.FileName, gatherer.MethodResolveCount, gatherer.TypesChecked, gatherer.MembersWithIssues, gatherer.TypeResolveCount);
return issues; return issues;
} }
#endregion #endregion

59
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantAssignmentIssue.cs

@ -26,7 +26,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.Semantics;
namespace ICSharpCode.NRefactory.CSharp.Refactoring namespace ICSharpCode.NRefactory.CSharp.Refactoring
@ -48,14 +47,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class GatherVisitor : GatherVisitorBase class GatherVisitor : GatherVisitorBase
{ {
static FindReferences refFinder = new FindReferences ();
SyntaxTree unit;
public GatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit) public GatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit)
: base (ctx) : base (ctx)
{ {
this.unit = unit;
} }
public override void VisitParameterDeclaration (ParameterDeclaration parameterDeclaration) public override void VisitParameterDeclaration (ParameterDeclaration parameterDeclaration)
@ -89,40 +83,45 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
if (rootStatement == null || resolveResult == null) if (rootStatement == null || resolveResult == null)
return; return;
var references = new HashSet<AstNode> (); var references = new HashSet<AstNode> ();
var refStatements = new HashSet<Statement> (); var refStatements = new HashSet<Statement> ();
var usedInLambda = false; var usedInLambda = false;
refFinder.FindLocalReferences (resolveResult.Variable, ctx.UnresolvedFile, unit, ctx.Compilation, var results = ctx.FindReferences (rootStatement, resolveResult.Variable);
(astNode, rr) => { foreach (var result in results) {
if (usedInLambda || astNode == variableDecl) var node = result.Node;
return; if (node == variableDecl)
continue;
var parent = astNode.Parent;
while (!(parent == null || parent is Statement || parent is LambdaExpression)) var parent = node.Parent;
parent = parent.Parent; while (!(parent == null || parent is Statement || parent is LambdaExpression))
if (parent == null) parent = parent.Parent;
return; if (parent == null)
continue;
var statement = parent as Statement;
if (statement != null) { var statement = parent as Statement;
references.Add (astNode); if (statement != null) {
refStatements.Add (statement); references.Add (node);
} refStatements.Add (statement);
}
while (parent != null && parent != rootStatement) { while (parent != null && parent != rootStatement) {
if (parent is LambdaExpression || parent is AnonymousMethodExpression) { if (parent is LambdaExpression || parent is AnonymousMethodExpression) {
usedInLambda = true; usedInLambda = true;
break; break;
}
parent = parent.Parent;
} }
}, ctx.CancellationToken); parent = parent.Parent;
}
if (usedInLambda) {
break;
}
}
// stop analyzing if the variable is used in any lambda expression or anonymous method // stop analyzing if the variable is used in any lambda expression or anonymous method
if (usedInLambda) if (usedInLambda)
return; return;
var startNode = VariableReferenceGraphBuilder.Build (rootStatement, references, refStatements, ctx); var startNode = new VariableReferenceGraphBuilder (ctx).Build (rootStatement, references, refStatements, ctx);
var variableInitializer = variableDecl as VariableInitializer; var variableInitializer = variableDecl as VariableInitializer;
if (variableInitializer != null && !variableInitializer.Initializer.IsNull) if (variableInitializer != null && !variableInitializer.Initializer.IsNull)
startNode.References.Insert (0, variableInitializer); startNode.References.Insert (0, variableInitializer);

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

@ -71,7 +71,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
base.VisitMemberType(memberType); base.VisitMemberType(memberType);
HandleMemberReference( HandleMemberReference(
memberType, memberType.Target, memberType.MemberNameToken, memberType.TypeArguments, NameLookupMode.Type, memberType, memberType.Target, memberType.MemberNameToken, memberType.TypeArguments, memberType.GetNameLookupMode(),
script => { script => {
script.Replace(memberType, RefactoringAstHelper.RemoveTarget(memberType)); script.Replace(memberType, RefactoringAstHelper.RemoveTarget(memberType));
}); });

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

@ -64,7 +64,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
void CheckExpressionInAutoCallContext(Expression expression) void CheckExpressionInAutoCallContext(Expression expression)
{ {
if (expression is InvocationExpression) { if (expression is InvocationExpression && !processedNodes.Contains(expression)) {
CheckInvocationInAutoCallContext((InvocationExpression)expression); CheckInvocationInAutoCallContext((InvocationExpression)expression);
} }
} }
@ -75,12 +75,12 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (memberExpression == null) { if (memberExpression == null) {
return; return;
} }
var resolveResult = ctx.Resolve(invocationExpression) as CSharpInvocationResolveResult; if (memberExpression.MemberName != "ToString" || invocationExpression.Arguments.Any ()) {
if (resolveResult == null) {
return; return;
} }
var member = resolveResult.Member;
if (member.Name != "ToString" || member.Parameters.Count != 0) { var resolveResult = ctx.Resolve(invocationExpression) as CSharpInvocationResolveResult;
if (resolveResult == null) {
return; return;
} }
AddRedundantToStringIssue(memberExpression, invocationExpression); AddRedundantToStringIssue(memberExpression, invocationExpression);
@ -88,9 +88,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
void AddRedundantToStringIssue(MemberReferenceExpression memberExpression, InvocationExpression invocationExpression) void AddRedundantToStringIssue(MemberReferenceExpression memberExpression, InvocationExpression invocationExpression)
{ {
if (processedNodes.Contains(invocationExpression)) { // Simon Lindgren 2012-09-14: Previously there was a check here to see if the node had already been processed
return; // This has been moved out to the callers, to check it earlier for a 30-40% run time reduction
}
processedNodes.Add(invocationExpression); processedNodes.Add(invocationExpression);
AddIssue(memberExpression.DotToken.StartLocation, invocationExpression.RParToken.EndLocation, AddIssue(memberExpression.DotToken.StartLocation, invocationExpression.RParToken.EndLocation,
@ -176,7 +175,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
void CheckTargetedObject(InvocationExpression invocationExpression, IType type, IMember member) void CheckTargetedObject(InvocationExpression invocationExpression, IType type, IMember member)
{ {
var memberExpression = invocationExpression.Target as MemberReferenceExpression; var memberExpression = invocationExpression.Target as MemberReferenceExpression;
if (memberExpression != null) { if (memberExpression != null && !processedNodes.Contains(invocationExpression)) {
if (type.IsKnownType(KnownTypeCode.String) && member.Name == "ToString") { if (type.IsKnownType(KnownTypeCode.String) && member.Name == "ToString") {
AddRedundantToStringIssue(memberExpression, invocationExpression); AddRedundantToStringIssue(memberExpression, invocationExpression);
} }

5
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceEqualsCalledWithValueTypeIssue.cs

@ -54,6 +54,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
base.VisitInvocationExpression (invocationExpression); base.VisitInvocationExpression (invocationExpression);
// Quickly determine if this invocation is eligible to speed up the inspector
var nameToken = invocationExpression.Target.GetChildByRole(Roles.Identifier);
if (nameToken.Name != "ReferenceEquals")
return;
var resolveResult = ctx.Resolve (invocationExpression) as InvocationResolveResult; var resolveResult = ctx.Resolve (invocationExpression) as InvocationResolveResult;
if (resolveResult == null || if (resolveResult == null ||
resolveResult.Member.DeclaringTypeDefinition == null || resolveResult.Member.DeclaringTypeDefinition == null ||

19
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ValueParameterUnusedIssue.cs

@ -45,13 +45,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class GatherVisitor : GatherVisitorBase class GatherVisitor : GatherVisitorBase
{ {
readonly BaseRefactoringContext context;
readonly FindReferences findRef = new FindReferences();
public GatherVisitor(BaseRefactoringContext context, ValueParameterUnusedIssue inspector) : base (context) public GatherVisitor(BaseRefactoringContext context, ValueParameterUnusedIssue inspector) : base (context)
{ {
this.context = context;
} }
public override void VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration) public override void VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration)
@ -77,22 +72,22 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (!IsEligible(body)) if (!IsEligible(body))
return; return;
var localResolveResult = context.GetResolverStateBefore(body) var localResolveResult = ctx.GetResolverStateBefore(body)
.LookupSimpleNameOrTypeName("value", new List<IType>(), NameLookupMode.Expression) as LocalResolveResult; .LookupSimpleNameOrTypeName("value", new List<IType>(), NameLookupMode.Expression) as LocalResolveResult;
if (localResolveResult == null) if (localResolveResult == null)
return; return;
var variable = localResolveResult.Variable;
bool referenceFound = false; bool referenceFound = false;
var syntaxTree = (SyntaxTree)context.RootNode; foreach (var result in ctx.FindReferences (body, localResolveResult.Variable)) {
findRef.FindLocalReferences(variable, context.UnresolvedFile, syntaxTree, context.Compilation, (n, entity) => { var node = result.Node;
if (n.StartLocation >= body.StartLocation && n.EndLocation <= body.EndLocation) { if (node.StartLocation >= body.StartLocation && node.EndLocation <= body.EndLocation) {
referenceFound = true; referenceFound = true;
break;
} }
}, CancellationToken.None); }
if(!referenceFound) if(!referenceFound)
AddIssue(anchor, context.TranslateString("The " + accessorName + " does not use the 'value' parameter")); AddIssue(anchor, ctx.TranslateString("The " + accessorName + " does not use the 'value' parameter"));
} }
static bool IsEligible(BlockStatement body) static bool IsEligible(BlockStatement body)

4
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableDeclaredInWideScopeIssue.cs

@ -210,6 +210,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var binaryOperator = node as BinaryOperatorExpression; var binaryOperator = node as BinaryOperatorExpression;
if (binaryOperator != null) { if (binaryOperator != null) {
var resolveResult = context.Resolve(binaryOperator) as OperatorResolveResult; var resolveResult = context.Resolve(binaryOperator) as OperatorResolveResult;
if (resolveResult == null)
return false;
// Built-in operators are ok, user defined ones not so much // Built-in operators are ok, user defined ones not so much
return resolveResult.UserDefinedOperatorMethod != null; return resolveResult.UserDefinedOperatorMethod != null;
} }
@ -226,6 +228,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var binaryOperator = node as BinaryOperatorExpression; var binaryOperator = node as BinaryOperatorExpression;
if (binaryOperator != null) { if (binaryOperator != null) {
var resolveResult = context.Resolve(binaryOperator) as OperatorResolveResult; var resolveResult = context.Resolve(binaryOperator) as OperatorResolveResult;
if (resolveResult == null)
return false;
return resolveResult.UserDefinedOperatorMethod != null; return resolveResult.UserDefinedOperatorMethod != null;
} }
return IsConflictingAssignment(node, identifiers, members, locals); return IsConflictingAssignment(node, identifiers, members, locals);

26
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/LocalVariableNotUsedIssue.cs

@ -25,6 +25,8 @@
// THE SOFTWARE. // THE SOFTWARE.
using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.Semantics;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Refactoring namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
@ -33,21 +35,22 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
Category = IssueCategories.Redundancies, Category = IssueCategories.Redundancies,
Severity = Severity.Warning, Severity = Severity.Warning,
IssueMarker = IssueMarker.GrayOut)] IssueMarker = IssueMarker.GrayOut)]
public class LocalVariableNotUsedIssue : VariableNotUsedIssue public class LocalVariableNotUsedIssue : ICodeIssueProvider
{ {
internal override GatherVisitorBase GetGatherVisitor (BaseRefactoringContext context, SyntaxTree unit) #region ICodeIssueProvider implementation
public System.Collections.Generic.IEnumerable<CodeIssue> GetIssues(BaseRefactoringContext context)
{ {
return new GatherVisitor (context, unit); return new GatherVisitor (context).GetIssues ();
} }
#endregion
class GatherVisitor : GatherVisitorBase class GatherVisitor : GatherVisitorBase
{ {
SyntaxTree unit; public GatherVisitor (BaseRefactoringContext ctx)
public GatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit)
: base (ctx) : base (ctx)
{ {
this.unit = unit;
} }
public override void VisitVariableInitializer (VariableInitializer variableInitializer) public override void VisitVariableInitializer (VariableInitializer variableInitializer)
@ -65,7 +68,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (resolveResult == null) if (resolveResult == null)
return; return;
if (FindUsage (ctx, unit, resolveResult.Variable, variableInitializer)) if (IsUsed (decl.Parent, resolveResult.Variable, variableInitializer))
return; return;
AddIssue (variableInitializer.NameToken, ctx.TranslateString ("Remove unused local variable"), AddIssue (variableInitializer.NameToken, ctx.TranslateString ("Remove unused local variable"),
@ -90,11 +93,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (resolveResult == null) if (resolveResult == null)
return; return;
if (FindUsage (ctx, unit, resolveResult.Variable, foreachStatement.VariableNameToken)) if (IsUsed (foreachStatement, resolveResult.Variable, foreachStatement.VariableNameToken))
return; return;
AddIssue (foreachStatement.VariableNameToken, ctx.TranslateString ("Local variable is never used")); AddIssue (foreachStatement.VariableNameToken, ctx.TranslateString ("Local variable is never used"));
} }
bool IsUsed(AstNode rootNode, IVariable variable, AstNode variableNode)
{
return ctx.FindReferences(rootNode, variable).Any(result => result.Node != variableNode);
}
} }
} }

18
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/ParameterNotUsedIssue.cs

@ -27,6 +27,7 @@
using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.Semantics;
using System.Linq; using System.Linq;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
@ -35,22 +36,20 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
Category = IssueCategories.Redundancies, Category = IssueCategories.Redundancies,
Severity = Severity.Warning, Severity = Severity.Warning,
IssueMarker = IssueMarker.GrayOut)] IssueMarker = IssueMarker.GrayOut)]
public class ParameterNotUsedIssue : VariableNotUsedIssue public class ParameterNotUsedIssue : ICodeIssueProvider
{ {
#region ICodeIssueProvider implementation
internal override GatherVisitorBase GetGatherVisitor (BaseRefactoringContext context, SyntaxTree unit) public IEnumerable<CodeIssue> GetIssues(BaseRefactoringContext context)
{ {
return new GatherVisitor (context, unit); return new GatherVisitor (context).GetIssues ();
} }
#endregion
class GatherVisitor : GatherVisitorBase class GatherVisitor : GatherVisitorBase
{ {
SyntaxTree unit; public GatherVisitor (BaseRefactoringContext ctx)
public GatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit)
: base (ctx) : base (ctx)
{ {
this.unit = unit;
} }
public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration) public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration)
@ -81,7 +80,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var resolveResult = ctx.Resolve (parameterDeclaration) as LocalResolveResult; var resolveResult = ctx.Resolve (parameterDeclaration) as LocalResolveResult;
if (resolveResult == null) if (resolveResult == null)
return; return;
if (FindUsage (ctx, unit, resolveResult.Variable, parameterDeclaration))
if (ctx.FindReferences (parameterDeclaration.Parent, resolveResult.Variable).Any(r => r.Node != parameterDeclaration))
return; return;
AddIssue (parameterDeclaration.NameToken, ctx.TranslateString ("Parameter is never used")); AddIssue (parameterDeclaration.NameToken, ctx.TranslateString ("Parameter is never used"));

60
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/VariableNotUsedIssue.cs

@ -1,60 +0,0 @@
//
// VariableNotUsedIssue.cs
//
// Author:
// Mansheng Yang <lightyang0@gmail.com>
//
// Copyright (c) 2012 Mansheng Yang <lightyang0@gmail.com>
//
// 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.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public abstract class VariableNotUsedIssue : ICodeIssueProvider
{
static FindReferences refFinder = new FindReferences ();
public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context)
{
var unit = context.RootNode as SyntaxTree;
if (unit == null)
return Enumerable.Empty<CodeIssue> ();
return GetGatherVisitor(context, unit).GetIssues ();
}
protected static bool FindUsage (BaseRefactoringContext context, SyntaxTree unit, IVariable variable,
AstNode declaration)
{
var found = false;
refFinder.FindLocalReferences (variable, context.UnresolvedFile, unit, context.Compilation,
(node, resolveResult) =>
{
found = found || node != declaration;
}, context.CancellationToken);
return found;
}
internal abstract GatherVisitorBase GetGatherVisitor (BaseRefactoringContext context, SyntaxTree unit);
}
}

11
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/LocalVariableOnlyAssignedIssue.cs

@ -36,19 +36,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
IssueMarker = IssueMarker.Underline)] IssueMarker = IssueMarker.Underline)]
public class LocalVariableOnlyAssignedIssue : VariableOnlyAssignedIssue public class LocalVariableOnlyAssignedIssue : VariableOnlyAssignedIssue
{ {
internal override GatherVisitorBase GetGatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit) internal override GatherVisitorBase GetGatherVisitor (BaseRefactoringContext ctx)
{ {
return new GatherVisitor (ctx, unit); return new GatherVisitor (ctx);
} }
class GatherVisitor : GatherVisitorBase class GatherVisitor : GatherVisitorBase
{ {
SyntaxTree unit; public GatherVisitor (BaseRefactoringContext ctx)
public GatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit)
: base (ctx) : base (ctx)
{ {
this.unit = unit;
} }
public override void VisitVariableInitializer (VariableInitializer variableInitializer) public override void VisitVariableInitializer (VariableInitializer variableInitializer)
@ -62,7 +59,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var resolveResult = ctx.Resolve (variableInitializer) as LocalResolveResult; var resolveResult = ctx.Resolve (variableInitializer) as LocalResolveResult;
if (resolveResult == null) if (resolveResult == null)
return; return;
if (!TestOnlyAssigned (ctx, unit, resolveResult.Variable)) if (!TestOnlyAssigned (ctx, decl.Parent, resolveResult.Variable))
return; return;
AddIssue (variableInitializer.NameToken, AddIssue (variableInitializer.NameToken,
ctx.TranslateString ("Local variable is assigned by its value is never used")); ctx.TranslateString ("Local variable is assigned by its value is never used"));

27
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/ParameterOnlyAssignedIssue.cs

@ -23,7 +23,6 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // 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 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.Semantics;
namespace ICSharpCode.NRefactory.CSharp.Refactoring namespace ICSharpCode.NRefactory.CSharp.Refactoring
@ -35,33 +34,33 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
IssueMarker = IssueMarker.Underline)] IssueMarker = IssueMarker.Underline)]
public class ParameterOnlyAssignedIssue : VariableOnlyAssignedIssue public class ParameterOnlyAssignedIssue : VariableOnlyAssignedIssue
{ {
internal override GatherVisitorBase GetGatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit) internal override GatherVisitorBase GetGatherVisitor(BaseRefactoringContext ctx)
{ {
return new GatherVisitor (ctx, unit); return new GatherVisitor(ctx);
} }
private class GatherVisitor : GatherVisitorBase private class GatherVisitor : GatherVisitorBase
{ {
SyntaxTree unit; public GatherVisitor(BaseRefactoringContext ctx)
public GatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit)
: base (ctx) : base (ctx)
{ {
this.unit = unit;
} }
public override void VisitParameterDeclaration (ParameterDeclaration parameterDeclaration) public override void VisitParameterDeclaration(ParameterDeclaration parameterDeclaration)
{ {
base.VisitParameterDeclaration (parameterDeclaration); base.VisitParameterDeclaration(parameterDeclaration);
var resolveResult = ctx.Resolve (parameterDeclaration) as LocalResolveResult; var resolveResult = ctx.Resolve(parameterDeclaration) as LocalResolveResult;
if (resolveResult == null) if (resolveResult == null)
return; return;
if (parameterDeclaration.ParameterModifier == ParameterModifier.Out || parameterDeclaration.ParameterModifier == ParameterModifier.Ref
|| !TestOnlyAssigned (ctx, unit, resolveResult.Variable)) var parameterModifier = parameterDeclaration.ParameterModifier;
if (parameterModifier == ParameterModifier.Out || parameterModifier == ParameterModifier.Ref ||
!TestOnlyAssigned(ctx, parameterDeclaration.Parent, resolveResult.Variable)) {
return; return;
AddIssue (parameterDeclaration.NameToken, }
ctx.TranslateString ("Parameter is assigned by its value is never used")); AddIssue(parameterDeclaration.NameToken,
ctx.TranslateString("Parameter is assigned by its value is never used"));
} }
} }
} }

69
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/VariableOnlyAssignedIssue.cs

@ -25,68 +25,61 @@
// THE SOFTWARE. // THE SOFTWARE.
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Refactoring namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
public abstract class VariableOnlyAssignedIssue : ICodeIssueProvider public abstract class VariableOnlyAssignedIssue : ICodeIssueProvider
{ {
static FindReferences refFinder = new FindReferences ();
public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context) public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context)
{ {
var unit = context.RootNode as SyntaxTree; return GetGatherVisitor (context).GetIssues ();
if (unit == null)
return Enumerable.Empty<CodeIssue> ();
return GetGatherVisitor (context, unit).GetIssues ();
} }
protected static bool TestOnlyAssigned (BaseRefactoringContext ctx, SyntaxTree unit, IVariable variable) protected static bool TestOnlyAssigned(BaseRefactoringContext ctx, AstNode rootNode, IVariable variable)
{ {
var assignment = false; var assignment = false;
var nonAssignment = false; var nonAssignment = false;
refFinder.FindLocalReferences (variable, ctx.UnresolvedFile, unit, ctx.Compilation, foreach (var result in ctx.FindReferences(rootNode, variable)) {
(node, resolveResult) => var node = result.Node;
{ if (node is ParameterDeclaration)
if (node is ParameterDeclaration) continue;
return;
if (node is VariableInitializer) { if (node is VariableInitializer) {
if (!(node as VariableInitializer).Initializer.IsNull) if (!(node as VariableInitializer).Initializer.IsNull)
assignment = true; assignment = true;
return; continue;
} }
if (node is IdentifierExpression) { if (node is IdentifierExpression) {
var parent = node.Parent; var parent = node.Parent;
if (parent is AssignmentExpression) { if (parent is AssignmentExpression) {
if (((AssignmentExpression)parent).Left == node) { if (((AssignmentExpression)parent).Left == node) {
assignment = true; assignment = true;
return; continue;
} }
} else if (parent is UnaryOperatorExpression) { } else if (parent is UnaryOperatorExpression) {
var op = ((UnaryOperatorExpression)parent).Operator; var op = ((UnaryOperatorExpression)parent).Operator;
switch (op) { switch (op) {
case UnaryOperatorType.Increment: case UnaryOperatorType.Increment:
case UnaryOperatorType.PostIncrement: case UnaryOperatorType.PostIncrement:
case UnaryOperatorType.Decrement: case UnaryOperatorType.Decrement:
case UnaryOperatorType.PostDecrement: case UnaryOperatorType.PostDecrement:
assignment = true; assignment = true;
return; continue;
} }
} else if (parent is DirectionExpression) { } else if (parent is DirectionExpression) {
if (((DirectionExpression)parent).FieldDirection == FieldDirection.Out) { if (((DirectionExpression)parent).FieldDirection == FieldDirection.Out) {
assignment = true; assignment = true;
return; continue;
}
} }
} }
nonAssignment = true; }
}, ctx.CancellationToken); nonAssignment = true;
}
return assignment && !nonAssignment; return assignment && !nonAssignment;
} }
internal abstract GatherVisitorBase GetGatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit); internal abstract GatherVisitorBase GetGatherVisitor (BaseRefactoringContext ctx);
} }
} }

154
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/LocalReferenceFinder.cs

@ -0,0 +1,154 @@
//
// LocalReferenceFinder.cs
//
// Author:
// Simon Lindgren <simon.n.lindgren@gmail.com>
//
// Copyright (c) 2012 Simon Lindgren
//
// 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.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Utils;
using System.Diagnostics;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Finds references to <see cref="IVariable">IVariables</see>.
/// </summary>
/// <remarks>
/// This class is more efficient than <see cref="FindReferences"/>
/// if there is already a resolved tree or if multiple searches needs
/// to be performed.
/// </remarks>
public class LocalReferenceFinder
{
LocalReferenceLocator locator;
MultiDictionary<IVariable, ReferenceResult> references = new MultiDictionary<IVariable, ReferenceResult>();
HashSet<AstNode> visitedRoots = new HashSet<AstNode>();
public LocalReferenceFinder(CSharpAstResolver resolver)
{
locator = new LocalReferenceLocator(resolver, this);
}
public LocalReferenceFinder(BaseRefactoringContext context) : this(context.Resolver)
{
}
void VisitIfNeccessary(AstNode rootNode)
{
// If any of the parent nodes are recorded as visited,
// we don't need to traverse rootNode this time.
var tmpRoot = rootNode;
while(tmpRoot != null){
if (visitedRoots.Contains(tmpRoot))
return;
tmpRoot = tmpRoot.Parent;
}
locator.ProccessRoot (rootNode);
}
/// <summary>
/// Finds the references to <paramref name="variable"/>.
/// </summary>
/// <param name='rootNode'>
/// Root node for the search.
/// </param>
/// <param name='variable'>
/// The variable to find references for.
/// </param>
/// <remarks>
/// When a single <see cref="LocalReferenceFinder"/> is reused for multiple
/// searches, which references outside of <paramref name="rootNode"/> are
/// or are not reported is undefined.
/// </remarks>
public IList<ReferenceResult> FindReferences(AstNode rootNode, IVariable variable)
{
lock (locator) {
VisitIfNeccessary(rootNode);
var lookup = (ILookup<IVariable, ReferenceResult>)references;
if (!lookup.Contains(variable))
return new List<ReferenceResult>();
// Clone the list for thread safety
return references[variable].ToList();
}
}
class LocalReferenceLocator : DepthFirstAstVisitor
{
CSharpAstResolver resolver;
LocalReferenceFinder referenceFinder;
public LocalReferenceLocator(CSharpAstResolver resolver, LocalReferenceFinder referenceFinder)
{
this.resolver = resolver;
this.referenceFinder = referenceFinder;
}
IList<IVariable> processedVariables = new List<IVariable>();
public void ProccessRoot (AstNode rootNode)
{
rootNode.AcceptVisitor(this);
referenceFinder.visitedRoots.Add(rootNode);
}
protected override void VisitChildren(AstNode node)
{
if (referenceFinder.visitedRoots.Contains(node))
return;
var localResolveResult = resolver.Resolve(node) as LocalResolveResult;
if (localResolveResult != null && !processedVariables.Contains(localResolveResult.Variable)) {
referenceFinder.references.Add(localResolveResult.Variable, new ReferenceResult(node, localResolveResult));
processedVariables.Add(localResolveResult.Variable);
base.VisitChildren(node);
Debug.Assert(processedVariables.Contains(localResolveResult.Variable), "Variable should still be in the list of processed variables.");
processedVariables.Remove(localResolveResult.Variable);
} else {
base.VisitChildren(node);
}
}
}
}
public class ReferenceResult
{
public ReferenceResult (AstNode node, LocalResolveResult resolveResult)
{
Node = node;
ResolveResult = resolveResult;
}
public AstNode Node { get; private set; }
public LocalResolveResult ResolveResult { get; private set; }
}
}

6
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/NamingHelper.cs

@ -103,6 +103,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
/// <param name='type'> /// <param name='type'>
/// The type of the variable. /// The type of the variable.
/// </param> /// </param>
/// <param name='baseName'>
/// Suggested base name.
/// </param>
public string GenerateVariableName(AstType type, string baseName = null) public string GenerateVariableName(AstType type, string baseName = null)
{ {
if (baseName == null) { if (baseName == null) {
@ -142,6 +145,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
/// <param name='type'> /// <param name='type'>
/// The type of the variable. /// The type of the variable.
/// </param> /// </param>
/// <param name='baseName'>
/// Suggested base name.
/// </param>
public string GenerateVariableName(IType type, string baseName = null) public string GenerateVariableName(IType type, string baseName = null)
{ {
AstType astType = ToAstType(type); AstType astType = ToAstType(type);

46
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/TypeSystemAstBuilder.cs

@ -55,6 +55,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
this.ShowTypeParameterConstraints = true; this.ShowTypeParameterConstraints = true;
this.ShowParameterNames = true; this.ShowParameterNames = true;
this.ShowConstantValues = true; this.ShowConstantValues = true;
this.UseAliases = true;
} }
/// <summary> /// <summary>
@ -129,6 +130,12 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
/// The default value is <c>false</c>. /// The default value is <c>false</c>.
/// </summary> /// </summary>
public bool ConvertUnboundTypeArguments { get; set;} public bool ConvertUnboundTypeArguments { get; set;}
/// <summary>
/// Controls if aliases should be used inside the type name or not.
/// The default value is <c>true</c>.
/// </summary>
public bool UseAliases { get; set;}
#endregion #endregion
#region Convert Type #region Convert Type
@ -218,11 +225,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (resolver != null) { if (resolver != null) {
// Look if there's an alias to the target type // Look if there's an alias to the target type
for (ResolvedUsingScope usingScope = resolver.CurrentUsingScope; usingScope != null; usingScope = usingScope.Parent) { if (UseAliases) {
foreach (var pair in usingScope.UsingAliases) { for (ResolvedUsingScope usingScope = resolver.CurrentUsingScope; usingScope != null; usingScope = usingScope.Parent) {
if (pair.Value is TypeResolveResult) { foreach (var pair in usingScope.UsingAliases) {
if (TypeMatches(pair.Value.Type, typeDef, typeArguments)) if (pair.Value is TypeResolveResult) {
return new SimpleType(pair.Key); if (TypeMatches(pair.Value.Type, typeDef, typeArguments))
return new SimpleType(pair.Key);
}
} }
} }
} }
@ -236,12 +245,15 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
} else { } else {
localTypeArguments = EmptyList<IType>.Instance; localTypeArguments = EmptyList<IType>.Instance;
} }
TypeResolveResult trr = resolver.ResolveSimpleName(typeDef.Name, localTypeArguments) as TypeResolveResult; ResolveResult rr = resolver.ResolveSimpleName(typeDef.Name, localTypeArguments);
if (trr != null && !trr.IsError && TypeMatches(trr.Type, typeDef, typeArguments)) { TypeResolveResult trr = rr as TypeResolveResult;
// We can use the short type name if (trr != null || (localTypeArguments.Count == 0 && resolver.IsVariableReferenceWithSameType(rr, typeDef.Name, out trr))) {
SimpleType shortResult = new SimpleType(typeDef.Name); if (!trr.IsError && TypeMatches(trr.Type, typeDef, typeArguments)) {
AddTypeArguments(shortResult, typeDef, typeArguments, outerTypeParameterCount, typeDef.TypeParameterCount); // We can use the short type name
return shortResult; SimpleType shortResult = new SimpleType(typeDef.Name);
AddTypeArguments(shortResult, typeDef, typeArguments, outerTypeParameterCount, typeDef.TypeParameterCount);
return shortResult;
}
} }
} }
@ -315,11 +327,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
if (resolver != null) { if (resolver != null) {
// Look if there's an alias to the target namespace // Look if there's an alias to the target namespace
for (ResolvedUsingScope usingScope = resolver.CurrentUsingScope; usingScope != null; usingScope = usingScope.Parent) { if (UseAliases) {
foreach (var pair in usingScope.UsingAliases) { for (ResolvedUsingScope usingScope = resolver.CurrentUsingScope; usingScope != null; usingScope = usingScope.Parent) {
NamespaceResolveResult nrr = pair.Value as NamespaceResolveResult; foreach (var pair in usingScope.UsingAliases) {
if (nrr != null && nrr.NamespaceName == ns) NamespaceResolveResult nrr = pair.Value as NamespaceResolveResult;
return new SimpleType(pair.Key); if (nrr != null && nrr.NamespaceName == ns)
return new SimpleType(pair.Key);
}
} }
} }
} }

36
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/VariableReferenceGraph.cs

@ -65,23 +65,30 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class VariableReferenceGraphBuilder class VariableReferenceGraphBuilder
{ {
static ControlFlowGraphBuilder cfgBuilder = new ControlFlowGraphBuilder (); ControlFlowGraphBuilder cfgBuilder = new ControlFlowGraphBuilder ();
static CfgVariableReferenceNodeBuilder cfgVrNodeBuilder = new CfgVariableReferenceNodeBuilder (); CfgVariableReferenceNodeBuilder cfgVrNodeBuilder;
BaseRefactoringContext ctx;
public static VariableReferenceNode Build (ISet<AstNode> references, CSharpAstResolver resolver, public VariableReferenceGraphBuilder(BaseRefactoringContext ctx)
{
this.ctx = ctx;
cfgVrNodeBuilder = new CfgVariableReferenceNodeBuilder (this);
}
public VariableReferenceNode Build (ISet<AstNode> references, CSharpAstResolver resolver,
Expression expression) Expression expression)
{ {
return ExpressionNodeCreationVisitor.CreateNode (references, resolver, new [] { expression }); return ExpressionNodeCreationVisitor.CreateNode (references, resolver, new [] { expression });
} }
public static VariableReferenceNode Build (Statement statement, ISet<AstNode> references, public VariableReferenceNode Build (Statement statement, ISet<AstNode> references,
ISet<Statement> refStatements, BaseRefactoringContext context) ISet<Statement> refStatements, BaseRefactoringContext context)
{ {
var cfg = cfgBuilder.BuildControlFlowGraph (statement, context.Resolver, context.CancellationToken); var cfg = cfgBuilder.BuildControlFlowGraph (statement, context.Resolver, context.CancellationToken);
return cfgVrNodeBuilder.Build (cfg [0], references, refStatements, context.Resolver); return cfgVrNodeBuilder.Build (cfg [0], references, refStatements, context.Resolver);
} }
public static VariableReferenceNode Build (Statement statement, ISet<AstNode> references, public VariableReferenceNode Build (Statement statement, ISet<AstNode> references,
ISet<Statement> refStatements, CSharpAstResolver resolver, CancellationToken cancellationToken = default(CancellationToken)) ISet<Statement> refStatements, CSharpAstResolver resolver, CancellationToken cancellationToken = default(CancellationToken))
{ {
var cfg = cfgBuilder.BuildControlFlowGraph (statement, resolver, cancellationToken); var cfg = cfgBuilder.BuildControlFlowGraph (statement, resolver, cancellationToken);
@ -169,13 +176,19 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class CfgVariableReferenceNodeBuilder class CfgVariableReferenceNodeBuilder
{ {
static GetExpressionsVisitor getExpr = new GetExpressionsVisitor (); readonly VariableReferenceGraphBuilder variableReferenceGraphBuilder;
GetExpressionsVisitor getExpr = new GetExpressionsVisitor ();
ISet<AstNode> references; ISet<AstNode> references;
ISet<Statement> refStatements; ISet<Statement> refStatements;
CSharpAstResolver resolver; CSharpAstResolver resolver;
Dictionary<ControlFlowNode, VariableReferenceNode> nodeDict; Dictionary<ControlFlowNode, VariableReferenceNode> nodeDict;
public CfgVariableReferenceNodeBuilder(VariableReferenceGraphBuilder variableReferenceGraphBuilder)
{
this.variableReferenceGraphBuilder = variableReferenceGraphBuilder;
}
public VariableReferenceNode Build (ControlFlowNode startNode, ISet<AstNode> references, public VariableReferenceNode Build (ControlFlowNode startNode, ISet<AstNode> references,
ISet<Statement> refStatements, CSharpAstResolver resolver) ISet<Statement> refStatements, CSharpAstResolver resolver)
{ {
@ -214,6 +227,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var node = new VariableReferenceNode (); var node = new VariableReferenceNode ();
var cfNode = startNode; var cfNode = startNode;
while (true) { while (true) {
if (variableReferenceGraphBuilder.ctx.CancellationToken.IsCancellationRequested)
return null;
if (nodeDict.ContainsKey (cfNode)) { if (nodeDict.ContainsKey (cfNode)) {
node.AddNextNode (nodeDict [cfNode]); node.AddNextNode (nodeDict [cfNode]);
break; break;
@ -246,12 +261,12 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (tryc != null) { if (tryc != null) {
VariableReferenceNode outNode = null; VariableReferenceNode outNode = null;
foreach (var n in tryc.CatchClauses) { foreach (var n in tryc.CatchClauses) {
var catchNode = VariableReferenceGraphBuilder.Build(n.Body, references, refStatements, this.resolver); var catchNode = variableReferenceGraphBuilder.Build(n.Body, references, refStatements, this.resolver);
(outNode ?? node).AddNextNode (catchNode); (outNode ?? node).AddNextNode (catchNode);
outNode = catchNode; outNode = catchNode;
} }
if (!tryc.FinallyBlock.IsNull) { if (!tryc.FinallyBlock.IsNull) {
var finallyNode = VariableReferenceGraphBuilder.Build(tryc.FinallyBlock, references, refStatements, this.resolver); var finallyNode = variableReferenceGraphBuilder.Build(tryc.FinallyBlock, references, refStatements, this.resolver);
(outNode ?? node).AddNextNode (finallyNode); (outNode ?? node).AddNextNode (finallyNode);
outNode = finallyNode; outNode = finallyNode;
} }
@ -261,7 +276,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
} }
} }
} }
return nodeDict [startNode]; VariableReferenceNode result;
if (!nodeDict.TryGetValue (startNode, out result))
return new VariableReferenceNode ();
return result;
} }
} }

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

@ -0,0 +1,80 @@
// 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.Linq;
using System.Linq.Expressions;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// Represents the result of an await expression.
/// </summary>
public class AwaitResolveResult : ResolveResult
{
/// <summary>
/// The method representing the GetAwaiter() call. Can be null if the GetAwaiter method was not found.
/// </summary>
public readonly ResolveResult GetAwaiterInvocation;
/// <summary>
/// Awaiter type. Will not be null (but can be UnknownType).
/// </summary>
public readonly IType AwaiterType;
/// <summary>
/// Property representing the IsCompleted property on the awaiter type. Can be null if the awaiter type or the property was not found, or when awaiting a dynamic expression.
/// </summary>
public readonly IProperty IsCompletedProperty;
/// <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.
/// </summary>
public readonly IMethod OnCompletedMethod;
/// <summary>
/// Method representing the GetResult method on the awaiter type. Can be null if the awaiter type or the method was not found, or when awaiting a dynamic expression.
/// </summary>
public readonly IMethod GetResultMethod;
public AwaitResolveResult(IType resultType, ResolveResult getAwaiterInvocation, IType awaiterType, IProperty isCompletedProperty, IMethod onCompletedMethod, IMethod getResultMethod)
: base(resultType)
{
if (awaiterType == null)
throw new ArgumentNullException("awaiterType");
if (getAwaiterInvocation == null)
throw new ArgumentNullException("getAwaiterInvocation");
this.GetAwaiterInvocation = getAwaiterInvocation;
this.AwaiterType = awaiterType;
this.IsCompletedProperty = isCompletedProperty;
this.OnCompletedMethod = onCompletedMethod;
this.GetResultMethod = getResultMethod;
}
public override bool IsError {
get { return this.GetAwaiterInvocation.IsError || (AwaiterType.Kind != TypeKind.Dynamic && (this.IsCompletedProperty == null || this.OnCompletedMethod == null || this.GetResultMethod == null)); }
}
public override IEnumerable<ResolveResult> GetChildResults() {
return new[] { GetAwaiterInvocation };
}
}
}

59
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs

@ -651,7 +651,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
long val = (long)rr.ConstantValue; long val = (long)rr.ConstantValue;
return val >= 0 && toTypeCode == TypeCode.UInt64; return val >= 0 && toTypeCode == TypeCode.UInt64;
} else if (fromTypeCode == TypeCode.Int32) { } else if (fromTypeCode == TypeCode.Int32) {
int val = (int)rr.ConstantValue; object cv = rr.ConstantValue;
if (cv == null)
return false;
int val = (int)cv;
switch (toTypeCode) { switch (toTypeCode) {
case TypeCode.SByte: case TypeCode.SByte:
return val >= SByte.MinValue && val <= SByte.MaxValue; return val >= SByte.MinValue && val <= SByte.MaxValue;
@ -903,13 +906,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
MethodGroupResolveResult rr = resolveResult as MethodGroupResolveResult; MethodGroupResolveResult rr = resolveResult as MethodGroupResolveResult;
if (rr == null) if (rr == null)
return Conversion.None; return Conversion.None;
IMethod m = toType.GetDelegateInvokeMethod(); IMethod invoke = toType.GetDelegateInvokeMethod();
if (m == null) if (invoke == null)
return Conversion.None; return Conversion.None;
ResolveResult[] args = new ResolveResult[m.Parameters.Count]; ResolveResult[] args = new ResolveResult[invoke.Parameters.Count];
for (int i = 0; i < args.Length; i++) { for (int i = 0; i < args.Length; i++) {
IParameter param = m.Parameters[i]; IParameter param = invoke.Parameters[i];
IType parameterType = param.Type; IType parameterType = param.Type;
if ((param.IsRef || param.IsOut) && parameterType.Kind == TypeKind.ByReference) { if ((param.IsRef || param.IsOut) && parameterType.Kind == TypeKind.ByReference) {
parameterType = ((ByReferenceType)parameterType).ElementType; parameterType = ((ByReferenceType)parameterType).ElementType;
@ -918,16 +921,58 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
args[i] = new ResolveResult(parameterType); args[i] = new ResolveResult(parameterType);
} }
} }
var or = rr.PerformOverloadResolution(compilation, args, allowExpandingParams: false, conversions: this); var or = rr.PerformOverloadResolution(compilation, args, allowExpandingParams: false, allowOptionalParameters: false, conversions: this);
if (or.FoundApplicableCandidate) { if (or.FoundApplicableCandidate) {
IMethod method = (IMethod)or.GetBestCandidateWithSubstitutedTypeArguments(); IMethod method = (IMethod)or.GetBestCandidateWithSubstitutedTypeArguments();
var thisRR = rr.TargetResult as ThisResolveResult; var thisRR = rr.TargetResult as ThisResolveResult;
bool isVirtual = method.IsOverridable && !(thisRR != null && thisRR.CausesNonVirtualInvocation); bool isVirtual = method.IsOverridable && !(thisRR != null && thisRR.CausesNonVirtualInvocation);
return Conversion.MethodGroupConversion(method, isVirtual); bool isValid = !or.IsAmbiguous && IsDelegateCompatible(method, invoke, or.IsExtensionMethodInvocation);
if (isValid)
return Conversion.MethodGroupConversion(method, isVirtual);
else
return Conversion.InvalidMethodGroupConversion(method, isVirtual);
} else { } else {
return Conversion.None; return Conversion.None;
} }
} }
/// <summary>
/// Gets whether a method <paramref name="m"/> is compatible with a delegate type.
/// §15.2 Delegate compatibility
/// </summary>
/// <param name="m">The method to test for compatibility</param>
/// <param name="invoke">The invoke method of the delegate</param>
/// <param name="isExtensionMethodInvocation">Gets whether m is accessed using extension method syntax.
/// If this parameter is true, the first parameter of <paramref name="m"/> will be ignored.</param>
bool IsDelegateCompatible(IMethod m, IMethod invoke, bool isExtensionMethodInvocation)
{
if (m == null)
throw new ArgumentNullException("m");
if (invoke == null)
throw new ArgumentNullException("invoke");
int firstParameterInM = isExtensionMethodInvocation ? 1 : 0;
if (m.Parameters.Count - firstParameterInM != invoke.Parameters.Count)
return false;
for (int i = 0; i < invoke.Parameters.Count; i++) {
var pm = m.Parameters[firstParameterInM + i];
var pd = invoke.Parameters[i];
// ret/out must match
if (pm.IsRef != pd.IsRef || pm.IsOut != pd.IsOut)
return false;
if (pm.IsRef || pm.IsOut) {
// ref/out parameters must have same types
if (!pm.Type.Equals(pd.Type))
return false;
} else {
// non-ref/out parameters must have an identity or reference conversion from pd to pm
if (!IdentityConversion(pd.Type, pm.Type) && !IsImplicitReferenceConversion(pd.Type, pm.Type))
return false;
}
}
// check return type compatibility
return IdentityConversion(m.ReturnType, invoke.ReturnType)
|| IsImplicitReferenceConversion(m.ReturnType, invoke.ReturnType);
}
#endregion #endregion
#region BetterConversion #region BetterConversion

8
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpInvocationResolveResult.cs

@ -107,8 +107,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
} }
} }
if (IsExpandedForm) if (IsExpandedForm){
results[results.Length - 1] = new ArrayCreateResolveResult(Member.Parameters.Last().Type, null, paramsArguments.ToArray()); IType arrayType = Member.Parameters.Last().Type;
IType int32 = Member.Compilation.FindType(KnownTypeCode.Int32);
ResolveResult[] sizeArguments = { new ConstantResolveResult(int32, paramsArguments.Count) };
results[results.Length - 1] = new ArrayCreateResolveResult(arrayType, sizeArguments, paramsArguments);
}
for (int i = 0; i < results.Length; i++) { for (int i = 0; i < results.Length; i++) {
if (results[i] == null) { if (results[i] == null) {

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

@ -360,8 +360,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region ResolveUnaryOperator method #region ResolveUnaryOperator method
public ResolveResult ResolveUnaryOperator(UnaryOperatorType op, ResolveResult expression) public ResolveResult ResolveUnaryOperator(UnaryOperatorType op, ResolveResult expression)
{ {
if (expression.Type.Kind == TypeKind.Dynamic) if (expression.Type.Kind == TypeKind.Dynamic) {
return UnaryOperatorResolveResult(SpecialType.Dynamic, op, expression); if (op == UnaryOperatorType.Await) {
return new AwaitResolveResult(SpecialType.Dynamic, new DynamicInvocationResolveResult(new DynamicMemberResolveResult(expression, "GetAwaiter"), DynamicInvocationType.Invocation, EmptyList<ResolveResult>.Instance), SpecialType.Dynamic, null, null, null);
}
else {
return UnaryOperatorResolveResult(SpecialType.Dynamic, op, expression);
}
}
// C# 4.0 spec: §7.3.3 Unary operator overload resolution // C# 4.0 spec: §7.3.3 Unary operator overload resolution
string overloadableOperatorName = GetOverloadableOperatorName(op); string overloadableOperatorName = GetOverloadableOperatorName(op);
@ -375,17 +381,37 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return ErrorResult; return ErrorResult;
case UnaryOperatorType.AddressOf: case UnaryOperatorType.AddressOf:
return UnaryOperatorResolveResult(new PointerType(expression.Type), op, expression); return UnaryOperatorResolveResult(new PointerType(expression.Type), op, expression);
case UnaryOperatorType.Await: case UnaryOperatorType.Await: {
ResolveResult getAwaiterMethodGroup = ResolveMemberAccess(expression, "GetAwaiter", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget); ResolveResult getAwaiterMethodGroup = ResolveMemberAccess(expression, "GetAwaiter", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget);
ResolveResult getAwaiterInvocation = ResolveInvocation(getAwaiterMethodGroup, new ResolveResult[0]); ResolveResult getAwaiterInvocation = ResolveInvocation(getAwaiterMethodGroup, new ResolveResult[0]);
var getResultMethodGroup = CreateMemberLookup().Lookup(getAwaiterInvocation, "GetResult", EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
var lookup = CreateMemberLookup();
IMethod getResultMethod;
IType awaitResultType;
var getResultMethodGroup = lookup.Lookup(getAwaiterInvocation, "GetResult", EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
if (getResultMethodGroup != null) { if (getResultMethodGroup != null) {
var or = getResultMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0], allowExtensionMethods: false, conversions: conversions); var getResultOR = getResultMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0], allowExtensionMethods: false, conversions: conversions);
IType awaitResultType = or.GetBestCandidateWithSubstitutedTypeArguments().ReturnType; getResultMethod = getResultOR.FoundApplicableCandidate ? getResultOR.GetBestCandidateWithSubstitutedTypeArguments() as IMethod : null;
return UnaryOperatorResolveResult(awaitResultType, UnaryOperatorType.Await, expression); awaitResultType = getResultMethod != null ? getResultMethod.ReturnType : SpecialType.UnknownType;
} else { }
return UnaryOperatorResolveResult(SpecialType.UnknownType, UnaryOperatorType.Await, expression); else {
getResultMethod = null;
awaitResultType = SpecialType.UnknownType;
}
var isCompletedRR = lookup.Lookup(getAwaiterInvocation, "IsCompleted", EmptyList<IType>.Instance, false);
var isCompletedProperty = (isCompletedRR is MemberResolveResult ? ((MemberResolveResult)isCompletedRR).Member as IProperty : null);
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);
} }
return new AwaitResolveResult(awaitResultType, getAwaiterInvocation, getAwaiterInvocation.Type, isCompletedProperty, onCompletedMethod, getResultMethod);
}
default: default:
throw new ArgumentException("Invalid value for UnaryOperatorType", "op"); throw new ArgumentException("Invalid value for UnaryOperatorType", "op");
} }
@ -1279,6 +1305,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return new ConstantResolveResult(targetType, CSharpPrimitiveCast(code, expression.ConstantValue)); return new ConstantResolveResult(targetType, CSharpPrimitiveCast(code, expression.ConstantValue));
} catch (OverflowException) { } catch (OverflowException) {
return new ErrorResolveResult(targetType); return new ErrorResolveResult(targetType);
} catch (InvalidCastException) {
return new ErrorResolveResult(targetType);
} }
} else if (code == TypeCode.String) { } else if (code == TypeCode.String) {
if (expression.ConstantValue == null || expression.ConstantValue is string) if (expression.ConstantValue == null || expression.ConstantValue is string)
@ -1292,6 +1320,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return new ConstantResolveResult(targetType, CSharpPrimitiveCast(code, expression.ConstantValue)); return new ConstantResolveResult(targetType, CSharpPrimitiveCast(code, expression.ConstantValue));
} catch (OverflowException) { } catch (OverflowException) {
return new ErrorResolveResult(targetType); return new ErrorResolveResult(targetType);
} catch (InvalidCastException) {
return new ErrorResolveResult(targetType);
} }
} }
} }
@ -2433,21 +2463,48 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// The array element type. /// The array element type.
/// Pass null to resolve an implicitly-typed array creation. /// Pass null to resolve an implicitly-typed array creation.
/// </param> /// </param>
/// <param name="dimensions"> /// <param name="sizeArguments">
/// The number of array dimensions. /// The size arguments.
/// The length of this array will be used as the number of dimensions of the array type.
/// Negative values will be treated as errors.
/// </param>
/// <param name="initializerElements">
/// The initializer elements. May be null if no array initializer was specified.
/// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
/// </param>
public ArrayCreateResolveResult ResolveArrayCreation(IType elementType, int[] sizeArguments, ResolveResult[] initializerElements = null)
{
ResolveResult[] sizeArgResults = new ResolveResult[sizeArguments.Length];
for (int i = 0; i < sizeArguments.Length; i++) {
if (sizeArguments[i] < 0)
sizeArgResults[i] = ErrorResolveResult.UnknownError;
else
sizeArgResults[i] = new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), sizeArguments[i]);
}
return ResolveArrayCreation(elementType, sizeArgResults, initializerElements);
}
/// <summary>
/// Resolves an array creation.
/// </summary>
/// <param name="elementType">
/// The array element type.
/// Pass null to resolve an implicitly-typed array creation.
/// </param> /// </param>
/// <param name="sizeArguments"> /// <param name="sizeArguments">
/// The size arguments. May be null if no explicit size was given. /// The size arguments.
/// The length of this array will be used as the number of dimensions of the array type.
/// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s! /// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
/// </param> /// </param>
/// <param name="initializerElements"> /// <param name="initializerElements">
/// The initializer elements. May be null if no array initializer was specified. /// The initializer elements. May be null if no array initializer was specified.
/// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s! /// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
/// </param> /// </param>
public ArrayCreateResolveResult ResolveArrayCreation(IType elementType, int dimensions = 1, ResolveResult[] sizeArguments = null, ResolveResult[] initializerElements = null) public ArrayCreateResolveResult ResolveArrayCreation(IType elementType, ResolveResult[] sizeArguments, ResolveResult[] initializerElements = null)
{ {
if (sizeArguments != null && dimensions != Math.Max(1, sizeArguments.Length)) int dimensions = sizeArguments.Length;
throw new ArgumentException("dimensions and sizeArguments.Length don't match"); if (dimensions == 0)
throw new ArgumentException("sizeArguments.Length must not be 0");
if (elementType == null) { if (elementType == null) {
TypeInference typeInference = new TypeInference(compilation, conversions); TypeInference typeInference = new TypeInference(compilation, conversions);
bool success; bool success;
@ -2455,8 +2512,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
IType arrayType = new ArrayType(compilation, elementType, dimensions); IType arrayType = new ArrayType(compilation, elementType, dimensions);
if (sizeArguments != null) AdjustArrayAccessArguments(sizeArguments);
AdjustArrayAccessArguments(sizeArguments);
if (initializerElements != null) { if (initializerElements != null) {
for (int i = 0; i < initializerElements.Length; i++) { for (int i = 0; i < initializerElements.Length; i++) {

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

@ -244,6 +244,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
scope = FindMemberReferences(entity, m => new FindPropertyReferences((IProperty)m)); scope = FindMemberReferences(entity, m => new FindPropertyReferences((IProperty)m));
if (entity.Name == "Current") if (entity.Name == "Current")
additionalScope = FindEnumeratorCurrentReferences((IProperty)entity); additionalScope = FindEnumeratorCurrentReferences((IProperty)entity);
else if (entity.Name == "IsCompleted")
additionalScope = FindAwaiterIsCompletedReferences((IProperty)entity);
break; break;
case EntityType.Event: case EntityType.Event:
scope = FindMemberReferences(entity, m => new FindEventReferences((IEvent)m)); scope = FindMemberReferences(entity, m => new FindEventReferences((IEvent)m));
@ -661,6 +663,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return imported != null ? new FindEnumeratorCurrentReferencesNavigator(imported) : null; return imported != null ? new FindEnumeratorCurrentReferencesNavigator(imported) : null;
}); });
} }
SearchScope FindAwaiterIsCompletedReferences(IProperty property)
{
return new SearchScope(
delegate(ICompilation compilation) {
IProperty imported = compilation.Import(property);
return imported != null ? new FindAwaiterIsCompletedReferencesNavigator(imported) : null;
});
}
sealed class FindEnumeratorCurrentReferencesNavigator : FindReferenceNavigator sealed class FindEnumeratorCurrentReferencesNavigator : FindReferenceNavigator
{ {
@ -682,6 +693,27 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return ferr != null && ferr.CurrentProperty != null && findReferences.IsMemberMatch(property, ferr.CurrentProperty, true); return ferr != null && ferr.CurrentProperty != null && findReferences.IsMemberMatch(property, ferr.CurrentProperty, true);
} }
} }
sealed class FindAwaiterIsCompletedReferencesNavigator : FindReferenceNavigator
{
IProperty property;
public FindAwaiterIsCompletedReferencesNavigator(IProperty property)
{
this.property = property;
}
internal override bool CanMatch(AstNode node)
{
return node is UnaryOperatorExpression;
}
internal override bool IsMatch(ResolveResult rr)
{
AwaitResolveResult arr = rr as AwaitResolveResult;
return arr != null && arr.IsCompletedProperty != null && findReferences.IsMemberMatch(property, arr.IsCompletedProperty, true);
}
}
#endregion #endregion
#region Find Method References #region Find Method References
@ -724,6 +756,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
case "MoveNext": case "MoveNext":
specialNodeType = typeof(ForeachStatement); specialNodeType = typeof(ForeachStatement);
break; break;
case "GetAwaiter":
case "GetResult":
case "OnCompleted":
specialNodeType = typeof(UnaryOperatorExpression);
break;
default: default:
specialNodeType = null; specialNodeType = null;
break; break;
@ -794,6 +831,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return IsMatch(ferr.GetEnumeratorCall) return IsMatch(ferr.GetEnumeratorCall)
|| (ferr.MoveNextMethod != null && findReferences.IsMemberMatch(method, ferr.MoveNextMethod, true)); || (ferr.MoveNextMethod != null && findReferences.IsMemberMatch(method, ferr.MoveNextMethod, true));
} }
var arr = rr as AwaitResolveResult;
if (arr != null) {
return IsMatch(arr.GetAwaiterInvocation)
|| (arr.GetResultMethod != null && findReferences.IsMemberMatch(method, arr.GetResultMethod, true))
|| (arr.OnCompletedMethod != null && findReferences.IsMemberMatch(method, arr.OnCompletedMethod, true));
}
} }
var mrr = rr as MemberResolveResult; var mrr = rr as MemberResolveResult;
return mrr != null && findReferences.IsMemberMatch(method, mrr.Member, mrr.IsVirtualCall); return mrr != null && findReferences.IsMemberMatch(method, mrr.Member, mrr.IsVirtualCall);

8
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs

@ -220,7 +220,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return string.Format("[{0} with {1} method(s)]", GetType().Name, this.Methods.Count()); return string.Format("[{0} with {1} method(s)]", GetType().Name, this.Methods.Count());
} }
public OverloadResolution PerformOverloadResolution(ICompilation compilation, ResolveResult[] arguments, string[] argumentNames = null, bool allowExtensionMethods = true, bool allowExpandingParams = true, bool checkForOverflow = false, CSharpConversions conversions = null) public OverloadResolution PerformOverloadResolution(ICompilation compilation, ResolveResult[] arguments, string[] argumentNames = null,
bool allowExtensionMethods = true,
bool allowExpandingParams = true,
bool allowOptionalParameters = true,
bool checkForOverflow = false, CSharpConversions conversions = null)
{ {
Log.WriteLine("Performing overload resolution for " + this); Log.WriteLine("Performing overload resolution for " + this);
Log.WriteCollection(" Arguments: ", arguments); Log.WriteCollection(" Arguments: ", arguments);
@ -228,6 +232,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
var typeArgumentArray = this.TypeArguments.ToArray(); var typeArgumentArray = this.TypeArguments.ToArray();
OverloadResolution or = new OverloadResolution(compilation, arguments, argumentNames, typeArgumentArray, conversions); OverloadResolution or = new OverloadResolution(compilation, arguments, argumentNames, typeArgumentArray, conversions);
or.AllowExpandingParams = allowExpandingParams; or.AllowExpandingParams = allowExpandingParams;
or.AllowOptionalParameters = allowOptionalParameters;
or.CheckForOverflow = checkForOverflow; or.CheckForOverflow = checkForOverflow;
or.AddMethodLists(methodLists); or.AddMethodLists(methodLists);
@ -249,6 +254,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
var extOr = new OverloadResolution(compilation, extArguments, extArgumentNames, typeArgumentArray, conversions); var extOr = new OverloadResolution(compilation, extArguments, extArgumentNames, typeArgumentArray, conversions);
extOr.AllowExpandingParams = allowExpandingParams; extOr.AllowExpandingParams = allowExpandingParams;
extOr.AllowOptionalParameters = allowOptionalParameters;
extOr.IsExtensionMethodInvocation = true; extOr.IsExtensionMethodInvocation = true;
extOr.CheckForOverflow = checkForOverflow; extOr.CheckForOverflow = checkForOverflow;

10
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs

@ -155,6 +155,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
this.conversions = conversions ?? CSharpConversions.Get(compilation); this.conversions = conversions ?? CSharpConversions.Get(compilation);
this.AllowExpandingParams = true; this.AllowExpandingParams = true;
this.AllowOptionalParameters = true;
} }
#endregion #endregion
@ -174,6 +175,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary> /// </summary>
public bool AllowExpandingParams { get; set; } public bool AllowExpandingParams { get; set; }
/// <summary>
/// Gets/Sets whether optional parameters may be left at their default value.
/// The default value is true.
/// If this property is set to false, optional parameters will be treated like regular parameters.
/// </summary>
public bool AllowOptionalParameters { get; set; }
/// <summary> /// <summary>
/// Gets/Sets whether ConversionResolveResults created by this OverloadResolution /// Gets/Sets whether ConversionResolveResults created by this OverloadResolution
/// instance apply overflow checking. /// instance apply overflow checking.
@ -543,7 +551,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (candidate.IsExpandedForm && i == argumentCountPerParameter.Length - 1) if (candidate.IsExpandedForm && i == argumentCountPerParameter.Length - 1)
continue; // any number of arguments is fine for the params-array continue; // any number of arguments is fine for the params-array
if (argumentCountPerParameter[i] == 0) { if (argumentCountPerParameter[i] == 0) {
if (candidate.Parameters[i].IsOptional) if (this.AllowOptionalParameters && candidate.Parameters[i].IsOptional)
candidate.HasUnmappedOptionalParameters = true; candidate.HasUnmappedOptionalParameters = true;
else else
candidate.AddError(OverloadResolutionErrors.MissingArgumentForRequiredParameter); candidate.AddError(OverloadResolutionErrors.MissingArgumentForRequiredParameter);

7
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/ResolveAtLocation.cs

@ -1,4 +1,4 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team // Copyright (c) AlphaSierraPapa for the SharpDevelop Team
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of this // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -53,6 +53,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
node = syntaxTree.GetNodeAt(location); node = syntaxTree.GetNodeAt(location);
if (node == null || node is ArrayInitializerExpression) if (node == null || node is ArrayInitializerExpression)
return null; return null;
if (node.Parent is UsingAliasDeclaration && node.Role == UsingAliasDeclaration.AliasRole) {
var r = new CSharpAstResolver(compilation.Value, syntaxTree, unresolvedFile);
return r.Resolve(((UsingAliasDeclaration)node.Parent).Import, cancellationToken);
}
if (CSharpAstResolver.IsUnresolvableNode(node)) { if (CSharpAstResolver.IsUnresolvableNode(node)) {
if (node is Identifier) { if (node is Identifier) {
node = node.Parent; node = node.Parent;
@ -81,6 +85,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return null; return null;
} }
} }
if (node == null) if (node == null)
return null; return null;

86
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs

@ -735,12 +735,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (aie != null && arrayType != null) { if (aie != null && arrayType != null) {
StoreCurrentState(aie); StoreCurrentState(aie);
List<Expression> initializerElements = new List<Expression>(); List<Expression> initializerElements = new List<Expression>();
UnpackArrayInitializer(initializerElements, aie, arrayType.Dimensions, true); int[] sizes = new int[arrayType.Dimensions];
UnpackArrayInitializer(initializerElements, sizes, aie, 0, true);
ResolveResult[] initializerElementResults = new ResolveResult[initializerElements.Count]; ResolveResult[] initializerElementResults = new ResolveResult[initializerElements.Count];
for (int i = 0; i < initializerElementResults.Length; i++) { for (int i = 0; i < initializerElementResults.Length; i++) {
initializerElementResults[i] = Resolve(initializerElements[i]); initializerElementResults[i] = Resolve(initializerElements[i]);
} }
var arrayCreation = resolver.ResolveArrayCreation(arrayType.ElementType, arrayType.Dimensions, null, initializerElementResults); var arrayCreation = resolver.ResolveArrayCreation(arrayType.ElementType, sizes, initializerElementResults);
StoreResult(aie, arrayCreation); StoreResult(aie, arrayCreation);
ProcessConversionResults(initializerElements, arrayCreation.InitializerElements); ProcessConversionResults(initializerElements, arrayCreation.InitializerElements);
} else if (variableInitializer.Parent is FixedStatement) { } else if (variableInitializer.Parent is FixedStatement) {
@ -1201,6 +1202,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult IAstVisitor<ResolveResult>.VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression) ResolveResult IAstVisitor<ResolveResult>.VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression)
{ {
int dimensions = arrayCreateExpression.Arguments.Count; int dimensions = arrayCreateExpression.Arguments.Count;
IEnumerable<Expression> sizeArgumentExpressions;
ResolveResult[] sizeArguments; ResolveResult[] sizeArguments;
IEnumerable<ArraySpecifier> additionalArraySpecifiers; IEnumerable<ArraySpecifier> additionalArraySpecifiers;
if (dimensions == 0) { if (dimensions == 0) {
@ -1213,24 +1215,29 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers; additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers;
} }
sizeArguments = null; sizeArguments = null;
sizeArgumentExpressions = null;
} else { } else {
sizeArgumentExpressions = arrayCreateExpression.Arguments;
sizeArguments = new ResolveResult[dimensions]; sizeArguments = new ResolveResult[dimensions];
int pos = 0; int pos = 0;
foreach (var node in arrayCreateExpression.Arguments) foreach (var node in sizeArgumentExpressions)
sizeArguments[pos++] = Resolve(node); sizeArguments[pos++] = Resolve(node);
additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers; additionalArraySpecifiers = arrayCreateExpression.AdditionalArraySpecifiers;
} }
int[] sizes;
List<Expression> initializerElements; List<Expression> initializerElements;
ResolveResult[] initializerElementResults; ResolveResult[] initializerElementResults;
if (arrayCreateExpression.Initializer.IsNull) { if (arrayCreateExpression.Initializer.IsNull) {
sizes = null;
initializerElements = null; initializerElements = null;
initializerElementResults = null; initializerElementResults = null;
} else { } else {
StoreCurrentState(arrayCreateExpression.Initializer); StoreCurrentState(arrayCreateExpression.Initializer);
initializerElements = new List<Expression>(); initializerElements = new List<Expression>();
UnpackArrayInitializer(initializerElements, arrayCreateExpression.Initializer, dimensions, true); sizes = new int[dimensions];
UnpackArrayInitializer(initializerElements, sizes, arrayCreateExpression.Initializer, 0, true);
initializerElementResults = new ResolveResult[initializerElements.Count]; initializerElementResults = new ResolveResult[initializerElements.Count];
for (int i = 0; i < initializerElementResults.Length; i++) { for (int i = 0; i < initializerElementResults.Length; i++) {
initializerElementResults[i] = Resolve(initializerElements[i]); initializerElementResults[i] = Resolve(initializerElements[i]);
@ -1238,39 +1245,59 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
StoreResult(arrayCreateExpression.Initializer, voidResult); StoreResult(arrayCreateExpression.Initializer, voidResult);
} }
ArrayCreateResolveResult acrr; IType elementType;
if (arrayCreateExpression.Type.IsNull) { if (arrayCreateExpression.Type.IsNull) {
acrr = resolver.ResolveArrayCreation(null, dimensions, sizeArguments, initializerElementResults); elementType = null;
} else { } else {
IType elementType = ResolveType(arrayCreateExpression.Type); elementType = ResolveType(arrayCreateExpression.Type);
foreach (var spec in additionalArraySpecifiers.Reverse()) { foreach (var spec in additionalArraySpecifiers.Reverse()) {
elementType = new ArrayType(resolver.Compilation, elementType, spec.Dimensions); elementType = new ArrayType(resolver.Compilation, elementType, spec.Dimensions);
} }
acrr = resolver.ResolveArrayCreation(elementType, dimensions, sizeArguments, initializerElementResults);
} }
ArrayCreateResolveResult acrr;
if (sizeArguments != null) {
acrr = resolver.ResolveArrayCreation(elementType, sizeArguments, initializerElementResults);
} else if (sizes != null) {
acrr = resolver.ResolveArrayCreation(elementType, sizes, initializerElementResults);
} else {
// neither size arguments nor an initializer exist -> error
return new ErrorResolveResult(new ArrayType(resolver.Compilation, elementType ?? SpecialType.UnknownType, dimensions));
}
if (sizeArgumentExpressions != null)
ProcessConversionResults(sizeArgumentExpressions, acrr.SizeArguments);
if (acrr.InitializerElements != null)
ProcessConversionResults(initializerElements, acrr.InitializerElements);
return acrr; return acrr;
} }
void UnpackArrayInitializer(List<Expression> elementList, ArrayInitializerExpression initializer, int dimensions, bool resolveNestedInitializesToVoid) void UnpackArrayInitializer(List<Expression> elementList, int[] sizes, ArrayInitializerExpression initializer, int dimension, bool resolveNestedInitializersToVoid)
{ {
Debug.Assert(dimensions >= 1); Debug.Assert(dimension < sizes.Length);
if (dimensions > 1) { int elementCount = 0;
if (dimension + 1 < sizes.Length) {
foreach (var node in initializer.Elements) { foreach (var node in initializer.Elements) {
ArrayInitializerExpression aie = node as ArrayInitializerExpression; ArrayInitializerExpression aie = node as ArrayInitializerExpression;
if (aie != null) { if (aie != null) {
if (resolveNestedInitializesToVoid) { if (resolveNestedInitializersToVoid) {
StoreCurrentState(aie); StoreCurrentState(aie);
StoreResult(aie, voidResult); StoreResult(aie, voidResult);
} }
UnpackArrayInitializer(elementList, aie, dimensions - 1, resolveNestedInitializesToVoid); UnpackArrayInitializer(elementList, sizes, aie, dimension + 1, resolveNestedInitializersToVoid);
} else { } else {
elementList.Add(node); elementList.Add(node);
} }
elementCount++;
} }
} else { } else {
foreach (var expr in initializer.Elements) foreach (var expr in initializer.Elements) {
elementList.Add(expr); elementList.Add(expr);
elementCount++;
}
} }
if (sizes[dimension] == 0) // 0 = uninitialized
sizes[dimension] = elementCount;
else if (sizes[dimension] != elementCount)
sizes[dimension] = -1; // -1 = error
} }
ResolveResult IAstVisitor<ResolveResult>.VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression) ResolveResult IAstVisitor<ResolveResult>.VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression)
@ -1556,7 +1583,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
var addRR = memberLookup.Lookup(initializedObject, "Add", EmptyList<IType>.Instance, true); var addRR = memberLookup.Lookup(initializedObject, "Add", EmptyList<IType>.Instance, true);
var mgrr = addRR as MethodGroupResolveResult; var mgrr = addRR as MethodGroupResolveResult;
if (mgrr != null) { if (mgrr != null) {
OverloadResolution or = mgrr.PerformOverloadResolution(resolver.Compilation, addArguments, null, false, false, resolver.CheckForOverflow, resolver.conversions); OverloadResolution or = mgrr.PerformOverloadResolution(resolver.Compilation, addArguments, null, false, false, false, resolver.CheckForOverflow, resolver.conversions);
var invocationRR = or.CreateResolveResult(initializedObject); var invocationRR = or.CreateResolveResult(initializedObject);
StoreResult(aie, invocationRR); StoreResult(aie, invocationRR);
ProcessInvocationResult(null, aie.Elements, invocationRR); ProcessInvocationResult(null, aie.Elements, invocationRR);
@ -2718,7 +2745,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} else { } else {
var getEnumeratorMethodGroup = memberLookup.Lookup(expression, "GetEnumerator", EmptyList<IType>.Instance, true) as MethodGroupResolveResult; var getEnumeratorMethodGroup = memberLookup.Lookup(expression, "GetEnumerator", EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
if (getEnumeratorMethodGroup != null) { if (getEnumeratorMethodGroup != null) {
var or = getEnumeratorMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0]); var or = getEnumeratorMethodGroup.PerformOverloadResolution(
compilation, new ResolveResult[0],
allowExtensionMethods: false, allowExpandingParams: false, allowOptionalParameters: false);
if (or.FoundApplicableCandidate && !or.IsAmbiguous && !or.BestCandidate.IsStatic && or.BestCandidate.IsPublic) { if (or.FoundApplicableCandidate && !or.IsAmbiguous && !or.BestCandidate.IsStatic && or.BestCandidate.IsPublic) {
collectionType = expression.Type; collectionType = expression.Type;
getEnumeratorInvocation = or.CreateResolveResult(expression); getEnumeratorInvocation = or.CreateResolveResult(expression);
@ -2735,7 +2764,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
IMethod moveNextMethod = null; IMethod moveNextMethod = null;
var moveNextMethodGroup = memberLookup.Lookup(new ResolveResult(enumeratorType), "MoveNext", EmptyList<IType>.Instance, false) as MethodGroupResolveResult; var moveNextMethodGroup = memberLookup.Lookup(new ResolveResult(enumeratorType), "MoveNext", EmptyList<IType>.Instance, false) as MethodGroupResolveResult;
if (moveNextMethodGroup != null) { if (moveNextMethodGroup != null) {
var or = moveNextMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0]); var or = moveNextMethodGroup.PerformOverloadResolution(
compilation, new ResolveResult[0],
allowExtensionMethods: false, allowExpandingParams: false, allowOptionalParameters: false);
moveNextMethod = or.GetBestCandidateWithSubstitutedTypeArguments() as IMethod; moveNextMethod = or.GetBestCandidateWithSubstitutedTypeArguments() as IMethod;
} }
@ -3237,7 +3268,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
// Figure out the correct lookup mode: // Figure out the correct lookup mode:
NameLookupMode lookupMode = GetNameLookupMode(simpleType); NameLookupMode lookupMode = simpleType.GetNameLookupMode();
var typeArguments = ResolveTypeArguments(simpleType.TypeArguments); var typeArguments = ResolveTypeArguments(simpleType.TypeArguments);
Identifier identifier = simpleType.IdentifierToken; Identifier identifier = simpleType.IdentifierToken;
@ -3252,23 +3283,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return rr; return rr;
} }
NameLookupMode GetNameLookupMode(AstType type)
{
AstType outermostType = type;
while (outermostType.Parent is AstType)
outermostType = (AstType)outermostType.Parent;
if (outermostType.Parent is UsingDeclaration || outermostType.Parent is UsingAliasDeclaration) {
return NameLookupMode.TypeInUsingDeclaration;
} else if (outermostType.Role == Roles.BaseType) {
// Use BaseTypeReference for a type's base type, and for a constraint on a type.
// Do not use it for a constraint on a method.
if (outermostType.Parent is TypeDeclaration || (outermostType.Parent is Constraint && outermostType.Parent.Parent is TypeDeclaration))
return NameLookupMode.BaseTypeReference;
}
return NameLookupMode.Type;
}
ResolveResult IAstVisitor<ResolveResult>.VisitMemberType(MemberType memberType) ResolveResult IAstVisitor<ResolveResult>.VisitMemberType(MemberType memberType)
{ {
ResolveResult target; ResolveResult target;
@ -3285,7 +3299,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
target = Resolve(memberType.Target); target = Resolve(memberType.Target);
} }
NameLookupMode lookupMode = GetNameLookupMode(memberType); NameLookupMode lookupMode = memberType.GetNameLookupMode();
var typeArguments = ResolveTypeArguments(memberType.TypeArguments); var typeArguments = ResolveTypeArguments(memberType.TypeArguments);
Identifier identifier = memberType.MemberNameToken; Identifier identifier = memberType.MemberNameToken;
ResolveResult rr = resolver.ResolveMemberAccess(target, identifier.Name, typeArguments, lookupMode); ResolveResult rr = resolver.ResolveMemberAccess(target, identifier.Name, typeArguments, lookupMode);

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs

@ -510,7 +510,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
var or = mgrr.PerformOverloadResolution(compilation, var or = mgrr.PerformOverloadResolution(compilation,
args, args,
allowExpandingParams: false); allowExpandingParams: false, allowOptionalParameters: false);
if (or.FoundApplicableCandidate && or.BestCandidateAmbiguousWith == null) { if (or.FoundApplicableCandidate && or.BestCandidateAmbiguousWith == null) {
IType returnType = or.GetBestCandidateWithSubstitutedTypeArguments().ReturnType; IType returnType = or.GetBestCandidateWithSubstitutedTypeArguments().ReturnType;
MakeLowerBoundInference(returnType, m.ReturnType); MakeLowerBoundInference(returnType, m.ReturnType);

4
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs

@ -99,6 +99,10 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
root = new NS(this); root = new NS(this);
Dictionary<string, NS> dict = new Dictionary<string, NS>(compilation.NameComparer); Dictionary<string, NS> dict = new Dictionary<string, NS>(compilation.NameComparer);
dict.Add(string.Empty, root); dict.Add(string.Empty, root);
// Add namespaces declared in C# files, even if they're empty:
foreach (var usingScope in projectContent.Files.OfType<CSharpUnresolvedFile>().SelectMany(f => f.UsingScopes)) {
GetOrAddNamespace(dict, usingScope.NamespaceName);
}
foreach (var pair in GetTypes()) { foreach (var pair in GetTypes()) {
NS ns = GetOrAddNamespace(dict, pair.Key.Namespace); NS ns = GetOrAddNamespace(dict, pair.Key.Namespace);
if (ns.types != null) if (ns.types != null)

5
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/TypeSystem/ConstantValues.cs

@ -480,10 +480,11 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem.ConstantValues
for (int i = 0; i < elements.Length; i++) { for (int i = 0; i < elements.Length; i++) {
elements[i] = arrayElements[i].Resolve(resolver); elements[i] = arrayElements[i].Resolve(resolver);
} }
int[] sizeArguments = { elements.Length };
if (elementType != null) { if (elementType != null) {
return resolver.ResolveArrayCreation(elementType.Resolve(resolver.CurrentTypeResolveContext), 1, null, elements); return resolver.ResolveArrayCreation(elementType.Resolve(resolver.CurrentTypeResolveContext), sizeArguments, elements);
} else { } else {
return resolver.ResolveArrayCreation(null, 1, null, elements); return resolver.ResolveArrayCreation(null, sizeArguments, elements);
} }
} }
} }

15
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CSharpOutputVisitorTests.cs

@ -86,11 +86,11 @@ namespace ICSharpCode.NRefactory.CSharp
public void InlineCommentAtEndOfCondition() public void InlineCommentAtEndOfCondition()
{ {
IfElseStatement condition = new IfElseStatement(); IfElseStatement condition = new IfElseStatement();
condition.AddChild(new CSharpTokenNode(new TextLocation(1, 1)), IfElseStatement.IfKeywordRole); condition.AddChild(new CSharpTokenNode(new TextLocation(1, 1), IfElseStatement.IfKeywordRole), IfElseStatement.IfKeywordRole);
condition.AddChild(new CSharpTokenNode(new TextLocation(1, 4)), Roles.LPar); condition.AddChild(new CSharpTokenNode(new TextLocation(1, 4), Roles.LPar), Roles.LPar);
condition.AddChild(new IdentifierExpression("cond", new TextLocation(1, 5)), IfElseStatement.ConditionRole); condition.AddChild(new IdentifierExpression("cond", new TextLocation(1, 5)), IfElseStatement.ConditionRole);
condition.AddChild(new Comment(CommentType.MultiLine, new TextLocation(1, 9), new TextLocation(1, 14)) { Content = "a" }, Roles.Comment); condition.AddChild(new Comment(CommentType.MultiLine, new TextLocation(1, 9), new TextLocation(1, 14)) { Content = "a" }, Roles.Comment);
condition.AddChild(new CSharpTokenNode(new TextLocation(1, 14)), Roles.RPar); condition.AddChild(new CSharpTokenNode(new TextLocation(1, 14), Roles.RPar), Roles.RPar);
condition.AddChild(new ReturnStatement(), IfElseStatement.TrueRole); condition.AddChild(new ReturnStatement(), IfElseStatement.TrueRole);
AssertOutput("if (cond/*a*/)\n$return;\n", condition); AssertOutput("if (cond/*a*/)\n$return;\n", condition);
@ -138,5 +138,14 @@ namespace ICSharpCode.NRefactory.CSharp
"case 3: {\n$int a = 3;\n$return a;\n}\n" + "case 3: {\n$int a = 3;\n$return a;\n}\n" +
"default:\n$break;\n}\n", type); "default:\n$break;\n}\n", type);
} }
[Test]
public void ZeroLiterals()
{
AssertOutput("0.0", new PrimitiveExpression(0.0));
AssertOutput("-0.0", new PrimitiveExpression(-0.0));
AssertOutput("0f", new PrimitiveExpression(0f));
AssertOutput("-0f", new PrimitiveExpression(-0f));
}
} }
} }

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

@ -0,0 +1,109 @@
using NUnit.Framework;
using ICSharpCode.NRefactory.CSharp.Refactoring;
namespace ICSharpCode.NRefactory.CSharp.CodeActions
{
[TestFixture]
public class SortUsingsTests : ContextActionTestBase
{
[Test]
public void TestActiveWhenCursorAtUsing()
{
Test<SortUsingsAction>(@"using Sys$tem.Linq;
using System;", @"using System;
using System.Linq;");
}
[Test]
public void TestActiveWhenCursorBehindUsing()
{
Test<SortUsingsAction>(@"using System.Linq;$
using System;", @"using System;
using System.Linq;");
}
[Test]
public void TestInActiveWhenCursorOutsideUsings()
{
TestWrongContext<SortUsingsAction>(@"using System.Linq;
using System;
$");
}
[Test]
public void TestSortsAllUsingBlocksInFile()
{
Test<SortUsingsAction>(@"using $System.Linq;
using System;
namespace Foo
{
using System.IO;
using System.Collections;
}
namespace Bar
{
using System.IO;
using System.Runtime;
using System.Diagnostics;
}", @"using System;
using System.Linq;
namespace Foo
{
using System.Collections;
using System.IO;
}
namespace Bar
{
using System.Diagnostics;
using System.IO;
using System.Runtime;
}");
}
[Test]
public void TestAliasesGoesToTheEnd()
{
Test<SortUsingsAction>(@"$using Sys = System;
using System;", @"using System;
using Sys = System;");
}
[Test]
public void TestUnknownNamespacesGoesAfterKnownOnes()
{
Test<SortUsingsAction>(@"$using Foo;
using System;", @"using System;
using Foo;");
}
[Test]
public void TestMixedStuff()
{
Test<SortUsingsAction>(@"$using Foo;
using System.Linq;
using Sys = System;
using System;
using FooAlias = Foo;
using Linq = System.Linq;", @"using System;
using System.Linq;
using Foo;
using Linq = System.Linq;
using Sys = System;
using FooAlias = Foo;");
}
[Test]
public void TestPreservesEmptyLinesWhichIsInFactABug()
{
Test<SortUsingsAction>(@"$using System.Linq;
using System;", @"using System;
using System.Linq;");
}
}
}

178
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs

@ -37,6 +37,8 @@ using ICSharpCode.NRefactory.CSharp.TypeSystem;
using ICSharpCode.NRefactory.Editor; using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using NUnit.Framework; using NUnit.Framework;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.CSharp.Refactoring;
namespace ICSharpCode.NRefactory.CSharp.CodeCompletion namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
{ {
@ -68,6 +70,16 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
class TestFactory class TestFactory
: ICompletionDataFactory : ICompletionDataFactory
{ {
readonly CSharpResolver state;
readonly TypeSystemAstBuilder builder;
public TestFactory(CSharpResolver state)
{
this.state = state;
builder = new TypeSystemAstBuilder(state);
builder.ConvertUnboundTypeArguments = true;
}
class CompletionData class CompletionData
: ICompletionData : ICompletionData
{ {
@ -141,13 +153,23 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
{ {
return new CompletionData (entity.Name); return new CompletionData (entity.Name);
} }
public ICompletionData CreateTypeCompletionData (ICSharpCode.NRefactory.TypeSystem.IType type, string shortType) public ICompletionData CreateTypeCompletionData (ICSharpCode.NRefactory.TypeSystem.IType type, bool fullName, bool isInAttributeContext)
{ {
return new CompletionData (shortType); string name = fullName ? builder.ConvertType(type).GetText() : type.Name;
if (isInAttributeContext && name.EndsWith("Attribute") && name.Length > "Attribute".Length) {
name = name.Substring(0, name.Length - "Attribute".Length);
}
return new CompletionData (name);
} }
public ICompletionData CreateMemberCompletionData(IType type, IEntity member)
{
string name = builder.ConvertType(type).GetText();
return new CompletionData (name + "."+ member.Name);
}
public ICompletionData CreateLiteralCompletionData (string title, string description, string insertText) public ICompletionData CreateLiteralCompletionData (string title, string description, string insertText)
{ {
return new CompletionData (title); return new CompletionData (title);
@ -196,12 +218,27 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
#endregion #endregion
} }
public static IUnresolvedAssembly SystemAssembly { get { return systemAssembly.Value; } }
static readonly Lazy<IUnresolvedAssembly> systemAssembly = new Lazy<IUnresolvedAssembly>( static readonly Lazy<IUnresolvedAssembly> systemAssembly = new Lazy<IUnresolvedAssembly>(
delegate { delegate {
return new CecilLoader().LoadAssemblyFile(typeof(System.ComponentModel.BrowsableAttribute).Assembly.Location); var loader = new CecilLoader();
loader.IncludeInternalMembers = true;
return loader.LoadAssemblyFile(typeof(System.ComponentModel.BrowsableAttribute).Assembly.Location);
}); });
static readonly Lazy<IUnresolvedAssembly> mscorlib = new Lazy<IUnresolvedAssembly>(
delegate {
var loader = new CecilLoader();
loader.IncludeInternalMembers = true;
return loader.LoadAssemblyFile(typeof(object).Assembly.Location);
});
static readonly Lazy<IUnresolvedAssembly> systemCore = new Lazy<IUnresolvedAssembly>(
delegate {
var loader = new CecilLoader();
loader.IncludeInternalMembers = true;
return loader.LoadAssemblyFile(typeof(System.Linq.Enumerable).Assembly.Location);
});
public static CSharpCompletionEngine CreateEngine(string text, out int cursorPosition, params IUnresolvedAssembly[] references) public static CSharpCompletionEngine CreateEngine(string text, out int cursorPosition, params IUnresolvedAssembly[] references)
{ {
string parsedText; string parsedText;
@ -222,7 +259,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
var doc = new ReadOnlyDocument(editorText); var doc = new ReadOnlyDocument(editorText);
IProjectContent pctx = new CSharpProjectContent(); IProjectContent pctx = new CSharpProjectContent();
var refs = new List<IUnresolvedAssembly> { CecilLoaderTests.Mscorlib, CecilLoaderTests.SystemCore, SystemAssembly }; var refs = new List<IUnresolvedAssembly> { mscorlib.Value, systemCore.Value, systemAssembly.Value };
if (references != null) if (references != null)
refs.AddRange (references); refs.AddRange (references);
@ -251,7 +288,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
} }
var mb = new DefaultCompletionContextProvider(doc, unresolvedFile); var mb = new DefaultCompletionContextProvider(doc, unresolvedFile);
mb.AddSymbol ("TEST"); mb.AddSymbol ("TEST");
var engine = new CSharpCompletionEngine(doc, mb, new TestFactory(), pctx, rctx); var engine = new CSharpCompletionEngine(doc, mb, new TestFactory(new CSharpResolver (rctx)), pctx, rctx);
engine.EolMarker = Environment.NewLine; engine.EolMarker = Environment.NewLine;
engine.FormattingPolicy = FormattingOptionsFactory.CreateMono(); engine.FormattingPolicy = FormattingOptionsFactory.CreateMono();
@ -283,7 +320,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
var cmp = pctx.CreateCompilation(); var cmp = pctx.CreateCompilation();
var mb = new DefaultCompletionContextProvider(doc, unresolvedFile); var mb = new DefaultCompletionContextProvider(doc, unresolvedFile);
var engine = new CSharpCompletionEngine (doc, mb, new TestFactory (), pctx, new CSharpTypeResolveContext (cmp.MainAssembly)); var engine = new CSharpCompletionEngine (doc, mb, new TestFactory (new CSharpResolver (new CSharpTypeResolveContext (cmp.MainAssembly))), pctx, new CSharpTypeResolveContext (cmp.MainAssembly));
engine.EolMarker = Environment.NewLine; engine.EolMarker = Environment.NewLine;
engine.FormattingPolicy = FormattingOptionsFactory.CreateMono (); engine.FormattingPolicy = FormattingOptionsFactory.CreateMono ();
return Tuple.Create (doc, engine); return Tuple.Create (doc, engine);
@ -5182,7 +5219,7 @@ class Foo
}); });
} }
[Test()] [Test, Ignore("broken")]
public void TestCatchContextFollowUp() public void TestCatchContextFollowUp()
{ {
CombinedProviderTest( CombinedProviderTest(
@ -5476,5 +5513,126 @@ public class FooBar
Assert.IsNull(provider.Find("using")); Assert.IsNull(provider.Find("using"));
}); });
} }
/// <summary>
/// Bug 7207 - Missing inherited enum in completion
/// </summary>
[Test()]
public void TestBug7207()
{
CombinedProviderTest(
@"using System;
class A
{
protected enum MyEnum
{
A
}
class Hidden {}
}
class C : A
{
class NotHidden {}
public static void Main ()
{
$var a2 = M$
}
}
", provider => {
Assert.IsNotNull(provider.Find("MyEnum"));
Assert.IsNotNull(provider.Find("NotHidden"));
Assert.IsNull(provider.Find("Hidden"));
});
}
/// <summary>
/// Bug 7191 - code completion problem with generic interface using nested type
/// </summary>
[Test()]
public void TestBug7191()
{
CombinedProviderTest(
@"using System.Collections.Generic;
namespace bug
{
public class Outer
{
public class Nested
{
}
}
public class TestClass
{
void Bar()
{
$IList<Outer.Nested> foo = new $
}
}
}
", provider => {
Assert.IsNotNull(provider.Find("List<Outer.Nested>"));
});
}
/// <summary>
/// Bug 6849 - Regression: Inaccesible types in completion
/// </summary>
[Test()]
public void TestBug6849()
{
CombinedProviderTest(
@"
namespace bug
{
public class TestClass
{
void Bar()
{
$new System.Collections.Generic.$
}
}
}
", provider => {
// it's likely to be mono specific.
Assert.IsNull(provider.Find("RBTree"));
Assert.IsNull(provider.Find("GenericComparer"));
Assert.IsNull(provider.Find("InternalStringComparer"));
});
}
[Test()]
public void TestBug6849Case2()
{
CombinedProviderTest(
@"
namespace bug
{
public class TestClass
{
void Bar()
{
$System.Collections.Generic.$
}
}
}
", provider => {
// it's likely to be mono specific.
Assert.IsNull(provider.Find("RBTree"));
Assert.IsNull(provider.Find("GenericComparer"));
Assert.IsNull(provider.Find("InternalStringComparer"));
});
}
} }
} }

18
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/KeywordTests.cs

@ -145,11 +145,27 @@ class Test
public void GetSetKeywordTest () public void GetSetKeywordTest ()
{ {
CodeCompletionBugTests.CombinedProviderTest ( CodeCompletionBugTests.CombinedProviderTest (
@"class Test @"class Test
{ {
public int MyProperty { public int MyProperty {
$g$ $g$
} }
", provider => {
Assert.IsNotNull (provider.Find ("public"), "keyword 'public' not found.");
Assert.IsNotNull (provider.Find ("get"), "keyword 'get' not found.");
Assert.IsNotNull (provider.Find ("set"), "keyword 'set' not found.");
});
}
[Test()]
public void GetSetKeywordIndexerCaseTest ()
{
CodeCompletionBugTests.CombinedProviderTest (
@"class Test
{
public int this[int i] {
$g$
}
", provider => { ", provider => {
Assert.IsNotNull (provider.Find ("public"), "keyword 'public' not found."); Assert.IsNotNull (provider.Find ("public"), "keyword 'public' not found.");
Assert.IsNotNull (provider.Find ("get"), "keyword 'get' not found."); Assert.IsNotNull (provider.Find ("get"), "keyword 'get' not found.");

3
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/NameContextTests.cs

@ -44,7 +44,6 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
Assert.IsTrue (provider == null || provider.Count == 0, "provider should be empty."); Assert.IsTrue (provider == null || provider.Count == 0, "provider should be empty.");
} }
[Ignore("Parser bug.")]
[Test()] [Test()]
public void TestNamespaceNameCase3 () public void TestNamespaceNameCase3 ()
{ {
@ -187,7 +186,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
Assert.AreEqual (0, provider.Count, "provider needs to be empty"); Assert.AreEqual (0, provider.Count, "provider needs to be empty");
}); });
} }
[Ignore("TODO")]
[Test()] [Test()]
public void TestIndexerParameterName () public void TestIndexerParameterName ()
{ {

58
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ObjectInitializerTests.cs

@ -587,6 +587,64 @@ class MyTest
); );
} }
/// <summary>
/// Bug 7383 - Object initializer completion inaccessible
/// </summary>
[Test()]
public void TestBug7383()
{
var provider = CodeCompletionBugTests.CreateCtrlSpaceProvider(
@"using System.Runtime.InteropServices;
class S
{
public int Foo { get; protected set; }
public int Bar { get; set; }
}
class C
{
public static void Main ()
{
var s = new S () {
$Fo$
};
}
}
");
Assert.IsNull(provider.Find("Foo"), "'Foo' found.");
Assert.IsNotNull(provider.Find("Bar"), "'Bar' not found.");
}
[Test()]
public void TestBug7383Case2()
{
var provider = CodeCompletionBugTests.CreateCtrlSpaceProvider(
@"using System.Runtime.InteropServices;
class S
{
public int Foo { get; protected set; }
public int Bar { get; set; }
}
class C : S
{
public static void Main ()
{
var s = new C () {
$Fo$
};
}
}
");
Assert.IsNotNull(provider.Find("Foo"), "'Foo' found.");
Assert.IsNotNull(provider.Find("Bar"), "'Bar' not found.");
}
} }
} }

53
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs

@ -985,5 +985,58 @@ public class B
Assert.IsNotNull (provider, "provider was not created."); Assert.IsNotNull (provider, "provider was not created.");
Assert.AreEqual (1, provider.Count); Assert.AreEqual (1, provider.Count);
} }
[Test()]
public void TestLambdaCase()
{
IParameterDataProvider provider = CreateProvider(
@"using System;
class TestClass
{
void F (Action i, int foo)
{
$F (()=> Something(),$
}
}
");
Assert.IsTrue (provider != null && provider.Count == 1);
}
[Test()]
public void TestJaggedArrayCreation()
{
IParameterDataProvider provider = CreateProvider(
@"using System;
class TestClass
{
void F (Action i, int foo)
{
$new foo[1,2][$
}
}
");
Assert.IsTrue (provider == null || provider.Count == 0);
}
[Test()]
public void TestJaggedArrayCreationCase2()
{
IParameterDataProvider provider = CreateProvider(
@"using System;
class TestClass
{
void F (Action i, int foo)
{
$new foo[1,2][1,$
}
}
");
Assert.IsTrue (provider == null || provider.Count == 0);
}
} }
} }

10
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/RedundantNamespaceUsageInspectorTests.cs

@ -81,5 +81,15 @@ class Foo
} }
}"); }");
} }
[Test]
public void UsingAlias()
{
var input = @"using IEnumerable = System.Collections.IEnumerable;";
TestRefactoringContext context;
var issues = GetIssues (new RedundantNamespaceUsageIssue (), input, out context);
Assert.AreEqual (0, issues.Count);
}
} }
} }

1
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PrimitiveExpressionTests.cs

@ -244,7 +244,6 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression
Assert.AreEqual(code, pe.LiteralValue); Assert.AreEqual(code, pe.LiteralValue);
} }
[Ignore("Waiting for upstream fix.")]
[Test] [Test]
public void LargeVerbatimString() public void LargeVerbatimString()
{ {

29
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs

@ -36,6 +36,16 @@ namespace ICSharpCode.NRefactory.CSharp.Parser
{ {
compilation = ParseTestCase().CreateCompilation(); compilation = ParseTestCase().CreateCompilation();
} }
static IProjectContent CreateContent (IUnresolvedFile unresolvedFile)
{
return new CSharpProjectContent()
.AddOrUpdateFiles(unresolvedFile)
.AddAssemblyReferences(new[] {
CecilLoaderTests.Mscorlib
})
.SetAssemblyName(typeof(TypeSystemTests).Assembly.GetName().Name);
}
internal static IProjectContent ParseTestCase() internal static IProjectContent ParseTestCase()
{ {
@ -47,11 +57,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser
syntaxTree = parser.Parse(s, fileName); syntaxTree = parser.Parse(s, fileName);
} }
var unresolvedFile = syntaxTree.ToTypeSystem(); return CreateContent(syntaxTree.ToTypeSystem());
return new CSharpProjectContent()
.AddOrUpdateFiles(unresolvedFile)
.AddAssemblyReferences(new[] { CecilLoaderTests.Mscorlib })
.SetAssemblyName(typeof(TypeSystemTests).Assembly.GetName().Name);
} }
[Test] [Test]
@ -80,6 +86,19 @@ namespace ICSharpCode.NRefactory.CSharp.Parser
var method = t.GetMethods(m => m.Name == "PartialMethodWithoutImplementation").Single(); var method = t.GetMethods(m => m.Name == "PartialMethodWithoutImplementation").Single();
Assert.AreEqual(1, method.Parts.Count); Assert.AreEqual(1, method.Parts.Count);
} }
[Test]
public void CyclicConstants()
{
var syntaxTree = SyntaxTree.Parse ("class Test { const int foo = foo; }");
syntaxTree.FileName = "a.cs";
var content = CreateContent (syntaxTree.ToTypeSystem());
var testType = content.CreateCompilation ().MainAssembly.GetTypeDefinition ("", "Test");
Assert.NotNull (testType);
var field = testType.Fields.First ();
Assert.IsTrue (field.IsConst);
Assert.IsNull (field.ConstantValue);
}
} }
[TestFixture] [TestFixture]

90
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Refactoring/TypeSystemAstBuilderTests.cs

@ -32,13 +32,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
[TestFixture] [TestFixture]
public class TypeSystemAstBuilderTests public class TypeSystemAstBuilderTests
{ {
const string program = @" const string mainProgram = @"
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using OtherNS; using OtherNS;
class Base<T> { class Base<T> {
public class Nested<X> { } public class Nested<X> { }
public class Sibling { }
} }
class Derived<T, S> : Base<S> { } class Derived<T, S> : Base<S> { }
@ -55,11 +56,22 @@ namespace OtherNS {
IProjectContent pc; IProjectContent pc;
ICompilation compilation; ICompilation compilation;
ITypeDefinition baseClass, derivedClass, nestedClass, systemClass; ITypeDefinition baseClass, derivedClass, nestedClass, siblingClass, systemClass;
CSharpUnresolvedFile unresolvedFile; CSharpUnresolvedFile unresolvedFile;
[SetUp] [SetUp]
public void SetUp() public void SetUp()
{
Init(mainProgram);
baseClass = compilation.RootNamespace.GetTypeDefinition("Base", 1);
nestedClass = baseClass.NestedTypes.Single(t => t.Name == "Nested");
siblingClass = baseClass.NestedTypes.Single(t => t.Name == "Sibling");
derivedClass = compilation.RootNamespace.GetTypeDefinition("Derived", 2);
systemClass = compilation.RootNamespace.GetChildNamespace("NS").GetTypeDefinition("System", 0);
}
void Init(string program)
{ {
pc = new CSharpProjectContent(); pc = new CSharpProjectContent();
pc = pc.SetAssemblyName("MyAssembly"); pc = pc.SetAssemblyName("MyAssembly");
@ -68,11 +80,6 @@ namespace OtherNS {
pc = pc.AddAssemblyReferences(new [] { CecilLoaderTests.Mscorlib }); pc = pc.AddAssemblyReferences(new [] { CecilLoaderTests.Mscorlib });
compilation = pc.CreateCompilation(); compilation = pc.CreateCompilation();
baseClass = compilation.RootNamespace.GetTypeDefinition("Base", 1);
nestedClass = baseClass.NestedTypes.Single();
derivedClass = compilation.RootNamespace.GetTypeDefinition("Derived", 2);
systemClass = compilation.RootNamespace.GetChildNamespace("NS").GetTypeDefinition("System", 0);
} }
TypeSystemAstBuilder CreateBuilder(ITypeDefinition currentTypeDef = null) TypeSystemAstBuilder CreateBuilder(ITypeDefinition currentTypeDef = null)
@ -92,20 +99,10 @@ namespace OtherNS {
} }
[Test] [Test]
public void PrimitiveVoid() public void PrimitiveTypeNames()
{ {
Assert.AreEqual("void", TypeToString(compilation.FindType(KnownTypeCode.Void))); Assert.AreEqual("void", TypeToString(compilation.FindType(KnownTypeCode.Void)));
}
[Test]
public void PrimitiveInt()
{
Assert.AreEqual("int", TypeToString(compilation.FindType(KnownTypeCode.Int32))); Assert.AreEqual("int", TypeToString(compilation.FindType(KnownTypeCode.Int32)));
}
[Test]
public void PrimitiveDecimal()
{
Assert.AreEqual("decimal", TypeToString(compilation.FindType(KnownTypeCode.Decimal))); Assert.AreEqual("decimal", TypeToString(compilation.FindType(KnownTypeCode.Decimal)));
} }
@ -150,19 +147,26 @@ namespace OtherNS {
Assert.AreEqual("L", TypeToString(type, systemClass)); Assert.AreEqual("L", TypeToString(type, systemClass));
} }
[Test]
public void AliasedTypeWrongTypeArgument()
{
var type = new ParameterizedType(compilation.FindType(typeof(List<>)).GetDefinition(), new[] { compilation.FindType(KnownTypeCode.Int32) });
Assert.AreEqual("List<int>", TypeToString(type, systemClass));
}
[Test] [Test]
public void UnboundType() public void UnboundType()
{ {
Assert.AreEqual("Base<>", TypeToString(baseClass)); Assert.AreEqual("Base<>", TypeToString(baseClass));
Assert.AreEqual("Base<>.Nested<>", TypeToString(nestedClass)); Assert.AreEqual("Base<>.Nested<>", TypeToString(nestedClass));
} }
[Test] [Test]
public void UnboundTypeConvertUnboundTypeArgumentsOption() public void UnboundTypeConvertUnboundTypeArgumentsOption()
{ {
Assert.AreEqual("Base<T>", TypeToString(baseClass, null, builder => builder.ConvertUnboundTypeArguments = true)); Assert.AreEqual("Base<T>", TypeToString(baseClass, null, builder => builder.ConvertUnboundTypeArguments = true));
Assert.AreEqual("Base<T>.Nested<X>", TypeToString(nestedClass, null, builder => builder.ConvertUnboundTypeArguments = true)); Assert.AreEqual("Base<T>.Nested<X>", TypeToString(nestedClass, null, builder => builder.ConvertUnboundTypeArguments = true));
} }
[Test] [Test]
public void NestedType() public void NestedType()
@ -195,6 +199,20 @@ namespace OtherNS {
Assert.AreEqual("Nested<string>", TypeToString(type2, derivedClass)); Assert.AreEqual("Nested<string>", TypeToString(type2, derivedClass));
} }
[Test]
public void SiblingClass()
{
var type = new ParameterizedType(siblingClass, new[] { baseClass.TypeParameters[0] });
Assert.AreEqual("Sibling", TypeToString(type, nestedClass));
}
[Test]
public void GenericClass()
{
var type = new ParameterizedType(nestedClass, new[] { baseClass.TypeParameters[0], compilation.FindType(KnownTypeCode.String) });
Assert.AreEqual("Nested<string>", TypeToString(type, siblingClass));
}
[Test] [Test]
public void MultidimensionalArray() public void MultidimensionalArray()
{ {
@ -219,5 +237,37 @@ namespace OtherNS {
Assert.AreEqual("System.Array", TypeToString(compilation.FindType(typeof(Array)))); Assert.AreEqual("System.Array", TypeToString(compilation.FindType(typeof(Array))));
Assert.AreEqual("OtherNS.Array", TypeToString(compilation.MainAssembly.GetTypeDefinition(new TopLevelTypeName("OtherNS", "Array")))); Assert.AreEqual("OtherNS.Array", TypeToString(compilation.MainAssembly.GetTypeDefinition(new TopLevelTypeName("OtherNS", "Array"))));
} }
[Test]
public void NestedFooCollidingWithProperty_SameType()
{
string program = @"class MainClass {
public enum Foo { Value1, Value2 }
public class Test {
Foo Foo { get; set; }
}
}";
Init(program);
var foo = compilation.MainAssembly.GetTypeDefinition(new FullTypeName("MainClass+Foo"));
var test = compilation.MainAssembly.GetTypeDefinition(new FullTypeName("MainClass+Test"));
Assert.AreEqual("Foo", TypeToString(foo, test));
}
[Test]
public void NestedFooCollidingWithProperty_DifferentType()
{
string program = @"class MainClass {
public enum Foo { Value1, Value2 }
public class Test {
int Foo { get; set; }
}
}";
Init(program);
var foo = compilation.MainAssembly.GetTypeDefinition(new FullTypeName("MainClass+Foo"));
var test = compilation.MainAssembly.GetTypeDefinition(new FullTypeName("MainClass+Test"));
Assert.AreEqual("MainClass.Foo", TypeToString(foo, test));
}
} }
} }

100
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ArrayCreateTests.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using NUnit.Framework; using NUnit.Framework;
@ -111,5 +112,104 @@ class A {
var result = Resolve(program); var result = Resolve(program);
Assert.AreEqual("System.Int32[,]", result.Type.ReflectionName); Assert.AreEqual("System.Int32[,]", result.Type.ReflectionName);
} }
[Test]
public void SizeArguments2x3()
{
string program = @"using System.Collections.Generic;
class A {
int[,] a = ${ { 1, 2, 3 }, { 4, 5, 6 } }$;
}
";
var result = Resolve<ArrayCreateResolveResult>(program);
Assert.AreEqual(6, result.InitializerElements.Count);
Assert.AreEqual(2, result.SizeArguments.Count);
Assert.AreEqual(2, result.SizeArguments[0].ConstantValue);
Assert.AreEqual(3, result.SizeArguments[1].ConstantValue);
}
[Test]
public void SizeArguments3x2()
{
string program = @"using System.Collections.Generic;
class A {
int[,] a = $new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 } }$;
}
";
var result = Resolve<ArrayCreateResolveResult>(program);
Assert.AreEqual("System.Int32[,]", result.Type.ReflectionName);
Assert.AreEqual(6, result.InitializerElements.Count);
Assert.AreEqual(2, result.SizeArguments.Count);
Assert.AreEqual(3, result.SizeArguments[0].ConstantValue);
Assert.AreEqual(2, result.SizeArguments[1].ConstantValue);
}
[Test]
public void SizeArguments2xInvalid()
{
string program = @"using System.Collections.Generic;
class A {
int[,] a = ${ { 1, 2, 3 }, { 4, 5 } }$;
}
";
var result = Resolve<ArrayCreateResolveResult>(program);
Assert.AreEqual("System.Int32[,]", result.Type.ReflectionName);
Assert.AreEqual(5, result.InitializerElements.Count);
Assert.AreEqual(2, result.SizeArguments.Count);
Assert.AreEqual(2, result.SizeArguments[0].ConstantValue);
Assert.IsTrue(result.SizeArguments[1].IsError);
}
[Test]
public void SizeArgumentsExplicitSizeInconsistentWithActualSize()
{
string program = @"using System.Collections.Generic;
class A {
int[,] a = $new int[5,6] { { 1, 2, 3 }, { 4, 5, 6 } }$;
}
";
var result = Resolve<ArrayCreateResolveResult>(program);
Assert.AreEqual("System.Int32[,]", result.Type.ReflectionName);
Assert.AreEqual(6, result.InitializerElements.Count);
Assert.AreEqual(2, result.SizeArguments.Count);
Assert.AreEqual(5, result.SizeArguments[0].ConstantValue);
Assert.AreEqual(6, result.SizeArguments[1].ConstantValue);
}
[Test]
public void ArraySizeArgumentConversion()
{
string program = @"using System.Collections.Generic;
class A {
static byte b = 5;
int[] a = new int[$b$];
}
";
Assert.AreEqual(Conversion.ImplicitNumericConversion, GetConversion(program));
}
[Test]
public void ArrayInitializerConversion()
{
string program = @"using System.Collections.Generic;
class A {
static byte b = 5;
int[] a = new int[] { $b$ };
}
";
Assert.AreEqual(Conversion.ImplicitNumericConversion, GetConversion(program));
}
[Test]
public void ArrayInitializerConversion2()
{
string program = @"using System.Collections.Generic;
class A {
static byte b = 5;
int[] a = { $b$ };
}
";
Assert.AreEqual(Conversion.ImplicitNumericConversion, GetConversion(program));
}
} }
} }

14
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ComTests.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Linq;
using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using NUnit.Framework; using NUnit.Framework;
@ -47,5 +48,18 @@ public class Test : Dummy {
Assert.AreEqual("Dummy", rr.Type.ReflectionName); Assert.AreEqual("Dummy", rr.Type.ReflectionName);
Assert.AreEqual(1, rr.Member.Parameters.Count); Assert.AreEqual(1, rr.Member.Parameters.Count);
} }
[Test]
public void CyclicCoClass()
{
string program = @"using System;
using System.Runtime.InteropServices;
[ComImport, Guid(""698D8281-3890-41A6-8A2F-DBC29CBAB8BC""), CoClass(typeof(Dummy))]
public interface $Dummy { }";
var trr = ResolveAtLocation<TypeResolveResult>(program);
Assert.AreEqual(0, trr.Type.GetConstructors().Count());
}
} }
} }

229
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs

@ -19,6 +19,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.CSharp.TypeSystem; using ICSharpCode.NRefactory.CSharp.TypeSystem;
using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
@ -602,5 +603,233 @@ class Test {
Assert.AreEqual(C.ImplicitReferenceConversion, GetConversion(program)); Assert.AreEqual(C.ImplicitReferenceConversion, GetConversion(program));
} }
[Test]
public void MethodGroupConversion_Void()
{
string program = @"using System;
delegate void D();
class Test {
D d = $M$;
public static void M() {}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsMethodGroupConversion);
Assert.IsNotNull(c.Method);
}
[Test]
public void MethodGroupConversion_MatchingSignature()
{
string program = @"using System;
delegate object D(int argument);
class Test {
D d = $M$;
public static object M(int argument) {}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsMethodGroupConversion);
}
[Test]
public void MethodGroupConversion_InvalidReturnType()
{
string program = @"using System;
delegate object D(int argument);
class Test {
D d = $M$;
public static int M(int argument) {}
}";
var c = GetConversion(program);
Assert.IsFalse(c.IsValid);
Assert.IsTrue(c.IsMethodGroupConversion);
}
[Test]
public void MethodGroupConversion_CovariantReturnType()
{
string program = @"using System;
delegate object D(int argument);
class Test {
D d = $M$;
public static string M(int argument) {}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsMethodGroupConversion);
}
[Test]
public void MethodGroupConversion_RefArgumentTypesEqual()
{
string program = @"using System;
delegate void D(ref object o);
class Test {
D d = $M$;
public static void M(ref object o) {}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsMethodGroupConversion);
}
[Test]
public void MethodGroupConversion_RefArgumentObjectVsDynamic()
{
string program = @"using System;
delegate void D(ref object o);
class Test {
D d = $M$;
public static void M(ref dynamic o) {}
}";
var c = GetConversion(program);
Assert.IsFalse(c.IsValid);
Assert.IsTrue(c.IsMethodGroupConversion);
}
[Test]
public void MethodGroupConversion_RefVsOut()
{
string program = @"using System;
delegate void D(ref object o);
class Test {
D d = $M$;
public static void M(out object o) {}
}";
var c = GetConversion(program);
Assert.IsFalse(c.IsValid);
}
[Test]
public void MethodGroupConversion_RefVsNormal()
{
string program = @"using System;
delegate void D(ref object o);
class Test {
D d = $M$;
public static void M(object o) {}
}";
var c = GetConversion(program);
Assert.IsFalse(c.IsValid);
}
[Test]
public void MethodGroupConversion_NormalVsOut()
{
string program = @"using System;
delegate void D(object o);
class Test {
D d = $M$;
public static void M(out object o) {}
}";
var c = GetConversion(program);
Assert.IsFalse(c.IsValid);
}
[Test]
public void MethodGroupConversion_MatchingNormalParameter()
{
string program = @"using System;
delegate void D(object o);
class Test {
D d = $M$;
public static void M(object o) {}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsMethodGroupConversion);
}
[Test]
public void MethodGroupConversion_IdentityConversion()
{
string program = @"using System;
delegate void D(object o);
class Test {
D d = $M$;
public static void M(dynamic o) {}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsMethodGroupConversion);
}
[Test]
public void MethodGroupConversion_Contravariance()
{
string program = @"using System;
delegate void D(string o);
class Test {
D d = $M$;
public static void M(object o) {}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsMethodGroupConversion);
}
[Test, Ignore("Not sure if this conversion should be valid or not... NR and mcs both accept it as valid, csc treats it as invalid")]
public void MethodGroupConversion_NoContravarianceDynamic()
{
string program = @"using System;
delegate void D(string o);
class Test {
D d = $M$;
public static void M(dynamic o) {}
}";
var c = GetConversion(program);
//Assert.IsFrue(c.IsValid);
Assert.IsTrue(c.IsMethodGroupConversion);
}
[Test]
public void MethodGroupConversion_ExactMatchIsBetter()
{
string program = @"using System;
class Test {
delegate void D(string a);
D d = $M$;
static void M(object x) {}
static void M(string x = null) {}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsMethodGroupConversion);
Assert.AreEqual("System.String", c.Method.Parameters.Single().Type.FullName);
}
[Test]
public void MethodGroupConversion_CannotLeaveOutOptionalParameters()
{
string program = @"using System;
class Test {
delegate void D(string a);
D d = $M$;
static void M(object x) {}
static void M(string x, string y = null) {}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsMethodGroupConversion);
Assert.AreEqual("System.Object", c.Method.Parameters.Single().Type.FullName);
}
[Test]
public void MethodGroupConversion_CannotUseExpandedParams()
{
string program = @"using System;
class Test {
delegate void D(string a);
D d = $M$;
static void M(object x) {}
static void M(params string[] x) {}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsMethodGroupConversion);
Assert.AreEqual("System.Object", c.Method.Parameters.Single().Type.FullName);
}
} }
} }

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

@ -211,5 +211,63 @@ class Calls {
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 9 && r is InvocationExpression)); Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 9 && r is InvocationExpression));
} }
#endregion #endregion
#region Await
const string awaitTest = @"using System;
class MyAwaiter {
public bool IsCompleted { get { return false; } }
public void OnCompleted(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;
}
}";
[Test]
public void GetAwaiterReferenceInAwaitExpressionIsFound() {
Init(awaitTest);
var test = compilation.MainAssembly.TopLevelTypeDefinitions.Single(t => t.Name == "MyAwaitable");
var method = test.Methods.Single(m => m.Name == "GetAwaiter");
var actual = FindReferences(method).ToList();
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 8 && r is MethodDeclaration));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 13 && r is UnaryOperatorExpression));
}
[Test]
public void GetResultReferenceInAwaitExpressionIsFound() {
Init(awaitTest);
var test = compilation.MainAssembly.TopLevelTypeDefinitions.Single(t => t.Name == "MyAwaiter");
var method = test.Methods.Single(m => m.Name == "GetResult");
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 == 13 && r is UnaryOperatorExpression));
}
[Test]
public void OnCompletedReferenceInAwaitExpressionIsFound() {
Init(awaitTest);
var test = compilation.MainAssembly.TopLevelTypeDefinitions.Single(t => t.Name == "MyAwaiter");
var method = test.Methods.Single(m => m.Name == "OnCompleted");
var actual = FindReferences(method).ToList();
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 4 && r is MethodDeclaration));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 13 && r is UnaryOperatorExpression));
}
[Test]
public void IsCompletedReferenceInAwaitExpressionIsFound() {
Init(awaitTest);
var test = compilation.MainAssembly.TopLevelTypeDefinitions.Single(t => t.Name == "MyAwaiter");
var property = test.Properties.Single(m => m.Name == "IsCompleted");
var actual = FindReferences(property).ToList();
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 3 && r is PropertyDeclaration));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 13 && r is UnaryOperatorExpression));
}
#endregion
} }
} }

18
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/MethodTests.cs

@ -22,7 +22,7 @@ using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using NUnit.Framework; using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Resolver namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
[TestFixture] [TestFixture]
public class MethodTests : ResolverTestBase public class MethodTests : ResolverTestBase
@ -225,5 +225,21 @@ class TestClass {
Assert.IsTrue(ReferenceEquals(value1, value2)); Assert.IsTrue(ReferenceEquals(value1, value2));
} }
[Test]
public void MethodWithInvalidCastInDefaultValue()
{
var input = @"
class TestClass
{
void TestMethod ($int x = true$)
{
}
}";
var rr = Resolve<LocalResolveResult>(input);
IParameter p = (IParameter)rr.Variable;
Assert.IsTrue(p.IsOptional);
Assert.IsNull(p.ConstantValue);
}
} }
} }

28
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs

@ -1065,5 +1065,33 @@ namespace foo {
var method = a.Methods.Single(m => m.Name == "M"); var method = a.Methods.Single(m => m.Name == "M");
Assert.AreEqual("A.B", method.TypeParameters.Single().DirectBaseTypes.Single().FullName); Assert.AreEqual("A.B", method.TypeParameters.Single().DirectBaseTypes.Single().FullName);
} }
[Test]
public void EmptyNamespaces()
{
// should maybe a typesystem test - but empty namespaces don't make sense in cecil.
string program = @"namespace A.B.C.D
{
}
namespace Test
{
using $A.B.C.D$;
public class C
{
public static void Main ()
{
}
}
}
";
var nrr = Resolve<NamespaceResolveResult>(program);
Assert.AreEqual("A.B.C.D", nrr.NamespaceName);
}
} }
} }

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

@ -274,5 +274,371 @@ class Test {
Assert.IsFalse(rr.IsError); Assert.IsFalse(rr.IsError);
Assert.AreEqual(unchecked( (ushort)~3 ), rr.ConstantValue); Assert.AreEqual(unchecked( (ushort)~3 ), rr.ConstantValue);
} }
[Test]
public void Await() {
string program = @"
using System;
class MyAwaiter {
public bool IsCompleted { get { return false; } }
public void OnCompleted(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.OnCompleted", 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 {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
}
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.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(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.IsNotNull(rr.GetResultMethod);
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")]
public void GetAwaiterMethodWithDefaultArgumentCannotBeUsed() {
string program = @"
using System;
class MyAwaiter {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
public MyAwaiter GetAwaiter(int i = 0) { 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.AreEqual(SpecialType.UnknownType, rr.Type);
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
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")]
public void GetAwaiterMethodWithDefaultArgumentHidesExtensionMethodAndResultsInError() {
string program = @"
using System;
namespace N {
class MyAwaiter {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
public MyAwaiter GetAwaiter(int i = 0) { 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.IsFalse(rr.IsError);
Assert.AreEqual(SpecialType.UnknownType, rr.Type);
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
Assert.IsTrue(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(rr.AwaiterType, SpecialType.UnknownType);
Assert.IsNull(rr.IsCompletedProperty);
Assert.IsNull(rr.OnCompletedMethod);
Assert.IsNull(rr.GetResultMethod);
}
[Test]
public void GetAwaiterMethodWithArgumentDoesNotHideExtensionMethod() {
string program = @"
using System;
namespace N {
class MyAwaiter {
public bool 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.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(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.IsNotNull(rr.GetResultMethod);
Assert.AreEqual("N.MyAwaiter.GetResult", rr.GetResultMethod.FullName);
}
[Test]
public void AwaiterWithNoSuitableGetResult() {
string program = @"
using System;
namespace N {
class MyAwaiter {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult(int i) { 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 {
public bool IsCompleted() { return false; }
public void OnCompleted(Action continuation) {}
public int GetResult(int i) { 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.IsNull(rr.IsCompletedProperty);
Assert.IsNotNull(rr.OnCompletedMethod);
Assert.AreEqual("N.MyAwaiter.OnCompleted", rr.OnCompletedMethod.FullName);
Assert.IsNull(rr.GetResultMethod);
}
[Test]
public void AwaiterWithNoOnCompletedMethodWithSuitableSignature() {
string program = @"
using System;
class MyAwaiter {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Func<int> 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.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(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.IsNull(rr.OnCompletedMethod);
Assert.IsNotNull(rr.GetResultMethod);
Assert.AreEqual("MyAwaiter.GetResult", rr.GetResultMethod.FullName);
}
[Test]
public void AwaitDynamic() {
string program = @"
public class C {
public async void M() {
dynamic x = null;
int i = $await x$;
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.AreEqual(SpecialType.Dynamic, rr.Type);
Assert.IsInstanceOf<DynamicInvocationResolveResult>(rr.GetAwaiterInvocation);
var getAwaiterInvocation = (DynamicInvocationResolveResult)rr.GetAwaiterInvocation;
Assert.IsFalse(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(DynamicInvocationType.Invocation, getAwaiterInvocation.InvocationType);
Assert.AreEqual(0, getAwaiterInvocation.Arguments.Count);
Assert.IsInstanceOf<DynamicMemberResolveResult>(getAwaiterInvocation.Target);
var target = (DynamicMemberResolveResult)getAwaiterInvocation.Target;
Assert.IsInstanceOf<LocalResolveResult>(target.Target);
Assert.AreEqual("GetAwaiter", target.Member);
Assert.AreEqual(SpecialType.Dynamic, rr.AwaiterType);
Assert.IsNull(rr.IsCompletedProperty);
Assert.IsNull(rr.OnCompletedMethod);
Assert.IsNull(rr.GetResultMethod);
}
} }
} }

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

@ -360,6 +360,7 @@
<Compile Include="CSharp\CodeIssues\ParameterCanBeDemotedIssue\SupportsIndexingCriterionTests.cs" /> <Compile Include="CSharp\CodeIssues\ParameterCanBeDemotedIssue\SupportsIndexingCriterionTests.cs" />
<Compile Include="CSharp\CodeActions\CreateBackingStoreTests.cs" /> <Compile Include="CSharp\CodeActions\CreateBackingStoreTests.cs" />
<Compile Include="CSharp\CodeIssues\RedundantWhereWithPredicateIssueTests.cs" /> <Compile Include="CSharp\CodeIssues\RedundantWhereWithPredicateIssueTests.cs" />
<Compile Include="CSharp\CodeActions\SortUsingsTests.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Mono.Cecil\Mono.Cecil.csproj"> <ProjectReference Include="..\..\Mono.Cecil\Mono.Cecil.csproj">

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

@ -794,6 +794,8 @@ namespace ICSharpCode.NRefactory.TypeSystem
ITypeDefinition type = GetTypeDefinition(typeof(ParamsAttribute)); ITypeDefinition type = GetTypeDefinition(typeof(ParamsAttribute));
var arr = (ArrayCreateResolveResult)type.Attributes.Single().PositionalArguments.Single(); var arr = (ArrayCreateResolveResult)type.Attributes.Single().PositionalArguments.Single();
Assert.AreEqual(5, arr.InitializerElements.Count); Assert.AreEqual(5, arr.InitializerElements.Count);
Assert.AreEqual(1, arr.SizeArguments.Count);
Assert.AreEqual(5, arr.SizeArguments[0].ConstantValue);
return arr.InitializerElements[index]; return arr.InitializerElements[index];
} }

6
src/Libraries/NRefactory/ICSharpCode.NRefactory/Semantics/ArrayCreateResolveResult.cs

@ -43,16 +43,18 @@ namespace ICSharpCode.NRefactory.Semantics
public ArrayCreateResolveResult(IType arrayType, IList<ResolveResult> sizeArguments, IList<ResolveResult> initializerElements) public ArrayCreateResolveResult(IType arrayType, IList<ResolveResult> sizeArguments, IList<ResolveResult> initializerElements)
: base(arrayType) : base(arrayType)
{ {
if (sizeArguments == null)
throw new ArgumentNullException("sizeArguments");
this.SizeArguments = sizeArguments; this.SizeArguments = sizeArguments;
this.InitializerElements = initializerElements; this.InitializerElements = initializerElements;
} }
public override IEnumerable<ResolveResult> GetChildResults() public override IEnumerable<ResolveResult> GetChildResults()
{ {
if (SizeArguments != null && InitializerElements != null) if (InitializerElements != null)
return SizeArguments.Concat(InitializerElements); return SizeArguments.Concat(InitializerElements);
else else
return SizeArguments ?? InitializerElements ?? EmptyList<ResolveResult>.Instance; return SizeArguments;
} }
} }
} }

17
src/Libraries/NRefactory/ICSharpCode.NRefactory/Semantics/Conversion.cs

@ -92,7 +92,14 @@ namespace ICSharpCode.NRefactory.Semantics
{ {
if (chosenMethod == null) if (chosenMethod == null)
throw new ArgumentNullException("chosenMethod"); throw new ArgumentNullException("chosenMethod");
return new MethodGroupConv(chosenMethod, isVirtualMethodLookup); return new MethodGroupConv(chosenMethod, isVirtualMethodLookup, isValid: true);
}
public static Conversion InvalidMethodGroupConversion(IMethod chosenMethod, bool isVirtualMethodLookup)
{
if (chosenMethod == null)
throw new ArgumentNullException("chosenMethod");
return new MethodGroupConv(chosenMethod, isVirtualMethodLookup, isValid: false);
} }
#endregion #endregion
@ -311,11 +318,17 @@ namespace ICSharpCode.NRefactory.Semantics
{ {
readonly IMethod method; readonly IMethod method;
readonly bool isVirtualMethodLookup; readonly bool isVirtualMethodLookup;
readonly bool isValid;
public MethodGroupConv(IMethod method, bool isVirtualMethodLookup) public MethodGroupConv(IMethod method, bool isVirtualMethodLookup, bool isValid)
{ {
this.method = method; this.method = method;
this.isVirtualMethodLookup = isVirtualMethodLookup; this.isVirtualMethodLookup = isVirtualMethodLookup;
this.isValid = isValid;
}
public override bool IsValid {
get { return isValid; }
} }
public override bool IsImplicit { public override bool IsImplicit {

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save