Browse Source

Merge NRefactory commit 'a3ced27e3e0515d4192e49318f2d24ec9f11fcd1' into SharpDevelop newNR branch.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
5e58218a22
  1. 95
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs
  2. 36
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs
  3. 16
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  4. 103
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs
  5. 19
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CheckIfParameterIsNull.cs
  6. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/ConvertForeachToFor.cs
  7. 36
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/IInspector.cs
  8. 61
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/InspectionIssue.cs
  9. 98
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/ConditionalToNullCoalescingInspector.cs
  10. 63
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/GatherVisitorBase.cs
  11. 77
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/NotImplementedExceptionInspector.cs
  12. 82
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/RedundantInternalInspector.cs
  13. 95
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/RedundantNamespaceUsageInspector.cs
  14. 143
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/RedundantPrivateInspector.cs
  15. 119
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/RedundantThisInspector.cs
  16. 77
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/RedundantUsingInspector.cs
  17. 121
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/StringIsNullOrEmptyInspector.cs
  18. 113
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/UseVarKeywordInspector.cs
  19. 40
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/PatternHelper.cs
  20. 49
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringAstHelper.cs
  21. 54
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringContext.cs
  22. 10
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs
  23. 13
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  24. 42
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/FindReferencedEntities.cs
  25. 178
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs
  26. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs
  27. 30
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs
  28. 16
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
  29. 24
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs
  30. 22
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs
  31. 13
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/NameContextTests.cs
  32. 23
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/ContextAction/ConvertForeachToForTests.cs
  33. 66
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs
  34. 28
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs
  35. 13
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ObjectCreationTests.cs
  36. 19
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/TypeInferenceTests.cs
  37. 48
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs
  38. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory/Documentation/IdStringProvider.cs
  39. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory/Editor/ITextSource.cs
  40. 19
      src/Libraries/NRefactory/ICSharpCode.NRefactory/Semantics/Conversion.cs
  41. 25
      src/Libraries/NRefactory/ICSharpCode.NRefactory/Semantics/MemberResolveResult.cs
  42. 12
      src/Libraries/NRefactory/ICSharpCode.NRefactory/Semantics/ThisResolveResult.cs
  43. 17
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs
  44. 1
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/IMember.cs
  45. 32
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs
  46. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs
  47. 3
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs
  48. 10
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/GetMembersHelper.cs
  49. 23
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedEvent.cs
  50. 15
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedField.cs
  51. 184
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs
  52. 103
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs
  53. 21
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedProperty.cs
  54. 45
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializingMemberReference.cs
  55. 94
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeParameterSubstitution.cs
  56. 17
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/InheritanceHelper.cs

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

@ -189,6 +189,29 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -189,6 +189,29 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
}
}
IEnumerable<ICompletionData> HandleMemberReferenceCompletion(ExpressionResult expr)
{
if (expr == null)
return null;
// do not complete <number>. (but <number>.<number>.)
if (expr.Node is PrimitiveExpression) {
var pexpr = (PrimitiveExpression)expr.Node;
if (!(pexpr.Value is string || pexpr.Value is char) && !pexpr.LiteralValue.Contains('.')) {
return null;
}
}
var resolveResult = ResolveExpression (expr);
if (resolveResult == null) {
return null;
}
if (expr.Node is AstType) {
return CreateTypeAndNamespaceCompletionData(location, resolveResult.Item1, expr.Node, resolveResult.Item2);
}
return CreateCompletionData(location, resolveResult.Item1, expr.Node, resolveResult.Item2);
}
IEnumerable<ICompletionData> MagicKeyCompletion(char completionChar, bool controlSpace)
{
ExpressionResult expr;
@ -201,26 +224,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -201,26 +224,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (IsInsideCommentOrString()) {
return Enumerable.Empty<ICompletionData>();
}
expr = GetExpressionBeforeCursor();
if (expr == null) {
return null;
}
// do not complete <number>. (but <number>.<number>.)
if (expr.Node is PrimitiveExpression) {
var pexpr = (PrimitiveExpression)expr.Node;
if (!(pexpr.Value is string || pexpr.Value is char) && !pexpr.LiteralValue.Contains('.')) {
return null;
}
}
resolveResult = ResolveExpression(expr);
if (resolveResult == null) {
return null;
}
if (expr.Node is AstType) {
return CreateTypeAndNamespaceCompletionData(location, resolveResult.Item1, expr.Node, resolveResult.Item2);
}
return CreateCompletionData(location, resolveResult.Item1, expr.Node, resolveResult.Item2);
return HandleMemberReferenceCompletion(GetExpressionBeforeCursor());
case '#':
if (IsInsideCommentOrString()) {
return null;
@ -506,20 +510,32 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -506,20 +510,32 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
var contextList = new CompletionDataWrapper (this);
var identifierStart = GetExpressionAtCursor();
if (identifierStart != null) {
if (identifierStart != null && identifierStart.Node is TypeParameterDeclaration) {
return null;
}
if (identifierStart.Node is TypeParameterDeclaration) {
return null;
}
if (identifierStart != null && identifierStart.Node is VariableInitializer && location <= ((VariableInitializer)identifierStart.Node).NameToken.EndLocation) {
return controlSpace ? HandleAccessorContext() ?? DefaultControlSpaceItems(identifierStart) : null;
}
if (identifierStart.Node is MemberReferenceExpression) {
return HandleMemberReferenceCompletion(new ExpressionResult (((MemberReferenceExpression)identifierStart.Node).Target, identifierStart.Unit));
}
if (identifierStart != null && identifierStart.Node is CatchClause) {
if (((CatchClause)identifierStart.Node).VariableNameToken.Contains(location)) {
return null;
if (identifierStart.Node is Identifier) {
// May happen in variable names
return controlSpace ? DefaultControlSpaceItems(identifierStart) : null;
}
if (identifierStart.Node is VariableInitializer && location <= ((VariableInitializer)identifierStart.Node).NameToken.EndLocation) {
return controlSpace ? HandleAccessorContext() ?? DefaultControlSpaceItems(identifierStart) : null;
}
if (identifierStart.Node is CatchClause) {
if (((CatchClause)identifierStart.Node).VariableNameToken.Contains(location)) {
return null;
}
identifierStart = null;
}
identifierStart = null;
}
if (!(char.IsLetter(completionChar) || completionChar == '_') && (!controlSpace || identifierStart == null || !(identifierStart.Node.Parent is ArrayInitializerExpression))) {
return controlSpace ? HandleAccessorContext() ?? DefaultControlSpaceItems(identifierStart) : null;
@ -2307,14 +2323,14 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -2307,14 +2323,14 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
ExpressionResult GetExpressionAtCursor()
{
// TextLocation memberLocation;
// if (currentMember != null) {
// memberLocation = currentMember.Region.Begin;
// } else if (currentType != null) {
// memberLocation = currentType.Region.Begin;
// } else {
// memberLocation = location;
// }
// TextLocation memberLocation;
// if (currentMember != null) {
// memberLocation = currentMember.Region.Begin;
// } else if (currentType != null) {
// memberLocation = currentType.Region.Begin;
// } else {
// memberLocation = location;
// }
var baseUnit = ParseStub("a");
var tmpUnit = baseUnit;
@ -2322,7 +2338,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -2322,7 +2338,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (expr == null) {
expr = baseUnit.GetNodeAt<AstType>(location.Line, location.Column - 1);
}
if (expr == null)
expr = baseUnit.GetNodeAt<Identifier>(location.Line, location.Column - 1);
// try insertStatement
if (expr == null && baseUnit.GetNodeAt<EmptyStatement>(location.Line, location.Column) != null) {
tmpUnit = baseUnit = ParseStub("a();", false);

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

@ -415,9 +415,9 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -415,9 +415,9 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
wrapper.Append (';');
}
protected CompilationUnit ParseStub (string continuation, bool appendSemicolon = true, string afterContinuation = null)
protected CompilationUnit ParseStub(string continuation, bool appendSemicolon = true, string afterContinuation = null)
{
var mt = GetMemberTextToCaret ();
var mt = GetMemberTextToCaret();
if (mt == null) {
return null;
}
@ -429,7 +429,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -429,7 +429,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
var wrapper = new StringBuilder ();
bool wrapInClass = memberLocation != new TextLocation (1, 1);
if (wrapInClass) {
var nodeAtLocation = Unit.GetNodeAt (memberLocation, n => n is TypeDeclaration || n is NamespaceDeclaration);
var nodeAtLocation = Unit.GetNodeAt(memberLocation, n => n is TypeDeclaration || n is NamespaceDeclaration);
if (nodeAtLocation != null) {
foreach (var n in nodeAtLocation.AncestorsAndSelf) {
if (memberLocation == n.StartLocation) {
@ -438,25 +438,25 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -438,25 +438,25 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (n is TypeDeclaration) {
var t = (TypeDeclaration)n;
switch (t.ClassType) {
case ClassType.Class:
wrapper.Append ("class");
break;
case ClassType.Struct:
wrapper.Append ("struct");
break;
case ClassType.Interface:
wrapper.Append ("interface");
break;
case ClassType.Enum:
wrapper.Append ("enum");
break;
case ClassType.Class:
wrapper.Append("class");
break;
case ClassType.Struct:
wrapper.Append("struct");
break;
case ClassType.Interface:
wrapper.Append("interface");
break;
case ClassType.Enum:
wrapper.Append("enum");
break;
}
wrapper.Append (" " + t.Name + " {");
wrapper.AppendLine ();
wrapper.Append(" " + t.Name + " {");
wrapper.AppendLine();
closingBrackets++;
generatedLines++;
} else {
Console.WriteLine (n);
Console.WriteLine(n);
}
}
}

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

@ -265,6 +265,8 @@ @@ -265,6 +265,8 @@
<Compile Include="Refactoring\ContextAction\UseVarKeyword.cs" />
<Compile Include="Refactoring\DocumentScript.cs" />
<Compile Include="Refactoring\IContextAction.cs" />
<Compile Include="Refactoring\PatternHelper.cs" />
<Compile Include="Refactoring\RefactoringAstHelper.cs" />
<Compile Include="Refactoring\RefactoringContext.cs" />
<Compile Include="Refactoring\Script.cs" />
<Compile Include="Refactoring\TypeSystemAstBuilder.cs" />
@ -322,6 +324,19 @@ @@ -322,6 +324,19 @@
<Compile Include="Refactoring\ContextAction\RemoveRegion.cs" />
<Compile Include="Refactoring\ContextAction\GenerateProperty.cs" />
<Compile Include="Ast\Roles.cs" />
<Compile Include="Refactoring\Inspector\ConditionalToNullCoalescingInspector.cs" />
<Compile Include="Refactoring\IInspector.cs" />
<Compile Include="Refactoring\InspectionIssue.cs" />
<Compile Include="Refactoring\BaseRefactoringContext.cs" />
<Compile Include="Refactoring\Inspector\GatherVisitorBase.cs" />
<Compile Include="Refactoring\Inspector\NotImplementedExceptionInspector.cs" />
<Compile Include="Refactoring\Inspector\RedundantInternalInspector.cs" />
<Compile Include="Refactoring\Inspector\RedundantNamespaceUsageInspector.cs" />
<Compile Include="Refactoring\Inspector\RedundantPrivateInspector.cs" />
<Compile Include="Refactoring\Inspector\RedundantThisInspector.cs" />
<Compile Include="Refactoring\Inspector\RedundantUsingInspector.cs" />
<Compile Include="Refactoring\Inspector\StringIsNullOrEmptyInspector.cs" />
<Compile Include="Refactoring\Inspector\UseVarKeywordInspector.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
@ -332,6 +347,7 @@ @@ -332,6 +347,7 @@
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<ItemGroup>
<Folder Include="Completion\" />
<Folder Include="Refactoring\Inspector\" />
</ItemGroup>
<ProjectExtensions>
<MonoDevelop>

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

@ -0,0 +1,103 @@ @@ -0,0 +1,103 @@
//
// BaseRefactoringContext.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Linq;
using System.Threading;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.CSharp.TypeSystem;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public abstract class BaseRefactoringContext
{
protected readonly CSharpAstResolver resolver;
readonly CancellationToken cancellationToken;
public virtual bool Supports(Version version)
{
return true;
}
public CancellationToken CancellationToken {
get { return cancellationToken; }
}
public virtual AstNode RootNode {
get { return resolver.RootNode; }
}
public ICompilation Compilation {
get { return resolver.Compilation; }
}
public BaseRefactoringContext (ICSharpCode.NRefactory.CSharp.Resolver.CSharpAstResolver resolver, System.Threading.CancellationToken cancellationToken)
{
this.resolver = resolver;
this.cancellationToken = cancellationToken;
}
#region Resolving
public ResolveResult Resolve (AstNode node)
{
return resolver.Resolve (node, cancellationToken);
}
public CSharpResolver GetResolverStateBefore(AstNode node)
{
return resolver.GetResolverStateBefore (node, cancellationToken);
}
public CSharpResolver GetResolverStateAfter(AstNode node)
{
return resolver.GetResolverStateAfter (node, cancellationToken);
}
public IType ResolveType (AstType type)
{
return resolver.Resolve (type, cancellationToken).Type;
}
public IType GetExpectedType (Expression expression)
{
return resolver.GetExpectedType(expression, cancellationToken);
}
public Conversion GetConversion (Expression expression)
{
return resolver.GetConversion(expression, cancellationToken);
}
#endregion
public abstract Script StartScript();
}
}

19
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CheckIfParameterIsNull.cs

@ -46,10 +46,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -46,10 +46,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (bodyStatement == null)
return false;
if (parameter.Type is PrimitiveType)
return (((PrimitiveType)parameter.Type).Keyword == "object" || ((PrimitiveType)parameter.Type).Keyword == "string") && !HasNullCheck (parameter);
var type = context.ResolveType(parameter.Type);
if (type.IsReferenceType == false)
return false;
// TODO: check for structs
return !HasNullCheck (parameter);
}
@ -83,25 +83,20 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -83,25 +83,20 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class CheckNullVisitor : DepthFirstAstVisitor<object, object>
{
ParameterDeclaration parameter;
readonly Expression pattern;
public bool ContainsNullCheck {
get;
set;
}
internal bool ContainsNullCheck;
public CheckNullVisitor (ParameterDeclaration parameter)
{
this.parameter = parameter;
this.pattern = PatternHelper.CommutativeOperator(new IdentifierExpression(parameter.Name), BinaryOperatorType.Any, new NullReferenceExpression());
}
public override object VisitIfElseStatement (IfElseStatement ifElseStatement, object data)
{
if (ifElseStatement.Condition is BinaryOperatorExpression) {
var binOp = ifElseStatement.Condition as BinaryOperatorExpression;
if ((binOp.Operator == BinaryOperatorType.Equality || binOp.Operator == BinaryOperatorType.InEquality) &&
binOp.Left.IsMatch (new IdentifierExpression (parameter.Name)) && binOp.Right.IsMatch (new NullReferenceExpression ()) ||
binOp.Right.IsMatch (new IdentifierExpression (parameter.Name)) && binOp.Left.IsMatch (new NullReferenceExpression ())) {
if ((binOp.Operator == BinaryOperatorType.Equality || binOp.Operator == BinaryOperatorType.InEquality) && pattern.IsMatch(binOp)) {
ContainsNullCheck = true;
}
}

6
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/ConvertForeachToFor.cs

@ -54,6 +54,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -54,6 +54,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var result = context.Resolve (foreachStatement.InExpression);
var countProperty = GetCountProperty (result.Type);
// TODO: use another variable name if 'i' is already in use
var initializer = new VariableDeclarationStatement (new PrimitiveType ("int"), "i", new PrimitiveExpression (0));
var id1 = new IdentifierExpression ("i");
var id2 = id1.Clone ();
@ -88,7 +89,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -88,7 +89,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (astNode == null)
return null;
var result = (astNode as ForeachStatement) ?? astNode.Parent as ForeachStatement;
if (result == null || context.Resolve (result.InExpression) == null)
if (result == null)
return null;
var collection = context.Resolve (result.InExpression);
if (collection.Type.Kind != TypeKind.Array && !collection.Type.GetProperties(p => p.IsIndexer).Any())
return null;
return result;
}

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

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
//
// IInspector.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public interface IInspector
{
IEnumerable<InspectionIssue> Run (BaseRefactoringContext context);
}
}

61
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/InspectionIssue.cs

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
//
// InspectionIssue.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class InspectionIssue
{
public string Title {
get;
private set;
}
public TextLocation Start {
get;
private set;
}
public TextLocation End {
get;
private set;
}
public System.Action Fix {
get;
private set;
}
public InspectionIssue (string title, TextLocation start, TextLocation end, System.Action fix)
{
this.Title = title;
this.Start = start;
this.End = end;
this.Fix = fix;
}
}
}

98
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/ConditionalToNullCoalescingInspector.cs

@ -0,0 +1,98 @@ @@ -0,0 +1,98 @@
//
// ConditionalToNullCoalescingInspector.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.PatternMatching;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Checks for "a != null ? a : other"<expr>
/// Converts to: "a ?? other"<expr>
/// </summary>
public class ConditionalToNullCoalescingInspector : IInspector
{
static readonly Pattern pattern = new Choice {
// a != null ? a : other
new ConditionalExpression(
PatternHelper.CommutativeOperator(new AnyNode("a"), BinaryOperatorType.InEquality, new NullReferenceExpression()),
new Backreference("a"),
new AnyNode("other")
),
// a == null ? other : a
new ConditionalExpression(
PatternHelper.CommutativeOperator(new AnyNode("a"), BinaryOperatorType.Equality, new NullReferenceExpression()),
new AnyNode("other"),
new Backreference("a")
),
};
string title = "Convert to '??' expression";
public string Title {
get {
return title;
}
set {
title = value;
}
}
public IEnumerable<InspectionIssue> Run (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
return visitor.FoundIssues;
}
class GatherVisitor : GatherVisitorBase
{
readonly ConditionalToNullCoalescingInspector inspector;
public GatherVisitor (BaseRefactoringContext ctx, ConditionalToNullCoalescingInspector inspector) : base (ctx)
{
this.inspector = inspector;
}
public override void VisitConditionalExpression(ConditionalExpression conditionalExpression)
{
Match m = pattern.Match(conditionalExpression);
if (m.Success) {
var a = m.Get<Expression>("a").Single();
var other = m.Get<Expression>("other").Single();
AddIssue(conditionalExpression, inspector.Title, delegate {
using (var script = ctx.StartScript ()) {
var expr = new BinaryOperatorExpression (a.Clone (), BinaryOperatorType.NullCoalescing, other.Clone ());
script.Replace (conditionalExpression, expr);
}
});
}
base.VisitConditionalExpression (conditionalExpression);
}
}
}
}

63
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/GatherVisitorBase.cs

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
//
// GatherVisitorBase.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp
{
class GatherVisitorBase : DepthFirstAstVisitor
{
protected readonly BaseRefactoringContext ctx;
public readonly List<InspectionIssue> FoundIssues = new List<InspectionIssue> ();
public GatherVisitorBase (BaseRefactoringContext ctx)
{
this.ctx = ctx;
}
protected override void VisitChildren (AstNode node)
{
if (ctx.CancellationToken.IsCancellationRequested)
return;
base.VisitChildren (node);
}
protected void AddIssue (AstNode node, string title, System.Action fix = null)
{
FoundIssues.Add (new InspectionIssue (title, node.StartLocation, node.EndLocation, fix));
}
protected void AddIssue(TextLocation start, TextLocation end, string title, System.Action fix = null)
{
FoundIssues.Add (new InspectionIssue (title, start, end, fix));
}
}
}

77
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/NotImplementedExceptionInspector.cs

@ -0,0 +1,77 @@ @@ -0,0 +1,77 @@
//
// NotImplementedExceptionInspector.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.PatternMatching;
using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// This inspector just shows that there is a not implemented exception. It doesn't offer a fix.
/// Should only be shown in overview bar, no underlining.
/// </summary>
public class NotImplementedExceptionInspector : IInspector
{
string title = "NotImplemented exception thrown";
public string Title {
get {
return title;
}
set {
title = value;
}
}
public IEnumerable<InspectionIssue> Run (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
return visitor.FoundIssues;
}
class GatherVisitor : GatherVisitorBase
{
readonly NotImplementedExceptionInspector inspector;
public GatherVisitor (BaseRefactoringContext ctx, NotImplementedExceptionInspector inspector) : base (ctx)
{
this.inspector = inspector;
}
public override void VisitThrowStatement(ThrowStatement throwStatement)
{
var result = ctx.Resolve (throwStatement.Expression);
if (result.Type.Equals (ctx.Compilation.FindType (typeof(System.NotImplementedException))))
AddIssue (throwStatement, inspector.Title);
base.VisitThrowStatement(throwStatement);
}
}
}
}

82
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/RedundantInternalInspector.cs

@ -0,0 +1,82 @@ @@ -0,0 +1,82 @@
//
// RedundantInternalInspector.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.PatternMatching;
using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Finds redundant internal modifiers.
/// </summary>
public class RedundantInternalInspector : IInspector
{
string title = "Remove redundant 'internal' modifier";
public string Title {
get {
return title;
}
set {
title = value;
}
}
public IEnumerable<InspectionIssue> Run (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
return visitor.FoundIssues;
}
class GatherVisitor : GatherVisitorBase
{
readonly RedundantInternalInspector inspector;
public GatherVisitor (BaseRefactoringContext ctx, RedundantInternalInspector inspector) : base (ctx)
{
this.inspector = inspector;
}
public override void VisitTypeDeclaration(TypeDeclaration typeDeclaration)
{
foreach (var token_ in typeDeclaration.ModifierTokens) {
var token = token_;
if (token.Modifier == Modifiers.Internal) {
AddIssue(token, inspector.Title, delegate {
using (var script = ctx.StartScript ()) {
script.Remove(token);
}
});
}
}
}
}
}
}

95
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/RedundantNamespaceUsageInspector.cs

@ -0,0 +1,95 @@ @@ -0,0 +1,95 @@
//
// RedundantNamespaceUsageInspector.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Finds redundant namespace usages.
/// </summary>
public class RedundantNamespaceUsageInspector : IInspector
{
string title = "Remove redundant namespace usage";
public string Title {
get {
return title;
}
set {
title = value;
}
}
public IEnumerable<InspectionIssue> Run (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
return visitor.FoundIssues;
}
class GatherVisitor : GatherVisitorBase
{
readonly RedundantNamespaceUsageInspector inspector;
public GatherVisitor (BaseRefactoringContext ctx, RedundantNamespaceUsageInspector inspector) : base (ctx)
{
this.inspector = inspector;
}
public override void VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression)
{
base.VisitMemberReferenceExpression(memberReferenceExpression);
var result = ctx.Resolve(memberReferenceExpression.Target);
if (!(result is NamespaceResolveResult)) {
return;
}
var wholeResult = ctx.Resolve(memberReferenceExpression);
if (!(wholeResult is TypeResolveResult)) {
return;
}
var state = ctx.GetResolverStateBefore(memberReferenceExpression);
var lookupName = state.LookupSimpleNameOrTypeName(memberReferenceExpression.MemberName, new List<IType> (), SimpleNameLookupMode.Expression);
if (lookupName is TypeResolveResult && !lookupName.IsError && wholeResult.Type.Equals(lookupName.Type)) {
AddIssue(memberReferenceExpression.StartLocation, memberReferenceExpression.MemberNameToken.StartLocation, inspector.Title, delegate {
using (var script = ctx.StartScript ()) {
script.Replace(memberReferenceExpression, RefactoringAstHelper.RemoveTarget(memberReferenceExpression));
}
}
);
}
}
}
}
}

143
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/RedundantPrivateInspector.cs

@ -0,0 +1,143 @@ @@ -0,0 +1,143 @@
//
// RedundantPrivateInspector.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.PatternMatching;
using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Finds redundant internal modifiers.
/// </summary>
public class RedundantPrivateInspector : IInspector
{
string title = "Remove redundant 'private' modifier";
public string Title {
get {
return title;
}
set {
title = value;
}
}
public IEnumerable<InspectionIssue> Run (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
return visitor.FoundIssues;
}
class GatherVisitor : GatherVisitorBase
{
readonly RedundantPrivateInspector inspector;
public GatherVisitor (BaseRefactoringContext ctx, RedundantPrivateInspector inspector) : base (ctx)
{
this.inspector = inspector;
}
void CheckNode(EntityDeclaration node)
{
foreach (var token_ in node.ModifierTokens) {
var token = token_;
if (token.Modifier == Modifiers.Private) {
AddIssue(token, inspector.Title, delegate {
using (var script = ctx.StartScript ()) {
script.Remove(token);
}
});
}
}
}
public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration)
{
base.VisitMethodDeclaration(methodDeclaration);
CheckNode(methodDeclaration);
}
public override void VisitFieldDeclaration(FieldDeclaration fieldDeclaration)
{
base.VisitFieldDeclaration(fieldDeclaration);
CheckNode(fieldDeclaration);
}
public override void VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration)
{
base.VisitPropertyDeclaration(propertyDeclaration);
CheckNode(propertyDeclaration);
}
public override void VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration)
{
base.VisitIndexerDeclaration(indexerDeclaration);
CheckNode(indexerDeclaration);
}
public override void VisitEventDeclaration(EventDeclaration eventDeclaration)
{
base.VisitEventDeclaration(eventDeclaration);
CheckNode(eventDeclaration);
}
public override void VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration)
{
base.VisitCustomEventDeclaration(eventDeclaration);
CheckNode(eventDeclaration);
}
public override void VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration)
{
base.VisitConstructorDeclaration(constructorDeclaration);
CheckNode(constructorDeclaration);
}
public override void VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration)
{
base.VisitOperatorDeclaration(operatorDeclaration);
CheckNode(operatorDeclaration);
}
public override void VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration)
{
base.VisitFixedFieldDeclaration(fixedFieldDeclaration);
CheckNode(fixedFieldDeclaration);
}
public override void VisitTypeDeclaration(TypeDeclaration typeDeclaration)
{
if (!(typeDeclaration.Parent is TypeDeclaration)) {
CheckNode(typeDeclaration);
}
base.VisitTypeDeclaration(typeDeclaration);
}
}
}
}

