Skip to content

Commit 3b49f91

Browse files
committed
Fix inspection xml-doc analyzers
Also adds analyzers for the type attribute of the module element.
1 parent 280bcc6 commit 3b49f91

File tree

4 files changed

+492
-31
lines changed

4 files changed

+492
-31
lines changed

RubberduckCodeAnalysis/InspectionXmlDocAnalyzer.cs

Lines changed: 77 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,28 @@ public class InspectionXmlDocAnalyzer : DiagnosticAnalyzer
8787
new LocalizableResourceString(nameof(Resources.MissingNameAttributeDescription), Resources.ResourceManager, typeof(Resources))
8888
);
8989

90+
public const string MissingTypeAttribute = "MissingTypeAttribute";
91+
private static readonly DiagnosticDescriptor MissingTypeAttributeRule = new DiagnosticDescriptor(
92+
MissingTypeAttribute,
93+
new LocalizableResourceString(nameof(Resources.MissingTypeAttribute), Resources.ResourceManager, typeof(Resources)),
94+
new LocalizableResourceString(nameof(Resources.MissingTypeAttributeMessageFormat), Resources.ResourceManager, typeof(Resources)),
95+
new LocalizableResourceString(nameof(Resources.XmlDocAnalyzerCategory), Resources.ResourceManager, typeof(Resources)).ToString(),
96+
DiagnosticSeverity.Error,
97+
true,
98+
new LocalizableResourceString(nameof(Resources.MissingTypeAttributeDescription), Resources.ResourceManager, typeof(Resources))
99+
);
100+
101+
public const string InvalidTypeAttribute = "InvalidTypeAttribute";
102+
private static readonly DiagnosticDescriptor InvalidTypeAttributeRule = new DiagnosticDescriptor(
103+
InvalidTypeAttribute,
104+
new LocalizableResourceString(nameof(Resources.InvalidTypeAttribute), Resources.ResourceManager, typeof(Resources)),
105+
new LocalizableResourceString(nameof(Resources.InvalidTypeAttributeMessageFormat), Resources.ResourceManager, typeof(Resources)),
106+
new LocalizableResourceString(nameof(Resources.XmlDocAnalyzerCategory), Resources.ResourceManager, typeof(Resources)).ToString(),
107+
DiagnosticSeverity.Error,
108+
true,
109+
new LocalizableResourceString(nameof(Resources.InvalidTypeAttributeDescription), Resources.ResourceManager, typeof(Resources))
110+
);
111+
90112
public const string MissingHasResultAttribute = "MissingHasResultAttribute";
91113
private static readonly DiagnosticDescriptor MissingHasResultAttributeRule = new DiagnosticDescriptor(
92114
MissingHasResultAttribute,
@@ -106,7 +128,9 @@ public class InspectionXmlDocAnalyzer : DiagnosticAnalyzer
106128
MissingHasResultAttributeRule,
107129
MissingNameAttributeRule,
108130
MissingModuleElementRule,
109-
MissingExampleElementRule
131+
MissingExampleElementRule,
132+
MissingTypeAttributeRule,
133+
InvalidTypeAttributeRule
110134
);
111135

