[SourceKit] Support location info for macro-expanded Clang imports

Currently, when we jump-to-definition for decls that are macro-expanded
from Clang imported decls (e.g., safe overloads generated by
@_SwiftifyImport), setLocationInfo() emits a bongus location pointing to
a generated buffer, leading the IDE to try to jump to a file that does
not exist.

The root cause here is that setLocationInfo() calls getOriginalRange()
(earlier, getOriginalLocation()), which was not written to account for
such cases where a macro is generated from another generated buffer
whose kind is 'AttributeFromClang'.

This patch fixes setLocationInfo() with some refactoring:

-   getOriginalRange() is inlined into setLocationInfo(), so that the
    generated buffer-handling logic is localized to that function. This
    includes how it handles buffers generated for ReplacedFunctionBody.

-   getOriginalLocation() is used in a couple of other places that only
    care about macros expanded from the same buffer (so other generated
    buffers not not relevant). This "macro-chasing" logic is simplified
    and moved from ModuleDecl::getOriginalRange() to a free-standing
    function, getMacroUnexpandedRange() (there is no reason for it to be
    a method of ModuleDecl).

-   GeneratedSourceInfo now carries an extra ClangNode field, which is
    populated by getClangSwiftAttrSourceFile() when constructing
    a generated buffer for an 'AttributeFromClang'. This could probably
    be union'ed with one or more of the other fields in the future.

rdar://151020332
(cherry picked from commit 44aba1382d)
This commit is contained in:
John Hui
2025-06-04 18:07:03 -07:00
parent 7fb85a3b67
commit c94955b571
10 changed files with 225 additions and 124 deletions

View File

@@ -0,0 +1,61 @@
// RUN: %empty-directory(%t)
// RUN: split-file %s %t
//--- Main.swift
import FromClang // NOTE: line offset = -4
// REQUIRES: swift_feature_SafeInteropWrappers
// REQUIRES: swift_feature_LifetimeDependence
// The macro-generated interface we're looking up source info for
// (this is more so for documentation than checking correctness)
//
// INTERFACE: @_alwaysEmitIntoClient @_disfavoredOverload public func hasBufferOverload(_ p: UnsafeMutableBufferPointer<Int32>)
// INTERFACE: @{{_?}}lifetime(p: copy p)
// INTERFACE-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func hasSpanOverload(_ p: inout MutableSpan<Int32>)
// RUN: %target-swift-ide-test \
// RUN: -print-module -module-to-print=FromClang -source-filename=x \
// RUN: -plugin-path %swift-plugin-dir -I %t/Inputs \
// RUN: -enable-experimental-feature SafeInteropWrappers \
// RUN: -enable-experimental-feature LifetimeDependence \
// RUN: | %FileCheck %t/Main.swift --check-prefix INTERFACE
@inlinable
public func callWithBufferPtr(_ p: UnsafeMutableBufferPointer<CInt>) {
hasBufferOverload(p)
// RUN: %sourcekitd-test -req=cursor -pos=%(line-4):3 %t/Main.swift -- -I %t/Inputs %t/Main.swift \
// RUN: -enable-experimental-feature SafeInteropWrappers \
// RUN: -enable-experimental-feature LifetimeDependence \
// RUN: | %FileCheck %t/Inputs/from-clang.h --check-prefix BUFFER-OVERLOAD
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@lifetime(p: copy p)
@inlinable
public func callReturnLifetimeBound(_ p: inout MutableSpan<CInt>) {
hasSpanOverload(p)
// RUN: %sourcekitd-test -req=cursor -pos=%(line-4):3 %t/Main.swift -- -I %t/Inputs %t/Main.swift \
// RUN: -enable-experimental-feature SafeInteropWrappers \
// RUN: -enable-experimental-feature LifetimeDependence \
// RUN: | %FileCheck %t/Inputs/from-clang.h --check-prefix SPAN-OVERLOAD
}
//--- Inputs/module.modulemap
module FromClang {
header "from-clang.h"
export *
}
//--- Inputs/from-clang.h
#pragma once
#define __counted_by(x) __attribute__((__counted_by__(x)))
#define __noescape __attribute__((noescape))
#define __lifetimebound __attribute__((lifetimebound))
void hasBufferOverload(int len, int * __counted_by(len) p);
// BUFFER-OVERLOAD: source.lang.swift.ref.function.free
// BUFFER-OVERLOAD-SAME: from-clang.h:[[@LINE-2]]
void hasSpanOverload(int len, int * __counted_by(len) __noescape p);
// SPAN-OVERLOAD: source.lang.swift.ref.function.free
// SPAN-OVERLOAD-SAME: from-clang.h:[[@LINE-2]]