Skip to content

Commit d0ebfb3

Browse files
author
Denis Krivak
committed
Refactor check functions.
1 parent 9f6abf7 commit d0ebfb3

File tree

2 files changed

+355
-200
lines changed

2 files changed

+355
-200
lines changed

checks.go

Lines changed: 79 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -43,26 +43,46 @@ func checkComments(comments []comment, settings Settings) []Issue {
4343
var issues []Issue
4444
for _, c := range comments {
4545
if settings.Period {
46-
if iss := checkCommentForPeriod(c); iss != nil {
46+
if iss := checkPeriod(c); iss != nil {
4747
issues = append(issues, *iss)
4848
}
4949
}
5050
if settings.Capital {
51-
if iss := checkCommentForCapital(c); len(iss) > 0 {
51+
if iss := checkCapital(c); len(iss) > 0 {
5252
issues = append(issues, iss...)
5353
}
5454
}
5555
}
5656
return issues
5757
}
5858

59-
// checkCommentForPeriod checks that the last sentense of the comment ends
59+
// checkPeriod checks that the last sentense of the comment ends
6060
// in a period.
61-
func checkCommentForPeriod(c comment) *Issue {
62-
pos, ok := checkPeriod(c.text)
63-
if ok {
61+
func checkPeriod(c comment) *Issue {
62+
// Check last non-empty line
63+
var found bool
64+
var line string
65+
var pos position
66+
lines := strings.Split(c.text, "\n")
67+
for i := len(lines) - 1; i >= 0; i-- {
68+
line = strings.TrimRightFunc(lines[i], unicode.IsSpace)
69+
if line == "" {
70+
continue
71+
}
72+
found = true
73+
pos.line = i + 1
74+
break
75+
}
76+
// All lines are empty
77+
if !found {
6478
return nil
6579
}
80+
// Correct line
81+
if hasSuffix(line, lastChars) {
82+
return nil
83+
}
84+
85+
pos.column = len(line) + 1
6686

6787
// Shift position to its real value. `c.text` doesn't contain comment's
6888
// special symbols: /* or //, and line indentations inside. It also
@@ -100,108 +120,30 @@ func checkCommentForPeriod(c comment) *Issue {
100120
return &iss
101121
}
102122

103-
// checkCommentForCapital checks that each sentense of the comment starts with
104-
// a capital letter.
105-
// nolint: unparam
106-
func checkCommentForCapital(c comment) []Issue {
107-
pp := checkCapital(c.text, c.decl)
108-
if len(pp) == 0 {
109-
return nil
110-
}
111-
112-
issues := make([]Issue, len(pp))
113-
for i, pos := range pp {
114-
// Shift position by the length of comment's special symbols: /* or //
115-
isBlock := strings.HasPrefix(c.lines[0], "/*")
116-
if (isBlock && pos.line == 1) || !isBlock {
117-
pos.column += 2
118-
}
119-
120-
iss := Issue{
121-
Pos: token.Position{
122-
Filename: c.start.Filename,
123-
Offset: c.start.Offset,
124-
Line: pos.line + c.start.Line - 1,
125-
Column: pos.column + c.start.Column - 1,
126-
},
127-
Message: noCapitalMessage,
128-
}
129-
130-
// Make a replacement. Use `pos.original` to get an original original from
131-
// attached lines. Use `iss.Pos.Column` because it's a position in
132-
// the original original.
133-
original := c.lines[pos.line-1]
134-
col := byteToRuneColumn(original, iss.Pos.Column) - 1
135-
rep := string(unicode.ToTitle([]rune(original)[col])) // capital letter
136-
if len(original) < iss.Pos.Column-1+len(rep) {
137-
// This should never happen. Avoid panics, skip this check.
138-
continue
139-
}
140-
iss.Replacement = original[:iss.Pos.Column-1] + rep +
141-
original[iss.Pos.Column-1+len(rep):]
142-
143-
// Save replacement to raw lines to be able to combine it with
144-
// further replacements
145-
c.lines[pos.line-1] = iss.Replacement
146-
147-
issues[i] = iss
148-
}
149-
150-
return issues
151-
}
152-
153-
// checkPeriod checks that the last sentense of the text ends in a period.
154-
// NOTE: Returned position is a position inside given text, not in the
155-
// original file.
156-
func checkPeriod(comment string) (pos position, ok bool) {
157-
// Check last non-empty line
158-
var found bool
159-
var line string
160-
lines := strings.Split(comment, "\n")
161-
for i := len(lines) - 1; i >= 0; i-- {
162-
line = strings.TrimRightFunc(lines[i], unicode.IsSpace)
163-
if line == "" {
164-
continue
165-
}
166-
found = true
167-
pos.line = i + 1
168-
break
169-
}
170-
// All lines are empty
171-
if !found {
172-
return position{}, true
173-
}
174-
// Correct line
175-
if hasSuffix(line, lastChars) {
176-
return position{}, true
177-
}
178-
179-
pos.column = len(line) + 1
180-
return pos, false
181-
}
182-
183-
// checkCapital checks that each sentense of the text starts with
123+
// checkCapital checks that each sentense of the comment starts with
184124
// a capital letter.
185-
// NOTE: First letter is not checked in declaration comments, because they
186-
// can describe unexported functions, which start with small letter.
187-
func checkCapital(comment string, skipFirst bool) (pp []position) {
125+
//
126+
//nolint:cyclop,funlen
127+
func checkCapital(c comment) []Issue {
188128
// Remove common abbreviations from the comment
189129
for _, abbr := range abbreviations {
190130
repl := strings.ReplaceAll(abbr, ".", "_")
191-
comment = strings.ReplaceAll(comment, abbr, repl)
131+
c.text = strings.ReplaceAll(c.text, abbr, repl)
192132
}
193133

194134
// List of states during the scan: `empty` - nothing special,
195135
// `endChar` - found one of sentence ending chars (.!?),
196136
// `endOfSentence` - found `endChar`, and then space or newline.
197137
const empty, endChar, endOfSentence = 1, 2, 3
198138

139+
var pp []position
199140
pos := position{line: 1}
200141
state := endOfSentence
201-
if skipFirst {
142+
if c.decl {
143+
// Skip first
202144
state = empty
203145
}
204-
for _, r := range comment {
146+
for _, r := range c.text {
205147
s := string(r)
206148

207149
pos.column++
@@ -229,12 +171,54 @@ func checkCapital(comment string, skipFirst bool) (pp []position) {
229171
if state == endOfSentence && unicode.IsLower(r) {
230172
pp = append(pp, position{
231173
line: pos.line,
232-
column: runeToByteColumn(comment, pos.column),
174+
column: runeToByteColumn(c.text, pos.column),
233175
})
234176
}
235177
state = empty
236178
}
237-
return pp
179+
if len(pp) == 0 {
180+
return nil
181+
}
182+
183+
issues := make([]Issue, len(pp))
184+
for i, pos := range pp {
185+
// Shift position by the length of comment's special symbols: /* or //
186+
isBlock := strings.HasPrefix(c.lines[0], "/*")
187+
if (isBlock && pos.line == 1) || !isBlock {
188+
pos.column += 2
189+
}
190+
191+
iss := Issue{
192+
Pos: token.Position{
193+
Filename: c.start.Filename,
194+
Offset: c.start.Offset,
195+
Line: pos.line + c.start.Line - 1,
196+
Column: pos.column + c.start.Column - 1,
197+
},
198+
Message: noCapitalMessage,
199+
}
200+
201+
// Make a replacement. Use `pos.original` to get an original original from
202+
// attached lines. Use `iss.Pos.Column` because it's a position in
203+
// the original original.
204+
original := c.lines[pos.line-1]
205+
col := byteToRuneColumn(original, iss.Pos.Column) - 1
206+
rep := string(unicode.ToTitle([]rune(original)[col])) // capital letter
207+
if len(original) < iss.Pos.Column-1+len(rep) {
208+
// This should never happen. Avoid panics, skip this check.
209+
continue
210+
}
211+
iss.Replacement = original[:iss.Pos.Column-1] + rep +
212+
original[iss.Pos.Column-1+len(rep):]
213+
214+
// Save replacement to raw lines to be able to combine it with
215+
// further replacements
216+
c.lines[pos.line-1] = iss.Replacement
217+
218+
issues[i] = iss
219+
}
220+
221+
return issues
238222
}
239223

240224
// isSpecialBlock checks that given block of comment lines is special and

0 commit comments

Comments
 (0)