2
// GatherVisitorBase.cs
5
// Mike KrĆ¼ger <mkrueger@xamarin.com>
7
// Copyright (c) 2012 Xamarin <http://xamarin.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 System.Collections.Generic;
28
using System.Diagnostics.CodeAnalysis;
30
using ICSharpCode.NRefactory.CSharp.Refactoring;
31
using ICSharpCode.NRefactory.TypeSystem;
33
namespace ICSharpCode.NRefactory.CSharp
36
/// A base class for writing issue provider visitor implementations.
38
class GatherVisitorBase<T> : DepthFirstAstVisitor where T : ICodeIssueProvider
41
/// The issue provider. May be <c>null</c> if none was specified.
43
protected readonly T IssueProvider;
45
protected readonly BaseRefactoringContext ctx;
47
bool isGloballySuppressed;
48
List<DomRegion> suppressedRegions =new List<DomRegion> ();
50
[SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
51
static string disableString;
53
[SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
54
static string restoreString;
56
[SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
57
static string suppressMessageCategory;
59
[SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
60
static string suppressMessageCheckId;
62
static void SetDisableKeyword(string disableKeyword)
64
disableString = "disable " + disableKeyword;
65
restoreString = "restore " + disableKeyword;
68
public readonly List<CodeIssue> FoundIssues = new List<CodeIssue> ();
70
static GatherVisitorBase()
72
var attr = (IssueDescriptionAttribute)typeof(T).GetCustomAttributes(false).FirstOrDefault(a => a is IssueDescriptionAttribute);
75
if (attr.ResharperDisableKeyword != null)
76
SetDisableKeyword(attr.ResharperDisableKeyword);
77
suppressMessageCheckId = attr.SuppressMessageCheckId;
78
suppressMessageCategory = attr.SuppressMessageCategory;
82
/// Initializes a new instance of the <see cref="ICSharpCode.NRefactory.CSharp.GatherVisitorBase"/> class.
84
/// <param name='ctx'>
85
/// The refactoring context.
87
/// <param name='issueProvider'>
88
/// The issue provider.
90
public GatherVisitorBase (BaseRefactoringContext ctx, T issueProvider = default(T))
93
this.IssueProvider = issueProvider;
94
if (suppressMessageCheckId != null) {
95
foreach (var attr in this.ctx.Compilation.MainAssembly.AssemblyAttributes) {
96
if (attr.AttributeType.Name == "SuppressMessageAttribute" && attr.AttributeType.Namespace == "System.Diagnostics.CodeAnalysis") {
97
if (attr.PositionalArguments.Count < 2)
99
var category = attr.PositionalArguments [0].ConstantValue;
100
if (category == null || category.ToString() != suppressMessageCategory)
102
var checkId = attr.PositionalArguments [1].ConstantValue;
103
if (checkId == null || checkId.ToString() != suppressMessageCheckId)
105
isGloballySuppressed = true;
112
/// Gets all the issues using the context root node as base.
117
public IEnumerable<CodeIssue> GetIssues()
119
ctx.RootNode.AcceptVisitor(this);
123
protected override void VisitChildren (AstNode node)
125
if (ctx.CancellationToken.IsCancellationRequested || isGloballySuppressed)
127
base.VisitChildren (node);
130
public override void VisitComment(Comment comment)
132
if (comment.CommentType == CommentType.SingleLine && restoreString != null) {
133
var txt = comment.Content;
134
if (string.IsNullOrEmpty(txt))
137
isDisabled &= txt.IndexOf(restoreString, StringComparison.InvariantCulture) < 0;
139
isDisabled |= txt.IndexOf(disableString, StringComparison.InvariantCulture) > 0;
144
public override void VisitAttribute(Attribute attribute)
146
base.VisitAttribute(attribute);
147
if (suppressMessageCheckId == null)
149
var resolveResult = ctx.Resolve(attribute);
150
if (resolveResult.Type.Name == "SuppressMessageAttribute" && resolveResult.Type.Namespace == "System.Diagnostics.CodeAnalysis") {
151
if (attribute.Arguments.Count < 2)
153
var category = attribute.Arguments.First () as PrimitiveExpression;
154
if (category == null || category.Value.ToString () != suppressMessageCategory)
156
var checkId = attribute.Arguments.Skip (1).First () as PrimitiveExpression;
157
if (checkId == null || checkId.Value.ToString() != suppressMessageCheckId)
159
suppressedRegions.Add (attribute.Parent.Parent.Region);
163
protected bool IsSuppressed(TextLocation location)
165
return isDisabled || isGloballySuppressed || suppressedRegions.Any(r => r.IsInside(location));
168
protected void AddIssue(AstNode node, string title, System.Action<Script> fix = null)
170
if (IsSuppressed(node.StartLocation))
172
FoundIssues.Add(new CodeIssue (title, node.StartLocation, node.EndLocation, fix != null ? new CodeAction (title, fix, node) : null));
175
protected void AddIssue(TextLocation start, TextLocation end, string title, System.Action<Script> fix = null)
177
if (IsSuppressed(start))
179
FoundIssues.Add(new CodeIssue(title, start, end, fix != null ? new CodeAction(title, fix, start, end) : null));
182
protected void AddIssue(AstNode node, string title, CodeAction fix)
184
if (IsSuppressed(node.StartLocation))
186
FoundIssues.Add(new CodeIssue(title, node.StartLocation, node.EndLocation, fix));
189
protected void AddIssue(TextLocation start, TextLocation end, string title, CodeAction fix)
191
if (IsSuppressed(start))
193
FoundIssues.Add(new CodeIssue (title, start, end, fix));
196
protected void AddIssue(AstNode node, string title, IEnumerable<CodeAction> fixes)
198
if (IsSuppressed(node.StartLocation))
200
FoundIssues.Add(new CodeIssue(title, node.StartLocation, node.EndLocation, fixes));
203
protected void AddIssue(TextLocation start, TextLocation end, string title, IEnumerable<CodeAction> fixes)
205
if (IsSuppressed(start))
207
FoundIssues.Add(new CodeIssue (title, start, end, fixes));