119
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/RedundantThisInspector.cs

@ -0,0 +1,119 @@ @@ -0,0 +1,119 @@
//
// RedundantThisInspector.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.PatternMatching;
using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.CSharp.Resolver;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Finds redundant namespace usages.
/// </summary>
public class RedundantThisInspector : IInspector
{
string title = "Remove redundant 'this.'";
public string Title {
get {
return title;
}
set {
title = value;
}
}
public IEnumerable<InspectionIssue> Run (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
return visitor.FoundIssues;
}
class GatherVisitor : GatherVisitorBase
{
readonly RedundantThisInspector inspector;
public GatherVisitor (BaseRefactoringContext ctx, RedundantThisInspector inspector) : base (ctx)
{
this.inspector = inspector;
}
static IMember GetMember (ResolveResult result)
{
if (result is MemberResolveResult) {
return ((MemberResolveResult)result).Member;
} else if (result is MethodGroupResolveResult) {
return ((MethodGroupResolveResult)result).Methods.FirstOrDefault ();
}
return null;
}
public override void VisitThisReferenceExpression (ThisReferenceExpression thisReferenceExpression)
{
base.VisitThisReferenceExpression (thisReferenceExpression);
var memberReference = thisReferenceExpression.Parent as MemberReferenceExpression;
if (memberReference == null) {
return;
}
var state = ctx.GetResolverStateAfter (thisReferenceExpression);
var wholeResult = ctx.Resolve (memberReference);
IMember member = GetMember (wholeResult);
if (member == null) {
return;
}
var result = state.LookupSimpleNameOrTypeName (memberReference.MemberName, EmptyList<IType>.Instance, SimpleNameLookupMode.Expression);
bool isRedundant;
if (result is MemberResolveResult) {
isRedundant = ((MemberResolveResult)result).Member.Region.Equals(member.Region);
} else if (result is MethodGroupResolveResult) {
isRedundant = ((MethodGroupResolveResult)result).Methods.Any(m => m.Region.Equals(member.Region));
} else {
return;
}
if (isRedundant) {
AddIssue(thisReferenceExpression.StartLocation, memberReference.MemberNameToken.StartLocation, inspector.Title, delegate {
using (var script = ctx.StartScript ()) {
script.Replace(memberReference, RefactoringAstHelper.RemoveTarget(memberReference));
}
}
);
}
}
}
}
}

77
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/RedundantUsingInspector.cs

@ -0,0 +1,77 @@ @@ -0,0 +1,77 @@
//
// RedundantUsingInspector.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.PatternMatching;
using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Semantics;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Finds redundant using declarations.
/// </summary>
public class RedundantUsingInspector : IInspector
{
string title = "Remove redundant using";
public string Title {
get {
return title;
}
set {
title = value;
}
}
public IEnumerable<InspectionIssue> Run (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
return visitor.FoundIssues;
}
class GatherVisitor : GatherVisitorBase
{
readonly RedundantUsingInspector inspector;
public GatherVisitor (BaseRefactoringContext ctx, RedundantUsingInspector inspector) : base (ctx)
{
this.inspector = inspector;
}
public override void VisitUsingDeclaration(UsingDeclaration usingDeclaration)
{
base.VisitUsingDeclaration(usingDeclaration);
// TODO
// return cSharpResolver.usedScopes
// .OfType<ITypeOrNamespaceReference> ()
// .Any (u => u.ResolveNamespace (ctx).NamespaceName == ns) || additionalNamespaces.Contains (ns);
}
}
}
}

