[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

@@ -68,6 +68,7 @@
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>
using namespace swift;
@@ -847,49 +848,6 @@ SourceFile *ModuleDecl::getSourceFileContainingLocation(SourceLoc loc) {
return nullptr;
}
std::pair<unsigned, SourceRange>
ModuleDecl::getOriginalRange(SourceRange range) const {
assert(range.isValid());
SourceManager &SM = getASTContext().SourceMgr;
unsigned bufferID = SM.findBufferContainingLoc(range.Start);
auto startRange = range;
unsigned startBufferID = bufferID;
while (const GeneratedSourceInfo *info =
SM.getGeneratedSourceInfo(bufferID)) {
switch (info->kind) {
#define MACRO_ROLE(Name, Description) \
case GeneratedSourceInfo::Name##MacroExpansion:
#include "swift/Basic/MacroRoles.def"
{
// Location was within a macro expansion, return the expansion site, not
// the insertion location.
if (info->attachedMacroCustomAttr) {
range = info->attachedMacroCustomAttr->getRange();
} else {
ASTNode expansionNode = ASTNode::getFromOpaqueValue(info->astNode);
range = expansionNode.getSourceRange();
}
bufferID = SM.findBufferContainingLoc(range.Start);
break;
}
case GeneratedSourceInfo::DefaultArgument:
// No original location as it's not actually in any source file
case GeneratedSourceInfo::ReplacedFunctionBody:
// There's not really any "original" location for locations within
// replaced function bodies. The body is actually different code to the
// original file.
case GeneratedSourceInfo::PrettyPrinted:
case GeneratedSourceInfo::AttributeFromClang:
// No original location, return the original buffer/location
return {startBufferID, startRange};
}
}
return {bufferID, range};
}
ArrayRef<SourceFile *>
PrimarySourceFilesRequest::evaluate(Evaluator &evaluator,
ModuleDecl *mod) const {
@@ -1431,11 +1389,11 @@ SourceFile::getExternalRawLocsForDecl(const Decl *D) const {
bool InGeneratedBuffer =
!SM.rangeContainsTokenLoc(SM.getRangeForBuffer(BufferID), MainLoc);
if (InGeneratedBuffer) {
unsigned UnderlyingBufferID;
std::tie(UnderlyingBufferID, MainLoc) =
D->getModuleContext()->getOriginalLocation(MainLoc);
if (BufferID != UnderlyingBufferID)
return std::nullopt;
if (auto R = getUnexpandedMacroRange(SM, MainLoc)) {
if (BufferID != SM.findBufferContainingLoc(R.Start))
return std::nullopt;
MainLoc = R.Start;
}
}
auto setLoc = [&](ExternalSourceLocs::RawLoc &RawLoc, SourceLoc Loc) {