Skip to content

Commit a0d3ad7

Browse files
authored
Merge pull request #82006 from j-hui/jump-to-def-for-macro-expanded-clang-imports
[SourceKit] Support location info for macro-expanded Clang imports
2 parents 5276f2e + 6b36996 commit a0d3ad7

File tree

10 files changed

+233
-131
lines changed

10 files changed

+233
-131
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"
@@ -8669,17 +8670,16 @@ bool importer::hasSameUnderlyingType(const clang::Type *a,
86698670
}
86708671

86718672
SourceFile &ClangImporter::Implementation::getClangSwiftAttrSourceFile(
8672-
ModuleDecl &module,
8673-
StringRef attributeText,
8674-
bool cached
8675-
) {
8673+
Decl *MappedDecl, StringRef attributeText, bool cached) {
8674+
auto *module = MappedDecl->getDeclContext()->getParentModule();
8675+
86768676
::TinyPtrVector<SourceFile *> *sourceFiles = nullptr;
86778677
if (cached) {
86788678
sourceFiles = &ClangSwiftAttrSourceFiles[attributeText];
86798679

86808680
// Check whether we've already created a source file.
86818681
for (auto sourceFile : *sourceFiles) {
8682-
if (sourceFile->getParentModule() == &module)
8682+
if (sourceFile->getParentModule() == module)
86838683
return *sourceFile;
86848684
}
86858685
}
@@ -8689,20 +8689,17 @@ SourceFile &ClangImporter::Implementation::getClangSwiftAttrSourceFile(
86898689
auto &sourceMgr = SwiftContext.SourceMgr;
86908690
auto bufferID = sourceMgr.addMemBufferCopy(attributeText);
86918691

8692-
// Note that this is for an attribute.
8693-
sourceMgr.setGeneratedSourceInfo(
8694-
bufferID,
8695-
{
8696-
GeneratedSourceInfo::AttributeFromClang,
8697-
CharSourceRange(),
8698-
sourceMgr.getRangeForBuffer(bufferID),
8699-
&module
8700-
}
8701-
);
8692+
auto info = GeneratedSourceInfo{GeneratedSourceInfo::AttributeFromClang,
8693+
CharSourceRange(),
8694+
sourceMgr.getRangeForBuffer(bufferID)};
8695+
info.astNode = static_cast<void *>(module);
8696+
info.clangNode = MappedDecl->getClangNode();
8697+
8698+
sourceMgr.setGeneratedSourceInfo(bufferID, info);
87028699

87038700
// Create the source file.
8704-
auto sourceFile = new (SwiftContext)
8705-
SourceFile(module, SourceFileKind::Library, bufferID);
8701+
auto sourceFile =
8702+
new (SwiftContext) SourceFile(*module, SourceFileKind::Library, bufferID);
87068703

87078704
if (cached)
87088705
sourceFiles->push_back(sourceFile);
@@ -8725,8 +8722,8 @@ void ClangImporter::Implementation::importNontrivialAttribute(
87258722
bool cached = true;
87268723
while (true) {
87278724
// Dig out a source file we can use for parsing.
8728-
auto &sourceFile = getClangSwiftAttrSourceFile(
8729-
*MappedDecl->getDeclContext()->getParentModule(), AttrString, cached);
8725+
auto &sourceFile =
8726+
getClangSwiftAttrSourceFile(MappedDecl, AttrString, cached);
87308727

87318728
auto topLevelDecls = sourceFile.getTopLevelDecls();
87328729

lib/ClangImporter/ImporterImpl.h

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

10671067
/// Retrieve the placeholder source file for use in parsing Swift attributes
1068-
/// in the given module.
1069-
SourceFile &getClangSwiftAttrSourceFile(
1070-
ModuleDecl &module, StringRef attributeText, bool cached);
1068+
/// of the given Decl.
1069+
SourceFile &getClangSwiftAttrSourceFile(Decl *MappedDecl,
1070+
StringRef attributeText, bool cached);
10711071

10721072
/// Create attribute with given text and attach it to decl, creating or
10731073
/// 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
@@ -39,6 +39,7 @@
3939
#include "llvm/ADT/SmallVector.h"
4040
#include "llvm/Support/ErrorHandling.h"
4141
#include "llvm/Support/FileSystem.h"
42+
#include <optional>
4243
#include <tuple>
4344

4445
using namespace swift;
@@ -1097,10 +1098,12 @@ class IndexSwiftASTWalker : public SourceEntityWalker {
10971098
!SrcMgr.rangeContainsTokenLoc(SrcMgr.getRangeForBuffer(bufferID), loc);
10981099

10991100
if (inGeneratedBuffer) {
1100-
std::tie(bufferID, loc) = CurrentModule->getOriginalLocation(loc);
1101-
if (BufferID.value() != bufferID) {
1102-
assert(false && "Location is not within file being indexed");
1103-
return std::nullopt;
1101+
if (auto unexpandedRange = getUnexpandedMacroRange(SrcMgr, loc)) {
1102+
loc = unexpandedRange.Start;
1103+
if (bufferID != SrcMgr.findBufferContainingLoc(loc)) {
1104+
assert(false && "Location should be within file being indexed");
1105+
return std::nullopt;
1106+
}
11041107
}
11051108
}
11061109

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)