121
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/StringIsNullOrEmptyInspector.cs

@ -0,0 +1,121 @@ @@ -0,0 +1,121 @@
//
// StringIsNullOrEmptyInspector.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.PatternMatching;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Checks for str == null && str == ""
/// Converts to: string.IsNullOrEmpty (str)
/// </summary>
public class StringIsNullOrEmptyInspector : IInspector
{
static readonly Pattern pattern = new Choice {
// str == null || str == ""
new BinaryOperatorExpression (
PatternHelper.CommutativeOperator(new AnyNode ("str"), BinaryOperatorType.Equality, new NullReferenceExpression ()),
BinaryOperatorType.ConditionalOr,
PatternHelper.CommutativeOperator(new Backreference ("str"), BinaryOperatorType.Equality, new PrimitiveExpression (""))
),
// str == "" || str == null
new BinaryOperatorExpression (
PatternHelper.CommutativeOperator(new Backreference ("str"), BinaryOperatorType.Equality, new PrimitiveExpression ("")),
BinaryOperatorType.ConditionalOr,
PatternHelper.CommutativeOperator(new AnyNode ("str"), BinaryOperatorType.Equality, new NullReferenceExpression ())
),
};
static readonly Pattern negPattern = new Choice {
// str != null && str != ""
new BinaryOperatorExpression (
PatternHelper.CommutativeOperator(new AnyNode ("str"), BinaryOperatorType.InEquality, new NullReferenceExpression ()),
BinaryOperatorType.ConditionalAnd,
PatternHelper.CommutativeOperator(new Backreference ("str"), BinaryOperatorType.InEquality, new PrimitiveExpression (""))
),
// str != "" && str != null
new BinaryOperatorExpression (
PatternHelper.CommutativeOperator(new Backreference ("str"), BinaryOperatorType.InEquality, new PrimitiveExpression ("")),
BinaryOperatorType.ConditionalAnd,
PatternHelper.CommutativeOperator(new AnyNode ("str"), BinaryOperatorType.InEquality, new NullReferenceExpression ())
),
};
string title = "Use string.IsNullOrEmpty";
public string Title {
get {
return title;
}
set {
title = value;
}
}
public IEnumerable<InspectionIssue> Run (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
return visitor.FoundIssues;
}
class GatherVisitor : GatherVisitorBase
{
readonly StringIsNullOrEmptyInspector inspector;
public GatherVisitor (BaseRefactoringContext ctx, StringIsNullOrEmptyInspector inspector) : base (ctx)
{
this.inspector = inspector;
}
public override void VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression)
{
base.VisitBinaryOperatorExpression(binaryOperatorExpression);
Match m = pattern.Match(binaryOperatorExpression);
bool isNegated = false;
if (!m.Success) {
m = negPattern.Match(binaryOperatorExpression);
isNegated = true;
}
if (m.Success) {
var str = m.Get<Expression>("str").Single();
AddIssue(binaryOperatorExpression, inspector.Title, delegate {
using (var script = ctx.StartScript ()) {
Expression expr = new PrimitiveType ("string").Invoke("IsNullOrEmpty", str.Clone());
if (isNegated)
expr = new UnaryOperatorExpression (UnaryOperatorType.Not, expr);
script.Replace(binaryOperatorExpression, expr);
}
});
return;
}
}
}
}
}

113
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/UseVarKeywordInspector.cs

@ -0,0 +1,113 @@ @@ -0,0 +1,113 @@
//
// UseVarKeywordInspector.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin <http://xamarin.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.PatternMatching;
using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Semantics;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Checks for places where the 'var' keyword can be used. Note that the action is actually done with a context
/// action.
/// </summary>
public class UseVarKeywordInspector : IInspector
{
string title = "Use 'var' keyword";
public string Title {
get {
return title;
}
set {
title = value;
}
}
public IEnumerable<InspectionIssue> Run (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
return visitor.FoundIssues;
}
class GatherVisitor : GatherVisitorBase
{
readonly UseVarKeywordInspector inspector;
public GatherVisitor (BaseRefactoringContext ctx, UseVarKeywordInspector inspector) : base (ctx)
{
this.inspector = inspector;
}
public override void VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement)
{
base.VisitVariableDeclarationStatement(variableDeclarationStatement);
if (variableDeclarationStatement.Type is PrimitiveType) {
return;
}
if (variableDeclarationStatement.Type is SimpleType && ((SimpleType)variableDeclarationStatement.Type).Identifier == "var") {
return;
}
if (variableDeclarationStatement.Variables.Count != 1) {
return;
}
//only checks for cases where the type would be obvious - assignment of new, cast, etc.
//also check the type actually matches else the user might want to assign different subclasses later
var v = variableDeclarationStatement.Variables.Single();
var arrCreate = v.Initializer as ArrayCreateExpression;
if (arrCreate != null) {
var n = variableDeclarationStatement.Type as ComposedType;
//FIXME: check the specifier compatibility
if (n != null && n.ArraySpecifiers.Any() && n.BaseType.IsMatch(arrCreate.Type)) {
AddIssue(variableDeclarationStatement);
}
}
var objCreate = v.Initializer as ObjectCreateExpression;
if (objCreate != null && objCreate.Type.IsMatch(variableDeclarationStatement.Type)) {
AddIssue(variableDeclarationStatement);
}
var asCast = v.Initializer as AsExpression;
if (asCast != null && asCast.Type.IsMatch(variableDeclarationStatement.Type)) {
AddIssue(variableDeclarationStatement);
}
var cast = v.Initializer as CastExpression;
if (cast != null && cast.Type.IsMatch(variableDeclarationStatement.Type)) {
AddIssue(variableDeclarationStatement);
}
}
void AddIssue(VariableDeclarationStatement variableDeclarationStatement)
{
AddIssue(variableDeclarationStatement.Type, inspector.Title);
}
}
}
}

40
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/PatternHelper.cs

@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.PatternMatching;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Helper class for constructing pattern ASTs.
/// </summary>
public class PatternHelper
{
/// <summary>
/// Produces a choice pattern for <c>expr1 op expr2</c> or <c>expr2 op expr1</c>.
/// </summary>
public static Expression CommutativeOperator(Expression expr1, BinaryOperatorType op, Expression expr2)
{
return new Choice {
new BinaryOperatorExpression(expr1, op, expr2),
new BinaryOperatorExpression(expr2.Clone(), op, expr1.Clone())
};
}
}
}

49
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringAstHelper.cs

@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Helper methods for constructing ASTs for refactoring.
/// These helpers work with frozen ASTs, i.e. they clone input nodes.
/// </summary>
public class RefactoringAstHelper
{
/// <summary>
/// Removes the target from a member reference while preserving the identifier and type arguments.
/// </summary>
public static IdentifierExpression RemoveTarget(MemberReferenceExpression mre)
{
IdentifierExpression ident = new IdentifierExpression(mre.MemberName);
ident.TypeArguments.AddRange(mre.TypeArguments.Select(t => t.Clone()));
return ident;
}
/// <summary>
/// Removes the target from a member reference while preserving the identifier and type arguments.
/// </summary>
public static SimpleType RemoveTarget(MemberType memberType)
{
return new SimpleType(memberType.MemberName, memberType.TypeArguments.Select(t => t.Clone()));
}
}
}

54
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringContext.cs

@ -36,36 +36,14 @@ using ICSharpCode.NRefactory.Editor; @@ -36,36 +36,14 @@ using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public abstract class RefactoringContext
public abstract class RefactoringContext : BaseRefactoringContext
{
readonly protected CSharpAstResolver resolver;
readonly CancellationToken cancellationToken;
public RefactoringContext(CSharpAstResolver resolver, CancellationToken cancellationToken)
public RefactoringContext(CSharpAstResolver resolver, CancellationToken cancellationToken) : base (resolver, cancellationToken)
{
this.resolver = resolver;
this.cancellationToken = cancellationToken;
}
public CancellationToken CancellationToken {
get { return cancellationToken; }
}
public virtual AstNode RootNode {
get { return resolver.RootNode; }
}
public abstract TextLocation Location { get; }
public virtual bool Supports(Version version)
{
return true;
}
public ICompilation Compilation {
get { return resolver.Compilation; }
}
public virtual AstType CreateShortType (IType fullType)
{
var csResolver = resolver.GetResolverStateBefore(GetNode());
@ -132,29 +110,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -132,29 +110,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
public abstract string GetText (ISegment segment);
#endregion
#region Resolving
public ResolveResult Resolve (AstNode node)
{
return resolver.Resolve (node, cancellationToken);
}
public IType ResolveType (AstType type)
{
return resolver.Resolve (type, cancellationToken).Type;
}
public IType GetExpectedType (Expression expression)
{
return resolver.GetExpectedType(expression, cancellationToken);
}
public Conversion GetConversion (Expression expression)
{
return resolver.GetConversion(expression, cancellationToken);
}
#endregion
public virtual string GetNameProposal (string name, bool camelCase = true)
{
string baseName = (camelCase ? char.ToLower (name [0]) : char.ToUpper (name [0])) + name.Substring (1);
@ -175,8 +131,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -175,8 +131,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
return baseName + (number > 0 ? (number + 1).ToString () : "");
}
public abstract Script StartScript();
}
}

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

@ -805,10 +805,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -805,10 +805,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
var or = rr.PerformOverloadResolution(compilation, args, allowExpandingParams: false, conversions: this);
if (or.FoundApplicableCandidate)
return Conversion.MethodGroupConversion((IMethod)or.GetBestCandidateWithSubstitutedTypeArguments());
else
if (or.FoundApplicableCandidate) {
IMethod method = (IMethod)or.GetBestCandidateWithSubstitutedTypeArguments();
var thisRR = rr.TargetResult as ThisResolveResult;
bool isVirtual = method.IsOverridable && !(thisRR != null && thisRR.CausesNonVirtualInvocation);
return Conversion.MethodGroupConversion(method, isVirtual);
} else {
return Conversion.None;
}
}
#endregion

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