112136
public override void Initialize(AnalysisContext context)
@@ -160,14 +184,14 @@ private static void CheckWhyElement(SymbolAnalysisContext context, INamedTypeSym
160184

161185
private static void CheckNameAttribute(SymbolAnalysisContext context, XElement element, Location location)
162186
{
163-
if (!element.Attributes().Any(a => a.Name.Equals("name")))
187+
if (!element.Attributes().Any(a => a.Name.LocalName.Equals("name")))
164188
{
165-
var diagnostic = Diagnostic.Create(MissingNameAttributeRule, location, element.Name);
189+
var diagnostic = Diagnostic.Create(MissingNameAttributeRule, location, element.Name.LocalName);
166190
context.ReportDiagnostic(diagnostic);
167191
}
168192
}
169193

170-
private static void CheckReferenceElement(SymbolAnalysisContext context, INamedTypeSymbol symbol, XElement xml, IEnumerable<AttributeData> requiredLibAttributes)
194+
private static void CheckReferenceElement(SymbolAnalysisContext context, INamedTypeSymbol symbol, XElement xml, ICollection<AttributeData> requiredLibAttributes)
171195
{
172196
if (requiredLibAttributes.Any() && !xml.Elements("reference").Any())
173197
{
@@ -218,23 +242,60 @@ private static void CheckExampleElement(SymbolAnalysisContext context, INamedTyp
218242
var examples = xml.Elements("example");
219243
foreach (var example in examples)
220244
{
221-
if (!example.Attributes().Any(a => a.Name.LocalName.Equals("hasresult", System.StringComparison.InvariantCultureIgnoreCase)))
222-
{
223-
var diagnostic = Diagnostic.Create(MissingHasResultAttributeRule, symbol.Locations[0]);
224-
context.ReportDiagnostic(diagnostic);
225-
}
245+
CheckHasResultAttribute(context, example, symbol.Locations[0]);
246+
CheckModuleElements(context, symbol, example);
247+
}
248+
}
226249

227-
if (!example.Elements("module").Any())
228-
{
229-
var diagnostic = Diagnostic.Create(MissingModuleElementRule, symbol.Locations[0]);
230-
context.ReportDiagnostic(diagnostic);
231-
}
250+
private static void CheckModuleElements(SymbolAnalysisContext context, INamedTypeSymbol symbol, XElement example)
251+
{
252+
if (!example.Elements("module").Any())
253+
{
254+
var diagnostic = Diagnostic.Create(MissingModuleElementRule, symbol.Locations[0]);
255+
context.ReportDiagnostic(diagnostic);
256+
}
257+
258+
foreach (var module in example.Elements("module"))
259+
{
260+
CheckNameAttribute(context, module, symbol.Locations[0]);
261+
CheckTypeAttribute(context, module, symbol.Locations[0]);
262+
}
263+
}
264+
265+
private static void CheckHasResultAttribute(SymbolAnalysisContext context, XElement element, Location location)
266+
{
267+
if (!element.Attributes().Any(a => a.Name.LocalName.Equals("hasresult", System.StringComparison.InvariantCultureIgnoreCase)))
268+
{
269+
var diagnostic = Diagnostic.Create(MissingHasResultAttributeRule, location);
270+
context.ReportDiagnostic(diagnostic);
271+
}
272+
}
232273

233-
foreach (var module in example.Elements("module"))
274+
private static void CheckTypeAttribute(SymbolAnalysisContext context, XElement element, Location location)
275+
{
276+
var nameAttribute = element.Attributes().FirstOrDefault(a => a.Name.LocalName.Equals("type"));
277+
if (nameAttribute == null)
278+
{
279+
var diagnostic = Diagnostic.Create(MissingTypeAttributeRule, location, element.Name.LocalName);
280+
context.ReportDiagnostic(diagnostic);
281+
}
282+
else
283+
{
284+
var typeNameValue = nameAttribute.Value;
285+
if (!ValidTypeAttributeValues.Contains(typeNameValue))
234286
{
235-
CheckNameAttribute(context, module, symbol.Locations[0]);
287+
var diagnostic = Diagnostic.Create(InvalidTypeAttributeRule, location, typeNameValue);
288+
context.ReportDiagnostic(diagnostic);
236289
}
237290
}
238291
}
292+
293+
private static readonly List<string> ValidTypeAttributeValues = new List<string>
294+
{
295+
"Standard Module",
296+
"Class Module",
297+
"Document",
298+
"User Form"
299+
};
239300
}
240301
}

RubberduckCodeAnalysis/Resources.Designer.cs

Lines changed: 54 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

RubberduckCodeAnalysis/Resources.resx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,4 +267,22 @@
267267
<data name="XmlDocAnalyzerCategory" xml:space="preserve">
268268
<value>Project website compatibility</value>
269269
</data>
270+
<data name="MissingTypeAttribute" xml:space="preserve">
271+
<value>Missing 'type' attribute.</value>
272+
</data>
273+
<data name="MissingTypeAttributeDescription" xml:space="preserve">
274+
<value>This attribute value will be used to determine the component type of each module in a code example.</value>
275+
</data>
276+
<data name="MissingTypeAttributeMessageFormat" xml:space="preserve">
277+
<value>A '{0}' element requires a 'type' attribute value.</value>
278+
</data>
279+
<data name="InvalidTypeAttribute" xml:space="preserve">
280+
<value>Invalid value for 'type' attribute.</value>
281+
</data>
282+
<data name="InvalidTypeAttributeDescription" xml:space="preserve">
283+
<value>The values of the 'type' attribute are restricted to the value 'Standard Module', 'Class Module', 'Document' and 'User Form'.</value>
284+
</data>
285+
<data name="InvalidTypeAttributeMessageFormat" xml:space="preserve">
286+
<value>The value '{0}' is not legal for the 'type' attribute.</value>
287+
</data>
270288
</root>

0 commit comments

Comments
 (0)