Browse Source

Update to NRefactory 5.3.0-37-g52d116e

newNRvisualizers
Daniel Grunwald 13 years ago
parent
commit
51675a7180
  1. 45
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/SyntaxExtensions.cs
  2. 29
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs
  3. 41
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs
  4. 7
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/CompletionDataWrapper.cs
  5. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/IParameterCompletionDataFactory.cs
  6. 1
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  7. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertParenthesesVisitor.cs
  8. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertToInitializer/ConvertToInitializerAction.cs
  9. 17
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertToInitializer/StatementsToInitializerConverter.cs
  10. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateClassDeclarationAction.cs
  11. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateFieldAction.cs
  12. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/IntroduceFormatItemAction.cs
  13. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/JoinStringAction.cs
  14. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/SplitStringAction.cs
  15. 10
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/CallToVirtualFunctionFromConstructorIssue.cs
  16. 22
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/NamingRule.cs
  17. 16
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/NegativeRelationalExpressionIssue.cs
  18. 51
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/ParameterNotUsedIssue.cs
  19. 228
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs
  20. 5
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpInvocationResolveResult.cs
  21. 27
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  22. 51
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs
  23. 19
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs
  24. 37
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ConvertToInitializer/ConvertToInitializerTests.cs
  25. 27
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionAccessibleTests.cs
  26. 25
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs
  27. 79
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs
  28. 19
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/CallToVirtualFunctionFromConstructorTests.cs
  29. 33
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/NegativeRelationalExpressionIssueTests.cs
  30. 48
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ParameterNotUsedIssueTests.cs
  31. 420
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs
  32. 32
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/DynamicTests.cs
  33. 344
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExplicitConversionsTest.cs
  34. 63
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs
  35. 12
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/OverloadResolutionTests.cs
  36. 100
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/TypeInferenceTests.cs
  37. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
  38. 1
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs
  39. 12
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs
  40. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  41. 30
      src/Libraries/NRefactory/ICSharpCode.NRefactory/Semantics/Conversion.cs
  42. 5
      src/Libraries/NRefactory/ICSharpCode.NRefactory/Semantics/InvocationResolveResult.cs
  43. 8
      src/Libraries/NRefactory/ICSharpCode.NRefactory/Semantics/MemberResolveResult.cs
  44. 11
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedParameter.cs
  45. 2
      src/Libraries/NRefactory/NRefactory.sln
  46. 3
      src/Libraries/NRefactory/README

45
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/SyntaxExtensions.cs

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
// Copyright (c) 2013 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
namespace ICSharpCode.NRefactory.CSharp
{
/// <summary>
/// Extension methods for the syntax tree.
/// </summary>
public static class SyntaxExtensions
{
public static bool IsComparisonOperator(this OperatorType operatorType)
{
switch (operatorType) {
case OperatorType.Equality:
case OperatorType.Inequality:
case OperatorType.GreaterThan:
case OperatorType.LessThan:
case OperatorType.GreaterThanOrEqual:
case OperatorType.LessThanOrEqual:
return true;
default:
return false;
}
}
}
}

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

@ -1862,7 +1862,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -1862,7 +1862,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
Action<ICompletionData, IType> typeCallback = null;
var inferredTypesCategory = new Category("Inferred Types", null);
var derivedTypesCategory = new Category("Derived Types", null);
if (hintType != null) {
if (hintType.Kind != TypeKind.Unknown) {
var lookup = new MemberLookup(
@ -1884,23 +1883,27 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -1884,23 +1883,27 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
// check for valid constructors
if (t.GetConstructors().Count() > 0) {
bool isProtectedAllowed = currentType != null ?
currentType.Resolve(ctx).GetDefinition().IsDerivedFrom(t.GetDefinition()) :
false;
if (!t.GetConstructors().Any(m => lookup.IsAccessible(
m,
isProtectedAllowed
)
)) {
currentType.Resolve(ctx).GetDefinition().IsDerivedFrom(t.GetDefinition()) : false;
if (!t.GetConstructors().Any(m => lookup.IsAccessible(m, isProtectedAllowed))) {
return null;
}
}
// check derived types
var typeDef = t.GetDefinition();
var hintDef = hintType.GetDefinition();
if (typeDef != null && hintDef != null && typeDef.IsDerivedFrom(hintDef)) {
var newType = wrapper.AddType(t, true);
if (newType != null) {
newType.CompletionCategory = inferredTypesCategory;
}
}
// check type inference
var typeInference = new TypeInference(Compilation);
typeInference.Algorithm = TypeInferenceAlgorithm.ImprovedReturnAllResults;
var inferedType = typeInference.FindTypeInBounds(
new [] { t },
new [] { hintType }
);
var inferedType = typeInference.FindTypeInBounds (new [] { t }, new [] { hintType });
if (inferedType != SpecialType.UnknownType) {
var newType = wrapper.AddType(inferedType, true);
if (newType != null) {
@ -2997,7 +3000,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -2997,7 +3000,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
restart:
string lineText = document.GetText(line);
if (!lineText.Trim().StartsWith("///"))
if (!lineText.Trim().StartsWith("///", StringComparison.Ordinal))
return null;
int startIndex = Math.Min(location.Column - 1, lineText.Length - 1) - 1;
while (startIndex > 0 && lineText [startIndex] != '<') {

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

@ -109,6 +109,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -109,6 +109,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (resolvedNode is IdentifierExpression && currentMember != null && currentMember.IsStatic || resolveResult.TargetResult is TypeResolveResult) {
onlyStatic = true;
}
var methods = new List<IMethod>();
foreach (var method in resolveResult.Methods) {
if (method.IsConstructor) {
continue;
@ -118,15 +119,47 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -118,15 +119,47 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (onlyStatic && !method.IsStatic) {
continue;
}
yield return method;
if (method.IsShadowing) {
for (int j = 0; j < methods.Count; j++) {
if (ParameterListComparer.Instance.Equals(methods[j].Parameters, method.Parameters)) {
methods.RemoveAt (j);
j--;
}
}
}
methods.Add (method);
}
foreach (var m in methods)
yield return m;
foreach (var extMethods in resolveResult.GetEligibleExtensionMethods (true)) {
foreach (var method in extMethods) {
yield return method;
}
}
}
IEnumerable<IProperty> GetAccessibleIndexers(IType type)
{
var lookup = new MemberLookup(ctx.CurrentTypeDefinition, Compilation.MainAssembly);
var properties = new List<IProperty>();
foreach (var property in type.GetProperties ()) {
if (!property.IsIndexer)
continue;
if (!lookup.IsAccessible (property, true))
continue;
if (property.IsShadowing) {
for (int j = 0; j < properties.Count; j++) {
if (ParameterListComparer.Instance.Equals(properties[j].Parameters, property.Parameters)) {
properties.RemoveAt (j);
j--;
}
}
}
properties.Add (property);
}
return properties;
}
public IParameterDataProvider GetParameterDataProvider(int offset, char completionChar)
{
@ -259,7 +292,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -259,7 +292,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
}
}
if (resolveResult != null) {
return factory.CreateIndexerParameterDataProvider(document.GetOffset(invoke.Node.StartLocation), resolveResult.Type, invoke.Node);
return factory.CreateIndexerParameterDataProvider(document.GetOffset(invoke.Node.StartLocation), resolveResult.Type, GetAccessibleIndexers (resolveResult.Type), invoke.Node);
}
break;
case '<':
@ -285,7 +318,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -285,7 +318,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (indexerExpression == null || indexerExpression.Item1 == null || indexerExpression.Item1.IsError) {
return null;
}
return factory.CreateIndexerParameterDataProvider(document.GetOffset(invoke.Node.StartLocation), indexerExpression.Item1.Type, invoke.Node);
return factory.CreateIndexerParameterDataProvider(document.GetOffset(invoke.Node.StartLocation), indexerExpression.Item1.Type, GetAccessibleIndexers (indexerExpression.Item1.Type), invoke.Node);
}
return null;
}

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

@ -111,7 +111,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -111,7 +111,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
ICompletionData usedType;
var data = Factory.CreateTypeCompletionData(type, showFullName, isInAttributeContext);
var text = data.DisplayText;
if (typeDisplayText.TryGetValue(text, out usedType)) {
usedType.AddOverload(data);
return usedType;
@ -158,9 +157,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -158,9 +157,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
public ICompletionData AddMember (IMember member)
{
if (data.ContainsKey (member.Name))
return null;
var newData = Factory.CreateEntityCompletionData (member);
if (member.ParentAssembly != completion.ctx.CurrentAssembly && !member.IsBrowsable ())
@ -175,8 +171,9 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -175,8 +171,9 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
}
List<ICompletionData> existingData;
data.TryGetValue (memberKey, out existingData);
if (existingData != null) {
if (member.EntityType == EntityType.Field || member.EntityType == EntityType.Property || member.EntityType == EntityType.Event)
return null;
var a = member as IEntity;
foreach (var d in existingData) {
if (!(d is IEntityCompletionData))

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/IParameterCompletionDataFactory.cs

@ -44,7 +44,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -44,7 +44,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
IParameterDataProvider CreateDelegateDataProvider (int startOffset, IType type);
IParameterDataProvider CreateIndexerParameterDataProvider (int startOffset, IType type, AstNode resolvedNode);
IParameterDataProvider CreateIndexerParameterDataProvider (int startOffset, IType type, IEnumerable<IProperty> accessibleIndexers, AstNode resolvedNode);
IParameterDataProvider CreateTypeParameterDataProvider (int startOffset, IEnumerable<IType> types);
}

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

@ -93,6 +93,7 @@ @@ -93,6 +93,7 @@
<Compile Include="Ast\AstType.cs" />
<Compile Include="Ast\DocumentationReference.cs" />
<Compile Include="Ast\IdentifierExpressionBackreference.cs" />
<Compile Include="Ast\SyntaxExtensions.cs" />
<Compile Include="Ast\SyntaxTree.cs" />
<Compile Include="Ast\ComposedType.cs" />
<Compile Include="Ast\CSharpModifierToken.cs" />

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertParenthesesVisitor.cs

@ -235,7 +235,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -235,7 +235,7 @@ namespace ICSharpCode.NRefactory.CSharp
ParenthesizeIfRequired(binaryOperatorExpression.Left, Primary);
ParenthesizeIfRequired(binaryOperatorExpression.Right, Primary);
} else {
// ?? is right-associate
// ?? is right-associative
ParenthesizeIfRequired(binaryOperatorExpression.Left, precedence + 1);
ParenthesizeIfRequired(binaryOperatorExpression.Right, precedence);
}

6
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertToInitializer/ConvertToInitializerAction.cs

@ -60,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -60,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
IList<AstNode> statements = GetNodes(context.GetNode<Statement>());
var converter = new StatementsToInitializerConverter(context);
var newInitializer = converter.ConvertToInitializer(initializer, ref statements);
if (statements.Count == 0)
if (newInitializer == null || statements.Count == 0)
return null;
return MakeAction(context, initializer, newInitializer, statements);
}
@ -68,7 +68,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -68,7 +68,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
CodeAction HandleExpressionStatement(RefactoringContext context, ExpressionStatement expressionStatement)
{
var expression = expressionStatement.Expression as AssignmentExpression;
if (expression == null)
if (expression == null || expression.Operator != AssignmentOperatorType.Assign)
return null;
if (!(expression.Right is ObjectCreateExpression))
return null;
@ -78,7 +78,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -78,7 +78,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
IList<AstNode> statements = GetNodes(context.GetNode<Statement>());
var converter = new StatementsToInitializerConverter(context);
var newExpression = converter.ConvertToInitializer(expression, ref statements);
if (statements.Count == 0)
if (newExpression == null || statements.Count == 0)
return null;
return MakeAction(context, expression, newExpression, statements);
}

17
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertToInitializer/StatementsToInitializerConverter.cs

@ -47,14 +47,15 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -47,14 +47,15 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
this.context = context;
}
void Initialize(AstNode targetNode)
bool Initialize(AstNode targetNode)
{
var target = context.Resolve(targetNode);
var targetInitializerPath = AccessPath.FromResolveResult(target);
if (targetInitializerPath == null)
throw new ArgumentException(string.Format("Could not create the main initializer path from resolve result ({0})", target));
return false;
mainAccessPath = targetInitializerPath;
return true;
}
public VariableInitializer ConvertToInitializer(VariableInitializer variableInitializer, ref IList<AstNode> statements)
@ -64,7 +65,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -64,7 +65,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (statements == null)
throw new ArgumentNullException("statements");
Initialize(variableInitializer);
if (!Initialize(variableInitializer))
return null;
accessPaths [mainAccessPath] = variableInitializer.Initializer.Clone();
Convert(statements);
@ -81,7 +83,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -81,7 +83,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (!(assignmentExpression.Right is ObjectCreateExpression))
throw new ArgumentException("assignmentExpression.Right must be an ObjectCreateExpression", "assignmentExpression");
Initialize(assignmentExpression.Left);
if (!Initialize(assignmentExpression.Left))
return null;
accessPaths [mainAccessPath] = assignmentExpression.Right.Clone();
Convert(statements);
@ -124,12 +127,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -124,12 +127,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return false;
}
variableInitializer = variableDeclarationStatement.Variables.FirstOrNullObject();
if (variableInitializer.IsNull)
if (variableInitializer.IsNull || variableInitializer.Initializer.IsNull)
return false;
var sourceResolveResult = context.Resolve(variableInitializer.Initializer) as LocalResolveResult;
if (HasDependency(variableInitializer.Initializer) && !CanReplaceDependent(sourceResolveResult))
return false;
var targetResolveResult = context.Resolve(variableInitializer) as LocalResolveResult;
if (targetResolveResult == null)
return false;
AddNewVariable(targetResolveResult.Variable, variableInitializer.Initializer, node);
return true;
}
@ -176,7 +181,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -176,7 +181,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
bool TryHandleAssignmentExpression(ExpressionStatement expressionStatement)
{
var assignmentExpression = expressionStatement.Expression as AssignmentExpression;
if (assignmentExpression == null)
if (assignmentExpression == null || assignmentExpression.Operator != AssignmentOperatorType.Assign)
return false;
var resolveResult = context.Resolve(assignmentExpression.Right);
if (HasDependency(assignmentExpression.Right) && !CanReplaceDependent(resolveResult))

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

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// CreateClassDeclarationAction.cs
//
// Author:
@ -86,7 +86,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -86,7 +86,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
string className = simpleType.Identifier;
if (simpleType.Parent is Attribute) {
if (!className.EndsWith("Attribute"))
if (!className.EndsWith("Attribute", System.StringComparison.Ordinal))
className += "Attribute";
}

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

@ -272,7 +272,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -272,7 +272,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return Enumerable.Empty<IType>();
}
static readonly IType[] emptyTypes = new IType[0];
internal static AstType GuessAstType(RefactoringContext context, Expression expr)
public static AstType GuessAstType(RefactoringContext context, Expression expr)
{
var type = GetValidTypes(context.Resolver, expr).ToArray();
var typeInference = new TypeInference(context.Compilation);
@ -283,7 +283,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -283,7 +283,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return context.CreateShortType(inferedType);
}
internal static IType GuessType(RefactoringContext context, Expression expr)
public static IType GuessType(RefactoringContext context, Expression expr)
{
var type = GetValidTypes(context.Resolver, expr).ToArray();
var typeInference = new TypeInference(context.Compilation);

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

@ -50,8 +50,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -50,8 +50,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (pexpr == null || !(pexpr.Value is string)) {
yield break;
}
if (pexpr.LiteralValue.StartsWith("@")) {
if (!(pexpr.StartLocation < new TextLocation (context.Location.Line, context.Location.Column - 1) && new TextLocation (context.Location.Line, context.Location.Column + 1) < pexpr.EndLocation)) {
if (pexpr.LiteralValue.StartsWith("@", StringComparison.Ordinal)) {
if (!(pexpr.StartLocation < new TextLocation(context.Location.Line, context.Location.Column - 1) && new TextLocation(context.Location.Line, context.Location.Column + 1) < pexpr.EndLocation)) {
yield break;
}
} else {

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

@ -47,8 +47,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -47,8 +47,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
!(left.Value is string) || !(right.Value is string) || !node.OperatorToken.Contains(context.Location))
return null;
var isLeftVerbatim = left.LiteralValue.StartsWith ("@");
var isRightVerbatime = right.LiteralValue.StartsWith ("@");
var isLeftVerbatim = left.LiteralValue.StartsWith("@", System.StringComparison.Ordinal);
var isRightVerbatime = right.LiteralValue.StartsWith("@", System.StringComparison.Ordinal);
if (isLeftVerbatim != isRightVerbatime)
return null;

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

@ -41,7 +41,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -41,7 +41,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (pexpr == null || !(pexpr.Value is string)) {
yield break;
}
if (pexpr.LiteralValue.StartsWith("@")) {
if (pexpr.LiteralValue.StartsWith("@", StringComparison.Ordinal)) {
if (!(pexpr.StartLocation < new TextLocation(context.Location.Line, context.Location.Column - 2) &&
new TextLocation(context.Location.Line, context.Location.Column + 2) < pexpr.EndLocation)) {
yield break;
@ -54,7 +54,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -54,7 +54,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
yield return new CodeAction(context.TranslateString("Split string literal"), script => {
int offset = context.GetOffset (context.Location);
script.InsertText (offset, pexpr.LiteralValue.StartsWith ("@") ? "\" + @\"" : "\" + \"");
script.InsertText (offset, pexpr.LiteralValue.StartsWith("@", StringComparison.Ordinal) ? "\" + @\"" : "\" + \"");
});
}
}

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

@ -144,6 +144,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -144,6 +144,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return true;
return false;
}
public override void VisitLambdaExpression(LambdaExpression lambdaExpression)
{
// ignore lambdas
}
public override void VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression)
{
// ignore anonymous methods
}
}
}
}