@ -1167,13 +1167,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1167,13 +1167,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
internal readonly IParameterizedMember nonLiftedOperator;
public LiftedUserDefinedOperator(IMethod nonLiftedMethod)
: base(nonLiftedMethod.DeclaringType, (IMethod)nonLiftedMethod.MemberDefinition,
EmptyList<IType>.Instance, new MakeNullableVisitor(nonLiftedMethod.Compilation))
: base(nonLiftedMethod, TypeParameterSubstitution.Identity)
{
this.nonLiftedOperator = nonLiftedMethod;
var substitution = new MakeNullableVisitor(nonLiftedMethod.Compilation);
this.Parameters = base.CreateParameters(substitution);
// Comparison operators keep the 'bool' return type even when lifted.
if (IsComparisonOperator(nonLiftedMethod))
this.ReturnType = nonLiftedMethod.ReturnType;
else
this.ReturnType = nonLiftedMethod.ReturnType.AcceptVisitor(substitution);
}
public IList<IParameter> NonLiftedParameters {
@ -1726,13 +1729,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1726,13 +1729,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (typeArguments != null && typeArguments.Count > 0) {
if (method.TypeParameters.Count != typeArguments.Count)
continue;
SpecializedMethod sm = new SpecializedMethod(method.DeclaringType, method, typeArguments);
SpecializedMethod sm = new SpecializedMethod(method, new TypeParameterSubstitution(null, typeArguments));
if (IsEligibleExtensionMethod(targetType, method, false, out inferredTypes))
outputGroup.Add(sm);
} else {
if (IsEligibleExtensionMethod(targetType, method, true, out inferredTypes)) {
if (substituteInferredTypes && inferredTypes != null) {
outputGroup.Add(new SpecializedMethod(method.DeclaringType, method, inferredTypes));
outputGroup.Add(new SpecializedMethod(method, new TypeParameterSubstitution(null, inferredTypes)));
} else {
outputGroup.Add(method);
}
@ -1854,7 +1857,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1854,7 +1857,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (mgrr != null) {
OverloadResolution or = mgrr.PerformOverloadResolution(compilation, arguments, argumentNames, conversions: conversions);
if (or.BestCandidate != null) {
if (or.BestCandidate.IsStatic && !(mgrr.TargetResult is TypeResolveResult))
if (or.BestCandidate.IsStatic && !or.IsExtensionMethodInvocation && !(mgrr.TargetResult is TypeResolveResult))
return or.CreateResolveResult(new TypeResolveResult(mgrr.TargetResult.Type));
else
return or.CreateResolveResult(mgrr.TargetResult);

42
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/FindReferencedEntities.cs

@ -27,13 +27,39 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -27,13 +27,39 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary>
public sealed class FindReferencedEntities : IResolveVisitorNavigator
{
readonly Action<AstNode, IEntity> referenceFound;
readonly Action<AstNode, IMember> memberReferenceFound;
readonly Action<AstNode, IType> typeReferenceFound;
/// <summary>
/// Creates a new FindReferencedEntities instance that
/// looks for entity definitions.
/// The visitor will report type definitions and member definitions (not specialized members).
/// </summary>
public FindReferencedEntities(Action<AstNode, IEntity> referenceFound)
{
if (referenceFound == null)
throw new ArgumentNullException("referenceFound");
this.referenceFound = referenceFound;
this.memberReferenceFound = (node, member) => referenceFound(node, member.MemberDefinition);
this.typeReferenceFound = (node, type) => {
var def = type.GetDefinition();
if (def != null)
referenceFound(node, def);
};
}
/// <summary>
/// Creates a new FindReferencedEntities instance that
/// looks for types and members.
/// The visitor will report parameterized types and potentially specialized members.
/// </summary>
public FindReferencedEntities(Action<AstNode, IType> typeReferenceFound, Action<AstNode, IMember> memberReferenceFound)
{
if (typeReferenceFound == null)
throw new ArgumentNullException("typeReferenceFound");
if (memberReferenceFound == null)
throw new ArgumentNullException("memberReferenceFound");
this.typeReferenceFound = typeReferenceFound;
this.memberReferenceFound = memberReferenceFound;
}
public ResolveVisitorNavigationMode Scan(AstNode node)
@ -48,28 +74,26 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -48,28 +74,26 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
MemberResolveResult mrr = result as MemberResolveResult;
if (mrr != null) {
referenceFound(node, mrr.Member.MemberDefinition);
memberReferenceFound(node, mrr.Member);
}
TypeResolveResult trr = result as TypeResolveResult;
if (trr != null) {
ITypeDefinition typeDef = trr.Type.GetDefinition();
if (typeDef != null)
referenceFound(node, typeDef);
typeReferenceFound(node, trr.Type);
}
ForEachResolveResult ferr = result as ForEachResolveResult;
if (ferr != null) {
Resolved(node, ferr.GetEnumeratorCall);
if (ferr.CurrentProperty != null)
referenceFound(node, ferr.CurrentProperty.MemberDefinition);
memberReferenceFound(node, ferr.CurrentProperty);
if (ferr.MoveNextMethod != null)
referenceFound(node, ferr.MoveNextMethod.MemberDefinition);
memberReferenceFound(node, ferr.MoveNextMethod);
}
}
public void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
if (conversion.IsUserDefined || conversion.IsMethodGroupConversion) {
referenceFound(expression, conversion.Method.MemberDefinition);
memberReferenceFound(expression, conversion.Method);
}
}
}

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

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using ICSharpCode.NRefactory.CSharp.Refactoring;
@ -42,9 +43,42 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -42,9 +43,42 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
#region Properties
/// <summary>
/// Gets/Sets whether to find type references even if an alias is being used.
/// Specifies whether to find type references even if an alias is being used.
/// Aliases may be <c>var</c> or <c>using Alias = ...;</c>.
/// </summary>
public bool FindTypeReferencesEvenIfAliased { get; set; }
/// <summary>
/// Specifies whether find references should only look for specialized matches
/// with equal type parameter substitution to the member we are searching for.
/// </summary>
public bool FindOnlySpecializedReferences { get; set; }
/// <summary>
/// If this option is enabled, find references on a overridden member
/// will find calls to the base member.
/// </summary>
public bool FindCallsThroughVirtualBaseMethod { get; set; }
/// <summary>
/// If this option is enabled, find references on a member implementing
/// an interface will also find calls to the interface.
/// </summary>
public bool FindCallsThroughInterface { get; set; }
/// <summary>
/// If this option is enabled, find references will look for all references
/// to the virtual method slot.
/// </summary>
public bool WholeVirtualSlot { get; set; }
/// <summary>
/// Specifies whether to look for references in documentation comments.
/// This will find entity references in <c>cref</c> attributes and
/// parameter references in <c>&lt;param&gt;</c> and <c>&lt;paramref&gt;</c> tags.
/// TODO: implement this feature.
/// </summary>
public bool SearchInDocumentationComments { get; set; }
#endregion
#region GetEffectiveAccessibility
@ -110,6 +144,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -110,6 +144,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
internal string searchTerm;
internal FindReferences findReferences;
internal ICompilation declarationCompilation;
internal Accessibility accessibility;
internal ITypeDefinition topLevelTypeDefinition;
@ -119,6 +154,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -119,6 +154,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
FindReferenceNavigator n = factory(compilation);
if (n != null) {
n.callback = callback;
n.findReferences = findReferences;
return n;
} else {
return new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Skip, null);
@ -145,6 +181,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -145,6 +181,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
abstract class FindReferenceNavigator : IResolveVisitorNavigator
{
internal FoundReferenceCallback callback;
internal FindReferences findReferences;
internal abstract bool CanMatch(AstNode node);
internal abstract bool IsMatch(ResolveResult rr);
@ -185,6 +222,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -185,6 +222,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (entity == null)
throw new ArgumentNullException("entity");
if (entity is IMember)
entity = NormalizeMember((IMember)entity);
Accessibility effectiveAccessibility = GetEffectiveAccessibility(entity);
ITypeDefinition topLevelTypeDefinition = entity.DeclaringTypeDefinition;
while (topLevelTypeDefinition != null && topLevelTypeDefinition.DeclaringTypeDefinition != null)
@ -219,7 +258,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -219,7 +258,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
scope = GetSearchScopeForOperator((IMethod)entity);
break;
case EntityType.Constructor:
IMethod ctor = (IMethod)((IMethod)entity).MemberDefinition;
IMethod ctor = (IMethod)entity;
scope = FindObjectCreateReferences(ctor);
additionalScope = FindChainedConstructorReferences(ctor);
break;
@ -233,11 +272,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -233,11 +272,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
scope.accessibility = effectiveAccessibility;
scope.declarationCompilation = entity.Compilation;
scope.topLevelTypeDefinition = topLevelTypeDefinition;
scope.findReferences = this;
if (additionalScope != null) {
if (additionalScope.accessibility == Accessibility.None)
additionalScope.accessibility = effectiveAccessibility;
additionalScope.declarationCompilation = entity.Compilation;
additionalScope.topLevelTypeDefinition = topLevelTypeDefinition;
additionalScope.findReferences = this;
return new[] { scope, additionalScope };
} else {
return new[] { scope };
@ -385,17 +426,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -385,17 +426,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (searchTerm.Length > 9 && searchTerm.EndsWith("Attribute", StringComparison.Ordinal)) {
// The type might be an attribute, so we also need to look for the short form:
string shortForm = searchTerm.Substring(0, searchTerm.Length - 9);
additionalScope = new SearchScope(
shortForm,
delegate (ICompilation compilation) {
ITypeDefinition imported = compilation.Import(typeDefinition);
if (imported != null)
return new FindTypeDefinitionReferencesNavigator(imported, shortForm);
else
return null;
});
additionalScope = FindTypeDefinitionReferences(typeDefinition, shortForm);
}
}
return FindTypeDefinitionReferences(typeDefinition, searchTerm);
}
SearchScope FindTypeDefinitionReferences(ITypeDefinition typeDefinition, string searchTerm)
{
return new SearchScope(
searchTerm,
delegate (ICompilation compilation) {
@ -462,11 +500,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -462,11 +500,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
SearchScope FindMemberReferences(IEntity member, Func<IMember, FindMemberReferencesNavigator> factory)
{
string searchTerm = member.Name;
IMember memberDefinition = ((IMember)member).MemberDefinition;
return new SearchScope(
searchTerm,
delegate(ICompilation compilation) {
IMember imported = compilation.Import(memberDefinition);
IMember imported = compilation.Import((IMember)member);
return imported != null ? factory(imported) : null;
});
}
@ -478,7 +515,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -478,7 +515,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public FindMemberReferencesNavigator(IMember member)
{
this.member = member.MemberDefinition;
this.member = member;
this.searchTerm = member.Name;
}
@ -506,8 +543,58 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -506,8 +543,58 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
internal override bool IsMatch(ResolveResult rr)
{
MemberResolveResult mrr = rr as MemberResolveResult;
return mrr != null && member == mrr.Member.MemberDefinition;
return mrr != null && findReferences.IsMemberMatch(member, mrr.Member, mrr.IsVirtualCall);
}
}
IMember NormalizeMember(IMember member)
{
if (WholeVirtualSlot && member.IsOverride)
member = InheritanceHelper.GetBaseMembers(member, false).FirstOrDefault(m => !m.IsOverride) ?? member;
if (!FindOnlySpecializedReferences)
member = member.MemberDefinition;
return member;
}
bool IsMemberMatch(IMember member, IMember referencedMember, bool isVirtualCall)
{
referencedMember = NormalizeMember(referencedMember);
if (member.Equals(referencedMember))
return true;
if (!isVirtualCall)
return false;
bool isInterfaceCall = referencedMember.DeclaringTypeDefinition != null && referencedMember.DeclaringTypeDefinition.Kind == TypeKind.Interface;
if (FindCallsThroughVirtualBaseMethod && member.IsOverride && !WholeVirtualSlot && !isInterfaceCall) {
// Test if 'member' overrides 'referencedMember':
foreach (var baseMember in InheritanceHelper.GetBaseMembers(member, false)) {
if (FindOnlySpecializedReferences) {
if (baseMember.Equals(referencedMember))
return true;
} else {
if (baseMember.MemberDefinition.Equals(referencedMember))
return true;
}
if (!baseMember.IsOverride)
break;
}
return false;
} else if (FindCallsThroughInterface && isInterfaceCall) {
// Test if 'member' implements 'referencedMember':
if (FindOnlySpecializedReferences) {
return member.ImplementedInterfaceMembers.Contains(referencedMember);
} else {
return member.ImplementedInterfaceMembers.Any(m => m.MemberDefinition.Equals(referencedMember));
}
}
return false;
}
bool PerformVirtualLookup(IMember member, IMember referencedMember)
{
if (FindCallsThroughVirtualBaseMethod && member.IsOverride && !WholeVirtualSlot)
return true;
var typeDef = referencedMember.DeclaringTypeDefinition;
return FindCallsThroughInterface && typeDef != null && typeDef.Kind == TypeKind.Interface;
}
sealed class FindFieldReferences : FindMemberReferencesNavigator
@ -568,10 +655,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -568,10 +655,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region Find References to IEnumerator.Current
SearchScope FindEnumeratorCurrentReferences(IProperty property)
{
IProperty propertyDefinition = (IProperty)property.MemberDefinition;
return new SearchScope(
delegate(ICompilation compilation) {
IProperty imported = compilation.Import(propertyDefinition);
IProperty imported = compilation.Import(property);
return imported != null ? new FindEnumeratorCurrentReferencesNavigator(imported) : null;
});
}
@ -593,7 +679,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -593,7 +679,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
internal override bool IsMatch(ResolveResult rr)
{
ForEachResolveResult ferr = rr as ForEachResolveResult;
return ferr != null && ferr.CurrentProperty != null && ferr.CurrentProperty.MemberDefinition == property;
return ferr != null && ferr.CurrentProperty != null && findReferences.IsMemberMatch(property, ferr.CurrentProperty, true);
}
}
#endregion
@ -601,8 +687,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -601,8 +687,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region Find Method References
SearchScope GetSearchScopeForMethod(IMethod method)
{
method = (IMethod)method.MemberDefinition;
Type specialNodeType;
switch (method.Name) {
case "Add":
@ -708,18 +792,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -708,18 +792,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
var ferr = rr as ForEachResolveResult;
if (ferr != null) {
return IsMatch(ferr.GetEnumeratorCall)
|| (ferr.MoveNextMethod != null && method == ferr.MoveNextMethod.MemberDefinition);
|| (ferr.MoveNextMethod != null && findReferences.IsMemberMatch(method, ferr.MoveNextMethod, true));
}
}
var mrr = rr as MemberResolveResult;
return mrr != null && method == mrr.Member.MemberDefinition;
return mrr != null && findReferences.IsMemberMatch(method, mrr.Member, mrr.IsVirtualCall);
}
internal override void NavigatorDone(CSharpAstResolver resolver, CancellationToken cancellationToken)
{
foreach (var expr in potentialMethodGroupConversions) {
var conversion = resolver.GetConversion(expr, cancellationToken);
if (conversion.IsMethodGroupConversion && conversion.Method.MemberDefinition == method) {
if (conversion.IsMethodGroupConversion && findReferences.IsMemberMatch(method, conversion.Method, conversion.IsVirtualMethodLookup)) {
IType targetType = resolver.GetExpectedType(expr, cancellationToken);
ResolveResult result = resolver.Resolve(expr, cancellationToken);
ReportMatch(expr, new ConversionResolveResult(targetType, result, conversion));
@ -733,7 +817,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -733,7 +817,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region Find Indexer References
SearchScope FindIndexerReferences(IProperty indexer)
{
indexer = (IProperty)indexer.MemberDefinition;
return new SearchScope(
delegate (ICompilation compilation) {
IProperty imported = compilation.Import(indexer);
@ -761,7 +844,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -761,7 +844,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
internal override bool IsMatch(ResolveResult rr)
{
MemberResolveResult mrr = rr as MemberResolveResult;
return mrr != null && indexer == mrr.Member.MemberDefinition;
return mrr != null && findReferences.IsMemberMatch(indexer, mrr.Member, mrr.IsVirtualCall);
}
}
#endregion
@ -834,7 +917,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -834,7 +917,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
SearchScope FindOperator(IMethod op, Func<IMethod, FindReferenceNavigator> factory)
{
op = (IMethod)op.MemberDefinition;
return new SearchScope(
delegate (ICompilation compilation) {
IMethod imported = compilation.Import(op);
@ -875,7 +957,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -875,7 +957,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
internal override bool IsMatch(ResolveResult rr)
{
MemberResolveResult mrr = rr as MemberResolveResult;
return mrr != null && op == mrr.Member.MemberDefinition;
return mrr != null && findReferences.IsMemberMatch(op, mrr.Member, mrr.IsVirtualCall);
}
}
@ -907,7 +989,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -907,7 +989,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
internal override bool IsMatch(ResolveResult rr)
{
MemberResolveResult mrr = rr as MemberResolveResult;
return mrr != null && op == mrr.Member.MemberDefinition;
return mrr != null && findReferences.IsMemberMatch(op, mrr.Member, mrr.IsVirtualCall);
}
}
@ -928,12 +1010,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -928,12 +1010,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
internal override bool IsMatch(ResolveResult rr)
{
MemberResolveResult mrr = rr as MemberResolveResult;
return mrr != null && op == mrr.Member.MemberDefinition;
return mrr != null && findReferences.IsMemberMatch(op, mrr.Member, mrr.IsVirtualCall);
}
public override void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
if (conversion.IsUserDefined && conversion.Method.MemberDefinition == op) {
if (conversion.IsUserDefined && findReferences.IsMemberMatch(op, conversion.Method, conversion.IsVirtualMethodLookup)) {
ReportMatch(expression, result);
}
}
@ -956,7 +1038,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -956,7 +1038,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
internal override bool IsMatch(ResolveResult rr)
{
ConversionResolveResult crr = rr as ConversionResolveResult;
return crr != null && crr.Conversion.IsUserDefined && crr.Conversion.Method.MemberDefinition == op;
return crr != null && crr.Conversion.IsUserDefined
&& findReferences.IsMemberMatch(op, crr.Conversion.Method, crr.Conversion.IsVirtualMethodLookup);
}
}
#endregion
@ -964,7 +1047,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -964,7 +1047,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region Find Constructor References
SearchScope FindObjectCreateReferences(IMethod ctor)
{
ctor = (IMethod)ctor.MemberDefinition;
string searchTerm = null;
if (KnownTypeReference.GetCSharpNameByTypeCode(ctor.DeclaringTypeDefinition.KnownTypeCode) == null) {
// not a built-in type
@ -1002,13 +1084,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1002,13 +1084,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
internal override bool IsMatch(ResolveResult rr)
{
MemberResolveResult mrr = rr as MemberResolveResult;
return mrr != null && ctor == mrr.Member.MemberDefinition;
return mrr != null && findReferences.IsMemberMatch(ctor, mrr.Member, mrr.IsVirtualCall);
}
}
SearchScope FindChainedConstructorReferences(IMethod ctor)
{
ctor = (IMethod)ctor.MemberDefinition;
SearchScope searchScope = new SearchScope(
delegate (ICompilation compilation) {
IMethod imported = compilation.Import(ctor);
@ -1042,7 +1123,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1042,7 +1123,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
internal override bool IsMatch(ResolveResult rr)
{
MemberResolveResult mrr = rr as MemberResolveResult;
return mrr != null && ctor == mrr.Member.MemberDefinition;
return mrr != null && findReferences.IsMemberMatch(ctor, mrr.Member, mrr.IsVirtualCall);
}
}
#endregion
@ -1050,22 +1131,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1050,22 +1131,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region Find Destructor References
SearchScope GetSearchScopeForDestructor(IMethod dtor)
{
dtor = (IMethod)dtor.MemberDefinition;
string searchTerm = null;
if (KnownTypeReference.GetCSharpNameByTypeCode(dtor.DeclaringTypeDefinition.KnownTypeCode) == null) {
// not a built-in type
searchTerm = dtor.DeclaringTypeDefinition.Name;
}
return new SearchScope (
searchTerm,
var scope = new SearchScope (
delegate (ICompilation compilation) {
IMethod imported = compilation.Import(dtor);
if (imported != null) {
return new FindDestructorReferencesNavigator (imported);
} else {
return null;
}
});
IMethod imported = compilation.Import(dtor);
if (imported != null) {
return new FindDestructorReferencesNavigator (imported);
} else {
return null;
}
});
scope.accessibility = Accessibility.Private;
return scope;
}
sealed class FindDestructorReferencesNavigator : FindReferenceNavigator
@ -1085,7 +1161,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1085,7 +1161,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
internal override bool IsMatch(ResolveResult rr)
{
MemberResolveResult mrr = rr as MemberResolveResult;
return mrr != null && dtor == mrr.Member.MemberDefinition;
return mrr != null && findReferences.IsMemberMatch(dtor, mrr.Member, mrr.IsVirtualCall);
}
}
#endregion

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

@ -164,7 +164,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -164,7 +164,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
this.TargetType, method, true, out inferredTypes))
{
if (substituteInferredTypes && inferredTypes != null) {
outputGroup.Add(new SpecializedMethod(method.DeclaringType, method, inferredTypes));
outputGroup.Add(new SpecializedMethod(method, new TypeParameterSubstitution(null, inferredTypes)));
} else {
outputGroup.Add(method);
}

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

@ -778,11 +778,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -778,11 +778,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (bestCandidate == null)
return arguments;
else
return GetArgumentsWithConversions(null);
}
IList<ResolveResult> GetArgumentsWithConversions(ResolveResult targetResolveResult)
{
var conversions = this.ArgumentConversions;
ResolveResult[] args = new ResolveResult[arguments.Length];
for (int i = 0; i < args.Length; i++) {
var argument = arguments[i];
if (this.IsExtensionMethodInvocation && i == 0 && targetResolveResult != null)
argument = targetResolveResult;
if (conversions[i] == Conversion.IdentityConversion) {
args[i] = arguments[i];
args[i] = argument;
} else {
int parameterIndex = bestCandidate.ArgumentToParameterMap[i];
IType parameterType;
@ -792,9 +801,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -792,9 +801,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
parameterType = SpecialType.UnknownType;
}
if (arguments[i].IsCompileTimeConstant && conversions[i] != Conversion.None) {
args[i] = new CSharpResolver(compilation).ResolveCast(parameterType, arguments[i]);
args[i] = new CSharpResolver(compilation).ResolveCast(parameterType, argument);
} else {
args[i] = new ConversionResolveResult(parameterType, arguments[i], conversions[i]);
args[i] = new ConversionResolveResult(parameterType, argument, conversions[i]);
}
}
}
@ -807,7 +816,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -807,7 +816,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return null;
IMethod method = bestCandidate.Member as IMethod;
if (method != null && method.TypeParameters.Count > 0) {
return new SpecializedMethod(method.DeclaringType, (IMethod)method.MemberDefinition, bestCandidate.InferredTypes);
SpecializedMethod sm = method as SpecializedMethod;
if (sm != null) {
// Do not compose the substitutions, but merge them.
// This is required for InvocationTests.SubstituteClassAndMethodTypeParametersAtOnce
return new SpecializedMethod(
(IMethod)method.MemberDefinition,
new TypeParameterSubstitution(sm.Substitution.ClassTypeArguments, bestCandidate.InferredTypes));
} else {
return new SpecializedMethod(method, new TypeParameterSubstitution(null, bestCandidate.InferredTypes));
}
} else {
return bestCandidate.Member;
}
@ -830,9 +848,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -830,9 +848,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
throw new InvalidOperationException();
return new CSharpInvocationResolveResult(
targetResolveResult,
this.IsExtensionMethodInvocation ? new TypeResolveResult(member.DeclaringType) : targetResolveResult,
member,
GetArgumentsWithConversions(),
GetArgumentsWithConversions(targetResolveResult),
this.BestCandidateErrors,
this.IsExtensionMethodInvocation,
this.BestCandidateIsExpandedForm,

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

@ -650,7 +650,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -650,7 +650,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult result = errorResult;
if (variableInitializer.Parent is FieldDeclaration || variableInitializer.Parent is EventDeclaration) {
if (resolver.CurrentMember != null) {
result = new MemberResolveResult(null, resolver.CurrentMember);
result = new MemberResolveResult(null, resolver.CurrentMember, false);
}
} else {
string identifier = variableInitializer.Name;
@ -707,7 +707,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -707,7 +707,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (resolverEnabled) {
ResolveResult result = errorResult;
if (resolver.CurrentMember != null) {
result = new MemberResolveResult(null, resolver.CurrentMember);
result = new MemberResolveResult(null, resolver.CurrentMember, false);
}
ResolveAndProcessConversion(fixedVariableInitializer.CountExpression, resolver.Compilation.FindType(KnownTypeCode.Int32));
return result;
@ -726,7 +726,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -726,7 +726,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ScanChildren(member);
if (resolver.CurrentMember != null)
return new MemberResolveResult(null, resolver.CurrentMember);
return new MemberResolveResult(null, resolver.CurrentMember, false);
else
return errorResult;
} finally {
@ -772,7 +772,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -772,7 +772,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
if (resolver.CurrentMember != null)
return new MemberResolveResult(null, resolver.CurrentMember);
return new MemberResolveResult(null, resolver.CurrentMember, false);
else
return errorResult;
} finally {
@ -805,7 +805,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -805,7 +805,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
if (resolver.CurrentMember != null)
return new MemberResolveResult(null, resolver.CurrentMember);
return new MemberResolveResult(null, resolver.CurrentMember, false);
else
return errorResult;
} finally {
@ -885,7 +885,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -885,7 +885,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (resolverEnabled && resolver.CurrentTypeDefinition != null) {
ResolveAndProcessConversion(enumMemberDeclaration.Initializer, resolver.CurrentTypeDefinition.EnumUnderlyingType);
if (resolverEnabled && resolver.CurrentMember != null)
return new MemberResolveResult(null, resolver.CurrentMember);
return new MemberResolveResult(null, resolver.CurrentMember, false);
else
return errorResult;
} else {
@ -1310,8 +1310,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1310,8 +1310,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (resolverEnabled || !objectCreateExpression.Initializer.IsNull) {
var typeResolveResult = Resolve(objectCreateExpression.Type);
if (typeResolveResult.IsError)
if (typeResolveResult.IsError) {
ScanChildren (objectCreateExpression);
return typeResolveResult;
}
IType type = typeResolveResult.Type;
List<ResolveResult> initializerStatements = null;

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

@ -629,15 +629,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -629,15 +629,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// Handle array types:
ArrayType arrU = U as ArrayType;
ArrayType arrV = V as ArrayType;
ParameterizedType pV = V as ParameterizedType;
if (arrU != null && arrV != null && arrU.Dimensions == arrV.Dimensions) {
MakeLowerBoundInference(arrU.ElementType, arrV.ElementType);
return;
} else if (arrU != null && IsIEnumerableCollectionOrList(pV) && arrU.Dimensions == 1) {
MakeLowerBoundInference(arrU.ElementType, pV.GetTypeArgument(0));
return;
}
// Handle parameterized types:
ParameterizedType pV = V as ParameterizedType;
if (pV != null) {
ParameterizedType uniqueBaseType = null;
foreach (IType baseU in U.GetAllBaseTypes()) {
@ -677,20 +674,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -677,20 +674,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Log.Unindent();
}
}
static bool IsIEnumerableCollectionOrList(ParameterizedType rt)
{
if (rt == null || rt.TypeParameterCount != 1)
return false;
switch (rt.GetDefinition().FullName) {
case "System.Collections.Generic.IList":
case "System.Collections.Generic.ICollection":
case "System.Collections.Generic.IEnumerable":
return true;
default:
return false;
}
}
#endregion
#region MakeUpperBoundInference (§7.5.2.10)
@ -713,15 +696,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -713,15 +696,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// Handle array types:
ArrayType arrU = U as ArrayType;
ArrayType arrV = V as ArrayType;
ParameterizedType pU = U as ParameterizedType;
if (arrV != null && arrU != null && arrU.Dimensions == arrV.Dimensions) {
MakeUpperBoundInference(arrU.ElementType, arrV.ElementType);
return;
} else if (arrV != null && IsIEnumerableCollectionOrList(pU) && arrV.Dimensions == 1) {
MakeUpperBoundInference(pU.GetTypeArgument(0), arrV.ElementType);
return;
}
// Handle parameterized types:
ParameterizedType pU = U as ParameterizedType;
if (pU != null) {
ParameterizedType uniqueBaseType = null;
foreach (IType baseV in V.GetAllBaseTypes()) {

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

@ -4789,5 +4789,27 @@ class B : A @@ -4789,5 +4789,27 @@ class B : A
Assert.AreEqual (2, provider.Data.Where (d => d.DisplayText == "Method").Count ());
}
/// <summary>
/// Bug 3973 - code completion forgets context if text is deleted
/// </summary>
[Test()]
public void TestBug3973 ()
{
var provider = CreateProvider (
@"
using System;
class A
{
public static void Main (string[] args)
{
Console.$W$
}
}
");
Assert.IsNotNull (provider.Find ("WriteLine"), "'WriteLine' not found.");
}
}
}

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

@ -122,6 +122,19 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion @@ -122,6 +122,19 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
Assert.IsTrue (provider == null || provider.Count == 0, "provider should be empty.");
}
[Test()]
public void TestForLoopLocalVariableName ()
{
var provider = CodeCompletionBugTests.CreateProvider (@"class MyClass {
void Test()
{
$for (int f$
}
}");
Assert.IsTrue (provider == null || provider.Count == 0, "provider should be empty.");
}
[Test()]
public void TestCatchExceptionName ()
{

23
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/ContextAction/ConvertForeachToForTests.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// ConvertForeachToForTests.cs
//
// Author:
@ -64,7 +64,7 @@ namespace ICSharpCode.NRefactory.CSharp.ContextActions @@ -64,7 +64,7 @@ namespace ICSharpCode.NRefactory.CSharp.ContextActions
}
[Test()]
public void TestEnumeration ()
public void TestListOfT ()
{
string result = RunContextAction (
new ConvertForeachToFor (),
@ -95,5 +95,24 @@ namespace ICSharpCode.NRefactory.CSharp.ContextActions @@ -95,5 +95,24 @@ namespace ICSharpCode.NRefactory.CSharp.ContextActions
" }" + Environment.NewLine +
"}", result);
}
[Test()]
public void TestEnumerableOfT ()
{
TestWrongContext (
new ConvertForeachToFor (),
"using System;" + Environment.NewLine +
"using System.Collections.Generic;" + Environment.NewLine +
"class TestClass" + Environment.NewLine +
"{" + Environment.NewLine +
" void Test (IEnumerable<string> args)" + Environment.NewLine +
" {" + Environment.NewLine +
" $foreach (var v in args) {" + Environment.NewLine +
" Console.WriteLine (v);" + Environment.NewLine +
" }" + Environment.NewLine +
" }" + Environment.NewLine +
"}"
);
}
}
}

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

@ -33,24 +33,26 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -33,24 +33,26 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
CompilationUnit compilationUnit;
CSharpParsedFile parsedFile;
ICompilation compilation;
FindReferences findReferences;
void Init(string code)
{
compilationUnit = new CSharpParser().Parse(new StringReader(code), "test.cs");
parsedFile = compilationUnit.ToTypeSystem();
compilation = TypeSystemHelper.CreateCompilation(parsedFile);
findReferences = new FindReferences();
}
AstNode[] FindReferences(IEntity entity)
{
var result = new List<AstNode>();
var findReferences = new FindReferences();
var searchScopes = findReferences.GetSearchScopes(entity);
findReferences.FindReferencesInFile(searchScopes, parsedFile, compilationUnit, compilation,
(node, rr) => result.Add(node), CancellationToken.None);
return result.OrderBy(n => n.StartLocation).ToArray();
}
#region Method Group
[Test]
public void FindMethodGroupReference()
{
@ -107,7 +109,9 @@ class Test { @@ -107,7 +109,9 @@ class Test {
Assert.AreEqual(new [] { new TextLocation(4, 49), new TextLocation(7, 2) },
FindReferences(m_string).Select(n => n.StartLocation).ToArray());
}
#endregion
#region GetEnumerator
[Test]
public void FindReferenceToGetEnumeratorUsedImplicitlyInForeach()
{
@ -129,7 +133,9 @@ class Test { @@ -129,7 +133,9 @@ class Test {
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 3 && r is MethodDeclaration));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 8 && r is ForeachStatement));
}
#endregion
#region Op_Implicit
[Test]
public void FindReferencesForOpImplicitInLocalVariableInitialization()
{
@ -147,5 +153,63 @@ class Test { @@ -147,5 +153,63 @@ class Test {
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 4 && r is ObjectCreateExpression));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 6 && r is OperatorDeclaration));
}
#endregion
#region Inheritance
const string inheritanceTest = @"using System;
class A { public virtual void M() {} }
class B : A { public override void M() {} }
class C : A { public override void M() {} }
class Calls {
void Test(A a, B b, C c) {
a.M();
b.M();
c.M();
}
}";
[Test]
public void InheritanceTest1()
{
Init(inheritanceTest);
var test = compilation.MainAssembly.TopLevelTypeDefinitions.Single(t => t.Name == "B");
var BM = test.Methods.Single(m => m.Name == "M");
var actual = FindReferences(BM).ToList();
Assert.AreEqual(2, actual.Count);
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 3 && r is MethodDeclaration));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 8 && r is InvocationExpression));
}
[Test]
public void InheritanceTest2()
{
Init(inheritanceTest);
findReferences.FindCallsThroughVirtualBaseMethod = true;
var test = compilation.MainAssembly.TopLevelTypeDefinitions.Single(t => t.Name == "B");
var BM = test.Methods.Single(m => m.Name == "M");
var actual = FindReferences(BM).ToList();
Assert.AreEqual(3, actual.Count);
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 3 && r is MethodDeclaration));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 7 && r is InvocationExpression));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 8 && r is InvocationExpression));
}
[Test]
public void InheritanceTest3()
{
Init(inheritanceTest);
findReferences.WholeVirtualSlot = true;
var test = compilation.MainAssembly.TopLevelTypeDefinitions.Single(t => t.Name == "B");
var BM = test.Methods.Single(m => m.Name == "M");
var actual = FindReferences(BM).ToList();
Assert.AreEqual(6, actual.Count);
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 2 && r is MethodDeclaration));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 3 && r is MethodDeclaration));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 4 && r is MethodDeclaration));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 7 && r is InvocationExpression));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 8 && r is InvocationExpression));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 9 && r is InvocationExpression));
}
#endregion
}
}

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

