Skip to content

Commit 0987033

Browse files
committed
[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 33b80ba)
1 parent 7fb85a3 commit 0987033

File tree

10 files changed

+231
-128
lines changed

10 files changed

+231
-128
lines changed

include/swift/AST/ASTNode.h

Lines changed: 8 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,13 @@ namespace swift {
9899
return llvm::hash_value(N.getOpaqueValue());
99100
}
100101
};
102+
103+
104+
/// Find the outermost range that \p range was originally generated from.
105+
/// Returns an invalid source range if \p range wasn't generated from a macro.
106+
SourceRange getUnexpandedMacroRange(const SourceManager &SM,
107+
SourceRange range);
108+
101109
} // namespace swift
102110

103111
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"
@@ -8647,17 +8648,16 @@ bool importer::hasSameUnderlyingType(const clang::Type *a,
86478648
}
86488649

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

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

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

86818678
// Create the source file.
8682-
auto sourceFile = new (SwiftContext)
8683-
SourceFile(module, SourceFileKind::Library, bufferID);
8679+
auto sourceFile =
8680+
new (SwiftContext) SourceFile(*module, SourceFileKind::Library, bufferID);
86848681

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

87098706
auto topLevelDecls = sourceFile.getTopLevelDecls();
87108707

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)