22
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/NamingRule.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// NamingRule.cs
//
// Author:
@ -82,7 +82,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -82,7 +82,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
string id = name;
bool foundPrefix = false;
if (RequiredPrefixes != null && RequiredPrefixes.Length > 0) {
var prefix = RequiredPrefixes.FirstOrDefault(p => id.StartsWith(p));
var prefix = RequiredPrefixes.FirstOrDefault(p => id.StartsWith(p, StringComparison.Ordinal));
if (prefix == null) {
return false;
}
@ -91,7 +91,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -91,7 +91,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
}
if (!foundPrefix && AllowedPrefixes != null && AllowedPrefixes.Length > 0) {
var prefix = AllowedPrefixes.FirstOrDefault(p => id.StartsWith(p));
var prefix = AllowedPrefixes.FirstOrDefault(p => id.StartsWith(p, StringComparison.Ordinal));
if (prefix != null) {
id = id.Substring(prefix.Length);
foundPrefix = true;
@ -99,19 +99,19 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -99,19 +99,19 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
}
if (!foundPrefix && ForbiddenPrefixes != null && ForbiddenPrefixes.Length > 0) {
if (ForbiddenPrefixes.Any(p => id.StartsWith(p))) {
if (ForbiddenPrefixes.Any(p => id.StartsWith(p, StringComparison.Ordinal))) {
return false;
}
}
if (RequiredSuffixes != null && RequiredSuffixes.Length > 0) {
var suffix = RequiredSuffixes.FirstOrDefault(s => id.EndsWith(s));
var suffix = RequiredSuffixes.FirstOrDefault(s => id.EndsWith(s, StringComparison.Ordinal));
if (suffix == null) {
return false;
}
id = id.Substring(0, id.Length - suffix.Length);
} else if (ForbiddenSuffixes != null && ForbiddenSuffixes.Length > 0) {
if (ForbiddenSuffixes.Any(p => id.EndsWith(p))) {
if (ForbiddenSuffixes.Any(p => id.EndsWith(p, StringComparison.Ordinal))) {
return false;
}
}
@ -166,14 +166,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -166,14 +166,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
string suffix = null;
if (AllowedPrefixes != null && AllowedPrefixes.Length > 0) {
allowedPrefix = AllowedPrefixes.FirstOrDefault(p => id.StartsWith(p));
allowedPrefix = AllowedPrefixes.FirstOrDefault(p => id.StartsWith(p, StringComparison.Ordinal));
if (allowedPrefix != null)
id = id.Substring(allowedPrefix.Length);
}
if (RequiredPrefixes != null && RequiredPrefixes.Length > 0) {
requiredPrefix = RequiredPrefixes.FirstOrDefault(p => id.StartsWith(p));
requiredPrefix = RequiredPrefixes.FirstOrDefault(p => id.StartsWith(p, StringComparison.Ordinal));
if (requiredPrefix == null) {
errorMessage = string.Format(ctx.TranslateString("Name should have prefix '{0}'."), RequiredPrefixes [0]);
missingRequiredPrefix = true;
@ -181,7 +181,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -181,7 +181,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
id = id.Substring(requiredPrefix.Length);
}
} else if (ForbiddenPrefixes != null && ForbiddenPrefixes.Length > 0) {
requiredPrefix = ForbiddenPrefixes.FirstOrDefault(p => id.StartsWith(p));
requiredPrefix = ForbiddenPrefixes.FirstOrDefault(p => id.StartsWith(p, StringComparison.Ordinal));
if (requiredPrefix != null) {
errorMessage = string.Format(ctx.TranslateString("Name has forbidden prefix '{0}'."), requiredPrefix);
id = id.Substring(requiredPrefix.Length);
@ -189,7 +189,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -189,7 +189,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
}
if (RequiredSuffixes != null && RequiredSuffixes.Length > 0) {
suffix = RequiredSuffixes.FirstOrDefault(s => id.EndsWith(s));
suffix = RequiredSuffixes.FirstOrDefault(s => id.EndsWith(s, StringComparison.Ordinal));
if (suffix == null) {
errorMessage = string.Format(ctx.TranslateString("Name should have suffix '{0}'."), RequiredSuffixes [0]);
missingRequiredSuffix = true;
@ -197,7 +197,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -197,7 +197,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
id = id.Substring(0, id.Length - suffix.Length);
}
} else if (ForbiddenSuffixes != null && ForbiddenSuffixes.Length > 0) {
suffix = ForbiddenSuffixes.FirstOrDefault(p => id.EndsWith(p));
suffix = ForbiddenSuffixes.FirstOrDefault(p => id.EndsWith(p, StringComparison.Ordinal));
if (suffix != null) {
errorMessage = string.Format(ctx.TranslateString("Name has forbidden suffix '{0}'."), suffix);
id = id.Substring(0, id.Length - suffix.Length);

16
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/NegativeRelationalExpressionIssue.cs

@ -74,14 +74,26 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -74,14 +74,26 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (negatedOp == BinaryOperatorType.Any)
return;
if (IsFloatingPoint (binaryOperatorExpr.Left) || IsFloatingPoint (binaryOperatorExpr.Right))
return;
if (IsFloatingPoint (binaryOperatorExpr.Left) || IsFloatingPoint (binaryOperatorExpr.Right)) {
if (negatedOp != BinaryOperatorType.Equality && negatedOp != BinaryOperatorType.InEquality)
return;
}
AddIssue (unaryOperatorExpression, ctx.TranslateString ("Simplify negative relational expression"),
script => script.Replace (unaryOperatorExpression,
new BinaryOperatorExpression (binaryOperatorExpr.Left.Clone (), negatedOp,
binaryOperatorExpr.Right.Clone ())));
}
public override void VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration)
{
if (operatorDeclaration.OperatorType.IsComparisonOperator()) {
// Ignore operator declaration; within them it's common to define one operator
// by negating another.
return;
}
base.VisitOperatorDeclaration(operatorDeclaration);
}
}
}
}

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

@ -34,10 +34,10 @@ using System; @@ -34,10 +34,10 @@ using System;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
[IssueDescription ("Unused parameter",
Description = "Parameter is never used.",
Category = IssueCategories.Redundancies,
Severity = Severity.Warning,
IssueMarker = IssueMarker.GrayOut)]
Description = "Parameter is never used.",
Category = IssueCategories.Redundancies,
Severity = Severity.Warning,
IssueMarker = IssueMarker.GrayOut)]
public class ParameterNotUsedIssue : ICodeIssueProvider
{
#region ICodeIssueProvider implementation
@ -63,29 +63,48 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -63,29 +63,48 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
public override void VisitIdentifierExpression(IdentifierExpression identifierExpression)
{
var mgr = ctx.Resolve (identifierExpression) as MethodGroupResolveResult;
if (mgr != null)
UsedMethods.AddRange (mgr.Methods);
if (!IsTargetOfInvocation(identifierExpression)) {
var mgr = ctx.Resolve (identifierExpression) as MethodGroupResolveResult;
if (mgr != null)
UsedMethods.AddRange (mgr.Methods);
}
base.VisitIdentifierExpression(identifierExpression);
}
public override void VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression)
{
var mgr = ctx.Resolve (memberReferenceExpression) as MethodGroupResolveResult;
if (mgr != null)
UsedMethods.AddRange (mgr.Methods);
if (!IsTargetOfInvocation(memberReferenceExpression)) {
var mgr = ctx.Resolve (memberReferenceExpression) as MethodGroupResolveResult;
if (mgr != null)
UsedMethods.AddRange (mgr.Methods);
}
base.VisitMemberReferenceExpression(memberReferenceExpression);
}
static bool IsTargetOfInvocation(AstNode node)
{
return node.Role == Roles.TargetExpression && node.Parent is InvocationExpression;
}
}
class GatherVisitor : GatherVisitorBase
{
GetDelgateUsagesVisitor usedDelegates;
bool currentTypeIsPartial;
public GatherVisitor (BaseRefactoringContext ctx, GetDelgateUsagesVisitor usedDelegates)
: base (ctx)
{
this.usedDelegates = usedDelegates;
}
public override void VisitTypeDeclaration(TypeDeclaration typeDeclaration)
{
bool outerTypeIsPartial = currentTypeIsPartial;
currentTypeIsPartial = typeDeclaration.HasModifier(Modifiers.Partial);
base.VisitTypeDeclaration(typeDeclaration);
currentTypeIsPartial = outerTypeIsPartial;
}
public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration)
{
@ -101,17 +120,23 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -101,17 +120,23 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return;
if (member.ImplementedInterfaceMembers.Any ())
return;
if (usedDelegates.UsedMethods.Any (m => m.Region.Begin == methodDeclaration.StartLocation))
if (usedDelegates.UsedMethods.Any (m => m.MemberDefinition == member))
return;
if (currentTypeIsPartial && methodDeclaration.Parameters.Count == 2) {
if (methodDeclaration.Parameters.First().Name == "sender") {
// Looks like an event handler; the registration might be in the designer part
return;
}
}
foreach (var parameter in methodDeclaration.Parameters)
parameter.AcceptVisitor (this);
}
public override void VisitParameterDeclaration (ParameterDeclaration parameterDeclaration)
{
base.VisitParameterDeclaration (parameterDeclaration);
base.VisitParameterDeclaration (parameterDeclaration);
if (!(parameterDeclaration.Parent is MethodDeclaration))
if (!(parameterDeclaration.Parent is MethodDeclaration || parameterDeclaration.Parent is ConstructorDeclaration))
return;
var resolveResult = ctx.Resolve (parameterDeclaration) as LocalResolveResult;

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

@ -99,27 +99,49 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -99,27 +99,49 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region ImplicitConversion
public Conversion ImplicitConversion(ResolveResult resolveResult, IType toType)
private Conversion ImplicitConversion(ResolveResult resolveResult, IType toType, bool allowUserDefined)
{
if (resolveResult == null)
throw new ArgumentNullException("resolveResult");
Conversion c;
if (resolveResult.IsCompileTimeConstant) {
c = ImplicitEnumerationConversion(resolveResult, toType);
if (c.IsValid) return c;
if (ImplicitConstantExpressionConversion(resolveResult, toType))
return Conversion.ImplicitConstantExpressionConversion;
c = StandardImplicitConversion(resolveResult.Type, toType);
if (c != Conversion.None) return c;
if (allowUserDefined) {
c = UserDefinedImplicitConversion(resolveResult, resolveResult.Type, toType);
if (c != Conversion.None) return c;
}
} else {
c = ImplicitConversion(resolveResult.Type, toType, allowUserDefined);
if (c != Conversion.None) return c;
}
c = ImplicitConversion(resolveResult.Type, toType);
if (c.IsValid) return c;
if (resolveResult.Type.Kind == TypeKind.Dynamic)
return Conversion.ImplicitDynamicConversion;
c = AnonymousFunctionConversion(resolveResult, toType);
if (c.IsValid) return c;
if (c != Conversion.None) return c;
c = MethodGroupConversion(resolveResult, toType);
return c;
}
private Conversion ImplicitConversion(IType fromType, IType toType, bool allowUserDefined)
{
// C# 4.0 spec: §6.1
var c = StandardImplicitConversion(fromType, toType);
if (c == Conversion.None && allowUserDefined) {
c = UserDefinedImplicitConversion(null, fromType, toType);
}
return c;
}
public Conversion ImplicitConversion(ResolveResult resolveResult, IType toType)
{
if (resolveResult == null)
throw new ArgumentNullException("resolveResult");
return ImplicitConversion(resolveResult, toType, allowUserDefined: true);
}
public Conversion ImplicitConversion(IType fromType, IType toType)
{
if (fromType == null)
@ -131,12 +153,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -131,12 +153,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Conversion c;
if (implicitConversionCache.TryGetValue(pair, out c))
return c;
// C# 4.0 spec: §6.1
c = StandardImplicitConversion(fromType, toType);
if (!c.IsValid) {
c = UserDefinedImplicitConversion(fromType, toType);
}
c = ImplicitConversion(fromType, toType, allowUserDefined: true);
implicitConversionCache[pair] = c;
return c;
}
@ -153,7 +172,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -153,7 +172,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (ImplicitNumericConversion(fromType, toType))
return Conversion.ImplicitNumericConversion;
Conversion c = ImplicitNullableConversion(fromType, toType);
if (c.IsValid)
if (c != Conversion.None)
return c;
if (NullLiteralConversion(fromType, toType))
return Conversion.NullLiteralConversion;
@ -211,11 +230,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -211,11 +230,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (resolveResult.Type.Kind == TypeKind.Dynamic)
return Conversion.ExplicitDynamicConversion;
Conversion c = ImplicitConversion(resolveResult, toType);
if (c.IsValid)
Conversion c = ImplicitConversion(resolveResult, toType, allowUserDefined: false);
if (c != Conversion.None)
return c;
else
return ExplicitConversionImpl(resolveResult.Type, toType);
c = ExplicitConversionImpl(resolveResult.Type, toType);
if (c != Conversion.None)
return c;
return UserDefinedExplicitConversion(resolveResult, resolveResult.Type, toType);
}
public Conversion ExplicitConversion(IType fromType, IType toType)
@ -225,11 +246,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -225,11 +246,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (toType == null)
throw new ArgumentNullException("toType");
Conversion c = ImplicitConversion(fromType, toType);
if (c.IsValid)
Conversion c = ImplicitConversion(fromType, toType, allowUserDefined: false);
if (c != Conversion.None)
return c;
else
return ExplicitConversionImpl(fromType, toType);
c = ExplicitConversionImpl(fromType, toType);
if (c != Conversion.None)
return c;
return UserDefinedExplicitConversion(null, fromType, toType);
}
Conversion ExplicitConversionImpl(IType fromType, IType toType)
@ -241,18 +264,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -241,18 +264,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (ExplicitEnumerationConversion(fromType, toType))
return Conversion.EnumerationConversion(false, false);
Conversion c = ExplicitNullableConversion(fromType, toType);
if (c.IsValid)
if (c != Conversion.None)
return c;
if (ExplicitReferenceConversion(fromType, toType))
return Conversion.ExplicitReferenceConversion;
if (UnboxingConversion(fromType, toType))
return Conversion.UnboxingConversion;
c = ExplicitTypeParameterConversion(fromType, toType);
if (c.IsValid)
if (c != Conversion.None)
return c;
if (ExplicitPointerConversion(fromType, toType))
return Conversion.ExplicitPointerConversion;
return UserDefinedExplicitConversion(fromType, toType);
return Conversion.None;
}
#endregion
@ -643,8 +666,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -643,8 +666,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region Implicit Constant-Expression Conversion
bool ImplicitConstantExpressionConversion(ResolveResult rr, IType toType)
{
if (rr == null || !rr.IsCompileTimeConstant)
return false;
// C# 4.0 spec: §6.1.9
Debug.Assert(rr.IsCompileTimeConstant);
TypeCode fromTypeCode = ReflectionHelper.GetTypeCode(rr.Type);
TypeCode toTypeCode = ReflectionHelper.GetTypeCode(NullableType.GetUnderlyingType(toType));
if (fromTypeCode == TypeCode.Int64) {
@ -744,27 +768,138 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -744,27 +768,138 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return a.Kind != TypeKind.Interface && b.Kind != TypeKind.Interface
&& (StandardImplicitConversion(a, b).IsValid || StandardImplicitConversion(b, a).IsValid);
}
Conversion UserDefinedImplicitConversion(IType fromType, IType toType)
IType FindMostEncompassedType(IEnumerable<IType> candidates)
{
IType best = null;
foreach (var current in candidates) {
if (best == null || IsEncompassedBy(current, best))
best = current;
else if (!IsEncompassedBy(best, current))
return null; // Ambiguous
}
return best;
}
IType FindMostEncompassingType(IEnumerable<IType> candidates)
{
IType best = null;
foreach (var current in candidates) {
if (best == null || IsEncompassedBy(best, current))
best = current;
else if (!IsEncompassedBy(current, best))
return null; // Ambiguous
}
return best;
}
Conversion SelectOperator(IType mostSpecificSource, IType mostSpecificTarget, IList<OperatorInfo> operators, bool isImplicit)
{
var selected = operators.Where(op => op.SourceType.Equals(mostSpecificSource) && op.TargetType.Equals(mostSpecificTarget)).ToList();
if (selected.Count == 0)
return Conversion.None;
if (selected.Count == 1)
return Conversion.UserDefinedConversion(selected[0].Method, isLifted: selected[0].IsLifted, isImplicit: isImplicit);
int nNonLifted = selected.Count(s => !s.IsLifted);
if (nNonLifted == 1) {
var op = selected.First(s => !s.IsLifted);
return Conversion.UserDefinedConversion(op.Method, isLifted: op.IsLifted, isImplicit: isImplicit);
}
return Conversion.UserDefinedConversion(selected[0].Method, isLifted: selected[0].IsLifted, isImplicit: isImplicit, isAmbiguous: true);
}
Conversion UserDefinedImplicitConversion(ResolveResult fromResult, IType fromType, IType toType)
{
// C# 4.0 spec §6.4.4 User-defined implicit conversions
var operators = GetApplicableConversionOperators(fromType, toType, false);
// TODO: Find most specific conversion
if (operators.Count > 0)
return Conversion.UserDefinedImplicitConversion(operators[0].Method, operators[0].IsLifted);
else
var operators = GetApplicableConversionOperators(fromResult, fromType, toType, false);
if (operators.Count > 0) {
var mostSpecificSource = operators.Any(op => op.SourceType.Equals(fromType)) ? fromType : FindMostEncompassedType(operators.Select(op => op.SourceType));
if (mostSpecificSource == null)
return Conversion.UserDefinedConversion(operators[0].Method, isImplicit: true, isLifted: operators[0].IsLifted, isAmbiguous: true);
var mostSpecificTarget = operators.Any(op => op.TargetType.Equals(toType)) ? toType : FindMostEncompassingType(operators.Select(op => op.TargetType));
if (mostSpecificTarget == null) {
if (NullableType.IsNullable(toType))
return UserDefinedImplicitConversion(fromResult, fromType, NullableType.GetUnderlyingType(toType));
else
return Conversion.UserDefinedConversion(operators[0].Method, isImplicit: true, isLifted: operators[0].IsLifted, isAmbiguous: true);
}
var selected = SelectOperator(mostSpecificSource, mostSpecificTarget, operators, true);
if (selected != Conversion.None) {
if (selected.IsLifted && NullableType.IsNullable(toType)) {
// Prefer A -> B -> B? over A -> A? -> B?
var other = UserDefinedImplicitConversion(fromResult, fromType, NullableType.GetUnderlyingType(toType));
if (other != Conversion.None)
return other;
}
return selected;
}
else if (NullableType.IsNullable(toType))
return UserDefinedImplicitConversion(fromResult, fromType, NullableType.GetUnderlyingType(toType));
else
return Conversion.None;
}
else {
return Conversion.None;
}
}
Conversion UserDefinedExplicitConversion(IType fromType, IType toType)
Conversion UserDefinedExplicitConversion(ResolveResult fromResult, IType fromType, IType toType)
{
// C# 4.0 spec §6.4.5 User-defined implicit conversions
var operators = GetApplicableConversionOperators(fromType, toType, true);
// TODO: Find most specific conversion
if (operators.Count > 0)
return Conversion.UserDefinedExplicitConversion(operators[0].Method, operators[0].IsLifted);
else
var operators = GetApplicableConversionOperators(fromResult, fromType, toType, true);
if (operators.Count > 0) {
IType mostSpecificSource;
if (operators.Any(op => op.SourceType.Equals(fromType))) {
mostSpecificSource = fromType;
} else {
var operatorsWithSourceEncompassingFromType = operators.Where(op => IsEncompassedBy(fromType, op.SourceType) || ImplicitConstantExpressionConversion(fromResult, NullableType.GetUnderlyingType(op.SourceType))).ToList();
if (operatorsWithSourceEncompassingFromType.Any())
mostSpecificSource = FindMostEncompassedType(operatorsWithSourceEncompassingFromType.Select(op => op.SourceType));
else
mostSpecificSource = FindMostEncompassingType(operators.Select(op => op.SourceType));
}
if (mostSpecificSource == null)
return Conversion.UserDefinedConversion(operators[0].Method, isImplicit: false, isLifted: operators[0].IsLifted, isAmbiguous: true);
IType mostSpecificTarget;
if (operators.Any(op => op.TargetType.Equals(toType)))
mostSpecificTarget = toType;
else if (operators.Any(op => IsEncompassedBy(op.TargetType, toType)))
mostSpecificTarget = FindMostEncompassingType(operators.Where(op => IsEncompassedBy(op.TargetType, toType)).Select(op => op.TargetType));
else
mostSpecificTarget = FindMostEncompassedType(operators.Select(op => op.TargetType));
if (mostSpecificTarget == null) {
if (NullableType.IsNullable(toType))
return UserDefinedExplicitConversion(fromResult, fromType, NullableType.GetUnderlyingType(toType));
else
return Conversion.UserDefinedConversion(operators[0].Method, isImplicit: false, isLifted: operators[0].IsLifted, isAmbiguous: true);
}
var selected = SelectOperator(mostSpecificSource, mostSpecificTarget, operators, false);
if (selected != Conversion.None) {
if (selected.IsLifted && NullableType.IsNullable(toType)) {
// Prefer A -> B -> B? over A -> A? -> B?
var other = UserDefinedImplicitConversion(fromResult, fromType, NullableType.GetUnderlyingType(toType));
if (other != Conversion.None)
return other;
}
return selected;
}
else if (NullableType.IsNullable(toType))
return UserDefinedExplicitConversion(fromResult, fromType, NullableType.GetUnderlyingType(toType));
else if (NullableType.IsNullable(fromType))
return UserDefinedExplicitConversion(null, NullableType.GetUnderlyingType(fromType), toType); // A? -> A -> B
else
return Conversion.None;
}
else {
return Conversion.None;
}
}
class OperatorInfo
@ -783,7 +918,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -783,7 +918,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
List<OperatorInfo> GetApplicableConversionOperators(IType fromType, IType toType, bool isExplicit)
List<OperatorInfo> GetApplicableConversionOperators(ResolveResult fromResult, IType fromType, IType toType, bool isExplicit)
{
// Find the candidate operators:
Predicate<IUnresolvedMethod> opFilter;
@ -802,26 +937,27 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -802,26 +937,27 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// Try if the operator is applicable:
bool isApplicable;
if (isExplicit) {
isApplicable = IsEncompassingOrEncompassedBy(fromType, sourceType)
isApplicable = (IsEncompassingOrEncompassedBy(fromType, sourceType) || ImplicitConstantExpressionConversion(fromResult, sourceType))
&& IsEncompassingOrEncompassedBy(targetType, toType);
} else {
isApplicable = IsEncompassedBy(fromType, sourceType) && IsEncompassedBy(targetType, toType);
isApplicable = (IsEncompassedBy(fromType, sourceType) || ImplicitConstantExpressionConversion(fromResult, sourceType))
&& IsEncompassedBy(targetType, toType);
}
// Try if the operator is applicable in lifted form:
if (isApplicable) {
result.Add(new OperatorInfo(op, sourceType, targetType, false));
}
// Try if the operator is applicable in lifted form:
if (NullableType.IsNonNullableValueType(sourceType)
&& NullableType.IsNonNullableValueType(targetType))
{
if (NullableType.IsNonNullableValueType(sourceType)) {
// An operator can be applicable in both lifted and non-lifted form in case of explicit conversions
IType liftedSourceType = NullableType.Create(compilation, sourceType);
IType liftedTargetType = NullableType.Create(compilation, targetType);
IType liftedTargetType = NullableType.IsNonNullableValueType(targetType) ? NullableType.Create(compilation, targetType) : targetType;
if (isExplicit) {
isApplicable = IsEncompassingOrEncompassedBy(fromType, liftedSourceType)
&& IsEncompassingOrEncompassedBy(liftedTargetType, toType);
} else {
isApplicable = IsEncompassedBy(fromType, liftedSourceType) && IsEncompassedBy(liftedTargetType, toType);
}
if (isApplicable) {
result.Add(new OperatorInfo(op, liftedSourceType, liftedTargetType, true));
}

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

@ -57,9 +57,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -57,9 +57,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
bool isExpandedForm = false,
bool isDelegateInvocation = false,
IList<int> argumentToParameterMap = null,
IList<ResolveResult> initializerStatements = null
IList<ResolveResult> initializerStatements = null,
IType returnTypeOverride = null
)
: base(targetResult, member, arguments, initializerStatements)
: base(targetResult, member, arguments, initializerStatements, returnTypeOverride)
{
this.OverloadResolutionErrors = overloadResolutionErrors;
this.IsExtensionMethodInvocation = isExtensionMethodInvocation;

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

@ -1188,18 +1188,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1188,18 +1188,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
static bool IsComparisonOperator(IMethod m)
{
var type = OperatorDeclaration.GetOperatorType(m.Name);
if (type.HasValue) {
switch (type.Value) {
case OperatorType.Equality:
case OperatorType.Inequality:
case OperatorType.GreaterThan:
case OperatorType.LessThan:
case OperatorType.GreaterThanOrEqual:
case OperatorType.LessThanOrEqual:
return true;
}
}
return false;
return type.HasValue && type.Value.IsComparisonOperator();
}
sealed class LiftedUserDefinedOperator : SpecializedMethod, OverloadResolution.ILiftedOperator
@ -1944,9 +1933,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1944,9 +1933,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return new DynamicInvocationResolveResult(target, DynamicInvocationType.Invocation, AddArgumentNamesIfNecessary(arguments, argumentNames));
}
bool isDynamic = arguments.Any(a => a.Type.Kind == TypeKind.Dynamic);
MethodGroupResolveResult mgrr = target as MethodGroupResolveResult;
if (mgrr != null) {
if (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic)) {
if (isDynamic) {
// If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable method.
var or2 = CreateOverloadResolution(arguments, argumentNames, mgrr.TypeArguments.ToArray());
var applicableMethods = mgrr.MethodsGroupedByDeclaringType.SelectMany(m => m, (x, m) => new { x.DeclaringType, Method = m }).Where(x => OverloadResolution.IsApplicable(or2.AddCandidate(x.Method))).ToList();
@ -1971,9 +1961,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1971,9 +1961,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
OverloadResolution or = mgrr.PerformOverloadResolution(compilation, arguments, argumentNames, checkForOverflow: checkForOverflow, conversions: conversions, allowOptionalParameters: allowOptionalParameters);
if (or.BestCandidate != null) {
if (or.BestCandidate.IsStatic && !or.IsExtensionMethodInvocation && !(mgrr.TargetResult is TypeResolveResult))
return or.CreateResolveResult(new TypeResolveResult(mgrr.TargetType));
return or.CreateResolveResult(new TypeResolveResult(mgrr.TargetType), returnTypeOverride: isDynamic ? SpecialType.Dynamic : null);
else
return or.CreateResolveResult(mgrr.TargetResult);
return or.CreateResolveResult(mgrr.TargetResult, returnTypeOverride: isDynamic ? SpecialType.Dynamic : null);
} else {
// No candidate found at all (not even an inapplicable one).
// This can happen with empty method groups (as sometimes used with extension methods)
@ -1998,7 +1988,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1998,7 +1988,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
or.GetArgumentsWithConversionsAndNames(), or.BestCandidateErrors,
isExpandedForm: or.BestCandidateIsExpandedForm,
isDelegateInvocation: true,
argumentToParameterMap: or.GetArgumentToParameterMap());
argumentToParameterMap: or.GetArgumentToParameterMap(),
returnTypeOverride: isDynamic ? SpecialType.Dynamic : null);
}
return ErrorResult;
}
@ -2320,7 +2311,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2320,7 +2311,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (!c.IsValid) {
var opTrue = input.Type.GetMethods(m => m.IsOperator && m.Name == "op_True").FirstOrDefault();
if (opTrue != null) {
c = Conversion.UserDefinedImplicitConversion(opTrue, false);
c = Conversion.UserDefinedConversion(opTrue, isImplicit: true);
}
}
return Convert(input, boolean, c);
@ -2340,7 +2331,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2340,7 +2331,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (!c.IsValid) {
var opFalse = input.Type.GetMethods(m => m.IsOperator && m.Name == "op_False").FirstOrDefault();
if (opFalse != null) {
c = Conversion.UserDefinedImplicitConversion(opFalse, false);
c = Conversion.UserDefinedConversion(opFalse, isImplicit: true);
return Convert(input, boolean, c);
}
}

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

@ -101,16 +101,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -101,16 +101,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
this.Member = member;
this.IsExpandedForm = isExpanded;
IMethod method = member as IMethod;
if (method != null && method.TypeParameters.Count > 0) {
// For generic methods, go back to the original parameters
// (without any type parameter substitution, not even class type parameters)
// We'll re-substitute them as part of RunTypeInference().
method = (IMethod)method.MemberDefinition;
this.Parameters = method.Parameters;
this.TypeParameters = method.TypeParameters;
} else {
this.Parameters = member.Parameters;
IParameterizedMember memberDefinition = (IParameterizedMember)member.MemberDefinition;
// For specificialized methods, go back to the original parameters:
// (without any type parameter substitution, not even class type parameters)
// We'll re-substitute them as part of RunTypeInference().
this.Parameters = memberDefinition.Parameters;
IMethod methodDefinition = memberDefinition as IMethod;
if (methodDefinition != null && methodDefinition.TypeParameters.Count > 0) {
this.TypeParameters = methodDefinition.TypeParameters;
}
this.ParameterTypes = new IType[this.Parameters.Count];
}
@ -251,7 +249,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -251,7 +249,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// <returns>True if the calculation was successful, false if the candidate should be removed without reporting an error</returns>
bool CalculateCandidate(Candidate candidate)
{
if (!ResolveParameterTypes(candidate))
if (!ResolveParameterTypes(candidate, false))
return false;
MapCorrespondingParameters(candidate);
RunTypeInference(candidate);
@ -260,10 +258,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -260,10 +258,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return true;
}
bool ResolveParameterTypes(Candidate candidate)
bool ResolveParameterTypes(Candidate candidate, bool useSpecializedParameters)
{
for (int i = 0; i < candidate.Parameters.Count; i++) {
IType type = candidate.Parameters[i].Type;
IType type;
if (useSpecializedParameters) {
// Use the parameter type of the specialized non-generic method or indexer
Debug.Assert(!candidate.IsGenericMethod);
type = candidate.Member.Parameters[i].Type;
} else {
// Use the type of the original formal parameter
type = candidate.Parameters[i].Type;
}
if (candidate.IsExpandedForm && i == candidate.Parameters.Count - 1) {
ArrayType arrayType = type as ArrayType;
if (arrayType != null && arrayType.Dimensions == 1)
@ -372,12 +378,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -372,12 +378,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region RunTypeInference
void RunTypeInference(Candidate candidate)
{
IMethod method = candidate.Member as IMethod;
if (method == null || method.TypeParameters.Count == 0) {
if (candidate.TypeParameters == null) {
if (explicitlyGivenTypeArguments != null) {
// method does not expect type arguments, but was given some
candidate.AddError(OverloadResolutionErrors.WrongNumberOfTypeArguments);
}
// Grab new parameter types:
ResolveParameterTypes(candidate, true);
return;
}
ParameterizedType parameterizedDeclaringType = candidate.Member.DeclaringType as ParameterizedType;
@ -389,12 +396,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -389,12 +396,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
// The method is generic:
if (explicitlyGivenTypeArguments != null) {
if (explicitlyGivenTypeArguments.Length == method.TypeParameters.Count) {
if (explicitlyGivenTypeArguments.Length == candidate.TypeParameters.Count) {
candidate.InferredTypes = explicitlyGivenTypeArguments;
} else {
candidate.AddError(OverloadResolutionErrors.WrongNumberOfTypeArguments);
// wrong number of type arguments given, so truncate the list or pad with UnknownType
candidate.InferredTypes = new IType[method.TypeParameters.Count];
candidate.InferredTypes = new IType[candidate.TypeParameters.Count];
for (int i = 0; i < candidate.InferredTypes.Length; i++) {
if (i < explicitlyGivenTypeArguments.Length)
candidate.InferredTypes[i] = explicitlyGivenTypeArguments[i];
@ -585,7 +592,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -585,7 +592,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (!(c == Conversion.IdentityConversion || c == Conversion.ImplicitReferenceConversion || c == Conversion.BoxingConversion))
candidate.AddError(OverloadResolutionErrors.ArgumentTypeMismatch);
} else {
if (!c.IsValid && parameterType.Kind != TypeKind.Unknown)
if ((!c.IsValid && !c.IsUserDefined && !c.IsMethodGroupConversion) && parameterType.Kind != TypeKind.Unknown)
candidate.AddError(OverloadResolutionErrors.ArgumentTypeMismatch);
}
}
@ -933,8 +940,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -933,8 +940,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// <param name="initializerStatements">
/// Statements for Objects/Collections initializer.
/// <see cref="InvocationResolveResult.InitializerStatements"/>
/// <param name="returnTypeOverride">
/// If not null, use this instead of the ReturnType of the member as the type of the created resolve result.
/// </param>
/// </param>
public CSharpInvocationResolveResult CreateResolveResult(ResolveResult targetResolveResult, IList<ResolveResult> initializerStatements = null)
public CSharpInvocationResolveResult CreateResolveResult(ResolveResult targetResolveResult, IList<ResolveResult> initializerStatements = null, IType returnTypeOverride = null)
{
IParameterizedMember member = GetBestCandidateWithSubstitutedTypeArguments();
if (member == null)
@ -949,7 +959,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -949,7 +959,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
this.BestCandidateIsExpandedForm,
isDelegateInvocation: false,
argumentToParameterMap: this.GetArgumentToParameterMap(),
initializerStatements: initializerStatements);
initializerStatements: initializerStatements,
returnTypeOverride: returnTypeOverride);
}
#endregion
}

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

@ -624,6 +624,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -624,6 +624,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
tp.LowerBounds.Add(U);
return;
}
// Handle nullable covariance:
if (NullableType.IsNullable(U) && NullableType.IsNullable(V)) {
MakeLowerBoundInference(NullableType.GetUnderlyingType(U), NullableType.GetUnderlyingType(V));
return;
}
// Handle array types:
ArrayType arrU = U as ArrayType;
@ -857,10 +862,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -857,10 +862,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
.Where(c => lowerBounds.All(b => conversions.ImplicitConversion(b, c).IsValid))
.Where(c => upperBounds.All(b => conversions.ImplicitConversion(c, b).IsValid))
.ToList(); // evaluate the query only once
Log.WriteCollection("FindTypesInBound, Candidates=", candidateTypes);
// According to the C# specification, we need to pick the most specific
// of the candidate types. (the type which has conversions to all others)
// However, csc actually seems to choose the least specific.
candidateTypes = candidateTypes.Where(
c => candidateTypes.All(o => conversions.ImplicitConversion(c, o).IsValid)
c => candidateTypes.All(o => conversions.ImplicitConversion(o, c).IsValid)
).ToList();
// If the specified algorithm produces a single candidate, we return
// that candidate.
// We also return the whole candidate list if we're not using the improved
@ -916,8 +927,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -916,8 +927,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
Log.WriteLine("Candidate type: " + candidate);
if (lowerBounds.Count > 0) {
// if there were lower bounds, we aim for the most specific candidate:
if (upperBounds.Count == 0) {
// if there were only lower bounds, we aim for the most specific candidate:
// if this candidate isn't made redundant by an existing, more specific candidate:
if (!candidateTypes.Any(c => c.GetDefinition().IsDerivedFrom(candidateDef))) {
@ -927,7 +938,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -927,7 +938,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
candidateTypes.Add(candidate);
}
} else {
// if there only were upper bounds, we aim for the least specific candidate:
// if there were upper bounds, we aim for the least specific candidate:
// if this candidate isn't made redundant by an existing, less specific candidate:
if (!candidateTypes.Any(c => candidateDef.IsDerivedFrom(c.GetDefinition()))) {

37
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ConvertToInitializer/ConvertToInitializerTests.cs

@ -35,7 +35,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -35,7 +35,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
{
// TODO: Remove this when the formatter handles object and collection initializers
// This tests the expected code vs the actual code based on their ASTs instead of the text they produce.
public new void Test<T>(string input, string output, int action = 0, bool expectErrors = false)
public new void Test<T>(string input, string output, int action = 0, bool expectErrors = false)
where T : ICodeActionProvider, new ()
{
string result = RunContextAction(new T(), HomogenizeEol(input), action, expectErrors);
@ -664,6 +664,41 @@ class TestClass @@ -664,6 +664,41 @@ class TestClass
}
}");
}
[Test]
public void DoesNotCrashOnVariableDeclarationWithoutInitializer()
{
TestWrongContext<ConvertToInitializerAction>(@"
class TestClass
{
void F()
{
TestClass $s1 = new TestClass();
TestClass s2;
}
}");
}
[Test]
public void DoesNotCrashOnDelegateAssignment()
{
TestWrongContext<ConvertToInitializerAction>(@"
using System;
using System.Collections.Generic;
class TestClass {
void F() {
((CheckBox)ControlDictionary[""ReplaceCheckBox""]).CheckedChanged = new E$ventHandler(ReplaceCheckBox_CheckedChanged);
}
Dictionary<string, Control> ControlDictionary;
void ReplaceCheckBox_CheckedChanged(object sender, EventArgs e) {}
}
class Control {}
class CheckBox : Control {
public EventHandler CheckedChanged;
}
");
}
}
}

27
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionAccessibleTests.cs

@ -1517,7 +1517,7 @@ class Test @@ -1517,7 +1517,7 @@ class Test
Assert.IsNull (provider.Find ("TestMethod"), "'TestMethod' found.");
});
}
[Test]
public void TestVariableHiding ()
{
@ -1537,5 +1537,30 @@ class Test @@ -1537,5 +1537,30 @@ class Test
Assert.AreEqual (1, provider.Data.Count (p => p.DisplayText == "test"));
});
}
[Test]
public void TestOverloadCount ()
{
CodeCompletionBugTests.CombinedProviderTest (@"
using System;
class Test
{
static void Foo () {}
static void Foo (int i) {}
static void Foo (int i, string s) {}
public static void Main (int test)
{
$f$
}
}
", provider => {
Assert.AreEqual (1, provider.Data.Count (p => p.DisplayText == "Foo"));
var data = provider.Find ("Foo");
Assert.AreEqual (3, data.OverloadedData.Count ());
});
}
}
}

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