@ -493,5 +493,33 @@ class Test : IVisitor<object, object> { @@ -493,5 +493,33 @@ class Test : IVisitor<object, object> {
Assert.AreEqual("System.Object", typeArguments[0].ReflectionName);
Assert.AreEqual("System.Object", typeArguments[1].ReflectionName);
}
[Test]
public void FirstParameterToExtensionMethod()
{
string program = @"
public class X {}
public static class Ex {
public static void F(this X x, int y, int z) {}
}
class C {
public void M() {
X a = null;
int b = 0, c = 0;
$a.F(b, c)$;
}
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.That(rr.IsExtensionMethodInvocation, Is.True);
Assert.That(rr.Arguments[0], Is.InstanceOf<LocalResolveResult>());
Assert.That(((LocalResolveResult)rr.Arguments[0]).Variable.Name, Is.EqualTo("a"));
Assert.That(rr.Arguments[1], Is.InstanceOf<LocalResolveResult>());
Assert.That(((LocalResolveResult)rr.Arguments[1]).Variable.Name, Is.EqualTo("b"));
Assert.That(rr.Arguments[2], Is.InstanceOf<LocalResolveResult>());
Assert.That(((LocalResolveResult)rr.Arguments[2]).Variable.Name, Is.EqualTo("c"));
Assert.That(rr.TargetResult, Is.InstanceOf<TypeResolveResult>());
}
}
}

