Skip to content

Commit 203b9e6

Browse files
committed
Implement paragraph style rules
* DOC100PlaceTextInParagraphs * DOC101UseChildBlocksConsistently * DOC102UseChildBlocksConsistentlyAcrossElementsOfTheSameKind Closes #19 Closes #20 Closes #21
1 parent 9244616 commit 203b9e6

26 files changed

Lines changed: 3297 additions & 4 deletions

DOCUMENTATION.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@ DocumentationAnalyzers provides warnings that indicate documentation rule violat
22

33
### Rule areas
44

5+
**[Style Rules (DOC100-)](docs/StyleRules.md)**
6+
7+
Rules related to the style of documentation comments.
8+
59
### Additional documentation
Lines changed: 345 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,345 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT license. See LICENSE in the project root for license information.
3+
4+
namespace DocumentationAnalyzers.Helpers
5+
{
6+
using System;
7+
using System.Xml.Linq;
8+
using Microsoft.CodeAnalysis;
9+
using Microsoft.CodeAnalysis.CSharp;
10+
using Microsoft.CodeAnalysis.CSharp.Syntax;
11+
12+
internal static class XmlSyntaxFactory
13+
{
14+
public static DocumentationCommentTriviaSyntax DocumentationComment(string newLineText, params XmlNodeSyntax[] content)
15+
{
16+
return SyntaxFactory.DocumentationCommentTrivia(SyntaxKind.SingleLineDocumentationCommentTrivia, List(content))
17+
.WithLeadingTrivia(SyntaxFactory.DocumentationCommentExterior("/// "))
18+
.WithTrailingTrivia(SyntaxFactory.EndOfLine(newLineText));
19+
}
20+
21+
public static XmlElementSyntax MultiLineElement(string localName, string newLineText, SyntaxList<XmlNodeSyntax> content)
22+
{
23+
return MultiLineElement(SyntaxFactory.XmlName(localName), newLineText, content);
24+
}
25+
26+
public static XmlElementSyntax MultiLineElement(XmlNameSyntax name, string newLineText, SyntaxList<XmlNodeSyntax> content)
27+
{
28+
var newContent = content.Insert(0, NewLine(newLineText)).Add(NewLine(newLineText));
29+
30+
for (var i = 1; i < newContent.Count; i++)
31+
{
32+
if (newContent[i] is XmlTextSyntax xmlTextSyntax
33+
&& xmlTextSyntax.TextTokens[0].ValueText == newLineText)
34+
{
35+
var previousTrailingTrivia = newContent[i - 1].GetTrailingTrivia();
36+
if (previousTrailingTrivia.Count > 0)
37+
{
38+
var lastTrivia = previousTrailingTrivia.Last();
39+
var updatedLastTriviaText = lastTrivia.ToString().TrimEnd(' ', '\t');
40+
41+
var updatedTrailingTrivia = previousTrailingTrivia.Replace(lastTrivia, SyntaxFactory.SyntaxTrivia(lastTrivia.Kind(), updatedLastTriviaText));
42+
newContent = newContent.Replace(newContent[i - 1], newContent[i - 1].WithTrailingTrivia(updatedTrailingTrivia));
43+
}
44+
}
45+
}
46+
47+
return SyntaxFactory.XmlElement(
48+
SyntaxFactory.XmlElementStartTag(name),
49+
newContent,
50+
SyntaxFactory.XmlElementEndTag(name));
51+
}
52+
53+
public static XmlElementSyntax Element(string localName, SyntaxList<XmlNodeSyntax> content)
54+
{
55+
return Element(SyntaxFactory.XmlName(localName), content);
56+
}
57+
58+
public static XmlElementSyntax Element(XmlNameSyntax name, SyntaxList<XmlNodeSyntax> content)
59+
{
60+
return SyntaxFactory.XmlElement(
61+
SyntaxFactory.XmlElementStartTag(name),
62+
content,
63+
SyntaxFactory.XmlElementEndTag(name));
64+
}
65+
66+
public static XmlEmptyElementSyntax EmptyElement(string localName)
67+
{
68+
return SyntaxFactory.XmlEmptyElement(SyntaxFactory.XmlName(localName));
69+
}
70+
71+
public static SyntaxList<XmlNodeSyntax> List(params XmlNodeSyntax[] nodes)
72+
{
73+
return SyntaxFactory.List(nodes);
74+
}
75+
76+
public static XmlTextSyntax Text(string value)
77+
{
78+
return Text(TextLiteral(value));
79+
}
80+
81+
public static XmlTextSyntax Text(params SyntaxToken[] textTokens)
82+
{
83+
return SyntaxFactory.XmlText(SyntaxFactory.TokenList(textTokens));
84+
}
85+
86+
public static XmlTextAttributeSyntax TextAttribute(string name, string value)
87+
{
88+
return TextAttribute(name, TextLiteral(value, true));
89+
}
90+
91+
public static XmlTextAttributeSyntax TextAttribute(string name, params SyntaxToken[] textTokens)
92+
{
93+
return TextAttribute(SyntaxFactory.XmlName(name), SyntaxKind.DoubleQuoteToken, SyntaxFactory.TokenList(textTokens));
94+
}
95+
96+
public static XmlTextAttributeSyntax TextAttribute(string name, SyntaxKind quoteKind, SyntaxTokenList textTokens)
97+
{
98+
return TextAttribute(SyntaxFactory.XmlName(name), quoteKind, textTokens);
99+
}
100+
101+
public static XmlTextAttributeSyntax TextAttribute(XmlNameSyntax name, SyntaxKind quoteKind, SyntaxTokenList textTokens)
102+
{
103+
return SyntaxFactory.XmlTextAttribute(
104+
name,
105+
SyntaxFactory.Token(quoteKind),
106+
textTokens,
107+
SyntaxFactory.Token(quoteKind))
108+
.WithLeadingTrivia(SyntaxFactory.Whitespace(" "));
109+
}
110+
111+
public static XmlNameAttributeSyntax NameAttribute(string parameterName)
112+
{
113+
return SyntaxFactory.XmlNameAttribute(
114+
SyntaxFactory.XmlName(XmlCommentHelper.NameArgumentName),
115+
SyntaxFactory.Token(SyntaxKind.DoubleQuoteToken),
116+
parameterName,
117+
SyntaxFactory.Token(SyntaxKind.DoubleQuoteToken))
118+
.WithLeadingTrivia(SyntaxFactory.Whitespace(" "));
119+
}
120+
121+
public static XmlCrefAttributeSyntax CrefAttribute(CrefSyntax cref)
122+
{
123+
return CrefAttribute(cref, SyntaxKind.DoubleQuoteToken);
124+
}
125+
126+
public static XmlCrefAttributeSyntax CrefAttribute(CrefSyntax cref, SyntaxKind quoteKind)
127+
{
128+
cref = cref.ReplaceTokens(cref.DescendantTokens(), ReplaceBraceTokens);
129+
return SyntaxFactory.XmlCrefAttribute(
130+
SyntaxFactory.XmlName(XmlCommentHelper.CrefArgumentName),
131+
SyntaxFactory.Token(quoteKind),
132+
cref,
133+
SyntaxFactory.Token(quoteKind))
134+
.WithLeadingTrivia(SyntaxFactory.Whitespace(" "));
135+
}
136+
137+
public static XmlTextSyntax NewLine(string text)
138+
{
139+
return Text(TextNewLine(text));
140+
}
141+
142+
public static SyntaxToken TextNewLine(string text)
143+
{
144+
return TextNewLine(text, true);
145+
}
146+
147+
public static SyntaxToken TextNewLine(string text, bool continueComment)
148+
{
149+
SyntaxToken token = SyntaxFactory.XmlTextNewLine(
150+
SyntaxFactory.TriviaList(),
151+
text,
152+
text,
153+
SyntaxFactory.TriviaList());
154+
155+
if (continueComment)
156+
{
157+
token = token.WithTrailingTrivia(SyntaxFactory.DocumentationCommentExterior("/// "));
158+
}
159+
160+
return token;
161+
}
162+
163+
public static SyntaxToken TextLiteral(string value)
164+
{
165+
return TextLiteral(value, false);
166+
}
167+
168+
public static SyntaxToken TextLiteral(string value, bool escapeQuotes)
169+
{
170+
string encoded = new XText(value).ToString();
171+
if (escapeQuotes)
172+
{
173+
encoded = encoded.Replace("\"", "&quot;");
174+
}
175+
176+
return SyntaxFactory.XmlTextLiteral(
177+
SyntaxFactory.TriviaList(),
178+
encoded,
179+
value,
180+
SyntaxFactory.TriviaList());
181+
}
182+
183+
public static XmlElementSyntax SummaryElement(string newLineText, params XmlNodeSyntax[] content)
184+
{
185+
return SummaryElement(newLineText, List(content));
186+
}
187+
188+
public static XmlElementSyntax SummaryElement(string newLineText, SyntaxList<XmlNodeSyntax> content)
189+
{
190+
return MultiLineElement(XmlCommentHelper.SummaryXmlTag, newLineText, content);
191+
}
192+
193+
public static XmlElementSyntax RemarksElement(string newLineText, params XmlNodeSyntax[] content)
194+
{
195+
return RemarksElement(newLineText, List(content));
196+
}
197+
198+
public static XmlElementSyntax RemarksElement(string newLineText, SyntaxList<XmlNodeSyntax> content)
199+
{
200+
return MultiLineElement("remarks", newLineText, content);
201+
}
202+
203+
public static XmlElementSyntax ReturnsElement(params XmlNodeSyntax[] content)
204+
{
205+
return ReturnsElement(List(content));
206+
}
207+
208+
public static XmlElementSyntax ReturnsElement(SyntaxList<XmlNodeSyntax> content)
209+
{
210+
return Element(XmlCommentHelper.ReturnsXmlTag, content);
211+
}
212+
213+
public static XmlElementSyntax ValueElement(string newLineText, params XmlNodeSyntax[] content)
214+
{
215+
return ValueElement(newLineText, List(content));
216+
}
217+
218+
public static XmlElementSyntax ValueElement(string newLineText, SyntaxList<XmlNodeSyntax> content)
219+
{
220+
return MultiLineElement(XmlCommentHelper.ValueXmlTag, newLineText, content);
221+
}
222+
223+
public static XmlElementSyntax ExceptionElement(CrefSyntax cref, params XmlNodeSyntax[] content)
224+
{
225+
return ExceptionElement(cref, List(content));
226+
}
227+
228+
public static XmlElementSyntax ExceptionElement(CrefSyntax cref, SyntaxList<XmlNodeSyntax> content)
229+
{
230+
XmlElementSyntax element = Element("exception", content);
231+
return element.WithStartTag(element.StartTag.AddAttributes(CrefAttribute(cref)));
232+
}
233+
234+
public static XmlElementSyntax ParaElement(params XmlNodeSyntax[] content)
235+
{
236+
return ParaElement(List(content));
237+
}
238+
239+
public static XmlElementSyntax ParaElement(SyntaxList<XmlNodeSyntax> content)
240+
{
241+
return Element("para", content);
242+
}
243+
244+
public static XmlElementSyntax ParamElement(string parameterName, params XmlNodeSyntax[] content)
245+
{
246+
return ParamElement(parameterName, List(content));
247+
}
248+
249+
public static XmlElementSyntax ParamElement(string parameterName, SyntaxList<XmlNodeSyntax> content)
250+
{
251+
XmlElementSyntax element = Element("param", content);
252+
return element.WithStartTag(element.StartTag.AddAttributes(NameAttribute(parameterName)));
253+
}
254+
255+
public static XmlElementSyntax TypeParamElement(string parameterName, params XmlNodeSyntax[] content)
256+
{
257+
return TypeParamElement(parameterName, List(content));
258+
}
259+
260+
public static XmlElementSyntax TypeParamElement(string parameterName, SyntaxList<XmlNodeSyntax> content)
261+
{
262+
XmlElementSyntax element = Element(XmlCommentHelper.TypeParamXmlTag, content);
263+
return element.WithStartTag(element.StartTag.AddAttributes(NameAttribute(parameterName)));
264+
}
265+
266+
public static XmlEmptyElementSyntax ParamRefElement(string parameterName)
267+
{
268+
return EmptyElement("paramref").AddAttributes(NameAttribute(parameterName));
269+
}
270+
271+
public static XmlEmptyElementSyntax SeeElement(CrefSyntax cref)
272+
{
273+
return EmptyElement("see").AddAttributes(CrefAttribute(cref));
274+
}
275+
276+
public static XmlEmptyElementSyntax SeeAlsoElement(CrefSyntax cref)
277+
{
278+
return EmptyElement(XmlCommentHelper.SeeAlsoXmlTag).AddAttributes(CrefAttribute(cref));
279+
}
280+
281+
public static XmlElementSyntax SeeAlsoElement(Uri linkAddress, SyntaxList<XmlNodeSyntax> linkText)
282+
{
283+
XmlElementSyntax element = Element(XmlCommentHelper.SeeAlsoXmlTag, linkText);
284+
return element.WithStartTag(element.StartTag.AddAttributes(TextAttribute("href", linkAddress.ToString())));
285+
}
286+
287+
public static XmlEmptyElementSyntax NullKeywordElement()
288+
{
289+
return KeywordElement("null");
290+
}
291+
292+
public static XmlElementSyntax PlaceholderElement(params XmlNodeSyntax[] content)
293+
{
294+
return PlaceholderElement(List(content));
295+
}
296+
297+
public static XmlElementSyntax PlaceholderElement(SyntaxList<XmlNodeSyntax> content)
298+
{
299+
return Element(XmlCommentHelper.PlaceholderTag, content);
300+
}
301+
302+
public static XmlEmptyElementSyntax ThreadSafetyElement()
303+
{
304+
return ThreadSafetyElement(true, false);
305+
}
306+
307+
public static XmlEmptyElementSyntax ThreadSafetyElement(bool @static, bool instance)
308+
{
309+
return EmptyElement("threadsafety").AddAttributes(
310+
TextAttribute("static", @static.ToString().ToLowerInvariant()),
311+
TextAttribute("instance", instance.ToString().ToLowerInvariant()));
312+
}
313+
314+
public static XmlEmptyElementSyntax PreliminaryElement()
315+
{
316+
return EmptyElement("preliminary");
317+
}
318+
319+
public static XmlElementSyntax TokenElement(string value)
320+
{
321+
return Element("token", List(Text(value)));
322+
}
323+
324+
private static XmlEmptyElementSyntax KeywordElement(string keyword)
325+
{
326+
return EmptyElement("see").AddAttributes(
327+
TextAttribute("langword", keyword));
328+
}
329+
330+
private static SyntaxToken ReplaceBraceTokens(SyntaxToken originalToken, SyntaxToken rewrittenToken)
331+
{
332+
if (rewrittenToken.IsKind(SyntaxKind.LessThanToken) && string.Equals("<", rewrittenToken.Text, StringComparison.Ordinal))
333+
{
334+
return SyntaxFactory.Token(rewrittenToken.LeadingTrivia, SyntaxKind.LessThanToken, "{", rewrittenToken.ValueText, rewrittenToken.TrailingTrivia);
335+
}
336+
337+
if (rewrittenToken.IsKind(SyntaxKind.GreaterThanToken) && string.Equals(">", rewrittenToken.Text, StringComparison.Ordinal))
338+
{
339+
return SyntaxFactory.Token(rewrittenToken.LeadingTrivia, SyntaxKind.GreaterThanToken, "}", rewrittenToken.ValueText, rewrittenToken.TrailingTrivia);
340+
}
341+
342+
return rewrittenToken;
343+
}
344+
}
345+
}

0 commit comments

Comments
 (0)