2
// ParameterNotUsedIssue.cs
5
// Mansheng Yang <lightyang0@gmail.com>
7
// Copyright (c) 2012 Mansheng Yang <lightyang0@gmail.com>
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
using ICSharpCode.NRefactory.Semantics;
29
using ICSharpCode.NRefactory.TypeSystem;
30
using System.Collections.Generic;
31
using ICSharpCode.NRefactory.CSharp.Resolver;
34
namespace ICSharpCode.NRefactory.CSharp.Refactoring
36
[IssueDescription ("Unused parameter",
37
Description = "Parameter is never used.",
38
Category = IssueCategories.Redundancies,
39
Severity = Severity.Warning,
40
IssueMarker = IssueMarker.GrayOut)]
41
public class ParameterNotUsedIssue : ICodeIssueProvider
43
#region ICodeIssueProvider implementation
44
public IEnumerable<CodeIssue> GetIssues(BaseRefactoringContext context)
46
var delegateVisitor = new GetDelgateUsagesVisitor (context);
47
context.RootNode.AcceptVisitor (delegateVisitor);
49
return new GatherVisitor (context, delegateVisitor).GetIssues ();
53
// Collect all methods that are used as delegate
54
class GetDelgateUsagesVisitor : DepthFirstAstVisitor
56
BaseRefactoringContext ctx;
57
public readonly List<IMethod> UsedMethods = new List<IMethod> ();
59
public GetDelgateUsagesVisitor(BaseRefactoringContext ctx)
64
public override void VisitIdentifierExpression(IdentifierExpression identifierExpression)
66
if (!IsTargetOfInvocation(identifierExpression)) {
67
var mgr = ctx.Resolve (identifierExpression) as MethodGroupResolveResult;
69
UsedMethods.AddRange (mgr.Methods);
71
base.VisitIdentifierExpression(identifierExpression);
74
public override void VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression)
76
if (!IsTargetOfInvocation(memberReferenceExpression)) {
77
var mgr = ctx.Resolve (memberReferenceExpression) as MethodGroupResolveResult;
79
UsedMethods.AddRange (mgr.Methods);
81
base.VisitMemberReferenceExpression(memberReferenceExpression);
84
static bool IsTargetOfInvocation(AstNode node)
86
return node.Role == Roles.TargetExpression && node.Parent is InvocationExpression;
90
class GatherVisitor : GatherVisitorBase<ParameterNotUsedIssue>
92
GetDelgateUsagesVisitor usedDelegates;
93
bool currentTypeIsPartial;
95
public GatherVisitor (BaseRefactoringContext ctx, GetDelgateUsagesVisitor usedDelegates)
98
this.usedDelegates = usedDelegates;
101
public override void VisitTypeDeclaration(TypeDeclaration typeDeclaration)
103
bool outerTypeIsPartial = currentTypeIsPartial;
104
currentTypeIsPartial = typeDeclaration.HasModifier(Modifiers.Partial);
105
base.VisitTypeDeclaration(typeDeclaration);
106
currentTypeIsPartial = outerTypeIsPartial;
109
public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration)
111
// Only some methods are candidates for the warning
113
if (methodDeclaration.Body.IsNull)
115
if (methodDeclaration.Modifiers.HasFlag (Modifiers.Virtual) ||
116
methodDeclaration.Modifiers.HasFlag (Modifiers.New) ||
117
methodDeclaration.Modifiers.HasFlag (Modifiers.Partial))
119
var methodResolveResult = ctx.Resolve(methodDeclaration) as MemberResolveResult;
120
if (methodResolveResult == null)
122
var member = methodResolveResult.Member;
123
if (member.IsOverride)
125
if (member.ImplementedInterfaceMembers.Any ())
127
if (usedDelegates.UsedMethods.Any (m => m.MemberDefinition == member))
129
if (currentTypeIsPartial && methodDeclaration.Parameters.Count == 2) {
130
if (methodDeclaration.Parameters.First().Name == "sender") {
131
// Looks like an event handler; the registration might be in the designer part
135
foreach (var parameter in methodDeclaration.Parameters)
136
parameter.AcceptVisitor (this);
139
public override void VisitParameterDeclaration (ParameterDeclaration parameterDeclaration)
141
base.VisitParameterDeclaration (parameterDeclaration);
143
if (!(parameterDeclaration.Parent is MethodDeclaration || parameterDeclaration.Parent is ConstructorDeclaration))
146
var resolveResult = ctx.Resolve (parameterDeclaration) as LocalResolveResult;
147
if (resolveResult == null)
150
if (ctx.FindReferences (parameterDeclaration.Parent, resolveResult.Variable).Any(r => r.Node != parameterDeclaration))
153
AddIssue (parameterDeclaration.NameToken, ctx.TranslateString ("Parameter is never used"));