Browse Source

Implemented "Find References".

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
a5865bdd8e
  1. 21
      ICSharpCode.NRefactory.Demo/CSDemo.Designer.cs
  2. 52
      ICSharpCode.NRefactory.Demo/CSDemo.cs
  3. 54
      ICSharpCode.NRefactory/CSharp/Resolver/CompositeResolveVisitorNavigator.cs
  4. 675
      ICSharpCode.NRefactory/CSharp/Resolver/FindReferences.cs
  5. 17
      ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs
  6. 2
      ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  7. 2
      ICSharpCode.NRefactory/Utils/ReferenceComparer.cs

21
ICSharpCode.NRefactory.Demo/CSDemo.Designer.cs generated

@ -48,6 +48,7 @@ namespace ICSharpCode.NRefactory.Demo @@ -48,6 +48,7 @@ namespace ICSharpCode.NRefactory.Demo
{
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
this.csharpCodeTextBox = new System.Windows.Forms.TextBox();
this.findReferencesButton = new System.Windows.Forms.Button();
this.resolveButton = new System.Windows.Forms.Button();
this.csharpTreeView = new System.Windows.Forms.TreeView();
this.csharpGenerateCodeButton = new System.Windows.Forms.Button();
@ -71,6 +72,7 @@ namespace ICSharpCode.NRefactory.Demo @@ -71,6 +72,7 @@ namespace ICSharpCode.NRefactory.Demo
//
// splitContainer1.Panel2
//
this.splitContainer1.Panel2.Controls.Add(this.findReferencesButton);
this.splitContainer1.Panel2.Controls.Add(this.resolveButton);
this.splitContainer1.Panel2.Controls.Add(this.csharpTreeView);
this.splitContainer1.Panel2.Controls.Add(this.csharpGenerateCodeButton);
@ -97,10 +99,22 @@ namespace ICSharpCode.NRefactory.Demo @@ -97,10 +99,22 @@ namespace ICSharpCode.NRefactory.Demo
this.csharpCodeTextBox.WordWrap = false;
this.csharpCodeTextBox.TextChanged += new System.EventHandler(this.CsharpCodeTextBoxTextChanged);
//
// findReferencesButton
//
this.findReferencesButton.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.findReferencesButton.Enabled = false;
this.findReferencesButton.Location = new System.Drawing.Point(344, 4);
this.findReferencesButton.Name = "findReferencesButton";
this.findReferencesButton.Size = new System.Drawing.Size(100, 23);
this.findReferencesButton.TabIndex = 4;
this.findReferencesButton.Text = "Find References";
this.findReferencesButton.UseVisualStyleBackColor = true;
this.findReferencesButton.Click += new System.EventHandler(this.FindReferencesButtonClick);
//
// resolveButton
//
this.resolveButton.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.resolveButton.Location = new System.Drawing.Point(187, 3);
this.resolveButton.Location = new System.Drawing.Point(132, 4);
this.resolveButton.Name = "resolveButton";
this.resolveButton.Size = new System.Drawing.Size(100, 23);
this.resolveButton.TabIndex = 3;
@ -123,7 +137,7 @@ namespace ICSharpCode.NRefactory.Demo @@ -123,7 +137,7 @@ namespace ICSharpCode.NRefactory.Demo
// csharpGenerateCodeButton
//
this.csharpGenerateCodeButton.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.csharpGenerateCodeButton.Location = new System.Drawing.Point(293, 2);
this.csharpGenerateCodeButton.Location = new System.Drawing.Point(238, 4);
this.csharpGenerateCodeButton.Name = "csharpGenerateCodeButton";
this.csharpGenerateCodeButton.Size = new System.Drawing.Size(100, 23);
this.csharpGenerateCodeButton.TabIndex = 1;
@ -134,7 +148,7 @@ namespace ICSharpCode.NRefactory.Demo @@ -134,7 +148,7 @@ namespace ICSharpCode.NRefactory.Demo
// csharpParseButton
//
this.csharpParseButton.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.csharpParseButton.Location = new System.Drawing.Point(81, 3);
this.csharpParseButton.Location = new System.Drawing.Point(26, 4);
this.csharpParseButton.Name = "csharpParseButton";
this.csharpParseButton.Size = new System.Drawing.Size(100, 23);
this.csharpParseButton.TabIndex = 0;
@ -156,6 +170,7 @@ namespace ICSharpCode.NRefactory.Demo @@ -156,6 +170,7 @@ namespace ICSharpCode.NRefactory.Demo
this.splitContainer1.ResumeLayout(false);
this.ResumeLayout(false);
}
private System.Windows.Forms.Button findReferencesButton;
private System.Windows.Forms.Button csharpParseButton;
private System.Windows.Forms.Button csharpGenerateCodeButton;
private System.Windows.Forms.TreeView csharpTreeView;