13
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ObjectCreationTests.cs

@ -260,5 +260,18 @@ class Test { @@ -260,5 +260,18 @@ class Test {
Assert.AreEqual("Test", rr.Type.ReflectionName);
Assert.AreEqual(5, rr.InitializerStatements.Count);
}
[Test]
public void CreateGeneric()
{
string program = @"using System;
class Test<T> where T : new() {
object x = $new T()$;
}";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.AreEqual(TypeKind.TypeParameter, rr.Type.Kind);
Assert.AreEqual(TypeKind.TypeParameter, rr.Member.DeclaringType.Kind);
}
}
}

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

@ -70,6 +70,25 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -70,6 +70,25 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Assert.IsTrue(success);
}
[Test]
public void ArrayToReadOnlyList()
{
ITypeParameter tp = new DefaultTypeParameter(compilation, EntityType.Method, 0, "T");
IType stringType = compilation.FindType(KnownTypeCode.String);
ITypeDefinition readOnlyListType = compilation.FindType(KnownTypeCode.IReadOnlyListOfT).GetDefinition();
if (readOnlyListType == null)
Assert.Ignore(".NET 4.5 IReadOnlyList not available");
bool success;
Assert.AreEqual(
new [] { stringType },
ti.InferTypeArguments(new [] { tp },
new [] { new ResolveResult(new ArrayType(compilation, stringType)) },
new [] { new ParameterizedType(readOnlyListType, new [] { tp }) },
out success));
Assert.IsTrue(success);
}
[Test]
public void EnumerableToArrayInContravariantType()
{

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

@ -182,6 +182,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -182,6 +182,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
IMethod m = testClass.Methods.Single(me => me.Name == "GetIndex");
Assert.AreEqual("T", m.TypeParameters[0].Name);
Assert.AreEqual(EntityType.Method, m.TypeParameters[0].OwnerType);
Assert.AreSame(m, m.TypeParameters[0].Owner);
ParameterizedType constraint = (ParameterizedType)m.TypeParameters[0].DirectBaseTypes.First();
Assert.AreEqual("IEquatable", constraint.Name);
@ -190,6 +191,53 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -190,6 +191,53 @@ namespace ICSharpCode.NRefactory.TypeSystem
Assert.AreSame(m.TypeParameters[0], constraint.TypeArguments[0]);
}
[Test]
public void GetIndexSpecializedTypeParameter()
{
var testClass = GetTypeDefinition(typeof(GenericClass<,>));
var methodDef = testClass.Methods.Single(me => me.Name == "GetIndex");
var m = new SpecializedMethod(methodDef, new TypeParameterSubstitution(
new[] { compilation.FindType(KnownTypeCode.Int16), compilation.FindType(KnownTypeCode.Int32) },
null
));
Assert.AreEqual("T", m.TypeParameters[0].Name);
Assert.AreEqual(EntityType.Method, m.TypeParameters[0].OwnerType);
Assert.AreSame(m, m.TypeParameters[0].Owner);
ParameterizedType constraint = (ParameterizedType)m.TypeParameters[0].DirectBaseTypes.First();
Assert.AreEqual("IEquatable", constraint.Name);
Assert.AreEqual(1, constraint.TypeParameterCount);
Assert.AreEqual(1, constraint.TypeArguments.Count);
Assert.AreSame(m.TypeParameters[0], constraint.TypeArguments[0]);
}
[Test]
public void GetIndexDoubleSpecialization()
{
var testClass = GetTypeDefinition(typeof(GenericClass<,>));
// GenericClass<A, B>.GetIndex<T>
var methodDef = testClass.Methods.Single(me => me.Name == "GetIndex");
// GenericClass<B, A>.GetIndex<A>
var m1 = new SpecializedMethod(methodDef, new TypeParameterSubstitution(
new[] { testClass.TypeParameters[1], testClass.TypeParameters[0] },
new[] { testClass.TypeParameters[0] }
));
// GenericClass<string, int>.GetIndex<int>
var m2 = new SpecializedMethod(m1, new TypeParameterSubstitution(
new[] { compilation.FindType(KnownTypeCode.Int32), compilation.FindType(KnownTypeCode.String) },
null
));
// GenericClass<string, int>.GetIndex<int>
var m12 = new SpecializedMethod(methodDef, new TypeParameterSubstitution(
new[] { compilation.FindType(KnownTypeCode.String), compilation.FindType(KnownTypeCode.Int32) },
new[] { compilation.FindType(KnownTypeCode.Int32) }
));
Assert.AreEqual(m12, m2);
}
[Test]
public void GenericEnum()
{

2
src/Libraries/NRefactory/ICSharpCode.NRefactory/Documentation/IdStringProvider.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.NRefactory.Documentation @@ -31,7 +31,7 @@ namespace ICSharpCode.NRefactory.Documentation
/// </summary>
public static class IdStringProvider
{
#region GetIDString
#region GetIdString
/// <summary>
/// Gets the ID string (C# 4.0 spec, §A.3.1) for the specified entity.
/// </summary>

2
src/Libraries/NRefactory/ICSharpCode.NRefactory/Editor/ITextSource.cs

@ -168,7 +168,7 @@ namespace ICSharpCode.NRefactory.Editor @@ -168,7 +168,7 @@ namespace ICSharpCode.NRefactory.Editor
/// <remarks>
/// Verions can be used to efficiently detect whether a document has changed and needs reparsing;
/// or even to implement incremental parsers.
/// It is a separate class from ITextBuffer to allow the GC to collect the text buffer while
/// It is a separate class from ITextSource to allow the GC to collect the text source while
/// the version checkpoint is still in use.
/// </remarks>
public interface ITextSourceVersion

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

@ -88,11 +88,11 @@ namespace ICSharpCode.NRefactory.Semantics @@ -88,11 +88,11 @@ namespace ICSharpCode.NRefactory.Semantics
return new UserDefinedConversion(false, operatorMethod, isLifted);
}
public static Conversion MethodGroupConversion(IMethod chosenMethod)
public static Conversion MethodGroupConversion(IMethod chosenMethod, bool isVirtualMethodLookup)
{
if (chosenMethod == null)
throw new ArgumentNullException("chosenMethod");
return new MethodGroupConv(chosenMethod);
return new MethodGroupConv(chosenMethod, isVirtualMethodLookup);
}
#endregion
@ -302,10 +302,12 @@ namespace ICSharpCode.NRefactory.Semantics @@ -302,10 +302,12 @@ namespace ICSharpCode.NRefactory.Semantics
sealed class MethodGroupConv : Conversion
{
readonly IMethod method;
readonly bool isVirtualMethodLookup;
public MethodGroupConv(IMethod method)
public MethodGroupConv(IMethod method, bool isVirtualMethodLookup)
{
this.method = method;
this.isVirtualMethodLookup = isVirtualMethodLookup;
}
public override bool IsImplicit {
@ -316,6 +318,10 @@ namespace ICSharpCode.NRefactory.Semantics @@ -316,6 +318,10 @@ namespace ICSharpCode.NRefactory.Semantics
get { return true; }
}
public override bool IsVirtualMethodLookup {
get { return isVirtualMethodLookup; }
}
public override IMethod Method {
get { return method; }
}
@ -434,6 +440,13 @@ namespace ICSharpCode.NRefactory.Semantics @@ -434,6 +440,13 @@ namespace ICSharpCode.NRefactory.Semantics
get { return false; }
}
/// <summary>
/// For method-group conversions, gets whether to perform a virtual method lookup at runtime.
/// </summary>
public virtual bool IsVirtualMethodLookup {
get { return false; }
}
/// <summary>
/// Gets whether this conversion is an anonymous function conversion.
/// </summary>

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

@ -34,12 +34,30 @@ namespace ICSharpCode.NRefactory.Semantics @@ -34,12 +34,30 @@ namespace ICSharpCode.NRefactory.Semantics
readonly bool isConstant;
readonly object constantValue;
readonly ResolveResult targetResult;
readonly bool isVirtualCall;
public MemberResolveResult(ResolveResult targetResult, IMember member)
: base(member.EntityType == EntityType.Constructor ? member.DeclaringType : member.ReturnType)
{
this.targetResult = targetResult;
this.member = member;
var thisRR = targetResult as ThisResolveResult;
this.isVirtualCall = member.IsOverridable && !(thisRR != null && thisRR.CausesNonVirtualInvocation);
IField field = member as IField;
if (field != null) {
isConstant = field.IsConst;
if (isConstant)
constantValue = field.ConstantValue;
}
}
public MemberResolveResult(ResolveResult targetResult, IMember member, bool isVirtualCall)
: base(member.EntityType == EntityType.Constructor ? member.DeclaringType : member.ReturnType)
{
this.targetResult = targetResult;
this.member = member;
this.isVirtualCall = isVirtualCall;
IField field = member as IField;
if (field != null) {
isConstant = field.IsConst;
@ -69,6 +87,13 @@ namespace ICSharpCode.NRefactory.Semantics @@ -69,6 +87,13 @@ namespace ICSharpCode.NRefactory.Semantics
get { return member; }
}
/// <summary>
/// Gets whether this MemberResolveResult is a virtual call.
/// </summary>
public bool IsVirtualCall {
get { return isVirtualCall; }
}
public override bool IsCompileTimeConstant {
get { return isConstant; }
}

12
src/Libraries/NRefactory/ICSharpCode.NRefactory/Semantics/ThisResolveResult.cs

@ -27,8 +27,18 @@ namespace ICSharpCode.NRefactory.Semantics @@ -27,8 +27,18 @@ namespace ICSharpCode.NRefactory.Semantics
/// </summary>
public class ThisResolveResult : ResolveResult
{
public ThisResolveResult(IType type) : base(type)
bool causesNonVirtualInvocation;
public ThisResolveResult(IType type, bool causesNonVirtualInvocation = false) : base(type)
{
this.causesNonVirtualInvocation = causesNonVirtualInvocation;
}
/// <summary>
/// Gets whether this resolve result causes member invocations to be non-virtual.
/// </summary>
public bool CausesNonVirtualInvocation {
get { return causesNonVirtualInvocation; }
}
}
}

17
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs

@ -246,19 +246,10 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -246,19 +246,10 @@ namespace ICSharpCode.NRefactory.TypeSystem
{
if (type == null)
throw new ArgumentNullException("type");
ITypeDefinition def = type.GetDefinition();
if (def != null && def.Kind == TypeKind.Delegate) {
foreach (IMember member in def.Members) {
if (member.Name == "Invoke" && member is IMethod) {
ParameterizedType pt = type as ParameterizedType;
if (pt != null) {
return new SpecializedMethod(pt, (IMethod)member);
}
return (IMethod)member;
}
}
}
return null;
if (type.Kind == TypeKind.Delegate)
return type.GetMethods(m => m.Name == "Invoke", GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
else
return null;
}
#endregion

1
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/IMember.cs

@ -20,6 +20,7 @@ using System; @@ -20,6 +20,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.TypeSystem
{

32
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.Utils;
@ -65,18 +66,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -65,18 +66,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
}
public override DocumentationComment Documentation {
get {
IUnresolvedDocumentationProvider docProvider = unresolved.ParsedFile as IUnresolvedDocumentationProvider;
if (docProvider != null) {
var doc = docProvider.GetDocumentation(unresolved, this);
if (doc != null)
return doc;
}
return base.Documentation;
}
}
IList<IMember> FindImplementedInterfaceMembers()
{
if (unresolved.IsExplicitInterfaceImplementation) {
@ -87,8 +76,25 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -87,8 +76,25 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
result.Add(member);
}
return result.ToArray();
} else if (unresolved.IsStatic) {
return EmptyList<IMember>.Instance;
} else {
throw new NotImplementedException();
// TODO: implement interface member mappings correctly
return InheritanceHelper.GetBaseMembers(this, true)
.Where(m => m.DeclaringTypeDefinition != null && m.DeclaringTypeDefinition.Kind == TypeKind.Interface)
.ToArray();
}
}
public override DocumentationComment Documentation {
get {
IUnresolvedDocumentationProvider docProvider = unresolved.ParsedFile as IUnresolvedDocumentationProvider;
if (docProvider != null) {
var doc = docProvider.GetDocumentation(unresolved, this);
if (doc != null)
return doc;
}
return base.Documentation;
}
}

2
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs

@ -261,7 +261,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -261,7 +261,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
if (this.HasDefaultConstructorConstraint || this.HasValueTypeConstraint) {
if (filter == null || filter(dummyConstructor)) {
var resolvedCtor = GetDummyConstructor(compilation);
IMethod m = new SpecializedMethod(this, resolvedCtor, EmptyList<IType>.Instance);
IMethod m = new SpecializedMethod(resolvedCtor, TypeParameterSubstitution.Identity) { DeclaringType = this };
return new [] { m };
}
}

3
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs

@ -781,7 +781,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -781,7 +781,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
IType coClass = ComHelper.GetCoClass(this);
using (var busyLock = BusyManager.Enter(this)) {
if (busyLock.Success) {
return coClass.GetConstructors(filter, options).Select(m => new SpecializedMethod(this, m));
return coClass.GetConstructors(filter, options)
.Select(m => new SpecializedMethod(m, TypeParameterSubstitution.Identity) { DeclaringType = this });
}
}
return EmptyList<IMethod>.Instance;

10
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/GetMembersHelper.cs

@ -132,7 +132,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -132,7 +132,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
else
substitution = new TypeParameterSubstitution(null, methodTypeArguments);
}
yield return new SpecializedMethod(baseType, m, methodTypeArguments, substitution);
yield return new SpecializedMethod(m, substitution);
}
} else {
foreach (IMethod m in declaredMethods) {
@ -162,7 +162,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -162,7 +162,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
ParameterizedType pt = baseType as ParameterizedType;
if (pt != null) {
var substitution = pt.GetSubstitution();
return declaredCtors.Select(m => new SpecializedMethod(pt, m, null, substitution));
return declaredCtors.Select(m => new SpecializedMethod(m, substitution) { DeclaringType = pt });
} else {
return declaredCtors;
}
@ -189,7 +189,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -189,7 +189,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
ParameterizedType pt = baseType as ParameterizedType;
if (pt != null) {
var substitution = pt.GetSubstitution();
return declaredProperties.Select(m => new SpecializedProperty(pt, m, substitution));
return declaredProperties.Select(m => new SpecializedProperty(m, substitution) { DeclaringType = pt });
} else {
return declaredProperties;
}
@ -216,7 +216,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -216,7 +216,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
ParameterizedType pt = baseType as ParameterizedType;
if (pt != null) {
var substitution = pt.GetSubstitution();
return declaredFields.Select(m => new SpecializedField(pt, m, substitution));
return declaredFields.Select(m => new SpecializedField(m, substitution) { DeclaringType = pt });
} else {
return declaredFields;
}
@ -243,7 +243,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -243,7 +243,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
ParameterizedType pt = baseType as ParameterizedType;
if (pt != null) {
var substitution = pt.GetSubstitution();
return declaredEvents.Select(m => new SpecializedEvent(pt, m, substitution));
return declaredEvents.Select(m => new SpecializedEvent(m, substitution) { DeclaringType = pt });
} else {
return declaredEvents;
}

23
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedEvent.cs

@ -27,18 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -27,18 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
readonly IEvent eventDefinition;
public SpecializedEvent(IType declaringType, IEvent eventDefinition)
: base(declaringType, eventDefinition)
public SpecializedEvent(IEvent eventDefinition, TypeParameterSubstitution substitution)
: base(eventDefinition)
{
this.eventDefinition = eventDefinition;
Initialize(GetSubstitution(declaringType));
}
internal SpecializedEvent(IType declaringType, IEvent eventDefinition, TypeVisitor substitution)
: base(declaringType, eventDefinition)
{
this.eventDefinition = eventDefinition;
Initialize(substitution);
AddSubstitution(substitution);
this.eventDefinition = (IEvent)base.MemberDefinition;
}
public bool CanAdd {
@ -53,16 +46,18 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -53,16 +46,18 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return eventDefinition.CanInvoke; }
}
IMethod addAccessor, removeAccessor, invokeAccessor;
public IMethod AddAccessor {
get { return WrapAccessor(eventDefinition.AddAccessor); }
get { return WrapAccessor(ref this.addAccessor, eventDefinition.AddAccessor); }
}
public IMethod RemoveAccessor {
get { return WrapAccessor(eventDefinition.RemoveAccessor); }
get { return WrapAccessor(ref this.removeAccessor, eventDefinition.RemoveAccessor); }
}
public IMethod InvokeAccessor {
get { return WrapAccessor(eventDefinition.InvokeAccessor); }
get { return WrapAccessor(ref this.invokeAccessor, eventDefinition.InvokeAccessor); }
}
}
}

