@@ -144,32 +144,30 @@ public struct AddTarget: ManifestEditRefactoringProvider {
144
144
to: & auxiliaryFiles
145
145
)
146
146
147
- if #available( macOS 13 . 0 , iOS 16 . 0 , watchOS 9 . 0 , tvOS 16 . 0 , * ) {
148
- if manifest. description. firstRange ( of: " swift-syntax " ) == nil {
149
- newPackageCall =
150
- try AddPackageDependency
151
- . addPackageDependencyLocal (
152
- . swiftSyntax(
153
- version: configuration. swiftSyntaxVersion
154
- ) ,
155
- to: newPackageCall
156
- )
157
-
158
- // Look for the first import declaration and insert an
159
- // import of `CompilerPluginSupport` there.
160
- let newImport = " import CompilerPluginSupport \n "
161
- for node in manifest. statements {
162
- if let importDecl = node. item. as ( ImportDeclSyntax . self) {
163
- let insertPos = importDecl
164
- . positionAfterSkippingLeadingTrivia
165
- extraManifestEdits. append (
166
- SourceEdit (
167
- range: insertPos..< insertPos,
168
- replacement: newImport
169
- )
147
+ if !manifest. containsStringLiteral ( " swift-syntax " ) {
148
+ newPackageCall =
149
+ try AddPackageDependency
150
+ . addPackageDependencyLocal (
151
+ . swiftSyntax(
152
+ version: configuration. swiftSyntaxVersion
153
+ ) ,
154
+ to: newPackageCall
155
+ )
156
+
157
+ // Look for the first import declaration and insert an
158
+ // import of `CompilerPluginSupport` there.
159
+ let newImport = " import CompilerPluginSupport \n "
160
+ for node in manifest. statements {
161
+ if let importDecl = node. item. as ( ImportDeclSyntax . self) {
162
+ let insertPos = importDecl
163
+ . positionAfterSkippingLeadingTrivia
164
+ extraManifestEdits. append (
165
+ SourceEdit (
166
+ range: insertPos..< insertPos,
167
+ replacement: newImport
170
168
)
171
- break
172
- }
169
+ )
170
+ break
173
171
}
174
172
}
175
173
}
@@ -388,3 +386,33 @@ fileprivate extension TargetDescription {
388
386
fileprivate extension String {
389
387
func localizedFirstWordCapitalized( ) -> String { prefix ( 1 ) . uppercased ( ) + dropFirst( ) }
390
388
}
389
+
390
+ extension SourceFileSyntax {
391
+ private class ContainsLiteralVisitor : SyntaxVisitor {
392
+ let string : String
393
+ var found : Bool = false
394
+
395
+ init ( string: String ) {
396
+ self . string = string
397
+ super. init ( viewMode: . sourceAccurate)
398
+ }
399
+
400
+ override func visit( _ node: StringLiteralExprSyntax ) -> SyntaxVisitorContinueKind {
401
+ if let representedLiteralValue = node. representedLiteralValue,
402
+ representedLiteralValue == string
403
+ {
404
+ found = true
405
+ }
406
+
407
+ return . skipChildren
408
+ }
409
+ }
410
+
411
+ /// Determine whether this source file contains a string literal
412
+ /// matching the given contents.
413
+ fileprivate func containsStringLiteral( _ contents: String ) -> Bool {
414
+ let visitor = ContainsLiteralVisitor ( string: contents)
415
+ visitor. walk ( self )
416
+ return visitor. found
417
+ }
418
+ }
0 commit comments