52
ICSharpCode.NRefactory.Demo/CSDemo.cs

@ -22,12 +22,12 @@ using System.ComponentModel; @@ -22,12 +22,12 @@ using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.TypeSystem;
@ -71,6 +71,7 @@ namespace ICSharpCode.NRefactory.Demo @@ -71,6 +71,7 @@ namespace ICSharpCode.NRefactory.Demo
}
SelectCurrentNode(csharpTreeView.Nodes);
resolveButton.Enabled = true;
findReferencesButton.Enabled = true;
}
TreeNode MakeTreeNode(AstNode node)
@ -245,6 +246,55 @@ namespace ICSharpCode.NRefactory.Demo @@ -245,6 +246,55 @@ namespace ICSharpCode.NRefactory.Demo
void CsharpCodeTextBoxTextChanged(object sender, EventArgs e)
{
resolveButton.Enabled = false;
findReferencesButton.Enabled = false;
}
void FindReferencesButtonClick(object sender, EventArgs e)
{
if (csharpTreeView.SelectedNode == null)
return;
SimpleProjectContent project = new SimpleProjectContent();
var parsedFile = new TypeSystemConvertVisitor(project, "dummy.cs").Convert(compilationUnit);
project.UpdateProjectContent(null, parsedFile);
List<ITypeResolveContext> projects = new List<ITypeResolveContext>();
projects.Add(project);
projects.AddRange(builtInLibs.Value);
using (var context = new CompositeTypeResolveContext(projects).Synchronize()) {
CSharpResolver resolver = new CSharpResolver(context);
AstNode node = (AstNode)csharpTreeView.SelectedNode.Tag;
IResolveVisitorNavigator navigator = new NodeListResolveVisitorNavigator(new[] { node });
ResolveVisitor visitor = new ResolveVisitor(resolver, parsedFile, navigator);
visitor.Scan(compilationUnit);
IEntity entity;
MemberResolveResult mrr = visitor.GetResolveResult(node) as MemberResolveResult;
TypeResolveResult trr = visitor.GetResolveResult(node) as TypeResolveResult;
if (mrr != null) {
entity = mrr.Member;
} else if (trr != null) {
entity = trr.Type.GetDefinition();
} else {
return;
}
FindReferences fr = new FindReferences();
int referenceCount = 0;
fr.ReferenceFound += delegate { referenceCount++; };
var searchScopes = fr.GetSearchScopes(entity);
navigator = new CompositeResolveVisitorNavigator(searchScopes.ToArray());
visitor = new ResolveVisitor(resolver, parsedFile, navigator);
visitor.Scan(compilationUnit);
csharpTreeView.BeginUpdate();
ShowResolveResultsInTree(csharpTreeView.Nodes, visitor);
csharpTreeView.EndUpdate();
MessageBox.Show("Found " + referenceCount + " references to " + entity.FullName);
}
}
}
}

54
ICSharpCode.NRefactory/CSharp/Resolver/CompositeResolveVisitorNavigator.cs

