Skip to content

Commit c8f7242

Browse files
committed
Replace the dynamic PropertyBag on inspection results
It is replaced by a generic method and a dedicated property for the names of disabled quick fixes. The three kinds of inspection results now also have one generic subtype each that takes an additional properties value of the generic type and returns it via the corresponding generic properties method. The consumer of the result properties still has to know the type of properties and what they represent (We want to avoid circular dependencies to the quick fixes.), but the properties can now be provided in a strongly typed fashion and lend themselves better to generation in inspection base classes.
1 parent 205e3dd commit c8f7242

File tree

39 files changed

+499
-322
lines changed

39 files changed

+499
-322
lines changed

Rubberduck.CodeAnalysis/Inspections/Abstract/DeclarationInspectionBase.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ protected DeclarationInspectionBase(RubberduckParserState state, DeclarationType
3131
protected abstract bool IsResultDeclaration(Declaration declaration, DeclarationFinder finder);
3232
protected abstract string ResultDescription(Declaration declaration);
3333

34+
protected virtual ICollection<string> DisabledQuickFixes(Declaration declaration) => new List<string>();
35+
3436
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
3537
{
3638
var finder = DeclarationFinderProvider.DeclarationFinder;
@@ -82,7 +84,8 @@ protected virtual IInspectionResult InspectionResult(Declaration declaration)
8284
return new DeclarationInspectionResult(
8385
this,
8486
ResultDescription(declaration),
85-
declaration);
87+
declaration,
88+
disabledQuickFixes: DisabledQuickFixes(declaration));
8689
}
8790
}
8891

@@ -108,6 +111,8 @@ protected DeclarationInspectionBase(RubberduckParserState state, DeclarationType
108111
protected abstract (bool isResult, T properties) IsResultDeclarationWithAdditionalProperties(Declaration declaration, DeclarationFinder finder);
109112
protected abstract string ResultDescription(Declaration declaration, T properties);
110113

114+
protected virtual ICollection<string> DisabledQuickFixes(Declaration declaration, T properties) => new List<string>();
115+
111116
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
112117
{
113118
var finder = DeclarationFinderProvider.DeclarationFinder;
@@ -158,11 +163,12 @@ protected virtual IEnumerable<Declaration> RelevantDeclarationsInModule(Qualifie
158163

159164
protected virtual IInspectionResult InspectionResult(Declaration declaration, T properties)
160165
{
161-
return new DeclarationInspectionResult(
166+
return new DeclarationInspectionResult<T>(
162167
this,
163168
ResultDescription(declaration, properties),
164169
declaration,
165-
properties: properties);
170+
properties: properties,
171+
disabledQuickFixes: DisabledQuickFixes(declaration, properties));
166172
}
167173
}
168174
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using Rubberduck.Inspections.Results;
4+
using Rubberduck.Parsing.Inspections.Abstract;
5+
using Rubberduck.Parsing.Symbols;
6+
using Rubberduck.Parsing.VBA;
7+
using Rubberduck.Parsing.VBA.DeclarationCaching;
8+
using Rubberduck.VBEditor;
9+
10+
namespace Rubberduck.Inspections.Abstract
11+
{
12+
public abstract class DeclarationInspectionMultiResultBase<T> : InspectionBase
13+
{
14+
protected readonly DeclarationType[] RelevantDeclarationTypes;
15+
protected readonly DeclarationType[] ExcludeDeclarationTypes;
16+
17+
protected DeclarationInspectionMultiResultBase(RubberduckParserState state, params DeclarationType[] relevantDeclarationTypes)
18+
: base(state)
19+
{
20+
RelevantDeclarationTypes = relevantDeclarationTypes;
21+
ExcludeDeclarationTypes = new DeclarationType[0];
22+
}
23+
24+
protected DeclarationInspectionMultiResultBase(RubberduckParserState state, DeclarationType[] relevantDeclarationTypes, DeclarationType[] excludeDeclarationTypes)
25+
: base(state)
26+
{
27+
RelevantDeclarationTypes = relevantDeclarationTypes;
28+
ExcludeDeclarationTypes = excludeDeclarationTypes;
29+
}
30+
31+
protected abstract IEnumerable<T> ResultProperties(Declaration declaration, DeclarationFinder finder);
32+
protected abstract string ResultDescription(Declaration declaration, T properties);
33+
34+
protected virtual ICollection<string> DisabledQuickFixes(Declaration declaration, T properties) => new List<string>();
35+
36+
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
37+
{
38+
var finder = DeclarationFinderProvider.DeclarationFinder;
39+
40+
var results = new List<IInspectionResult>();
41+
foreach (var moduleDeclaration in State.DeclarationFinder.UserDeclarations(DeclarationType.Module))
42+
{
43+
if (moduleDeclaration == null)
44+
{
45+
continue;
46+
}
47+
48+
var module = moduleDeclaration.QualifiedModuleName;
49+
results.AddRange(DoGetInspectionResults(module, finder));
50+
}
51+
52+
return results;
53+
}
54+
55+
private IEnumerable<IInspectionResult> DoGetInspectionResults(QualifiedModuleName module)
56+
{
57+
var finder = DeclarationFinderProvider.DeclarationFinder;
58+
return DoGetInspectionResults(module, finder);
59+
}
60+
61+
private IEnumerable<IInspectionResult> DoGetInspectionResults(QualifiedModuleName module, DeclarationFinder finder)
62+
{
63+
var objectionableDeclarationsWithAdditionalProperties = RelevantDeclarationsInModule(module, finder)
64+
.SelectMany(declaration => ResultProperties(declaration, finder)
65+
.Select(properties => (declaration, properties)));
66+
67+
return objectionableDeclarationsWithAdditionalProperties
68+
.Select(tpl => InspectionResult(tpl.declaration, tpl.properties))
69+
.ToList();
70+
}
71+
72+
protected virtual IEnumerable<Declaration> RelevantDeclarationsInModule(QualifiedModuleName module, DeclarationFinder finder)
73+
{
74+
var potentiallyRelevantDeclarations = RelevantDeclarationTypes.Length == 0
75+
? finder.AllUserDeclarations
76+
: RelevantDeclarationTypes
77+
.SelectMany(declarationType => finder.Members(module, declarationType))
78+
.Distinct();
79+
return potentiallyRelevantDeclarations
80+
.Where(declaration => ! ExcludeDeclarationTypes.Contains(declaration.DeclarationType));
81+
}
82+
83+
protected virtual IInspectionResult InspectionResult(Declaration declaration, T properties)
84+
{
85+
return new DeclarationInspectionResult<T>(
86+
this,
87+
ResultDescription(declaration, properties),
88+
declaration,
89+
properties: properties,
90+
disabledQuickFixes: DisabledQuickFixes(declaration, properties));
91+
}
92+
}
93+
}

Rubberduck.CodeAnalysis/Inspections/Abstract/IdentifierReferenceInspectionBase.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ protected IdentifierReferenceInspectionBase(RubberduckParserState state)
1818
protected abstract bool IsResultReference(IdentifierReference reference, DeclarationFinder finder);
1919
protected abstract string ResultDescription(IdentifierReference reference);
2020

21+
protected virtual ICollection<string> DisabledQuickFixes(IdentifierReference reference) => new List<string>();
22+
2123
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
2224
{
2325
var finder = DeclarationFinderProvider.DeclarationFinder;
@@ -64,7 +66,8 @@ protected virtual IInspectionResult InspectionResult(IdentifierReference referen
6466
this,
6567
ResultDescription(reference),
6668
declarationFinderProvider,
67-
reference);
69+
reference,
70+
DisabledQuickFixes(reference));
6871
}
6972
}
7073