@ -138,6 +138,27 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion @@ -138,6 +138,27 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
}
}
public class EntityCompletionData : CompletionData, IEntityCompletionData
{
#region IEntityCompletionData implementation
public IEntity Entity {
get;
private set;
}
#endregion
public EntityCompletionData(IEntity entity) : this(entity, entity.Name)
{
}
public EntityCompletionData(IEntity entity, string txt) : base(txt)
{
this.Entity = entity;
}
}
public class ImportCompletionData : CompletionData
{
public IType Type {
@ -160,7 +181,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion @@ -160,7 +181,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
#region ICompletionDataFactory implementation
public ICompletionData CreateEntityCompletionData (ICSharpCode.NRefactory.TypeSystem.IEntity entity)
{
return new CompletionData (entity.Name);
return new EntityCompletionData (entity);
}
public ICompletionData CreateEntityCompletionData (ICSharpCode.NRefactory.TypeSystem.IEntity entity, string text)
@ -185,7 +206,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion @@ -185,7 +206,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
public ICompletionData CreateMemberCompletionData(IType type, IEntity member)
{
string name = builder.ConvertType(type).GetText();
return new CompletionData (name + "."+ member.Name);
return new EntityCompletionData (member, name + "."+ member.Name);
}

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

@ -262,13 +262,13 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion @@ -262,13 +262,13 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
};
}
public IParameterDataProvider CreateIndexerParameterDataProvider(int startOffset, IType type, AstNode resolvedNode)
public IParameterDataProvider CreateIndexerParameterDataProvider(int startOffset, IType type, IEnumerable<IProperty> accessibleIndexers, AstNode resolvedNode)
{
Assert.IsTrue(type.Kind != TypeKind.Unknown);
if (type.Kind == TypeKind.Array)
return new ArrayProvider ();
return new IndexerProvider () {
Data = type.GetProperties (p => p.IsIndexer)
Data = accessibleIndexers
};
}
@ -1040,7 +1040,7 @@ class TestClass @@ -1040,7 +1040,7 @@ class TestClass
Assert.IsTrue (provider == null || provider.Count == 0);
}
[Test()]
[Test]
public void TestJaggedArrayCreationCase2()
{
IParameterDataProvider provider = CreateProvider(
@ -1057,5 +1057,78 @@ class TestClass @@ -1057,5 +1057,78 @@ class TestClass
Assert.IsTrue (provider == null || provider.Count == 0);
}
/// <summary>
/// Bug 9301 - Inaccessible indexer overload in completion
/// </summary>
[Test]
public void TestBug9301()
{
IParameterDataProvider provider = CreateProvider(
@"using System;
public class A
{
public virtual int this [int i, string s] {
get {
return 1;
}
}
}
public class B : A
{
public new bool this [int i, string s2] {
get {
return true;
}
}
}
public class Test
{
public static int Main ()
{
B p = new B ();
$p[$
return 0;
}
}
");
Assert.AreEqual (1, provider.Count);
}
[Test]
public void TestBug9301Case2()
{
IParameterDataProvider provider = CreateProvider(
@"using System;
public class A
{
public virtual int Test (int i, string s) {
return 1;
}
}
public class B : A
{
public new bool Test (int i, string s2) {
return true;
}
}
public class Test
{
public static int Main ()
{
B p = new B ();
$p.Test($
return 0;
}
}
");
Assert.AreEqual (1, provider.Count);
}
}
}

19
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/CallToVirtualFunctionFromConstructorTests.cs

@ -105,6 +105,25 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues @@ -105,6 +105,25 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues
f.Bar();
}
virtual void Bar ()
{
}
}";
TestRefactoringContext context;
var issues = GetIssues(new CallToVirtualFunctionFromConstructorIssue(), input, out context);
Assert.AreEqual(0, issues.Count);
}
[Test]
public void IgnoresEventHandlers()
{
var input = @"class Foo
{
Foo()
{
SomeEvent += delegate { Bar(); };
}
virtual void Bar ()
{
}

33
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/NegativeRelationalExpressionIssueTests.cs

@ -100,6 +100,39 @@ class TestClass @@ -100,6 +100,39 @@ class TestClass
{
var x = !(d > 0.1);
}
}";
Test<NegativeRelationalExpressionIssue> (input, 0);
}
[Test]
public void TestFloatingPointEquality ()
{
var input = @"
class TestClass
{
void TestMethod (double d)
{
var x = !(d == 0.1);
}
}";
Test<NegativeRelationalExpressionIssue> (input, 1);
}
[Test]
public void TestUserDefinedOperator ()
{
var input = @"
struct LineChangeInfo
{
public static bool operator ==(LineChangeInfo lhs, LineChangeInfo rhs)
{
return lhs.Equals(rhs);
}
public static bool operator !=(LineChangeInfo lhs, LineChangeInfo rhs)
{
return !(lhs == rhs);
}
}";
Test<NegativeRelationalExpressionIssue> (input, 0);
}