@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
// 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;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
public sealed class CompositeResolveVisitorNavigator : IResolveVisitorNavigator
{
IResolveVisitorNavigator[] navigators;
public CompositeResolveVisitorNavigator(IResolveVisitorNavigator[] navigators)
{
this.navigators = navigators;
}
public ResolveVisitorNavigationMode Scan(AstNode node)
{
ResolveVisitorNavigationMode mode = ResolveVisitorNavigationMode.Skip;
foreach (var navigator in navigators) {
ResolveVisitorNavigationMode newMode = navigator.Scan(node);
if (newMode == ResolveVisitorNavigationMode.ResolveAll)
return newMode; // ResolveAll has highest priority
if (newMode == ResolveVisitorNavigationMode.Resolve)
mode = newMode; // resolve has high priority and replaces the previous mode
else if (mode == ResolveVisitorNavigationMode.Skip)
mode = newMode; // skip has lowest priority and always gets replaced
}
return mode;
}
public void Resolved(AstNode node, ResolveResult result)
{
foreach (var navigator in navigators) {
navigator.Resolved(node, result);
}
}
}
}

675
ICSharpCode.NRefactory/CSharp/Resolver/FindReferences.cs

@ -0,0 +1,675 @@ @@ -0,0 +1,675 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// 'Find references' implementation.
/// </summary>
public class FindReferences
{
CancellationToken cancellationToken;
/// <summary>
/// Callback that is invoked whenever a reference is found.
/// </summary>
public event Action<AstNode, ResolveResult> ReferenceFound;
#region Constructor
public FindReferences(CancellationToken cancellationToken = default(CancellationToken))
{
this.cancellationToken = cancellationToken;
}
#endregion
#region GetEffectiveAccessibility
/// <summary>
/// Gets the effective accessibility of the specified entity -
/// that is, the accessibility viewed from the top level.
/// </summary>
/// <remarks>
/// internal member in public class -> internal
/// public member in internal class -> internal
/// protected member in public class -> protected
/// protected member in internal class -> protected and internal
/// </remarks>
public static Accessibility GetEffectiveAccessibility(IEntity entity)
{
if (entity == null)
throw new ArgumentNullException("entity");
Accessibility a = entity.Accessibility;
for (ITypeDefinition declType = entity.DeclaringTypeDefinition; declType != null; declType = declType.DeclaringTypeDefinition) {
a = MergeAccessibility(declType.Accessibility, a);
}
return a;
}
static Accessibility MergeAccessibility(Accessibility outer, Accessibility inner)
{
if (outer == inner)
return inner;
if (outer == Accessibility.None || inner == Accessibility.None)
return Accessibility.None;
if (outer == Accessibility.Private || inner == Accessibility.Private)
return Accessibility.Private;
if (outer == Accessibility.Public)
return inner;
if (inner == Accessibility.Public)
return outer;
// Inner and outer are both in { protected, internal, protected and internal, protected or internal }
// (but they aren't both the same)
if (outer == Accessibility.ProtectedOrInternal)
return inner;
if (inner == Accessibility.ProtectedOrInternal)
return outer;
// Inner and outer are both in { protected, internal, protected and internal },
// but aren't both the same, so the result is protected and internal.
return Accessibility.ProtectedAndInternal;
}
#endregion
#region class SearchScope
public abstract class SearchScope : IResolveVisitorNavigator
{
protected string searchTerm;
internal Accessibility accessibility;
internal IEntity topLevelEntity;
internal FindReferences findReferences;
/// <summary>
/// Gets the search term. Only files that contain this identifier need to be parsed.
/// Can return null if all files need to be parsed.
/// </summary>
public string SearchTerm { get { return searchTerm; } }
/// <summary>
/// Gets the accessibility that defines the search scope.
/// </summary>
public Accessibility Accessibility { get { return accessibility; } }
/// <summary>
/// Gets the top-level entity that defines the search scope.
/// </summary>
public IEntity TopLevelEntity { get { return topLevelEntity; } }
internal abstract bool CanMatch(AstNode node);
internal abstract bool IsMatch(ResolveResult rr);
ResolveVisitorNavigationMode IResolveVisitorNavigator.Scan(AstNode node)
{
if (CanMatch(node))
return ResolveVisitorNavigationMode.Resolve;
else
return ResolveVisitorNavigationMode.Scan;
}
void IResolveVisitorNavigator.Resolved(AstNode node, ResolveResult result)
{
if (CanMatch(node) && IsMatch(result)) {
var referenceFound = findReferences.ReferenceFound;
if (referenceFound != null)
referenceFound(node, result);
}
}
}
#endregion
#region GetSearchScopes
public IList<SearchScope> GetSearchScopes(IEntity entity)
{
if (entity == null)
throw new ArgumentNullException("entity");
Accessibility effectiveAccessibility = GetEffectiveAccessibility(entity);
IEntity topLevelEntity = entity;
while (topLevelEntity.DeclaringTypeDefinition != null)
topLevelEntity = topLevelEntity.DeclaringTypeDefinition;
SearchScope scope;
SearchScope additionalScope = null;
switch (entity.EntityType) {
case EntityType.TypeDefinition:
scope = new FindTypeDefinitionReferences((ITypeDefinition)entity);
break;
case EntityType.Field:
scope = new FindFieldReferences((IField)entity);
break;
case EntityType.Property:
scope = new FindPropertyReferences((IProperty)entity);
break;
case EntityType.Event:
scope = new FindEventReferences((IEvent)entity);
break;
case EntityType.Method:
scope = GetSearchScopeForMethod((IMethod)entity);
break;
case EntityType.Indexer:
scope = new FindIndexerReferences((IProperty)entity);
break;
case EntityType.Operator:
scope = GetSearchScopeForOperator((IMethod)entity);
break;
case EntityType.Constructor:
IMethod ctor = (IMethod)entity;
scope = new FindObjectCreateReferences(ctor);
additionalScope = new FindChainedConstructorReferences(ctor);
break;
case EntityType.Destructor:
return EmptyList<SearchScope>.Instance;
default:
throw new ArgumentException("Unknown entity type " + entity.EntityType);
}
if (scope.accessibility == Accessibility.None)
scope.accessibility = effectiveAccessibility;
scope.topLevelEntity = topLevelEntity;
scope.findReferences = this;
if (additionalScope != null) {
if (additionalScope.accessibility == Accessibility.None)
additionalScope.accessibility = effectiveAccessibility;
additionalScope.topLevelEntity = topLevelEntity;
additionalScope.findReferences = this;
return new[] { scope, additionalScope };
} else {
return new[] { scope };
}
}
#endregion
#region FindReferencesInFile
/// <summary>
/// Finds all references in the given file.
/// </summary>
/// <param name="searchScope">The search scopes for which to look.</param>
/// <param name="parsedFile">The type system representation of the file being searched.</param>
/// <param name="compilationUnit">The compilation unit of the file being searched.</param>
/// <param name="context">The type resolve context to use for resolving the file.</param>
public void FindReferencesInFile(IList<SearchScope> searchScopes, ParsedFile parsedFile, CompilationUnit compilationUnit, ITypeResolveContext context)
{
if (searchScopes == null)
throw new ArgumentNullException("searchScopes");
if (parsedFile == null)
throw new ArgumentNullException("parsedFile");
if (compilationUnit == null)
throw new ArgumentNullException("compilationUnit");
if (context == null)
throw new ArgumentNullException("context");
cancellationToken.ThrowIfCancellationRequested();
if (searchScopes.Count == 0)
return;
foreach (SearchScope scope in searchScopes) {
if (scope.findReferences != this)
throw new ArgumentException("Cannot use a search scope that was created by another FindReferences instance");
}
using (var ctx = context.Synchronize()) {
IResolveVisitorNavigator navigator;
if (searchScopes.Count == 1)
navigator = searchScopes[0];
else
navigator = new CompositeResolveVisitorNavigator(searchScopes.ToArray());
navigator = new DetectSkippableNodesNavigator(navigator, compilationUnit);
CSharpResolver resolver = new CSharpResolver(ctx, cancellationToken);
ResolveVisitor v = new ResolveVisitor(resolver, parsedFile, navigator);
v.Scan(compilationUnit);
}
}
#endregion
#region Find TypeDefinition References
sealed class FindTypeDefinitionReferences : SearchScope
{
ITypeDefinition typeDefinition;
public FindTypeDefinitionReferences(ITypeDefinition typeDefinition)
{
this.typeDefinition = typeDefinition;
if (ReflectionHelper.GetTypeCode(typeDefinition) == TypeCode.Empty) {
// not a built-in type
this.searchTerm = typeDefinition.Name;
}
}
internal override bool CanMatch(AstNode node)
{
IdentifierExpression ident = node as IdentifierExpression;
if (ident != null)
return searchTerm == null || ident.Identifier == searchTerm;
MemberReferenceExpression mre = node as MemberReferenceExpression;
if (mre != null)
return searchTerm == null || mre.MemberName == searchTerm;
SimpleType st = node as SimpleType;
if (st != null)
return searchTerm == null || st.Identifier == searchTerm;
MemberType mt = node as MemberType;
if (mt != null)
return searchTerm == null || mt.MemberName == searchTerm;
if (searchTerm == null && node is PrimitiveType)
return true;
return false;
}
internal override bool IsMatch(ResolveResult rr)
{
TypeResolveResult trr = rr as TypeResolveResult;
return trr != null && typeDefinition.Equals(trr.Type.GetDefinition());
}
}
#endregion
#region Find Member References
class FindMemberReferences : SearchScope
{
readonly IMember member;
public FindMemberReferences(IMember member)
{
this.member = member.MemberDefinition;
this.searchTerm = member.Name;
}
internal override bool CanMatch(AstNode node)
{
IdentifierExpression ident = node as IdentifierExpression;
if (ident != null)
return ident.Identifier == searchTerm;
MemberReferenceExpression mre = node as MemberReferenceExpression;
if (mre != null)
return mre.MemberName == searchTerm;
PointerReferenceExpression pre = node as PointerReferenceExpression;
if (pre != null)
return pre.MemberName == searchTerm;
NamedExpression ne = node as NamedExpression;
if (ne != null)
return ne.Identifier == searchTerm;
return false;
}
internal override bool IsMatch(ResolveResult rr)
{
MemberResolveResult mrr = rr as MemberResolveResult;
return mrr != null && member == mrr.Member.MemberDefinition;
}
}
sealed class FindFieldReferences : FindMemberReferences
{
public FindFieldReferences(IField field) : base(field)
{
}
internal override bool CanMatch(AstNode node)
{
return node is FieldDeclaration || base.CanMatch(node);
}
}
sealed class FindPropertyReferences : FindMemberReferences
{
public FindPropertyReferences(IProperty property) : base(property)
{
}
internal override bool CanMatch(AstNode node)
{
return node is PropertyDeclaration || base.CanMatch(node);
}
}
sealed class FindEventReferences : FindMemberReferences
{
public FindEventReferences(IEvent ev) : base(ev)
{
}
internal override bool CanMatch(AstNode node)
{
return node is EventDeclaration || base.CanMatch(node);
}
}
#endregion
#region Find Method References
SearchScope GetSearchScopeForMethod(IMethod method)
{
switch (method.Name) {
case "Add":
return new FindMethodReferences(method, typeof(ArrayInitializerExpression));
case "Where":
return new FindMethodReferences(method, typeof(QueryWhereClause));
case "Select":
return new FindMethodReferences(method, typeof(QuerySelectClause));
case "SelectMany":
return new FindMethodReferences(method, typeof(QueryFromClause));
case "Join":
case "GroupJoin":
return new FindMethodReferences(method, typeof(QueryJoinClause));
case "OrderBy":
case "OrderByDescending":
case "ThenBy":
case "ThenByDescending":
return new FindMethodReferences(method, typeof(QueryOrdering));
case "GroupBy":
return new FindMethodReferences(method, typeof(QueryGroupClause));
default:
return new FindMethodReferences(method);
}
}
sealed class FindMethodReferences : SearchScope
{
readonly IMethod method;
readonly Type specialNodeType;
public FindMethodReferences(IMethod method, Type specialNodeType = null)
{
this.method = (IMethod)method.MemberDefinition;
this.specialNodeType = specialNodeType;
if (specialNodeType == null)
this.searchTerm = method.Name;
}
internal override bool CanMatch(AstNode node)
{
InvocationExpression ie = node as InvocationExpression;
if (ie != null) {
Expression target = ResolveVisitor.UnpackParenthesizedExpression(ie.Target);
IdentifierExpression ident = target as IdentifierExpression;
if (ident != null)
return ident.Identifier == method.Name;
MemberReferenceExpression mre = target as MemberReferenceExpression;
if (mre != null)
return mre.MemberName == method.Name;
PointerReferenceExpression pre = target as PointerReferenceExpression;
if (pre != null)
return pre.MemberName == method.Name;
}
if (node is MethodDeclaration)
return true;
if (specialNodeType != null)
return specialNodeType.IsInstanceOfType(node);
else
return false;
}
internal override bool IsMatch(ResolveResult rr)
{
MemberResolveResult mrr = rr as MemberResolveResult;
return mrr != null && method == mrr.Member.MemberDefinition;
}
}
#endregion
#region Find Indexer References
sealed class FindIndexerReferences : SearchScope
{
readonly IProperty indexer;
public FindIndexerReferences(IProperty indexer)
{
this.indexer = (IProperty)indexer.MemberDefinition;
}
internal override bool CanMatch(AstNode node)
{
return node is IndexerExpression || node is IndexerDeclaration;
}
internal override bool IsMatch(ResolveResult rr)
{
MemberResolveResult mrr = rr as MemberResolveResult;
return mrr != null && indexer == mrr.Member.MemberDefinition;
}
}
#endregion
#region Find Operator References
SearchScope GetSearchScopeForOperator(IMethod op)
{
OperatorType? opType = OperatorDeclaration.GetOperatorType(op.Name);
if (opType == null)
return new FindMethodReferences(op);
switch (opType.Value) {
case OperatorType.LogicalNot:
return new FindUnaryOperator(op, UnaryOperatorType.Not);
case OperatorType.OnesComplement:
return new FindUnaryOperator(op, UnaryOperatorType.BitNot);
case OperatorType.UnaryPlus:
return new FindUnaryOperator(op, UnaryOperatorType.Plus);
case OperatorType.UnaryNegation:
return new FindUnaryOperator(op, UnaryOperatorType.Minus);
case OperatorType.Increment:
return new FindUnaryOperator(op, UnaryOperatorType.Increment);
case OperatorType.Decrement:
return new FindUnaryOperator(op, UnaryOperatorType.Decrement);
case OperatorType.True:
case OperatorType.False:
// TODO: implement search for op_True/op_False correctly
return new FindMethodReferences(op);
case OperatorType.Addition:
return new FindBinaryOperator(op, BinaryOperatorType.Add);
case OperatorType.Subtraction:
return new FindBinaryOperator(op, BinaryOperatorType.Subtract);
case OperatorType.Multiply:
return new FindBinaryOperator(op, BinaryOperatorType.Multiply);
case OperatorType.Division:
return new FindBinaryOperator(op, BinaryOperatorType.Divide);
case OperatorType.Modulus:
return new FindBinaryOperator(op, BinaryOperatorType.Modulus);
case OperatorType.BitwiseAnd:
// TODO: an overloaded bitwise operator can also be called using the corresponding logical operator
// (if op_True/op_False is defined)
return new FindBinaryOperator(op, BinaryOperatorType.BitwiseAnd);
case OperatorType.BitwiseOr:
return new FindBinaryOperator(op, BinaryOperatorType.BitwiseOr);
case OperatorType.ExclusiveOr:
return new FindBinaryOperator(op, BinaryOperatorType.ExclusiveOr);
case OperatorType.LeftShift:
return new FindBinaryOperator(op, BinaryOperatorType.ShiftLeft);
case OperatorType.RightShift:
return new FindBinaryOperator(op, BinaryOperatorType.ShiftRight);
case OperatorType.Equality:
return new FindBinaryOperator(op, BinaryOperatorType.Equality);
case OperatorType.Inequality:
return new FindBinaryOperator(op, BinaryOperatorType.InEquality);
case OperatorType.GreaterThan:
return new FindBinaryOperator(op, BinaryOperatorType.GreaterThan);
case OperatorType.LessThan:
return new FindBinaryOperator(op, BinaryOperatorType.LessThan);
case OperatorType.GreaterThanOrEqual:
return new FindBinaryOperator(op, BinaryOperatorType.GreaterThanOrEqual);
case OperatorType.LessThanOrEqual:
return new FindBinaryOperator(op, BinaryOperatorType.LessThanOrEqual);
case OperatorType.Implicit:
return new FindImplicitOperator(op);
case OperatorType.Explicit:
return new FindExplicitOperator(op);
default:
throw new InvalidOperationException("Invalid value for OperatorType");
}
}
sealed class FindUnaryOperator : SearchScope
{
readonly IMethod op;
readonly UnaryOperatorType operatorType;
public FindUnaryOperator(IMethod op, UnaryOperatorType operatorType)
{
this.op = op;
this.operatorType = operatorType;
}
internal override bool CanMatch(AstNode node)
{
UnaryOperatorExpression uoe = node as UnaryOperatorExpression;
if (uoe != null) {
if (operatorType == UnaryOperatorType.Increment)
return uoe.Operator == UnaryOperatorType.Increment || uoe.Operator == UnaryOperatorType.PostIncrement;
else if (operatorType == UnaryOperatorType.Decrement)
return uoe.Operator == UnaryOperatorType.Decrement || uoe.Operator == UnaryOperatorType.PostDecrement;
else
return uoe.Operator == operatorType;
}
return node is OperatorDeclaration;
}
internal override bool IsMatch(ResolveResult rr)
{
MemberResolveResult mrr = rr as MemberResolveResult;
return mrr != null && op == mrr.Member.MemberDefinition;
}
}
sealed class FindBinaryOperator : SearchScope
{
readonly IMethod op;
readonly BinaryOperatorType operatorType;
public FindBinaryOperator(IMethod op, BinaryOperatorType operatorType)
{
this.op = op;
this.operatorType = operatorType;
}
internal override bool CanMatch(AstNode node)
{
BinaryOperatorExpression boe = node as BinaryOperatorExpression;
if (boe != null) {
return boe.Operator == operatorType;
}
return node is OperatorDeclaration;
}
internal override bool IsMatch(ResolveResult rr)
{
MemberResolveResult mrr = rr as MemberResolveResult;
return mrr != null && op == mrr.Member.MemberDefinition;
}
}
sealed class FindImplicitOperator : SearchScope
{
readonly IMethod op;
public FindImplicitOperator(IMethod op)
{
this.op = op;
}
internal override bool CanMatch(AstNode node)
{
return true;
}
internal override bool IsMatch(ResolveResult rr)
{
throw new NotImplementedException();
}
}
sealed class FindExplicitOperator : SearchScope
{
readonly IMethod op;
public FindExplicitOperator(IMethod op)
{
this.op = op;
}
internal override bool CanMatch(AstNode node)
{
return node is CastExpression;
}
internal override bool IsMatch(ResolveResult rr)
{
ConversionResolveResult crr = rr as ConversionResolveResult;
return crr != null && crr.Conversion.IsUserDefined && crr.Conversion.Method.MemberDefinition == op;
}
}
#endregion
#region Find Constructor References
sealed class FindObjectCreateReferences : SearchScope
{
readonly IMethod ctor;
public FindObjectCreateReferences(IMethod ctor)
{
this.ctor = (IMethod)ctor.MemberDefinition;
if (ReflectionHelper.GetTypeCode(ctor.DeclaringTypeDefinition) == TypeCode.Empty) {
// not a built-in type
this.searchTerm = ctor.DeclaringTypeDefinition.Name;
}
}
internal override bool CanMatch(AstNode node)
{
return node is ObjectCreateExpression || node is ConstructorDeclaration;
}
internal override bool IsMatch(ResolveResult rr)
{
MemberResolveResult mrr = rr as MemberResolveResult;
return mrr != null && ctor == mrr.Member.MemberDefinition;
}
}
sealed class FindChainedConstructorReferences : SearchScope
{
readonly IMethod ctor;
public FindChainedConstructorReferences(IMethod ctor)
{
this.ctor = (IMethod)ctor.MemberDefinition;
if (ctor.DeclaringTypeDefinition.IsSealed)
this.accessibility = Accessibility.Private;
else
this.accessibility = Accessibility.Protected;
this.accessibility = MergeAccessibility(GetEffectiveAccessibility(ctor), this.accessibility);
}
internal override bool CanMatch(AstNode node)
{
return node is ConstructorInitializer;
}
internal override bool IsMatch(ResolveResult rr)
{
MemberResolveResult mrr = rr as MemberResolveResult;
return mrr != null && ctor == mrr.Member.MemberDefinition;
}
}
#endregion
}
}

