From 7629411914e8fa65a50ebd583323606774e142c3 Mon Sep 17 00:00:00 2001 From: Ruslan A Date: Sat, 8 Jun 2024 23:00:29 +0400 Subject: [PATCH] Fixed crash when inline function has out of bound indexes (#1342) --- .../Sources/Parsing/Utils/StringView.swift | 8 +++- SourceryTests/SourcerySpec.swift | 45 +++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/SourceryFramework/Sources/Parsing/Utils/StringView.swift b/SourceryFramework/Sources/Parsing/Utils/StringView.swift index 441bbe059..871523d4e 100644 --- a/SourceryFramework/Sources/Parsing/Utils/StringView.swift +++ b/SourceryFramework/Sources/Parsing/Utils/StringView.swift @@ -392,8 +392,12 @@ public struct StringView { - returns: An equivalent `NSRange`. */ public func NSRangeToByteRange(start: Int, length: Int) -> ByteRange? { - let startUTF16Index = utf16View.index(utf16View.startIndex, offsetBy: start) - let endUTF16Index = utf16View.index(startUTF16Index, offsetBy: length) + guard + let startUTF16Index = utf16View.index(utf16View.startIndex, offsetBy: start, limitedBy: utf16View.endIndex), + let endUTF16Index = utf16View.index(startUTF16Index, offsetBy: length, limitedBy: utf16View.endIndex) + else { + return nil + } guard let startUTF8Index = startUTF16Index.samePosition(in: utf8View), let endUTF8Index = endUTF16Index.samePosition(in: utf8View) else { diff --git a/SourceryTests/SourcerySpec.swift b/SourceryTests/SourcerySpec.swift index 30643f1a8..343330d91 100644 --- a/SourceryTests/SourcerySpec.swift +++ b/SourceryTests/SourcerySpec.swift @@ -530,6 +530,51 @@ class SourcerySpecTests: QuickSpec { expect(result).to(equal(expectedResult)) } + it("replaces inline contents without crashing") { + update(code: """ + struct MyStruct { + // sourcery:inline:MyStruct.Inlined + // This will be replaced + // sourcery:end + // sourcery:inline:MyStruct.Inlined.Foo + // sourcery: stub = "A" + let basic: String; + // sourcery: stub = "B" + let caseProperty: String; + // sourcery: stub = "C" + let casesProperty: String; + // sourcery: stub = "D" + let CaseProperty: String; + // sourcery:end + } + """, in: sourcePath) + update(code: """ + // sourcery:inline:MyStruct.Inlined + {% for type in types.all %} + {% for variable in type.storedVariables %} + let {{ variable.name }}XXX = "{{ variable.annotations["stub"] }}"; + {% endfor %} + {% endfor %} + // sourcery:end + // sourcery:inline:MyStruct.Inlined.Foo + // sourcery:end + """, in: templatePath) + + expect { try Sourcery(watcherEnabled: false, cacheDisabled: true).processFiles(.sources(Paths(include: [sourcePath])), usingTemplates: Paths(include: [templatePath]), output: output, baseIndentation: 0) }.toNot(throwError()) + + let expectedResult = """ + struct MyStruct { + // sourcery:inline:MyStruct.Inlined + // sourcery:end + // sourcery:inline:MyStruct.Inlined.Foo + // sourcery:end + } + """ + + let result = try? sourcePath.read(.utf8) + expect(result).to(equal(expectedResult)) + } + it("handles previously generated code with UTF16 characters") { update(code: """ class A {