15
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedField.cs

@ -27,18 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -27,18 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
readonly IField fieldDefinition;
public SpecializedField(IType declaringType, IField fieldDefinition)
: base(declaringType, fieldDefinition)
public SpecializedField(IField fieldDefinition, TypeParameterSubstitution substitution)
: base(fieldDefinition)
{
this.fieldDefinition = fieldDefinition;
Initialize(GetSubstitution(declaringType));
}
internal SpecializedField(IType declaringType, IField fieldDefinition, TypeVisitor substitution)
: base(declaringType, fieldDefinition)
{
this.fieldDefinition = fieldDefinition;
Initialize(substitution);
AddSubstitution(substitution);
this.fieldDefinition = (IField)base.MemberDefinition;
}
public bool IsReadOnly {

184
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
@ -31,58 +32,115 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -31,58 +32,115 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// </summary>
public abstract class SpecializedMember : IMember
{
readonly IType declaringType;
readonly IMember memberDefinition;
TypeParameterSubstitution substitution;
IType declaringType;
IType returnType;
protected SpecializedMember(IType declaringType, IMember memberDefinition)
protected SpecializedMember(IMember memberDefinition)
{
if (declaringType == null)
throw new ArgumentNullException("declaringType");
if (memberDefinition == null)
throw new ArgumentNullException("memberDefinition");
this.declaringType = declaringType;
this.memberDefinition = memberDefinition;
SpecializedMember sm = memberDefinition as SpecializedMember;
if (sm != null) {
this.memberDefinition = sm.memberDefinition;
this.substitution = sm.substitution;
} else {
this.memberDefinition = memberDefinition;
this.substitution = TypeParameterSubstitution.Identity;
}
}
protected virtual void Initialize(TypeVisitor substitution)
/// <summary>
/// Performs a substitution. This method may only be called by constructors in derived classes.
/// </summary>
protected void AddSubstitution(TypeParameterSubstitution newSubstitution)
{
this.returnType = Substitute(memberDefinition.ReturnType, substitution);
Debug.Assert(declaringType == null);
Debug.Assert(returnType == null);
this.substitution = TypeParameterSubstitution.Compose(newSubstitution, this.substitution);
}
public virtual IMemberReference ToMemberReference()
public static SpecializedMember Create(IMember memberDefinition, TypeParameterSubstitution substitution)
{
return new SpecializingMemberReference(declaringType.ToTypeReference(), memberDefinition.ToMemberReference());
if (memberDefinition == null) {
return null;
} else if (memberDefinition is IMethod) {
return new SpecializedMethod((IMethod)memberDefinition, substitution);
} else if (memberDefinition is IProperty) {
return new SpecializedProperty((IProperty)memberDefinition, substitution);
} else if (memberDefinition is IField) {
return new SpecializedField((IField)memberDefinition, substitution);
} else if (memberDefinition is IEvent) {
return new SpecializedEvent((IEvent)memberDefinition, substitution);
} else {
throw new NotSupportedException("Unknown IMember: " + memberDefinition);
}
}
internal static TypeVisitor GetSubstitution(IType declaringType)
public IMemberReference ToMemberReference()
{
ParameterizedType pt = declaringType as ParameterizedType;
if (pt != null)
return pt.GetSubstitution();
else
return null;
return new SpecializingMemberReference(
memberDefinition.ToMemberReference(),
ToTypeReference(substitution.ClassTypeArguments),
ToTypeReference(substitution.MethodTypeArguments));
}
internal static IType Substitute(IType type, TypeVisitor substitution)
static IList<ITypeReference> ToTypeReference(IList<IType> typeArguments)
{
if (substitution == null)
return type;
if (typeArguments == null)
return null;
else
return type.AcceptVisitor(substitution);
return typeArguments.Select(t => t.ToTypeReference()).ToArray();
}
internal IMethod WrapAccessor(IMethod accessorDefinition)
internal IMethod WrapAccessor(ref IMethod cachingField, IMethod accessorDefinition)
{
if (accessorDefinition == null)
return null;
var result = LazyInit.VolatileRead(ref cachingField);
if (result != null)
return result;
else
return new SpecializedMethod(declaringType, accessorDefinition);
return LazyInit.GetOrSet(ref cachingField, new SpecializedMethod(accessorDefinition, substitution));
}
/// <summary>
/// Gets the substitution belonging to this specialized member.
/// </summary>
public TypeParameterSubstitution Substitution {
get { return substitution; }
}
public IType DeclaringType {
get { return declaringType; }
get {
var result = LazyInit.VolatileRead(ref this.declaringType);
if (result != null)
return result;
IType definitionDeclaringType = memberDefinition.DeclaringType;
ITypeDefinition definitionDeclaringTypeDef = definitionDeclaringType as ITypeDefinition;
if (definitionDeclaringTypeDef != null && definitionDeclaringType.TypeParameterCount > 0) {
if (substitution.ClassTypeArguments != null && substitution.ClassTypeArguments.Count == definitionDeclaringType.TypeParameterCount) {
result = new ParameterizedType(definitionDeclaringTypeDef, substitution.ClassTypeArguments);
} else {
result = new ParameterizedType(definitionDeclaringTypeDef, definitionDeclaringTypeDef.TypeParameters).AcceptVisitor(substitution);
}
} else {
result = definitionDeclaringType.AcceptVisitor(substitution);
}
return LazyInit.GetOrSet(ref this.declaringType, result);
}
internal set {
// This setter is used as an optimization when the code constructing
// the SpecializedMember already knows the declaring type.
Debug.Assert(this.declaringType == null);
Debug.Assert(value != null);
// As this setter is used only during construction before the member is published
// to other threads, we don't need a volatile write.
this.declaringType = value;
}
}
public IMember MemberDefinition {
@ -94,8 +152,21 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -94,8 +152,21 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
public IType ReturnType {
get { return returnType; }
protected set { returnType = value; }
get {
var result = LazyInit.VolatileRead(ref this.returnType);
if (result != null)
return result;
else
return LazyInit.GetOrSet(ref this.returnType, memberDefinition.ReturnType.AcceptVisitor(substitution));
}
protected set {
// This setter is used for LiftedUserDefinedOperator, a special case of specialized member
// (not a normal type parameter substitution).
// As this setter is used only during construction before the member is published
// to other threads, we don't need a volatile write.
this.returnType = value;
}
}
public bool IsVirtual {
@ -143,19 +214,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -143,19 +214,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
var definitionImplementations = memberDefinition.ImplementedInterfaceMembers;
IMember[] result = new IMember[definitionImplementations.Count];
for (int i = 0; i < result.Length; i++) {
result[i] = Specialize(definitionImplementations[i]);
result[i] = SpecializedMember.Create(definitionImplementations[i], substitution);
}
return result;
}
/// <summary>
/// Specialize another member using the same type arguments as this member.
/// </summary>
protected virtual IMember Specialize(IMember otherMember)
{
return SpecializingMemberReference.CreateSpecializedMember(declaringType, memberDefinition, null);
}
public bool IsExplicitInterfaceImplementation {
get { return memberDefinition.IsExplicitInterfaceImplementation; }
}
@ -241,13 +304,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -241,13 +304,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
SpecializedMember other = obj as SpecializedMember;
if (other == null)
return false;
return this.declaringType.Equals(other.declaringType) && this.memberDefinition.Equals(other.memberDefinition);
return this.memberDefinition.Equals(other.memberDefinition) && this.substitution.Equals(other.substitution);
}
public override int GetHashCode()
{
unchecked {
return 1000000007 * declaringType.GetHashCode() + 1000000009 * memberDefinition.GetHashCode();
return 1000000007 * memberDefinition.GetHashCode() + 1000000009 * substitution.GetHashCode();
}
}
@ -256,11 +319,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -256,11 +319,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
StringBuilder b = new StringBuilder("[");
b.Append(GetType().Name);
b.Append(' ');
b.Append(declaringType.ToString());
b.Append(this.DeclaringType.ToString());
b.Append('.');
b.Append(this.Name);
b.Append(':');
b.Append(returnType.ToString());
b.Append(this.ReturnType.ToString());
b.Append(']');
return b.ToString();
}
@ -270,36 +333,48 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -270,36 +333,48 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
IList<IParameter> parameters;
protected SpecializedParameterizedMember(IType declaringType, IParameterizedMember memberDefinition)
: base(declaringType, memberDefinition)
protected SpecializedParameterizedMember(IParameterizedMember memberDefinition)
: base(memberDefinition)
{
}
protected override void Initialize(TypeVisitor substitution)
public IList<IParameter> Parameters {
get {
var result = LazyInit.VolatileRead(ref this.parameters);
if (result != null)
return result;
else
return LazyInit.GetOrSet(ref this.parameters, CreateParameters(this.Substitution));
}
protected set {
// This setter is used for LiftedUserDefinedOperator, a special case of specialized member
// (not a normal type parameter substitution).
// As this setter is used only during construction before the member is published
// to other threads, we don't need a volatile write.
this.parameters = value;
}
}
protected IList<IParameter> CreateParameters(TypeVisitor substitution)
{
base.Initialize(substitution);
var paramDefs = ((IParameterizedMember)this.MemberDefinition).Parameters;
if (paramDefs.Count == 0) {
this.parameters = EmptyList<IParameter>.Instance;
return EmptyList<IParameter>.Instance;
} else {
var parameters = new IParameter[paramDefs.Count];
for (int i = 0; i < parameters.Length; i++) {
IType newType = Substitute(paramDefs[i].Type, substitution);
IType newType = paramDefs[i].Type.AcceptVisitor(substitution);
if (newType != paramDefs[i].Type) {
parameters[i] = new SpecializedParameter(paramDefs[i], newType);
} else {
parameters[i] = paramDefs[i];
}
}
this.parameters = Array.AsReadOnly(parameters);
return Array.AsReadOnly(parameters);
}
}
public IList<IParameter> Parameters {
get { return parameters; }
}
public override string ToString()
{
StringBuilder b = new StringBuilder("[");
@ -309,9 +384,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -309,9 +384,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
b.Append('.');
b.Append(this.Name);
b.Append('(');
for (int i = 0; i < parameters.Count; i++) {
for (int i = 0; i < this.Parameters.Count; i++) {
if (i > 0) b.Append(", ");
b.Append(parameters[i].ToString());
b.Append(this.Parameters[i].ToString());
}
b.Append("):");
b.Append(this.ReturnType.ToString());
@ -326,7 +401,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -326,7 +401,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public SpecializedParameter(IParameter originalParameter, IType newType)
{
this.originalParameter = originalParameter;
if (originalParameter is SpecializedParameter)
this.originalParameter = ((SpecializedParameter)originalParameter).originalParameter;
else
this.originalParameter = originalParameter;
this.newType = newType;
}

103
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs

@ -32,50 +32,36 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -32,50 +32,36 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public class SpecializedMethod : SpecializedParameterizedMember, IMethod
{
readonly IMethod methodDefinition;
readonly IList<IType> typeArguments;
readonly IList<ITypeParameter> specializedTypeParameters;
readonly ITypeParameter[] specializedTypeParameters;
public SpecializedMethod(IType declaringType, IMethod methodDefinition, IList<IType> typeArguments = null)
: this(declaringType, methodDefinition, typeArguments, GetSubstitution(declaringType, typeArguments))
public SpecializedMethod(IMethod methodDefinition, TypeParameterSubstitution substitution)
: base(methodDefinition)
{
}
internal protected SpecializedMethod(IType declaringType, IMethod methodDefinition, IList<IType> typeArguments, TypeVisitor substitution)
: base(declaringType, methodDefinition)
{
if (declaringType == null)
throw new ArgumentNullException("declaringType");
if (methodDefinition == null)
throw new ArgumentNullException("methodDefinition");
// The base ctor might have unpacked a SpecializedMember
// (in case we are specializing an already-specialized method)
methodDefinition = (IMethod)base.MemberDefinition;
this.methodDefinition = methodDefinition;
this.typeArguments = typeArguments ?? EmptyList<IType>.Instance;
if (methodDefinition.TypeParameters.Any(ConstraintNeedsSpecialization)) {
// The method is generic, and we need to specialize the type parameters
specializedTypeParameters = new ITypeParameter[methodDefinition.TypeParameters.Count];
for (int i = 0; i < specializedTypeParameters.Count; i++) {
for (int i = 0; i < specializedTypeParameters.Length; i++) {
ITypeParameter tp = methodDefinition.TypeParameters[i];
if (ConstraintNeedsSpecialization(tp))
tp = new SpecializedTypeParameter(tp, this, substitution);
tp = new SpecializedTypeParameter(tp, this);
specializedTypeParameters[i] = tp;
}
// add substitution that replaces the base method's type parameters with our specialized version
AddSubstitution(new TypeParameterSubstitution(null, specializedTypeParameters));
}
if (typeArguments != null && typeArguments.Count > 0) {
if (typeArguments.Count != methodDefinition.TypeParameters.Count)
throw new ArgumentException("Incorrect number of type arguments");
} else if (specializedTypeParameters != null) {
// No type arguments were specified, but the method is generic.
// -> substitute original type parameters with the specialized ones
substitution = GetSubstitution(declaringType, specializedTypeParameters.ToArray<IType>());
for (int i = 0; i < specializedTypeParameters.Count; i++) {
if (ConstraintNeedsSpecialization(methodDefinition.TypeParameters[i])) {
((SpecializedTypeParameter)specializedTypeParameters[i]).substitution = substitution;
}
// Add the main substitution after the method type parameter specialization.
AddSubstitution(substitution);
if (specializedTypeParameters != null) {
// Set the substitution on the type parameters to the final composed substitution
foreach (var tp in specializedTypeParameters.OfType<SpecializedTypeParameter>()) {
if (tp.Owner == this)
tp.substitution = base.Substitution;
}
}
Initialize(substitution);
}
static bool ConstraintNeedsSpecialization(ITypeParameter tp)
@ -95,53 +81,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -95,53 +81,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return null;
}
public override IMemberReference ToMemberReference()
{
return new SpecializingMemberReference(
this.DeclaringType.ToTypeReference(),
this.MemberDefinition.ToMemberReference(),
typeArguments.Select(ta => ta.ToTypeReference()).ToList()
);
}
protected override IMember Specialize(IMember otherMember)
{
return SpecializingMemberReference.CreateSpecializedMember(this.DeclaringType, this.MemberDefinition, typeArguments);
}
/// <summary>
/// Gets the type arguments passed to this method.
/// If only the type parameters for the class were specified and the generic method
/// itself is not specialized yet, this property will return an empty list.
/// </summary>
public IList<IType> TypeArguments {
get { return typeArguments; }
}
public override int GetHashCode()
{
int hashCode = base.GetHashCode();
unchecked {
for (int i = 0; i < typeArguments.Count; i++) {
hashCode *= 362631391;
hashCode += typeArguments[i].GetHashCode();
}
}
return hashCode;
}
public override bool Equals(object obj)
{
SpecializedMethod other = obj as SpecializedMethod;
if (!base.Equals(other))
return false;
if (typeArguments.Count != other.typeArguments.Count)
return false;
for (int i = 0; i < typeArguments.Count; i++) {
if (!typeArguments[i].Equals(other.typeArguments[i]))
return false;
}
return true;
get { return this.Substitution.MethodTypeArguments ?? EmptyList<IType>.Instance; }
}
public IList<IUnresolvedMethod> Parts {
@ -182,11 +128,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -182,11 +128,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
b.Append(this.DeclaringType.ToString());
b.Append('.');
b.Append(this.Name);
if (typeArguments.Count > 0) {
if (this.TypeArguments.Count > 0) {
b.Append('[');
for (int i = 0; i < typeArguments.Count; i++) {
for (int i = 0; i < this.TypeArguments.Count; i++) {
if (i > 0) b.Append(", ");
b.Append(typeArguments[i].ToString());
b.Append(this.TypeArguments[i].ToString());
}
b.Append(']');
}
@ -205,14 +151,15 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -205,14 +151,15 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
readonly ITypeParameter baseTp;
// not readonly: The substition may be replaced at the end of SpecializedMethod constructor
// The substition is set at the end of SpecializedMethod constructor
internal TypeVisitor substitution;
public SpecializedTypeParameter(ITypeParameter baseTp, IMethod specializedOwner, TypeVisitor substitution)
public SpecializedTypeParameter(ITypeParameter baseTp, IMethod specializedOwner)
: base(specializedOwner, baseTp.Index, baseTp.Name, baseTp.Variance, baseTp.Attributes, baseTp.Region)
{
// We don't have to consider already-specialized baseTps because
// we read the baseTp directly from the unpacked memberDefinition.
this.baseTp = baseTp;
this.substitution = substitution;
}
public override int GetHashCode()

21
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedProperty.cs

@ -27,18 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -27,18 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
readonly IProperty propertyDefinition;
public SpecializedProperty(IType declaringType, IProperty propertyDefinition)
: base(declaringType, propertyDefinition)
public SpecializedProperty(IProperty propertyDefinition, TypeParameterSubstitution substitution)
: base(propertyDefinition)
{
this.propertyDefinition = propertyDefinition;
Initialize(GetSubstitution(declaringType));
}
internal SpecializedProperty(IType declaringType, IProperty propertyDefinition, TypeVisitor substitution)
: base(declaringType, propertyDefinition)
{
this.propertyDefinition = propertyDefinition;
Initialize(substitution);
AddSubstitution(substitution);
this.propertyDefinition = (IProperty)base.MemberDefinition;
}
public bool CanGet {
@ -49,12 +42,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -49,12 +42,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return propertyDefinition.CanSet; }
}
IMethod getter, setter;
public IMethod Getter {
get { return WrapAccessor(propertyDefinition.Getter); }
get { return WrapAccessor(ref this.getter, propertyDefinition.Getter); }
}
public IMethod Setter {
get { return WrapAccessor(propertyDefinition.Setter); }
get { return WrapAccessor(ref this.setter, propertyDefinition.Setter); }
}
public bool IsIndexer {

45
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializingMemberReference.cs

@ -24,50 +24,29 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -24,50 +24,29 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
[Serializable]
public sealed class SpecializingMemberReference : IMemberReference
{
ITypeReference declaringTypeReference;
IMemberReference memberDefinitionReference;
IList<ITypeReference> typeArgumentReferences;
IList<ITypeReference> classTypeArgumentReferences;
IList<ITypeReference> methodTypeArgumentReferences;
public SpecializingMemberReference(ITypeReference declaringTypeReference, IMemberReference memberDefinitionReference, IList<ITypeReference> typeArgumentReferences = null)
public SpecializingMemberReference(IMemberReference memberDefinitionReference, IList<ITypeReference> classTypeArgumentReferences = null, IList<ITypeReference> methodTypeArgumentReferences = null)
{
if (declaringTypeReference == null)
throw new ArgumentNullException("declaringTypeReference");
if (memberDefinitionReference == null)
throw new ArgumentNullException("memberDefinitionReference");
this.declaringTypeReference = declaringTypeReference;
this.memberDefinitionReference = memberDefinitionReference;
this.typeArgumentReferences = typeArgumentReferences;
this.classTypeArgumentReferences = classTypeArgumentReferences;
this.methodTypeArgumentReferences = methodTypeArgumentReferences;
}
public IMember Resolve(ITypeResolveContext context)
{
var declaringType = declaringTypeReference.Resolve(context);
var memberDefinition = memberDefinitionReference.Resolve(context);
IType[] typeArguments = null;
if (typeArgumentReferences != null) {
typeArguments = new IType[typeArgumentReferences.Count];
for (int i = 0; i < typeArguments.Length; i++) {
typeArguments[i] = typeArgumentReferences[i].Resolve(context);
}
}
return CreateSpecializedMember(declaringType, memberDefinition, typeArguments);
}
internal static IMember CreateSpecializedMember(IType declaringType, IMember memberDefinition, IList<IType> typeArguments)
{
if (memberDefinition == null) {
return null;
} else if (memberDefinition is IMethod) {
return new SpecializedMethod(declaringType, (IMethod)memberDefinition, typeArguments);
} else if (memberDefinition is IProperty) {
return new SpecializedProperty(declaringType, (IProperty)memberDefinition);
} else if (memberDefinition is IField) {
return new SpecializedField(declaringType, (IField)memberDefinition);
} else if (memberDefinition is IEvent) {
return new SpecializedEvent(declaringType, (IEvent)memberDefinition);
} else {
throw new NotSupportedException("Unknown IMember: " + memberDefinition);
}
return SpecializedMember.Create(
memberDefinition,
new TypeParameterSubstitution(
classTypeArgumentReferences != null ? classTypeArgumentReferences.Resolve(context) : null,
methodTypeArgumentReferences != null ? methodTypeArgumentReferences.Resolve(context) : null
)
);
}
}
}

94
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeParameterSubstitution.cs

@ -27,6 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -27,6 +27,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// </summary>
public class TypeParameterSubstitution : TypeVisitor
{
/// <summary>
/// The identity function.
/// </summary>
public static readonly TypeParameterSubstitution Identity = new TypeParameterSubstitution(null, null);
readonly IList<IType> classTypeArguments;
readonly IList<IType> methodTypeArguments;
@ -47,6 +52,95 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -47,6 +52,95 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
this.methodTypeArguments = methodTypeArguments;
}
/// <summary>
/// Gets the list of class type arguments.
/// Returns <c>null</c> if this substitution keeps class type parameter unmodified.
/// </summary>
public IList<IType> ClassTypeArguments {
get { return classTypeArguments; }
}
public IList<IType> MethodTypeArguments {
get { return methodTypeArguments; }
}
#region Compose
/// <summary>
/// Computes a single TypeParameterSubstitution so that for all types <c>t</c>:
/// <c>t.AcceptVisitor(Compose(g, f)) equals t.AcceptVisitor(f).AcceptVisitor(g)</c>
/// </summary>
/// <remarks>If you consider type parameter substitution to be a function, this is function composition.</remarks>
public static TypeParameterSubstitution Compose(TypeParameterSubstitution g, TypeParameterSubstitution f)
{
if (g == null)
return f;
if (f == null || (f.classTypeArguments == null && f.methodTypeArguments == null))
return g;
// The composition is a copy of 'f', with 'g' applied on the array elements.
// If 'f' has a null list (keeps type parameters unmodified), we have to treat it as
// the identity function, and thus use the list from 'g'.
var classTypeArguments = f.classTypeArguments != null ? GetComposedTypeArguments(f.classTypeArguments, g) : g.classTypeArguments;
var methodTypeArguments = f.methodTypeArguments != null ? GetComposedTypeArguments(f.methodTypeArguments, g) : g.methodTypeArguments;
return new TypeParameterSubstitution(classTypeArguments, methodTypeArguments);
}
static IList<IType> GetComposedTypeArguments(IList<IType> input, TypeParameterSubstitution substitution)
{
IType[] result = new IType[input.Count];
for (int i = 0; i < result.Length; i++) {
result[i] = input[i].AcceptVisitor(substitution);
}
return result;
}
#endregion
#region Equals and GetHashCode implementation
public override bool Equals(object obj)
{
TypeParameterSubstitution other = obj as TypeParameterSubstitution;
if (other == null)
return false;
return TypeListEquals(classTypeArguments, other.classTypeArguments)
&& TypeListEquals(methodTypeArguments, other.methodTypeArguments);
}
public override int GetHashCode()
{
unchecked {
return 1124131 * TypeListHashCode(classTypeArguments) + 1821779 * TypeListHashCode(methodTypeArguments);
}
}
static bool TypeListEquals(IList<IType> a, IList<IType> b)
{
if (a == b)
return true;
if (a == null || b == null)
return false;
if (a.Count != b.Count)
return false;
for (int i = 0; i < a.Count; i++) {
if (!a[i].Equals(b[i]))
return false;
}
return true;
}
static int TypeListHashCode(IList<IType> obj)
{
if (obj == null)
return 0;
unchecked {
int hashCode = 1;
foreach (var element in obj) {
hashCode *= 27;
hashCode += element.GetHashCode();
}
return hashCode;
}
}
#endregion
public override IType VisitTypeParameter(ITypeParameter type)
{
int index = type.Index;

17
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/InheritanceHelper.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.TypeSystem
{
@ -50,13 +51,15 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -50,13 +51,15 @@ namespace ICSharpCode.NRefactory.TypeSystem
if (member == null)
throw new ArgumentNullException("member");
member = member.MemberDefinition;
if (member.IsExplicitInterfaceImplementation && member.ImplementedInterfaceMembers.Count == 1) {
// C#-style explicit interface implementation
yield return member.ImplementedInterfaceMembers[0];
member = member.ImplementedInterfaceMembers[0].MemberDefinition;
member = member.ImplementedInterfaceMembers[0];
yield return member;
}
SpecializedMember specializedMember = member as SpecializedMember;
member = member.MemberDefinition;
IEnumerable<IType> allBaseTypes;
if (includeImplementedInterfaces) {
allBaseTypes = member.DeclaringTypeDefinition.GetAllBaseTypes();
@ -68,8 +71,12 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -68,8 +71,12 @@ namespace ICSharpCode.NRefactory.TypeSystem
continue;
foreach (IMember baseMember in baseType.GetMembers(m => m.Name == member.Name, GetMemberOptions.IgnoreInheritedMembers)) {
if (SignatureComparer.Ordinal.Equals(member, baseMember))
yield return baseMember;
if (SignatureComparer.Ordinal.Equals(member, baseMember)) {
if (specializedMember != null)
yield return SpecializedMember.Create(baseMember, specializedMember.Substitution);
else
yield return baseMember;
}
}
}
}

Loading…
Cancel
Save