Skip to content

Commit a2bd6ca

Browse files
authored
Merge pull request #82171 from j-hui/j-hui/6.2/jump-to-def-for-macro-expanded-clang-imports
🍒 [6.2] [SourceKit] Support location info for macro-expanded Clang imports
2 parents 5f48a7e + c94955b commit a2bd6ca

File tree

10 files changed

+229
-128
lines changed

10 files changed

+229
-128
lines changed

include/swift/AST/ASTNode.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/ADT/ArrayRef.h"
2222
#include "llvm/ADT/PointerUnion.h"
2323
#include "swift/Basic/Debug.h"
24+
#include "swift/Basic/SourceManager.h"
2425
#include "swift/AST/TypeAlignments.h"
2526

2627
namespace llvm {
@@ -98,6 +99,12 @@ namespace swift {
9899
return llvm::hash_value(N.getOpaqueValue());
99100
}
100101
};
102+
103+
/// Find the outermost range that \p range was originally generated from.
104+
/// Returns an invalid source range if \p range wasn't generated from a macro.
105+
SourceRange getUnexpandedMacroRange(const SourceManager &SM,
106+
SourceRange range);
107+
101108
} // namespace swift
102109

103110
namespace llvm {

include/swift/AST/Module.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -434,19 +434,6 @@ class ModuleDecl
434434
/// \c nullptr if the source location isn't in this module.
435435
SourceFile *getSourceFileContainingLocation(SourceLoc loc);
436436

437-
// Retrieve the buffer ID and source range of the outermost node that
438-
// caused the generation of the buffer containing \p range. \p range and its
439-
// buffer if it isn't in a generated buffer or has no original range.
440-
std::pair<unsigned, SourceRange> getOriginalRange(SourceRange range) const;
441-
442-
// Retrieve the buffer ID and source location of the outermost location that
443-
// caused the generation of the buffer containing \p loc. \p loc and its
444-
// buffer if it isn't in a generated buffer or has no original location.
445-
std::pair<unsigned, SourceLoc> getOriginalLocation(SourceLoc loc) const {
446-
auto [buffer, range] = getOriginalRange(loc);
447-
return std::make_pair(buffer, range.Start);
448-
}
449-
450437
/// Creates a map from \c #filePath strings to corresponding \c #fileID
451438
/// strings, diagnosing any conflicts.
452439
///

include/swift/Basic/SourceManager.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef SWIFT_BASIC_SOURCEMANAGER_H
1414
#define SWIFT_BASIC_SOURCEMANAGER_H
1515

16+
#include "swift/AST/ClangNode.h"
1617
#include "swift/Basic/FileSystem.h"
1718
#include "swift/Basic/SourceLoc.h"
1819
#include "clang/Basic/FileManager.h"
@@ -22,6 +23,7 @@
2223
#include "llvm/Support/SourceMgr.h"
2324
#include <map>
2425
#include <optional>
26+
#include <utility>
2527
#include <vector>
2628

2729
namespace swift {
@@ -122,6 +124,10 @@ class GeneratedSourceInfo {
122124
/// Contains the ancestors of this source buffer, starting with the root source
123125
/// buffer and ending at this source buffer.
124126
mutable llvm::ArrayRef<unsigned> ancestors = llvm::ArrayRef<unsigned>();
127+
128+
/// Clang node where this buffer comes from. This should be set when this is
129+
/// an 'AttributeFromClang'.
130+
ClangNode clangNode = ClangNode();
125131
};
126132

127133
/// This class manages and owns source buffers.

lib/AST/ASTNode.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,29 @@ FUNC(Expr)
157157
FUNC(Decl)
158158
FUNC(Pattern)
159159
#undef FUNC
160+
161+
SourceRange swift::getUnexpandedMacroRange(const SourceManager &SM,
162+
SourceRange range) {
163+
unsigned bufferID = SM.findBufferContainingLoc(range.Start);
164+
SourceRange outerRange;
165+
while (const auto *info = SM.getGeneratedSourceInfo(bufferID)) {
166+
switch (info->kind) {
167+
#define MACRO_ROLE(Name, Description) \
168+
case GeneratedSourceInfo::Name##MacroExpansion:
169+
#include "swift/Basic/MacroRoles.def"
170+
if (auto *customAttr = info->attachedMacroCustomAttr)
171+
outerRange = customAttr->getRange();
172+
else
173+
outerRange =
174+
ASTNode::getFromOpaqueValue(info->astNode).getSourceRange();
175+
bufferID = SM.findBufferContainingLoc(outerRange.Start);
176+
continue;
177+
case GeneratedSourceInfo::ReplacedFunctionBody:
178+
case GeneratedSourceInfo::PrettyPrinted:
179+
case GeneratedSourceInfo::DefaultArgument:
180+
case GeneratedSourceInfo::AttributeFromClang:
181+
return SourceRange();
182+
}
183+
}
184+
return outerRange;
185+
}

lib/AST/Module.cpp

Lines changed: 6 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
#include "llvm/Support/SaveAndRestore.h"
6969
#include "llvm/Support/YAMLTraits.h"
7070
#include "llvm/Support/raw_ostream.h"
71+
#include <optional>
7172

7273
using namespace swift;
7374

@@ -847,49 +848,6 @@ SourceFile *ModuleDecl::getSourceFileContainingLocation(SourceLoc loc) {
847848
return nullptr;
848849
}
849850

850-
std::pair<unsigned, SourceRange>
851-
ModuleDecl::getOriginalRange(SourceRange range) const {
852-
assert(range.isValid());
853-
854-
SourceManager &SM = getASTContext().SourceMgr;
855-
unsigned bufferID = SM.findBufferContainingLoc(range.Start);
856-
857-
auto startRange = range;
858-
unsigned startBufferID = bufferID;
859-
while (const GeneratedSourceInfo *info =
860-
SM.getGeneratedSourceInfo(bufferID)) {
861-
switch (info->kind) {
862-
#define MACRO_ROLE(Name, Description) \
863-
case GeneratedSourceInfo::Name##MacroExpansion:
864-
#include "swift/Basic/MacroRoles.def"
865-
{
866-
// Location was within a macro expansion, return the expansion site, not
867-
// the insertion location.
868-
if (info->attachedMacroCustomAttr) {
869-
range = info->attachedMacroCustomAttr->getRange();
870-
} else {
871-
ASTNode expansionNode = ASTNode::getFromOpaqueValue(info->astNode);
872-
range = expansionNode.getSourceRange();
873-
}
874-
bufferID = SM.findBufferContainingLoc(range.Start);
875-
break;
876-
}
877-
case GeneratedSourceInfo::DefaultArgument:
878-
// No original location as it's not actually in any source file
879-
case GeneratedSourceInfo::ReplacedFunctionBody:
880-
// There's not really any "original" location for locations within
881-
// replaced function bodies. The body is actually different code to the
882-
// original file.
883-
case GeneratedSourceInfo::PrettyPrinted:
884-
case GeneratedSourceInfo::AttributeFromClang:
885-
// No original location, return the original buffer/location
886-
return {startBufferID, startRange};
887-
}
888-
}
889-
890-
return {bufferID, range};
891-
}
892-
893851
ArrayRef<SourceFile *>
894852
PrimarySourceFilesRequest::evaluate(Evaluator &evaluator,
895853
ModuleDecl *mod) const {
@@ -1431,11 +1389,11 @@ SourceFile::getExternalRawLocsForDecl(const Decl *D) const {
14311389
bool InGeneratedBuffer =
14321390
!SM.rangeContainsTokenLoc(SM.getRangeForBuffer(BufferID), MainLoc);
14331391
if (InGeneratedBuffer) {
1434-
unsigned UnderlyingBufferID;
1435-
std::tie(UnderlyingBufferID, MainLoc) =
1436-
D->getModuleContext()->getOriginalLocation(MainLoc);
1437-
if (BufferID != UnderlyingBufferID)
1438-
return std::nullopt;
1392+
if (auto R = getUnexpandedMacroRange(SM, MainLoc)) {
1393+
if (BufferID != SM.findBufferContainingLoc(R.Start))
1394+
return std::nullopt;
1395+
MainLoc = R.Start;
1396+
}
14391397
}
14401398

14411399
auto setLoc = [&](ExternalSourceLocs::RawLoc &RawLoc, SourceLoc Loc) {

lib/ClangImporter/ImportDecl.cpp

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include "swift/Basic/Defer.h"
4747
#include "swift/Basic/PrettyStackTrace.h"
4848
#include "swift/Basic/SourceLoc.h"
49+
#include "swift/Basic/SourceManager.h"
4950
#include "swift/Basic/Statistic.h"
5051
#include "swift/Basic/StringExtras.h"
5152
#include "swift/Basic/Version.h"
@@ -8648,17 +8649,16 @@ bool importer::hasSameUnderlyingType(const clang::Type *a,
86488649
}
86498650

86508651
SourceFile &ClangImporter::Implementation::getClangSwiftAttrSourceFile(
8651-
ModuleDecl &module,
8652-
StringRef attributeText,
8653-
bool cached
8654-
) {
8652+
Decl *MappedDecl, StringRef attributeText, bool cached) {
8653+
auto *module = MappedDecl->getDeclContext()->getParentModule();
8654+
86558655
::TinyPtrVector<SourceFile *> *sourceFiles = nullptr;
86568656
if (cached) {
86578657
sourceFiles = &ClangSwiftAttrSourceFiles[attributeText];
86588658

86598659
// Check whether we've already created a source file.
86608660
for (auto sourceFile : *sourceFiles) {
8661-
if (sourceFile->getParentModule() == &module)
8661+
if (sourceFile->getParentModule() == module)
86628662
return *sourceFile;
86638663
}
86648664
}
@@ -8668,20 +8668,17 @@ SourceFile &ClangImporter::Implementation::getClangSwiftAttrSourceFile(
86688668
auto &sourceMgr = SwiftContext.SourceMgr;
86698669
auto bufferID = sourceMgr.addMemBufferCopy(attributeText);
86708670

8671-
// Note that this is for an attribute.
8672-
sourceMgr.setGeneratedSourceInfo(
8673-
bufferID,
8674-
{
8675-
GeneratedSourceInfo::AttributeFromClang,
8676-
CharSourceRange(),
8677-
sourceMgr.getRangeForBuffer(bufferID),
8678-
&module
8679-
}
8680-
);
8671+
auto info = GeneratedSourceInfo{GeneratedSourceInfo::AttributeFromClang,
8672+
CharSourceRange(),
8673+
sourceMgr.getRangeForBuffer(bufferID)};
8674+
info.astNode = static_cast<void *>(module);
8675+
info.clangNode = MappedDecl->getClangNode();
8676+
8677+
sourceMgr.setGeneratedSourceInfo(bufferID, info);
86818678

86828679
// Create the source file.
8683-
auto sourceFile = new (SwiftContext)
8684-
SourceFile(module, SourceFileKind::Library, bufferID);
8680+
auto sourceFile =
8681+
new (SwiftContext) SourceFile(*module, SourceFileKind::Library, bufferID);
86858682

86868683
if (cached)
86878684
sourceFiles->push_back(sourceFile);
@@ -8704,8 +8701,8 @@ void ClangImporter::Implementation::importNontrivialAttribute(
87048701
bool cached = true;
87058702
while (true) {
87068703
// Dig out a source file we can use for parsing.
8707-
auto &sourceFile = getClangSwiftAttrSourceFile(
8708-
*MappedDecl->getDeclContext()->getParentModule(), AttrString, cached);
8704+
auto &sourceFile =
8705+
getClangSwiftAttrSourceFile(MappedDecl, AttrString, cached);
87098706

87108707
auto topLevelDecls = sourceFile.getTopLevelDecls();
87118708

lib/ClangImporter/ImporterImpl.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,9 +1057,9 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
10571057
StringRef getSwiftNameFromClangName(StringRef name);
10581058

10591059
/// Retrieve the placeholder source file for use in parsing Swift attributes
1060-
/// in the given module.
1061-
SourceFile &getClangSwiftAttrSourceFile(
1062-
ModuleDecl &module, StringRef attributeText, bool cached);
1060+
/// of the given Decl.
1061+
SourceFile &getClangSwiftAttrSourceFile(Decl *MappedDecl,
1062+
StringRef attributeText, bool cached);
10631063

10641064
/// Create attribute with given text and attach it to decl, creating or
10651065
/// retrieving a chached source file as needed.

lib/Index/Index.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "llvm/ADT/SmallVector.h"
3939
#include "llvm/Support/ErrorHandling.h"
4040
#include "llvm/Support/FileSystem.h"
41+
#include <optional>
4142
#include <tuple>
4243

4344
using namespace swift;
@@ -1093,10 +1094,12 @@ class IndexSwiftASTWalker : public SourceEntityWalker {
10931094
!SrcMgr.rangeContainsTokenLoc(SrcMgr.getRangeForBuffer(bufferID), loc);
10941095

10951096
if (inGeneratedBuffer) {
1096-
std::tie(bufferID, loc) = CurrentModule->getOriginalLocation(loc);
1097-
if (BufferID.value() != bufferID) {
1098-
assert(false && "Location is not within file being indexed");
1099-
return std::nullopt;
1097+
if (auto unexpandedRange = getUnexpandedMacroRange(SrcMgr, loc)) {
1098+
loc = unexpandedRange.Start;
1099+
if (bufferID != SrcMgr.findBufferContainingLoc(loc)) {
1100+
assert(false && "Location should be within file being indexed");
1101+
return std::nullopt;
1102+
}
11001103
}
11011104
}
11021105

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
//--- Main.swift
4+
import FromClang // NOTE: line offset = -4
5+
6+
// REQUIRES: swift_feature_SafeInteropWrappers
7+
// REQUIRES: swift_feature_LifetimeDependence
8+
9+
// The macro-generated interface we're looking up source info for
10+
// (this is more so for documentation than checking correctness)
11+
//
12+
// INTERFACE: @_alwaysEmitIntoClient @_disfavoredOverload public func hasBufferOverload(_ p: UnsafeMutableBufferPointer<Int32>)
13+
// INTERFACE: @{{_?}}lifetime(p: copy p)
14+
// INTERFACE-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func hasSpanOverload(_ p: inout MutableSpan<Int32>)
15+
// RUN: %target-swift-ide-test \
16+
// RUN: -print-module -module-to-print=FromClang -source-filename=x \
17+
// RUN: -plugin-path %swift-plugin-dir -I %t/Inputs \
18+
// RUN: -enable-experimental-feature SafeInteropWrappers \
19+
// RUN: -enable-experimental-feature LifetimeDependence \
20+
// RUN: | %FileCheck %t/Main.swift --check-prefix INTERFACE
21+
22+
@inlinable
23+
public func callWithBufferPtr(_ p: UnsafeMutableBufferPointer<CInt>) {
24+
hasBufferOverload(p)
25+
// RUN: %sourcekitd-test -req=cursor -pos=%(line-4):3 %t/Main.swift -- -I %t/Inputs %t/Main.swift \
26+
// RUN: -enable-experimental-feature SafeInteropWrappers \
27+
// RUN: -enable-experimental-feature LifetimeDependence \
28+
// RUN: | %FileCheck %t/Inputs/from-clang.h --check-prefix BUFFER-OVERLOAD
29+
}
30+
31+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
32+
@lifetime(p: copy p)
33+
@inlinable
34+
public func callReturnLifetimeBound(_ p: inout MutableSpan<CInt>) {
35+
hasSpanOverload(p)
36+
// RUN: %sourcekitd-test -req=cursor -pos=%(line-4):3 %t/Main.swift -- -I %t/Inputs %t/Main.swift \
37+
// RUN: -enable-experimental-feature SafeInteropWrappers \
38+
// RUN: -enable-experimental-feature LifetimeDependence \
39+
// RUN: | %FileCheck %t/Inputs/from-clang.h --check-prefix SPAN-OVERLOAD
40+
}
41+
42+
//--- Inputs/module.modulemap
43+
module FromClang {
44+
header "from-clang.h"
45+
export *
46+
}
47+
48+
//--- Inputs/from-clang.h
49+
#pragma once
50+
51+
#define __counted_by(x) __attribute__((__counted_by__(x)))
52+
#define __noescape __attribute__((noescape))
53+
#define __lifetimebound __attribute__((lifetimebound))
54+
55+
void hasBufferOverload(int len, int * __counted_by(len) p);
56+
// BUFFER-OVERLOAD: source.lang.swift.ref.function.free
57+
// BUFFER-OVERLOAD-SAME: from-clang.h:[[@LINE-2]]
58+
59+
void hasSpanOverload(int len, int * __counted_by(len) __noescape p);
60+
// SPAN-OVERLOAD: source.lang.swift.ref.function.free
61+
// SPAN-OVERLOAD-SAME: from-clang.h:[[@LINE-2]]

0 commit comments

Comments
 (0)