48
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ParameterNotUsedIssueTests.cs

@ -44,6 +44,19 @@ class TestClass { @@ -44,6 +44,19 @@ class TestClass {
Test<ParameterNotUsedIssue> (input, 1);
}
[Test]
public void TestUnusedParameterMethodGetsCalled ()
{
var input = @"
class TestClass {
void TestMethod (int i)
{
TestMethod(0);
}
}";
Test<ParameterNotUsedIssue> (input, 1);
}
[Test]
public void TestInterfaceImplementation ()
{
@ -130,5 +143,40 @@ class TestClass { @@ -130,5 +143,40 @@ class TestClass {
}";
Test<ParameterNotUsedIssue> (input, 0);
}
[Test]
public void TestMethodLooksLikeEventHandlerButNotUsedAsSuch ()
{
var input = @"using System;
class TestClass {
void FooBar (object sender, EventArgs e) {}
}";
Test<ParameterNotUsedIssue> (input, 2);
}
[Test]
public void TestMethodUsedAsDelegateInOtherPart ()
{
// This test doesn't add the second part;
// but the issue doesn't look at other files after all;
// we just rely on heuristics if the class is partial
var input = @"using System;
partial class TestClass {
void FooBar (object sender, EventArgs e) {}
}";
Test<ParameterNotUsedIssue> (input, 0);
}
[Test]
public void UnusedParameterInConstructor()
{
var input = @"
class TestClass {
public TestClass(int i)
{
}
}";
Test<ParameterNotUsedIssue> (input, 1);
}
}
}

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