@@ -77,6 +80,8 @@ protected IdentifierReferenceInspectionBase(RubberduckParserState state)
7780
protected abstract (bool isResult, T properties) IsResultReferenceWithAdditionalProperties(IdentifierReference reference, DeclarationFinder finder);
7881
protected abstract string ResultDescription(IdentifierReference reference, T properties);
7982

83+
protected virtual ICollection<string> DisabledQuickFixes(IdentifierReference reference, T properties) => new List<string>();
84+
8085
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
8186
{
8287
var finder = DeclarationFinderProvider.DeclarationFinder;
@@ -121,12 +126,13 @@ protected virtual IEnumerable<IdentifierReference> ReferencesInModule(QualifiedM
121126

122127
protected virtual IInspectionResult InspectionResult(IdentifierReference reference, IDeclarationFinderProvider declarationFinderProvider, T properties)
123128
{
124-
return new IdentifierReferenceInspectionResult(
129+
return new IdentifierReferenceInspectionResult<T>(
125130
this,
126131
ResultDescription(reference, properties),
127132
declarationFinderProvider,
128133
reference,
129-
properties);
134+
properties,
135+
DisabledQuickFixes(reference, properties));
130136
}
131137
}
132138
}

Rubberduck.CodeAnalysis/Inspections/Abstract/IdentifierReferenceInspectionFromDeclarationsBase.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ protected IdentifierReferenceInspectionFromDeclarationsBase(RubberduckParserStat
1818
protected abstract IEnumerable<Declaration> ObjectionableDeclarations(DeclarationFinder finder);
1919
protected abstract string ResultDescription(IdentifierReference reference);
2020

21+
protected virtual ICollection<string> DisabledQuickFixes(IdentifierReference reference) => new List<string>();
22+
2123
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
2224
{
2325
var finder = DeclarationFinderProvider.DeclarationFinder;
@@ -60,7 +62,8 @@ protected virtual IInspectionResult InspectionResult(IdentifierReference referen
6062
this,
6163
ResultDescription(reference),
6264
declarationFinderProvider,
63-
reference);
65+
reference,
66+
DisabledQuickFixes(reference));
6467
}
6568
}
6669

