Skip to content

Commit 8c99cf3

Browse files
committed
Add override comment command
1 parent 08221d1 commit 8c99cf3

File tree

9 files changed

+169
-37
lines changed

9 files changed

+169
-37
lines changed

Sources/PeripheryKit/Results/CodeClimateFormatter.swift

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,27 @@ final class CodeClimateFormatter: OutputFormatter {
1414
var jsonObject: [Any] = []
1515

1616
for result in results {
17+
let location = declarationLocation(from: result.declaration)
18+
1719
let lines: [AnyHashable: Any] = [
18-
"begin": result.declaration.location.line,
20+
"begin": location.line,
1921
]
2022

21-
let location: [AnyHashable: Any] = [
22-
"path": outputPath(result.declaration.location).url.relativePath,
23+
let locationDict: [AnyHashable: Any] = [
24+
"path": outputPath(location).url.relativePath,
2325
"lines": lines,
2426
]
2527

2628
let description = describe(result, colored: colored)
2729
.map(\.1)
2830
.joined(separator: ", ")
29-
30-
let fingerprint: String = if result.declaration.kind == .varParameter,
31-
let parentFingerprint = result.declaration.parent?.usrs.sorted().joined(separator: "."),
32-
let argumentName = result.declaration.name
33-
{
34-
// As function parameters do not have a mangled name that can be used for the fingerprint
35-
// we take the mangled name of the function and append the position
36-
"\(parentFingerprint)-\(argumentName)"
37-
} else {
38-
result.declaration.usrs.sorted().joined(separator: ".")
39-
}
31+
let fingerprint = result.declaration.usrs.sorted().joined(separator: ".")
4032

4133
let object: [AnyHashable: Any] = [
4234
"description": description,
4335
"fingerprint": fingerprint,
4436
"severity": "major",
45-
"location": location,
37+
"location": locationDict,
4638
]
4739

4840
jsonObject.append(object)

Sources/PeripheryKit/Results/CsvFormatter.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ final class CsvFormatter: OutputFormatter {
1616

1717
for result in results {
1818
let line = format(
19-
kind: result.declaration.kind.rawValue,
19+
kind: declarationKind(from: result.declaration),
2020
name: result.declaration.name,
2121
modifiers: result.declaration.modifiers,
2222
attributes: result.declaration.attributes,
2323
accessibility: result.declaration.accessibility.value.rawValue,
2424
usrs: result.declaration.usrs,
25-
location: result.declaration.location,
25+
location: declarationLocation(from: result.declaration),
2626
hint: describe(result.annotation)
2727
)
2828
lines.append(line)

Sources/PeripheryKit/Results/JsonFormatter.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,17 @@ final class JsonFormatter: OutputFormatter {
1414
var jsonObject: [Any] = []
1515

1616
for result in results {
17+
let location = declarationLocation(from: result.declaration)
1718
let object: [AnyHashable: Any] = [
18-
"kind": result.declaration.kind.rawValue,
19-
"modules": result.declaration.location.file.modules.sorted(),
19+
"kind": declarationKind(from: result.declaration),
20+
"modules": location.file.modules.sorted(),
2021
"name": result.declaration.name ?? "",
2122
"modifiers": result.declaration.modifiers.sorted(),
2223
"attributes": result.declaration.attributes.sorted(),
2324
"accessibility": result.declaration.accessibility.value.rawValue,
2425
"ids": result.declaration.usrs.sorted(),
2526
"hints": [describe(result.annotation)],
26-
"location": locationDescription(result.declaration.location),
27+
"location": locationDescription(location),
2728
]
2829
jsonObject.append(object)
2930

Sources/PeripheryKit/Results/OutputDeclarationFilter.swift

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,36 @@ public final class OutputDeclarationFilter {
4343

4444
return declarations
4545
.filter { [contextualLogger] in
46-
let path = $0.declaration.location.file.path
46+
var path = $0.declaration.location.file.path
47+
48+
// If the declaration has a location override, use it as the path for filtering.
49+
for command in $0.declaration.commentCommands {
50+
switch command {
51+
case let .override(overrides):
52+
for override in overrides {
53+
switch override {
54+
case let .location(location):
55+
path = location.file.path
56+
default:
57+
break
58+
}
59+
}
60+
default:
61+
break
62+
}
63+
}
4764

4865
if configuration.reportIncludeMatchers.isEmpty {
4966
if configuration.reportExcludeMatchers.anyMatch(filename: path.string) {
50-
contextualLogger.debug("Excluding \(path.string)")
67+
contextualLogger.debug("Excluding \(path)")
5168
return false
5269
}
5370

5471
return true
5572
}
5673

5774
if configuration.reportIncludeMatchers.anyMatch(filename: path.string) {
58-
contextualLogger.debug("Including \(path.string)")
75+
contextualLogger.debug("Including \(path)")
5976
return true
6077
}
6178

Sources/PeripheryKit/Results/OutputFormatter.swift

Lines changed: 72 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,11 @@ extension OutputFormatter {
3838
func describe(_ result: ScanResult, colored: Bool) -> [(Location, String)] {
3939
var description = ""
4040
var secondaryResults: [(Location, String)] = []
41+
let location = declarationLocation(from: result.declaration)
42+
let kindDisplayName = declarationKindDisplayName(from: result.declaration)
4143

4244
if var name = result.declaration.name {
43-
if let kind = result.declaration.kind.displayName, let first_ = kind.first {
44-
let first = String(first_)
45-
description += "\(first.uppercased())\(kind.dropFirst()) "
46-
}
47-
45+
description += "\(kindDisplayName.first?.uppercased() ?? "")\(kindDisplayName.dropFirst()) "
4846
name = colored ? Logger.colorize(name, .lightBlue) : name
4947
description += "'\(name)'"
5048

@@ -72,14 +70,14 @@ extension OutputFormatter {
7270
description += "unused"
7371
}
7472

75-
return [(result.declaration.location, description)] + secondaryResults
73+
return [(location, description)] + secondaryResults
7674
}
7775

7876
func outputPath(_ location: Location) -> FilePath {
7977
var path = location.file.path.lexicallyNormalized()
8078

81-
if configuration.relativeResults {
82-
path = path.relativeTo(currentFilePath)
79+
if configuration.relativeResults, path.isAbsolute {
80+
path = path.relativeTo(currentFilePath).removingRoot()
8381
}
8482

8583
return path
@@ -93,6 +91,72 @@ extension OutputFormatter {
9391
]
9492
.joined(separator: ":")
9593
}
94+
95+
func declarationKind(from declaration: Declaration) -> String {
96+
var kind = declaration.kind.rawValue
97+
98+
for command in declaration.commentCommands {
99+
switch command {
100+
case let .override(overrides):
101+
for override in overrides {
102+
switch override {
103+
case let .kind(overrideKind):
104+
kind = overrideKind
105+
default:
106+
break
107+
}
108+
}
109+
default:
110+
break
111+
}
112+
}
113+
114+
return kind
115+
}
116+
117+
func declarationKindDisplayName(from declaration: Declaration) -> String {
118+
var kind = declaration.kind.displayName
119+
120+
for command in declaration.commentCommands {
121+
switch command {
122+
case let .override(overrides):
123+
for override in overrides {
124+
switch override {
125+
case let .kind(overrideKind):
126+
kind = overrideKind
127+
default:
128+
break
129+
}
130+
}
131+
default:
132+
break
133+
}
134+
}
135+
136+
return kind
137+
}
138+
139+
func declarationLocation(from declaration: Declaration) -> Location {
140+
var location = declaration.location
141+
142+
for command in declaration.commentCommands {
143+
switch command {
144+
case let .override(overrides):
145+
for override in overrides {
146+
switch override {
147+
case let .location(overrideLocation):
148+
location = overrideLocation
149+
default:
150+
break
151+
}
152+
}
153+
default:
154+
break
155+
}
156+
}
157+
158+
return location
159+
}
96160
}
97161

98162
public extension OutputFormat {

Sources/PeripheryKit/Results/XcodeFormatter.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,19 @@ final class XcodeFormatter: OutputFormatter {
2929

3030
private func prefix(for location: Location, colored: Bool) -> String {
3131
let path = outputPath(location)
32-
let dir = path.removingLastComponent()
32+
var dir = path.removingLastComponent().string
33+
34+
if !dir.isEmpty {
35+
dir += "/"
36+
}
37+
3338
let file = colorize(path.lastComponent?.stem ?? "", .bold, colored: colored)
3439
let ext = path.extension ?? "swift"
3540
let lineNum = colorize(String(location.line), .bold, colored: colored)
3641
let column = location.column
3742
let warning = colorize("warning:", .boldYellow, colored: colored)
3843

39-
return "\(dir)/\(file).\(ext):\(lineNum):\(column): \(warning) "
44+
return "\(dir)\(file).\(ext):\(lineNum):\(column): \(warning) "
4045
}
4146

4247
private func colorize(_ text: String, _ color: ANSIColor, colored: Bool) -> String {

Sources/SourceGraph/Elements/CommentCommand.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
11
import Foundation
22

33
public enum CommentCommand: CustomStringConvertible, Hashable {
4+
public enum Override: CustomStringConvertible, Hashable {
5+
case location(Location)
6+
case kind(String)
7+
8+
public var description: String {
9+
switch self {
10+
case let .location(location):
11+
"location=\"\(location.file.path):\(location.line):\(location.column)\""
12+
case let .kind(kind):
13+
"kind=\"\(kind)\""
14+
}
15+
}
16+
}
17+
418
case ignore
519
case ignoreAll
620
case ignoreParameters([String])
21+
case override([Override])
722

823
public var description: String {
924
switch self {
@@ -14,6 +29,9 @@ public enum CommentCommand: CustomStringConvertible, Hashable {
1429
case let .ignoreParameters(params):
1530
let formattedParams = params.sorted().joined(separator: ",")
1631
return "ignore:parameters \(formattedParams)"
32+
case let .override(overrides):
33+
let formattedOverrides = overrides.map(\.description).joined(separator: " ")
34+
return "override \(formattedOverrides)"
1735
}
1836
}
1937
}

Sources/SourceGraph/Elements/Declaration.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ public final class Declaration {
176176
[.class, .struct, .enum]
177177
}
178178

179-
public var displayName: String? {
179+
public var displayName: String {
180180
switch self {
181181
case .module:
182182
"imported module"
@@ -198,16 +198,18 @@ public final class Declaration {
198198
"initializer"
199199
case .extension, .extensionEnum, .extensionClass, .extensionStruct, .extensionProtocol:
200200
"extension"
201-
case .functionMethodClass, .functionMethodStatic, .functionMethodInstance, .functionFree, .functionOperator, .functionOperatorInfix, .functionOperatorPostfix, .functionOperatorPrefix, .functionSubscript:
201+
case .functionMethodClass, .functionMethodStatic, .functionMethodInstance, .functionFree, .functionOperator, .functionOperatorInfix, .functionOperatorPostfix, .functionOperatorPrefix, .functionSubscript, .functionAccessorAddress, .functionAccessorMutableaddress, .functionAccessorDidset, .functionAccessorGetter, .functionAccessorSetter, .functionAccessorWillset, .functionAccessorRead, .functionAccessorModify, .functionAccessorInit, .functionDestructor:
202202
"function"
203203
case .varStatic, .varInstance, .varClass, .varGlobal, .varLocal:
204204
"property"
205205
case .varParameter:
206206
"parameter"
207207
case .genericTypeParam:
208208
"generic type parameter"
209-
default:
210-
nil
209+
case .precedenceGroup:
210+
"precedence group"
211+
case .macro:
212+
"macro"
211213
}
212214
}
213215
}

Sources/SyntaxAnalysis/CommentCommand.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import SourceGraph
22
import SwiftSyntax
3+
import SystemPackage
34

45
extension CommentCommand {
56
static func parseCommands(in trivia: Trivia?) -> [CommentCommand] {
@@ -33,6 +34,38 @@ extension CommentCommand {
3334
} else if rawCommand.hasPrefix("ignore:parameters") {
3435
guard let params = rawCommand.split(separator: " ").last?.split(separator: ",").map({ String($0).trimmed }) else { return nil }
3536
return .ignoreParameters(params)
37+
} else if rawCommand.hasPrefix("override") {
38+
let pattern = #/(?<key>\w+)="(?<value>[^"]*)"/#
39+
var params: [String: String] = [:]
40+
41+
for match in rawCommand.matches(of: pattern) {
42+
let key = String(match.output.key)
43+
let value = String(match.output.value)
44+
params[key] = value
45+
}
46+
47+
var overrides = [Override]()
48+
49+
for (key, value) in params {
50+
switch key {
51+
case "location":
52+
let parts = value.split(separator: ":")
53+
guard let file = parts[safe: 0] else { break }
54+
55+
let line = Int(parts[safe: 1] ?? "1") ?? 1
56+
let column = Int(parts[safe: 2] ?? "1") ?? 1
57+
let sourceFile = SourceFile(path: FilePath(String(file)), modules: [])
58+
let location = Location(file: sourceFile, line: line, column: column)
59+
60+
overrides.append(.location(location))
61+
case "kind":
62+
overrides.append(.kind(value))
63+
default:
64+
break
65+
}
66+
}
67+
68+
return .override(overrides)
3669
}
3770

3871
return nil

0 commit comments

Comments
 (0)