17
ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs

@ -1881,10 +1881,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1881,10 +1881,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
AstNode parent = lambda.LambdaExpression.Parent;
// Continue going upwards until we find a node that can be resolved and provides
// an expected type.
while (parent is ParenthesizedExpression
|| parent is CheckedExpression || parent is UncheckedExpression
|| parent is NamedArgumentExpression || parent is ArrayInitializerExpression)
{
while (ActsAsParenthesizedExpression(parent) || parent is NamedArgumentExpression || parent is ArrayInitializerExpression) {
parent = parent.Parent;
}
CSharpResolver storedResolver;
@ -1905,6 +1902,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1905,6 +1902,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Log.Unindent();
Log.WriteLine("MergeUndecidedLambdas() finished.");
}
internal static bool ActsAsParenthesizedExpression(AstNode expression)
{
return expression is ParenthesizedExpression || expression is CheckedExpression || expression is UncheckedExpression;
}
internal static Expression UnpackParenthesizedExpression(Expression expr)
{
while (ActsAsParenthesizedExpression(expr))
expr = expr.GetChildByRole(ParenthesizedExpression.Roles.Expression);
return expr;
}
#endregion
#region AnalyzeLambda

2
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -101,7 +101,9 @@ @@ -101,7 +101,9 @@
<Compile Include="CSharp\Ast\GeneralScope\TypeParameterDeclaration.cs" />
<Compile Include="CSharp\Ast\MemberType.cs" />
<Compile Include="CSharp\Refactoring\TypeSystemAstBuilder.cs" />
<Compile Include="CSharp\Resolver\CompositeResolveVisitorNavigator.cs" />
<Compile Include="CSharp\Resolver\DetectSkippableNodesNavigator.cs" />
<Compile Include="CSharp\Resolver\FindReferences.cs" />
<Compile Include="CSharp\Resolver\Log.cs" />
<Compile Include="CSharp\Resolver\OperatorResolveResult.cs" />
<Compile Include="CSharp\Resolver\ConversionResolveResult.cs" />

2
ICSharpCode.NRefactory/Utils/ReferenceComparer.cs

@ -28,7 +28,7 @@ namespace ICSharpCode.NRefactory.Utils @@ -28,7 +28,7 @@ namespace ICSharpCode.NRefactory.Utils
public new bool Equals(object a, object b)
{
return ReferenceEquals(a, b);
return a == b;
}
public int GetHashCode(object obj)

Loading…
Cancel
Save