@@ -74,6 +77,8 @@ protected IdentifierReferenceInspectionFromDeclarationsBase(RubberduckParserStat
7477
protected abstract (bool isResult, T properties) IsResultReferenceWithAdditionalProperties(IdentifierReference reference, DeclarationFinder finder);
7578
protected abstract string ResultDescription(IdentifierReference reference, T properties);
7679

80+
protected virtual ICollection<string> DisabledQuickFixes(IdentifierReference reference, T properties) => new List<string>();
81+
7782
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
7883
{
7984
var finder = DeclarationFinderProvider.DeclarationFinder;
@@ -112,12 +117,13 @@ protected IEnumerable<IInspectionResult> DoGetInspectionResults(QualifiedModuleN
112117

113118
protected virtual IInspectionResult InspectionResult(IdentifierReference reference, IDeclarationFinderProvider declarationFinderProvider, T properties)
114119
{
115-
return new IdentifierReferenceInspectionResult(
120+
return new IdentifierReferenceInspectionResult<T>(
116121
this,
117122
ResultDescription(reference, properties),
118123
declarationFinderProvider,
119124
reference,
120-
properties);
125+
properties,
126+
DisabledQuickFixes(reference, properties));
121127
}
122128
}
123129
}

Rubberduck.CodeAnalysis/Inspections/Abstract/InspectionResultBase.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System.Collections.Generic;
22
using Antlr4.Runtime;
33
using Rubberduck.Common;
4-
using Rubberduck.Parsing.Inspections;
54
using Rubberduck.Parsing.Inspections.Abstract;
65
using Rubberduck.Parsing.Symbols;
76
using Rubberduck.VBEditor;
@@ -18,7 +17,7 @@ protected InspectionResultBase(IInspection inspection,
1817
Declaration target,
1918
QualifiedSelection qualifiedSelection,
2019
QualifiedMemberName? qualifiedMemberName,
21-
dynamic properties)
20+
ICollection<string> disabledQuickFixes = null)
2221
{
2322
Inspection = inspection;
2423
Description = description?.Capitalize();
@@ -27,7 +26,7 @@ protected InspectionResultBase(IInspection inspection,
2726
Target = target;
2827
QualifiedSelection = qualifiedSelection;
2928
QualifiedMemberName = qualifiedMemberName;
30-
Properties = properties ?? new PropertyBag();
29+
DisabledQuickFixes = disabledQuickFixes ?? new List<string>();
3130
}
3231

3332
public IInspection Inspection { get; }
@@ -36,7 +35,9 @@ protected InspectionResultBase(IInspection inspection,
3635
public QualifiedMemberName? QualifiedMemberName { get; }
3736
public ParserRuleContext Context { get; }
3837
public Declaration Target { get; }
39-
public dynamic Properties { get; }
38+
public ICollection<string> DisabledQuickFixes { get; }
39+
40+
public virtual T Properties<T>() => default;
4041

4142
public virtual bool ChangesInvalidateResult(ICollection<QualifiedModuleName> modifiedModules)
4243
{
Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
using System.Collections.Generic;
22
using System.Linq;
33
using Rubberduck.Inspections.Abstract;
4-
using Rubberduck.Inspections.Results;
5-
using Rubberduck.Parsing;
64
using Rubberduck.Parsing.Annotations;
75
using Rubberduck.Parsing.Inspections;
8-
using Rubberduck.Parsing.Inspections.Abstract;
96
using Rubberduck.Parsing.Symbols;
107
using Rubberduck.Parsing.VBA;
8+
using Rubberduck.Parsing.VBA.DeclarationCaching;
119
using Rubberduck.Resources.Inspections;
1210
using Rubberduck.VBEditor.SafeComWrappers;
1311

@@ -39,45 +37,36 @@ namespace Rubberduck.Inspections.Concrete
3937
/// ]]>
4038
/// </example>
4139
[CannotAnnotate]
42-
public sealed class AttributeValueOutOfSyncInspection : InspectionBase
40+
public sealed class AttributeValueOutOfSyncInspection : DeclarationInspectionMultiResultBase<(IParseTreeAnnotation Annotation, string AttributeName, IReadOnlyList<string> AttributeValues)>
4341
{
4442
public AttributeValueOutOfSyncInspection(RubberduckParserState state)
4543
:base(state)
4644
{
4745
}
4846

49-
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
47+
protected override IEnumerable<(IParseTreeAnnotation Annotation, string AttributeName, IReadOnlyList<string> AttributeValues)> ResultProperties(Declaration declaration, DeclarationFinder finder)
5048
{
51-
var declarationsWithAttributeAnnotations = State.DeclarationFinder.AllUserDeclarations
52-
.Where(declaration => declaration.Annotations.Any(pta => pta.Annotation is IAttributeAnnotation));
53-
var results = new List<DeclarationInspectionResult>();
54-
foreach (var declaration in declarationsWithAttributeAnnotations.Where(decl => decl.QualifiedModuleName.ComponentType != ComponentType.Document))
49+
if (declaration.QualifiedModuleName.ComponentType == ComponentType.Document)
5550
{
56-
foreach (var annotationInstance in declaration.Annotations.Where(pta => pta.Annotation is IAttributeAnnotation))
57-
{
58-
// cast is safe given the predicate in the foreach
59-
var annotation = (IAttributeAnnotation)annotationInstance.Annotation;
60-
if (HasDifferingAttributeValues(declaration, annotationInstance, out var attributeValues))
61-
{
62-
var attributeName = annotation.Attribute(annotationInstance);
63-
64-
var description = string.Format(InspectionResults.AttributeValueOutOfSyncInspection,
65-
attributeName,
66-
string.Join(", ", attributeValues),
67-
annotation.Name);
51+
return Enumerable.Empty<(IParseTreeAnnotation Annotation, string AttributeName, IReadOnlyList<string> AttributeValues)>();
52+
}
6853

69-
var result = new DeclarationInspectionResult(this, description, declaration,
70-
new QualifiedContext(declaration.QualifiedModuleName, annotationInstance.Context));
71-
result.Properties.Annotation = annotationInstance;
72-
result.Properties.AttributeName = attributeName;
73-
result.Properties.AttributeValues = attributeValues;
54+
return OutOfSyncAttributeAnnotations(declaration);
55+
}
7456

75-
results.Add(result);
76-
}
57+
private static IEnumerable<(IParseTreeAnnotation Annotation, string AttributeName, IReadOnlyList<string> AttributeValues)> OutOfSyncAttributeAnnotations(Declaration declaration)
58+
{
59+
foreach (var pta in declaration.Annotations)
60+
{
61+
if (!(pta.Annotation is IAttributeAnnotation annotation)
62+
|| !HasDifferingAttributeValues(declaration, pta, out var attributeValues))
63+
{
64+
continue;
7765
}
78-
}
7966

80-
return results;
67+
var attributeName = annotation.Attribute(pta);
68+
yield return (pta, attributeName, attributeValues);
69+
}
8170
}
8271

8372
private static bool HasDifferingAttributeValues(Declaration declaration, IParseTreeAnnotation annotationInstance, out IReadOnlyList<string> attributeValues)
@@ -87,10 +76,10 @@ private static bool HasDifferingAttributeValues(Declaration declaration, IParseT
8776
attributeValues = new List<string>();
8877
return false;
8978
}
90-
var attribute = annotation.Attribute(annotationInstance);
79+
9180
var attributeNodes = declaration.DeclarationType.HasFlag(DeclarationType.Module)
92-
? declaration.Attributes.AttributeNodesFor(annotationInstance)
93-
: declaration.Attributes.AttributeNodesFor(annotationInstance, declaration.IdentifierName);
81+
? declaration.Attributes.AttributeNodesFor(annotationInstance)
82+
: declaration.Attributes.AttributeNodesFor(annotationInstance, declaration.IdentifierName);
9483

9584
foreach (var attributeNode in attributeNodes)
9685
{
@@ -104,5 +93,15 @@ private static bool HasDifferingAttributeValues(Declaration declaration, IParseT
10493
attributeValues = new List<string>();
10594
return false;
10695
}
96+
97+
protected override string ResultDescription(Declaration declaration, (IParseTreeAnnotation Annotation, string AttributeName, IReadOnlyList<string> AttributeValues) properties)
98+
{
99+
var (pta, attributeName, attributeValues) = properties;
100+
var annotationName = pta.Annotation.Name;
101+
return string.Format(InspectionResults.AttributeValueOutOfSyncInspection,
102+
attributeName,
103+
string.Join(", ", attributeValues),
104+
annotationName);
105+
}
107106
}
108107
}

0 commit comments

Comments
 (0)