@ -831,5 +831,425 @@ class Test { @@ -831,5 +831,425 @@ class Test {
Assert.IsTrue(c.IsMethodGroupConversion);
Assert.AreEqual("System.Object", c.Method.Parameters.Single().Type.FullName);
}
[Test]
public void UserDefined_IntLiteral_ViaUInt_ToCustomStruct()
{
string program = @"using System;
struct T {
public static implicit operator T(uint a) { return new T(); }
}
class Test {
static void M() {
T t = $1$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
}
[Test]
public void UserDefined_NullLiteral_ViaString_ToCustomStruct()
{
string program = @"using System;
struct T {
public static implicit operator T(string a) { return new T(); }
}
class Test {
static void M() {
T t = $null$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
}
[Test]
public void UserDefined_CanUseLiftedEvenIfReturnTypeAlreadyNullable()
{
string program = @"using System;
struct S {
public static implicit operator short?(S s) { return 0; }
}
class Test {
static void M(S? s) {
int? i = $s$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
Assert.IsTrue(c.IsLifted);
}
[Test]
public void UserDefinedImplicitConversion_PicksExactSourceTypeIfPossible() {
string program = @"using System;
class Convertible {
public static implicit operator Convertible(int i) {return new Convertible(); }
public static implicit operator Convertible(short s) {return new Convertible(); }
}
class Test {
public void M() {
Convertible a = $33$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
Assert.AreEqual("i", c.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedImplicitConversion_PicksMostEncompassedSourceType() {
string program = @"using System;
class Convertible {
public static implicit operator Convertible(long l) {return new Convertible(); }
public static implicit operator Convertible(uint ui) {return new Convertible(); }
}
class Test {
public void M() {
Convertible a = $(ushort)33$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
Assert.AreEqual("ui", c.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedImplicitConversion_NoMostEncompassedSourceTypeIsInvalid() {
string program = @"using System;
class Convertible {
public static implicit operator Convertible(ulong l) {return new Convertible(); }
public static implicit operator Convertible(int ui) {return new Convertible(); }
}
class Test {
public void M() {
Convertible a = $(ushort)33$;
}
}";
var c = GetConversion(program);
Assert.IsFalse(c.IsValid);
}
[Test]
public void UserDefinedImplicitConversion_PicksExactTargetTypeIfPossible() {
string program = @"using System;
class Convertible {
public static implicit operator int(Convertible i) {return 0; }
public static implicit operator short(Convertible s) {return 0; }
}
class Test {
public void M() {
int a = $new Convertible()$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
Assert.AreEqual("i", c.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedImplicitConversion_PicksMostEncompassingTargetType() {
string program = @"using System;
class Convertible {
public static implicit operator int(Convertible i) {return 0; }
public static implicit operator ushort(Convertible us) {return 0; }
}
class Test {
public void M() {
ulong a = $new Convertible()$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
Assert.AreEqual("us", c.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedImplicitConversion_NoMostEncompassingTargetTypeIsInvalid() {
string program = @"using System;
class Convertible {
public static implicit operator uint(Convertible i) {return 0; }
public static implicit operator short(Convertible us) {return 0; }
}
class Test {
public void M() {
long a = $new Convertible()$;
}
}";
var c = GetConversion(program);
Assert.IsFalse(c.IsValid);
}
[Test]
public void UserDefinedImplicitConversion_AmbiguousIsInvalid() {
string program = @"using System;
class Convertible1 {
public static implicit operator Convertible2(Convertible1 c) {return 0; }
}
class Convertible2 {
public static implicit operator Convertible2(Convertible1 c) {return 0; }
}
class Test {
public void M() {
Convertible2 a = $new Convertible1()$;
}
}";
var c = GetConversion(program);
Assert.IsFalse(c.IsValid);
}
[Test]
public void UserDefinedImplicitConversion_DefinedNullableTakesPrecedenceOverLifted() {
string program = @"using System;
struct Convertible {
public static implicit operator Convertible(int i) {return new Convertible(); }
public static implicit operator Convertible?(int? ni) {return new Convertible(); }
}
class Test {
public void M() {
Convertible? a = $(int?)33$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
Assert.IsFalse(c.IsLifted);
Assert.AreEqual("ni", c.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedImplicitConversion_UIntConstant() {
string program = @"using System;
class Convertible {
public static implicit operator Convertible(long l) {return new Convertible(); }
public static implicit operator Convertible(uint ui) {return new Convertible(); }
}
class Test {
public void M() {
Convertible a = $33$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
Assert.AreEqual("ui", c.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedImplicitConversion_NullableUIntConstant() {
string program = @"using System;
class Convertible {
public static implicit operator Convertible(long? l) {return new Convertible(); }
public static implicit operator Convertible(uint? ui) {return new Convertible(); }
}
class Test {
public void M() {
Convertible a = $33$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
Assert.AreEqual("ui", c.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedImplicitConversion_UseShortResult_BecauseNullableCannotBeUnpacked()
{
string program = @"using System;
class Test {
public static implicit operator int?(Test i) { return 0; }
public static implicit operator short(Test s) { return 0; }
}
class Program {
public static void Main(string[] args)
{
int x = $new Test()$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
Assert.AreEqual("System.Int16", c.Method.ReturnType.FullName);
}
[Test]
public void UserDefinedImplicitConversion_Short_Or_NullableByte_Target()
{
string program = @"using System;
class Test {
public static implicit operator short(Test s) { return 0; }
public static implicit operator byte?(Test b) { return 0; }
}
class Program {
public static void Main(string[] args)
{
int? x = $new Test()$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
Assert.AreEqual("System.Int16", c.Method.ReturnType.FullName);
}
[Test]
public void UserDefinedImplicitConversion_Byte_Or_NullableShort_Target()
{
string program = @"using System;
class Test {
public static implicit operator byte(Test b) { return 0; }
public static implicit operator short?(Test s) { return 0; }
}
class Program {
public static void Main(string[] args)
{
int? x = $new Test()$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
Assert.AreEqual("s", c.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedImplicitConversion_Int_Or_NullableLong_Source()
{
string program = @"using System;
class Test {
public static implicit operator Test(int i) { return new Test(); }
public static implicit operator Test(long? l) { return new Test(); }
}
class Program {
static void Main() {
short s = 0;
Test t = $s$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
Assert.AreEqual("i", c.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedImplicitConversion_NullableInt_Or_Long_Source()
{
string program = @"using System;
class Test {
public static implicit operator Test(int? i) { return new Test(); }
public static implicit operator Test(long l) { return new Test(); }
}
class Program {
static void Main() {
short s = 0;
Test t = $s$;
}
}";
var c = GetConversion(program);
Assert.IsFalse(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
}
[Test]
public void UserDefinedImplicitConversion_NullableInt_Or_Long_Constant_Source() {
string program = @"using System;
class Test {
public static implicit operator Test(int? i) { return new Test(); }
public static implicit operator Test(long l) { return new Test(); }
}
class Program {
static void Main() {
Test t = $1$;
}
}";
var c = GetConversion(program);
Assert.IsFalse(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
}
[Test]
public void UserDefinedImplicitConversion_NullableInt_Or_NullableLong_Source()
{
string program = @"using System;
class Test {
public static implicit operator Test(int? i) { return new Test(); }
public static implicit operator Test(long? l) { return new Test(); }
}
class Program {
static void Main() {
short s = 0;
Test t = $s$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Assert.IsTrue(c.IsUserDefined);
Assert.AreEqual("i", c.Method.Parameters[0].Name);
}
[Test]
public void PreferUserDefinedConversionOverReferenceConversion()
{
// actually this is not because user-defined conversions are better;
// but because string is a better conversion target
string program = @"
class AA {
public static implicit operator string(AA a) { return null; }
}
class Test {
static void M(object obj) {}
static void M(string str) {}
static void Main() {
$M(new AA())$;
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.AreEqual("str", rr.Member.Parameters[0].Name);
}
[Test]
public void PreferAmbiguousConversionOverReferenceConversion()
{
// Ambiguous conversions are a compiler error; but they are not
// preventing the overload from being chosen.
// The user-defined conversion wins because BB is a better conversion target than object.
string program = @"
class AA {
public static implicit operator BB(AA a) { return null; }
}
class BB {
public static implicit operator BB(AA a) { return null; }
}
class Test {
static void M(BB b) {}
static void M(object o) {}
static void Main() {
M($new AA()$);
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsUserDefined);
Assert.IsFalse(c.IsValid);
}
}
}

32
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/DynamicTests.cs

@ -110,8 +110,8 @@ class TestClass { @@ -110,8 +110,8 @@ class TestClass {
public void InvocationWithDynamicArgumentWithOneApplicableMethod() {
string program = @"using System;
class TestClass {
public void SomeMethod(int a) {}
public void SomeMethod(int a, string b) {}
public int SomeMethod(int a) {}
public int SomeMethod(int a, string b) {}
void F() {
dynamic obj = null;
@ -119,7 +119,9 @@ class TestClass { @@ -119,7 +119,9 @@ class TestClass {
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr, Is.Not.Null);
Assert.That(rr.Member.Name, Is.EqualTo("SomeMethod"));
Assert.That(rr.Type.Kind == TypeKind.Dynamic);
Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
var cr = rr.Arguments[0] as ConversionResolveResult;
@ -129,6 +131,30 @@ class TestClass { @@ -129,6 +131,30 @@ class TestClass {
Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj");
}
[Test]
public void InvocationWithDynamicArgumentWithOneApplicableMethodReturningVoid() {
string program = @"using System;
class TestClass {
public void SomeMethod(int a) {}
void F() {
dynamic obj = null;
var x = $this.SomeMethod(obj)$;
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.IsError, Is.False);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.Member.Name, Is.EqualTo("SomeMethod"));
Assert.That(rr.Member.Parameters.Count, Is.EqualTo(1));
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
var cr = rr.Arguments[0] as ConversionResolveResult;
Assert.That(cr, Is.Not.Null);
Assert.That(cr.Conversion.IsImplicit, Is.True);
Assert.That(cr.Conversion.IsDynamicConversion, Is.True);
Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj");
}
[Test]
public void InvocationWithDynamicArgumentWhenBothAnOwnAndABaseMethodAreApplicable() {
string program = @"using System;
@ -286,7 +312,7 @@ class TestClass { @@ -286,7 +312,7 @@ class TestClass {
var x = $this.SomeMethod(obj)$;
}
}";
var rr = Resolve(program);
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.That(rr.IsError, Is.True);
}

344
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExplicitConversionsTest.cs

@ -509,7 +509,6 @@ class C { @@ -509,7 +509,6 @@ class C {
}
[Test]
[Ignore("Not implemented yet.")]
public void BothDirectConversionAndBaseClassConversionAvailable()
{
var rr = Resolve<ConversionResolveResult>(@"
@ -528,5 +527,348 @@ class C { @@ -528,5 +527,348 @@ class C {
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.AreEqual("b", rr.Conversion.Method.Parameters.Single().Name);
}
[Test]
public void UserDefinedExplicitConversion_PicksExactSourceTypeIfPossible() {
string program = @"using System;
class Convertible {
public static explicit operator Convertible(int i) {return new Convertible(); }
public static explicit operator Convertible(short s) {return new Convertible(); }
}
class Test {
public void M() {
var a = $(Convertible)33$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsValid);
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.AreEqual("i", rr.Conversion.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedExplicitConversion_PicksMostEncompassedSourceTypeIfPossible() {
string program = @"using System;
class Convertible {
public static explicit operator Convertible(long l) {return new Convertible(); }
public static explicit operator Convertible(uint ui) {return new Convertible(); }
}
class Test {
public void M() {
var a = $(Convertible)(ushort)33$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsValid);
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.AreEqual("ui", rr.Conversion.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedExplicitConversion_PicksMostEncompassingSourceType() {
string program = @"using System;
class Convertible {
public static explicit operator Convertible(int i) {return new Convertible(); }
public static explicit operator Convertible(ushort us) {return new Convertible(); }
}
class Test {
public void M() {
var a = $(Convertible)(long)33$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsValid);
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.AreEqual("i", rr.Conversion.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedExplicitConversion_NoMostEncompassingSourceTypeIsInvalid() {
string program = @"using System;
class Convertible {
public static explicit operator Convertible(uint i) {return new Convertible(); }
public static explicit operator Convertible(short us) {return new Convertible(); }
}
class Test {
public void M() {
var a = $(Convertible)(long)33$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsFalse(rr.Conversion.IsValid);
}
[Test]
public void UserDefinedExplicitConversion_PicksExactTargetTypeIfPossible() {
string program = @"using System;
class Convertible {
public static explicit operator int(Convertible i) {return 0; }
public static explicit operator short(Convertible s) {return 0; }
}
class Test {
public void M() {
var a = $(int)new Convertible()$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsValid);
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.AreEqual("i", rr.Conversion.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedExplicitConversion_PicksMostEncompassingTargetTypeIfPossible() {
string program = @"using System;
class Convertible {
public static explicit operator int(Convertible i) {return 0; }
public static explicit operator ushort(Convertible us) {return 0; }
}
class Test {
public void M() {
var a = $(ulong)new Convertible()$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsValid);
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.AreEqual("us", rr.Conversion.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedExplicitConversion_PicksMostEncompassedTargetType() {
string program = @"using System;
class Convertible {
public static explicit operator long(Convertible l) { return 0; }
public static explicit operator uint(Convertible ui) { return 0; }
}
class Test {
public void M() {
var a = $(ushort)new Convertible()$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsValid);
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.AreEqual("ui", rr.Conversion.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedExplicitConversion_NoMostEncompassedTargetTypeIsInvalid() {
string program = @"using System;
class Convertible {
public static explicit operator ulong(Convertible l) { return 0; }
public static explicit operator int(Convertible ui) { return 0; }
}
class Test {
public void M() {
var a = $(ushort)new Convertible()$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsFalse(rr.Conversion.IsValid);
}
[Test]
public void UserDefinedExplicitConversion_AmbiguousIsInvalid() {
string program = @"using System;
class Convertible1 {
public static explicit operator Convertible2(Convertible1 c) {return 0; }
}
class Convertible2 {
public static explicit operator Convertible2(Convertible1 c) {return 0; }
}
class Test {
public void M() {
var a = $(Convertible2)new Convertible1()$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsFalse(rr.Conversion.IsValid);
}
[Test]
public void UserDefinedExplicitConversion_Lifted() {
string program = @"using System;
struct Convertible {
public static explicit operator Convertible(int i) {return new Convertible(); }
}
class Test {
public void M(int? i) {
a = $(Convertible?)i$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsValid);
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.IsTrue(rr.Conversion.IsLifted);
}
[Test]
public void UserDefinedExplicitConversionFollowedByImplicitNullableConversion() {
string program = @"using System;
struct Convertible {
public static explicit operator Convertible(int i) {return new Convertible(); }
}
class Test {
public void M(int i) {
a = $(Convertible?)i$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsValid);
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.IsFalse(rr.Conversion.IsLifted);
}
[Test]
public void UserDefinedExplicitConversion_ExplicitNullable_ThenUserDefined() {
string program = @"using System;
struct Convertible {
public static explicit operator Convertible(int i) {return new Convertible(); }
public static explicit operator Convertible?(int? ni) {return new Convertible(); }
}
class Test {
public void M(int? i) {
a = $(Convertible)i$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsValid);
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.IsFalse(rr.Conversion.IsLifted);
Assert.AreEqual("i", rr.Conversion.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedExplicitConversion_DefinedNullableTakesPrecedenceOverLifted() {
string program = @"using System;
struct Convertible {
public static explicit operator Convertible(int i) {return new Convertible(); }
public static explicit operator Convertible?(int? ni) {return new Convertible(); }
}
class Test {
public void M() {
a = $(Convertible?)(int?)33$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsValid);
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.IsFalse(rr.Conversion.IsLifted);
Assert.AreEqual("ni", rr.Conversion.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedExplicitConversion_UIntConstant() {
string program = @"using System;
class Convertible {
public static explicit operator Convertible(long l) {return new Convertible(); }
public static explicit operator Convertible(uint ui) {return new Convertible(); }
}
class Test {
public void M() {
var a = $(Convertible)33$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsValid);
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.AreEqual("ui", rr.Conversion.Method.Parameters[0].Name);
}
[Test]
public void UserDefinedExplicitConversion_NullableUIntConstant() {
string program = @"using System;
class Convertible {
public static explicit operator Convertible(long? l) {return new Convertible(); }
public static explicit operator Convertible(uint? ui) {return new Convertible(); }
}
class Test {
public void M() {
Convertible a = $(Convertible)33$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsValid);
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.AreEqual("ui", rr.Conversion.Method.Parameters[0].Name);
}
[Test]
public void UseDefinedExplicitConversion_Lifted() {
string program = @"
struct Convertible {
public static explicit operator Convertible(int i) { return new Convertible(); }
}
class Test {
public void M(int? i) {
a = $(Convertible?)i$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsValid);
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.IsTrue(rr.Conversion.IsLifted);
Assert.IsTrue(rr.Input is LocalResolveResult);
}
[Test]
public void UserDefinedExplicitConversion_Short_Or_NullableByte_Target()
{
string program = @"using System;
class Test {
public static explicit operator short(Test s) { return 0; }
public static explicit operator byte?(Test b) { return 0; }
}
class Program {
public static void Main(string[] args)
{
int? x = $(int?)new Test()$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsValid);
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.AreEqual("System.Int16", rr.Conversion.Method.ReturnType.FullName);
}
[Test]
public void UserDefinedExplicitConversion_Byte_Or_NullableShort_Target()
{
string program = @"using System;
class Test {
public static explicit operator byte(Test b) { return 0; }
public static explicit operator short?(Test s) { return 0; }
}
class Program {
public static void Main(string[] args)
{
int? x = $(int?)new Test()$;
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsValid);
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.AreEqual("s", rr.Conversion.Method.Parameters[0].Name);
}
[Test]
public void ExplicitConversionOperatorsCanOverrideApplicableImplicitOnes()
{
string program = @"
struct Convertible {
public static explicit operator int(Convertible ci) {return 0; }
public static implicit operator short(Convertible cs) {return 0; }
}
class Test {
static void Main() {
int i = $(int)new Convertible()$; // csc uses the explicit conversion operator
}
}";
var rr = Resolve<ConversionResolveResult>(program);
Assert.IsTrue(rr.Conversion.IsValid);
Assert.IsTrue(rr.Conversion.IsUserDefined);
Assert.AreEqual("ci", rr.Conversion.Method.Parameters[0].Name);
}
}
}

63
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs

@ -735,5 +735,68 @@ public class C { @@ -735,5 +735,68 @@ public class C {
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.IsFalse(rr.IsError);
}
[Test]
public void OverloadResolutionIsAmbiguousEvenIfNotDelegateCompatible() {
string program = @"
class Test {
static void M(Func<int> o) {}
static void M(Action o) {}
static int K() { return 0; }
static void Main() {
$M(K)$;
}
}";
// K is only delegate-compatible with one of the overloads; yet we get an invalid match.
// This is because the conversion exists even though it is invalid.
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.AreEqual(OverloadResolutionErrors.AmbiguousMatch, rr.OverloadResolutionErrors);
}
[Test]
public void IndexerWithMoreSpecificParameterTypesIsPreferred()
{
string program = @"
class A {
public static void Test(B<object> b) {
x = $b[4]$;
}
}
public class B<T> {
public string this[T key] {
get { return ""1""; }
}
public int this[object key] {
get { return 2; }
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.AreEqual("System.Int32", rr.Member.ReturnType.FullName);
}
[Test]
public void MethodWithMoreSpecificParameterTypesIsPreferred()
{
string program = @"
class A {
public static void Test(B<object> b) {
$b.M(4)$;
}
}
public class B<T> {
public string M(T key) {
return ""1"";
}
public int M(object key) {
return 2;
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.AreEqual("System.Int32", rr.Member.ReturnType.FullName);
}
}
}

12
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/OverloadResolutionTests.cs

@ -89,6 +89,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -89,6 +89,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Assert.AreSame(c1, r.BestCandidate);
}
[Test]
public void PreferUIntOverLong_FromIntLiteral()
{
ResolveResult[] args = { new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), 1) };
OverloadResolution r = new OverloadResolution(compilation, args);
var c1 = MakeMethod(typeof(uint));
Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(c1));
Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeMethod(typeof(long))));
Assert.IsFalse(r.IsAmbiguous);
Assert.AreSame(c1, r.BestCandidate);
}
[Test]
public void NullableIntAndNullableUIntIsAmbiguous()
{

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

@ -21,7 +21,7 @@ using System.Collections; @@ -21,7 +21,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.CompilerServices;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
@ -30,9 +30,8 @@ using NUnit.Framework; @@ -30,9 +30,8 @@ using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
[TestFixture]
public class TypeInferenceTests
public class TypeInferenceTests : ResolverTestBase
{
readonly ICompilation compilation = new SimpleCompilation(CecilLoaderTests.Mscorlib);
TypeInference ti;
[SetUp]
@ -456,9 +455,102 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -456,9 +455,102 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public void CommonSubTypeIEnumerableClonableIEnumerableComparableList()
{
Assert.AreEqual(
Resolve(typeof(List<string>), typeof(List<Version>), typeof(Collection<string>), typeof(Collection<Version>), typeof(ReadOnlyCollection<string>), typeof(ReadOnlyCollection<Version>)),
Resolve(typeof(List<string>), typeof(List<Version>), typeof(Collection<string>), typeof(Collection<Version>),
typeof(ReadOnlyCollectionBuilder<string>), typeof(ReadOnlyCollectionBuilder<Version>),
typeof(ReadOnlyCollection<string>), typeof(ReadOnlyCollection<Version>)),
FindAllTypesInBounds(Resolve(), Resolve(typeof(IEnumerable<ICloneable>), typeof(IEnumerable<IComparable>), typeof(IList))));
}
#endregion
[Test]
public void NullablePick()
{
string program = @"
interface ICo<out T> {}
interface IContra<in T> {}
class Test
{
static T Pick<T> (T? a, T? b)
{
return a;
}
public static void Test(int? i, long? l)
{
$Pick(i, l)$;
}
}
";
var mrr = Resolve<CSharpInvocationResolveResult>(program);
Assert.AreEqual("System.Int64", mrr.Type.FullName);
Assert.IsFalse(mrr.IsError);
}
[Test]
public void CoContraPick()
{
string program = @"
interface ICo<out T> {}
interface IContra<in T> {}
class Test
{
static T Pick<T> (ICo<T> a, IContra<T> b)
{
return a;
}
public static void Test(ICo<string> i, IContra<object> l)
{
$Pick(i, l)$;
}
}
";
// String and Object are both valid choices; and csc ends up picking object,
// even though the C# specification says it should pick string:
// 7.5.2.11 Fixing - both string and object are in the candidate set;
// string has a conversion to object (the other candidate),
// object doesn't have that; so string should be chosen as the result.
// We follow the csc behavior.
var mrr = Resolve<CSharpInvocationResolveResult>(program);
Assert.AreEqual("System.Object", mrr.Type.FullName);
Assert.IsFalse(mrr.IsError);
}
/// <summary>
/// Bug 9300 - Unknown Resolve Error
/// </summary>
[Test]
public void TestBug9300()
{
string program = @"struct S
{
public static implicit operator string (S s)
{
return ""a"";
}
}
interface I<in T>
{
}
class C : I<string>
{
static T Foo<T> (T a, I<T> b)
{
return a;
}
public static void Main ()
{
S s = new S ();
I<string> i = new C ();
var result = $Foo (s, i)$;
}
}
";
var mrr = Resolve<CSharpInvocationResolveResult>(program);
Assert.AreEqual("System.String", mrr.Type.FullName);
Assert.IsFalse(mrr.IsError);
}
}
}

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

@ -370,7 +370,7 @@ @@ -370,7 +370,7 @@
<Compile Include="CSharp\CodeCompletion\ImportCompletionTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Mono.Cecil\Mono.Cecil.csproj">
<ProjectReference Include="..\..\cecil\Mono.Cecil.csproj">
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
<Name>Mono.Cecil</Name>
<Private>False</Private>

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

@ -149,6 +149,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase @@ -149,6 +149,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase
public void MethodWithOutParameter(out int x) { x = 0; }
public void MethodWithParamsArray(params object[] x) {}
public void MethodWithOptionalParameter(int x = 4) {}
public void MethodWithExplicitOptionalParameter([Optional] int x) {}
public void MethodWithEnumOptionalParameter(StringComparison x = StringComparison.OrdinalIgnoreCase) {}
}

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

@ -605,6 +605,18 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -605,6 +605,18 @@ namespace ICSharpCode.NRefactory.TypeSystem
Assert.AreEqual(0, p.Attributes.Count);
Assert.AreEqual(4, p.ConstantValue);
}
[Test]
public void MethodWithExplicitOptionalParameter()
{
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithExplicitOptionalParameter").Parameters.Single();
Assert.IsTrue(p.IsOptional);
Assert.IsFalse(p.IsRef);
Assert.IsFalse(p.IsOut);
Assert.IsFalse(p.IsParams);
// explicit optional parameter appears in type system if it's read from C#, but not when read from IL
//Assert.AreEqual(1, p.Attributes.Count);
}
[Test]
public void MethodWithEnumOptionalParameter()

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

@ -272,7 +272,7 @@ @@ -272,7 +272,7 @@
<Folder Include="Utils\CompositeFormatStringParser\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Mono.Cecil\Mono.Cecil.csproj">
<ProjectReference Include="..\..\cecil\Mono.Cecil.csproj">
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
<Name>Mono.Cecil</Name>
</ProjectReference>

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

@ -74,18 +74,27 @@ namespace ICSharpCode.NRefactory.Semantics @@ -74,18 +74,27 @@ namespace ICSharpCode.NRefactory.Semantics
/// </summary>
public static readonly Conversion TryCast = new BuiltinConversion(false, 9);
[Obsolete("Use UserDefinedConversion() instead")]
public static Conversion UserDefinedImplicitConversion(IMethod operatorMethod, bool isLifted)
{
if (operatorMethod == null)
throw new ArgumentNullException("operatorMethod");
return new UserDefinedConversion(true, operatorMethod, isLifted);
return new UserDefinedConv(true, operatorMethod, isLifted, false);
}
[Obsolete("Use UserDefinedConversion() instead")]
public static Conversion UserDefinedExplicitConversion(IMethod operatorMethod, bool isLifted)
{
if (operatorMethod == null)
throw new ArgumentNullException("operatorMethod");
return new UserDefinedConversion(false, operatorMethod, isLifted);
return new UserDefinedConv(false, operatorMethod, isLifted, false);
}
public static Conversion UserDefinedConversion(IMethod operatorMethod, bool isImplicit, bool isLifted = false, bool isAmbiguous = false)
{
if (operatorMethod == null)
throw new ArgumentNullException("operatorMethod");
return new UserDefinedConv(isImplicit, operatorMethod, isLifted, isAmbiguous);
}
public static Conversion MethodGroupConversion(IMethod chosenMethod, bool isVirtualMethodLookup)
@ -262,17 +271,23 @@ namespace ICSharpCode.NRefactory.Semantics @@ -262,17 +271,23 @@ namespace ICSharpCode.NRefactory.Semantics
}
}
sealed class UserDefinedConversion : Conversion
sealed class UserDefinedConv : Conversion
{
readonly IMethod method;
readonly bool isLifted;
readonly bool isImplicit;
readonly bool isValid;
public UserDefinedConversion(bool isImplicit, IMethod method, bool isLifted)
public UserDefinedConv(bool isImplicit, IMethod method, bool isLifted, bool isAmbiguous)
{
this.method = method;
this.isLifted = isLifted;
this.isImplicit = isImplicit;
this.isValid = !isAmbiguous;
}
public override bool IsValid {
get { return isValid; }
}
public override bool IsImplicit {
@ -297,19 +312,20 @@ namespace ICSharpCode.NRefactory.Semantics @@ -297,19 +312,20 @@ namespace ICSharpCode.NRefactory.Semantics
public override bool Equals(Conversion other)
{
UserDefinedConversion o = other as UserDefinedConversion;
return o != null && isLifted == o.isLifted && isImplicit == o.isImplicit && method.Equals(o.method);
UserDefinedConv o = other as UserDefinedConv;
return o != null && isLifted == o.isLifted && isImplicit == o.isImplicit && isValid == o.isValid && method.Equals(o.method);
}
public override int GetHashCode()
{
return unchecked(method.GetHashCode() * (isLifted ? 31 : 27) * (isImplicit ? 71 : 61));
return unchecked(method.GetHashCode() + (isLifted ? 31 : 27) + (isImplicit ? 71 : 61) + (isValid ? 107 : 109));
}
public override string ToString()
{
return (isImplicit ? "implicit" : "explicit")
+ (isLifted ? " lifted" : "")
+ (isValid ? "" : " ambiguous")
+ "user-defined conversion (" + method + ")";
}
}

5
src/Libraries/NRefactory/ICSharpCode.NRefactory/Semantics/InvocationResolveResult.cs

@ -45,8 +45,9 @@ namespace ICSharpCode.NRefactory.Semantics @@ -45,8 +45,9 @@ namespace ICSharpCode.NRefactory.Semantics
public InvocationResolveResult(ResolveResult targetResult, IParameterizedMember member,
IList<ResolveResult> arguments = null,
IList<ResolveResult> initializerStatements = null)
: base(targetResult, member)
IList<ResolveResult> initializerStatements = null,
IType returnTypeOverride = null)
: base(targetResult, member, returnTypeOverride)
{
this.Arguments = arguments ?? EmptyList<ResolveResult>.Instance;
this.InitializerStatements = initializerStatements ?? EmptyList<ResolveResult>.Instance;

8
src/Libraries/NRefactory/ICSharpCode.NRefactory/Semantics/MemberResolveResult.cs

@ -38,8 +38,8 @@ namespace ICSharpCode.NRefactory.Semantics @@ -38,8 +38,8 @@ namespace ICSharpCode.NRefactory.Semantics
readonly ResolveResult targetResult;
readonly bool isVirtualCall;
public MemberResolveResult(ResolveResult targetResult, IMember member)
: base(member.EntityType == EntityType.Constructor ? member.DeclaringType : member.ReturnType)
public MemberResolveResult(ResolveResult targetResult, IMember member, IType returnTypeOverride = null)
: base(returnTypeOverride ?? (member.EntityType == EntityType.Constructor ? member.DeclaringType : member.ReturnType))
{
this.targetResult = targetResult;
this.member = member;
@ -54,8 +54,8 @@ namespace ICSharpCode.NRefactory.Semantics @@ -54,8 +54,8 @@ namespace ICSharpCode.NRefactory.Semantics
}
}
public MemberResolveResult(ResolveResult targetResult, IMember member, bool isVirtualCall)
: base(member.EntityType == EntityType.Constructor ? member.DeclaringType : member.ReturnType)
public MemberResolveResult(ResolveResult targetResult, IMember member, bool isVirtualCall, IType returnTypeOverride = null)
: base(returnTypeOverride ?? (member.EntityType == EntityType.Constructor ? member.DeclaringType : member.ReturnType))
{
this.targetResult = targetResult;
this.member = member;

11
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedParameter.cs

@ -190,6 +190,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -190,6 +190,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
return b.ToString();
}
static bool IsOptionalAttribute (IType attributeType)
{
return attributeType.Name == "OptionalAttribute" && attributeType.Namespace == "System.Runtime.InteropServices";
}
public IParameter CreateResolvedParameter(ITypeResolveContext context)
{
@ -205,8 +210,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -205,8 +210,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
IsParams = this.IsParams
};
} else {
return new DefaultParameter(type.Resolve(context), name, region,
attributes.CreateResolvedAttributes(context), IsRef, IsOut, IsParams);
var resolvedAttributes = attributes.CreateResolvedAttributes (context);
bool isOptional = resolvedAttributes != null && resolvedAttributes.Any (a => IsOptionalAttribute (a.AttributeType));
return new DefaultParameter (type.Resolve (context), name, region,
resolvedAttributes, IsRef, IsOut, IsParams, isOptional);
}
}

2
src/Libraries/NRefactory/NRefactory.sln

@ -14,7 +14,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory", "I @@ -14,7 +14,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory", "I
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.Tests", "ICSharpCode.NRefactory.Tests\ICSharpCode.NRefactory.Tests.csproj", "{63D3B27A-D966-4902-90B3-30290E1692F1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil", "..\Mono.Cecil\Mono.Cecil.csproj", "{D68133BD-1E63-496E-9EDE-4FBDBF77B486}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil", "..\cecil\Mono.Cecil.csproj", "{D68133BD-1E63-496E-9EDE-4FBDBF77B486}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.CSharp", "ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj", "{53DCA265-3C3C-42F9-B647-F72BA678122B}"
EndProject

3
src/Libraries/NRefactory/README

@ -9,7 +9,8 @@ How to download: @@ -9,7 +9,8 @@ How to download:
How to compile:
1. Get Mono.Cecil
Download Cecil from https://github.com/jbevain/cecil/ and unzip it into a directory named "Mono.Cecil"
Get Cecil from https://github.com/jbevain/cecil ('git clone git://github.com/jbevain/cecil.git')
or download Cecil from https://github.com/jbevain/cecil/ and unzip it into a directory named "cecil"
next to the directory containing NRefactory.
2. Open NRefactory.sln in your favorite .NET IDE and compile.

Loading…
Cancel
Save