mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[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:
@@ -21,6 +21,7 @@
|
|||||||
#include "llvm/ADT/ArrayRef.h"
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
#include "llvm/ADT/PointerUnion.h"
|
#include "llvm/ADT/PointerUnion.h"
|
||||||
#include "swift/Basic/Debug.h"
|
#include "swift/Basic/Debug.h"
|
||||||
|
#include "swift/Basic/SourceManager.h"
|
||||||
#include "swift/AST/TypeAlignments.h"
|
#include "swift/AST/TypeAlignments.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
@@ -98,6 +99,12 @@ namespace swift {
|
|||||||
return llvm::hash_value(N.getOpaqueValue());
|
return llvm::hash_value(N.getOpaqueValue());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Find the outermost range that \p range was originally generated from.
|
||||||
|
/// Returns an invalid source range if \p range wasn't generated from a macro.
|
||||||
|
SourceRange getUnexpandedMacroRange(const SourceManager &SM,
|
||||||
|
SourceRange range);
|
||||||
|
|
||||||
} // namespace swift
|
} // namespace swift
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|||||||
@@ -434,19 +434,6 @@ public:
|
|||||||
/// \c nullptr if the source location isn't in this module.
|
/// \c nullptr if the source location isn't in this module.
|
||||||
SourceFile *getSourceFileContainingLocation(SourceLoc loc);
|
SourceFile *getSourceFileContainingLocation(SourceLoc loc);
|
||||||
|
|
||||||
// Retrieve the buffer ID and source range of the outermost node that
|
|
||||||
// caused the generation of the buffer containing \p range. \p range and its
|
|
||||||
// buffer if it isn't in a generated buffer or has no original range.
|
|
||||||
std::pair<unsigned, SourceRange> getOriginalRange(SourceRange range) const;
|
|
||||||
|
|
||||||
// Retrieve the buffer ID and source location of the outermost location that
|
|
||||||
// caused the generation of the buffer containing \p loc. \p loc and its
|
|
||||||
// buffer if it isn't in a generated buffer or has no original location.
|
|
||||||
std::pair<unsigned, SourceLoc> getOriginalLocation(SourceLoc loc) const {
|
|
||||||
auto [buffer, range] = getOriginalRange(loc);
|
|
||||||
return std::make_pair(buffer, range.Start);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a map from \c #filePath strings to corresponding \c #fileID
|
/// Creates a map from \c #filePath strings to corresponding \c #fileID
|
||||||
/// strings, diagnosing any conflicts.
|
/// strings, diagnosing any conflicts.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#ifndef SWIFT_BASIC_SOURCEMANAGER_H
|
#ifndef SWIFT_BASIC_SOURCEMANAGER_H
|
||||||
#define SWIFT_BASIC_SOURCEMANAGER_H
|
#define SWIFT_BASIC_SOURCEMANAGER_H
|
||||||
|
|
||||||
|
#include "swift/AST/ClangNode.h"
|
||||||
#include "swift/Basic/FileSystem.h"
|
#include "swift/Basic/FileSystem.h"
|
||||||
#include "swift/Basic/SourceLoc.h"
|
#include "swift/Basic/SourceLoc.h"
|
||||||
#include "clang/Basic/FileManager.h"
|
#include "clang/Basic/FileManager.h"
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
#include "llvm/Support/SourceMgr.h"
|
#include "llvm/Support/SourceMgr.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace swift {
|
namespace swift {
|
||||||
@@ -122,6 +124,10 @@ public:
|
|||||||
/// Contains the ancestors of this source buffer, starting with the root source
|
/// Contains the ancestors of this source buffer, starting with the root source
|
||||||
/// buffer and ending at this source buffer.
|
/// buffer and ending at this source buffer.
|
||||||
mutable llvm::ArrayRef<unsigned> ancestors = llvm::ArrayRef<unsigned>();
|
mutable llvm::ArrayRef<unsigned> ancestors = llvm::ArrayRef<unsigned>();
|
||||||
|
|
||||||
|
/// Clang node where this buffer comes from. This should be set when this is
|
||||||
|
/// an 'AttributeFromClang'.
|
||||||
|
ClangNode clangNode = ClangNode();
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This class manages and owns source buffers.
|
/// This class manages and owns source buffers.
|
||||||
|
|||||||
@@ -157,3 +157,29 @@ FUNC(Expr)
|
|||||||
FUNC(Decl)
|
FUNC(Decl)
|
||||||
FUNC(Pattern)
|
FUNC(Pattern)
|
||||||
#undef FUNC
|
#undef FUNC
|
||||||
|
|
||||||
|
SourceRange swift::getUnexpandedMacroRange(const SourceManager &SM,
|
||||||
|
SourceRange range) {
|
||||||
|
unsigned bufferID = SM.findBufferContainingLoc(range.Start);
|
||||||
|
SourceRange outerRange;
|
||||||
|
while (const auto *info = SM.getGeneratedSourceInfo(bufferID)) {
|
||||||
|
switch (info->kind) {
|
||||||
|
#define MACRO_ROLE(Name, Description) \
|
||||||
|
case GeneratedSourceInfo::Name##MacroExpansion:
|
||||||
|
#include "swift/Basic/MacroRoles.def"
|
||||||
|
if (auto *customAttr = info->attachedMacroCustomAttr)
|
||||||
|
outerRange = customAttr->getRange();
|
||||||
|
else
|
||||||
|
outerRange =
|
||||||
|
ASTNode::getFromOpaqueValue(info->astNode).getSourceRange();
|
||||||
|
bufferID = SM.findBufferContainingLoc(outerRange.Start);
|
||||||
|
continue;
|
||||||
|
case GeneratedSourceInfo::ReplacedFunctionBody:
|
||||||
|
case GeneratedSourceInfo::PrettyPrinted:
|
||||||
|
case GeneratedSourceInfo::DefaultArgument:
|
||||||
|
case GeneratedSourceInfo::AttributeFromClang:
|
||||||
|
return SourceRange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return outerRange;
|
||||||
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@
|
|||||||
#include "llvm/Support/SaveAndRestore.h"
|
#include "llvm/Support/SaveAndRestore.h"
|
||||||
#include "llvm/Support/YAMLTraits.h"
|
#include "llvm/Support/YAMLTraits.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
using namespace swift;
|
using namespace swift;
|
||||||
|
|
||||||
@@ -847,49 +848,6 @@ SourceFile *ModuleDecl::getSourceFileContainingLocation(SourceLoc loc) {
|
|||||||
return nullptr;
|
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 *>
|
ArrayRef<SourceFile *>
|
||||||
PrimarySourceFilesRequest::evaluate(Evaluator &evaluator,
|
PrimarySourceFilesRequest::evaluate(Evaluator &evaluator,
|
||||||
ModuleDecl *mod) const {
|
ModuleDecl *mod) const {
|
||||||
@@ -1431,11 +1389,11 @@ SourceFile::getExternalRawLocsForDecl(const Decl *D) const {
|
|||||||
bool InGeneratedBuffer =
|
bool InGeneratedBuffer =
|
||||||
!SM.rangeContainsTokenLoc(SM.getRangeForBuffer(BufferID), MainLoc);
|
!SM.rangeContainsTokenLoc(SM.getRangeForBuffer(BufferID), MainLoc);
|
||||||
if (InGeneratedBuffer) {
|
if (InGeneratedBuffer) {
|
||||||
unsigned UnderlyingBufferID;
|
if (auto R = getUnexpandedMacroRange(SM, MainLoc)) {
|
||||||
std::tie(UnderlyingBufferID, MainLoc) =
|
if (BufferID != SM.findBufferContainingLoc(R.Start))
|
||||||
D->getModuleContext()->getOriginalLocation(MainLoc);
|
|
||||||
if (BufferID != UnderlyingBufferID)
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
MainLoc = R.Start;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto setLoc = [&](ExternalSourceLocs::RawLoc &RawLoc, SourceLoc Loc) {
|
auto setLoc = [&](ExternalSourceLocs::RawLoc &RawLoc, SourceLoc Loc) {
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
#include "swift/Basic/Defer.h"
|
#include "swift/Basic/Defer.h"
|
||||||
#include "swift/Basic/PrettyStackTrace.h"
|
#include "swift/Basic/PrettyStackTrace.h"
|
||||||
#include "swift/Basic/SourceLoc.h"
|
#include "swift/Basic/SourceLoc.h"
|
||||||
|
#include "swift/Basic/SourceManager.h"
|
||||||
#include "swift/Basic/Statistic.h"
|
#include "swift/Basic/Statistic.h"
|
||||||
#include "swift/Basic/StringExtras.h"
|
#include "swift/Basic/StringExtras.h"
|
||||||
#include "swift/Basic/Version.h"
|
#include "swift/Basic/Version.h"
|
||||||
@@ -8647,17 +8648,16 @@ bool importer::hasSameUnderlyingType(const clang::Type *a,
|
|||||||
}
|
}
|
||||||
|
|
||||||
SourceFile &ClangImporter::Implementation::getClangSwiftAttrSourceFile(
|
SourceFile &ClangImporter::Implementation::getClangSwiftAttrSourceFile(
|
||||||
ModuleDecl &module,
|
Decl *MappedDecl, StringRef attributeText, bool cached) {
|
||||||
StringRef attributeText,
|
auto *module = MappedDecl->getDeclContext()->getParentModule();
|
||||||
bool cached
|
|
||||||
) {
|
|
||||||
::TinyPtrVector<SourceFile *> *sourceFiles = nullptr;
|
::TinyPtrVector<SourceFile *> *sourceFiles = nullptr;
|
||||||
if (cached) {
|
if (cached) {
|
||||||
sourceFiles = &ClangSwiftAttrSourceFiles[attributeText];
|
sourceFiles = &ClangSwiftAttrSourceFiles[attributeText];
|
||||||
|
|
||||||
// Check whether we've already created a source file.
|
// Check whether we've already created a source file.
|
||||||
for (auto sourceFile : *sourceFiles) {
|
for (auto sourceFile : *sourceFiles) {
|
||||||
if (sourceFile->getParentModule() == &module)
|
if (sourceFile->getParentModule() == module)
|
||||||
return *sourceFile;
|
return *sourceFile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8667,20 +8667,17 @@ SourceFile &ClangImporter::Implementation::getClangSwiftAttrSourceFile(
|
|||||||
auto &sourceMgr = SwiftContext.SourceMgr;
|
auto &sourceMgr = SwiftContext.SourceMgr;
|
||||||
auto bufferID = sourceMgr.addMemBufferCopy(attributeText);
|
auto bufferID = sourceMgr.addMemBufferCopy(attributeText);
|
||||||
|
|
||||||
// Note that this is for an attribute.
|
auto info = GeneratedSourceInfo{GeneratedSourceInfo::AttributeFromClang,
|
||||||
sourceMgr.setGeneratedSourceInfo(
|
|
||||||
bufferID,
|
|
||||||
{
|
|
||||||
GeneratedSourceInfo::AttributeFromClang,
|
|
||||||
CharSourceRange(),
|
CharSourceRange(),
|
||||||
sourceMgr.getRangeForBuffer(bufferID),
|
sourceMgr.getRangeForBuffer(bufferID)};
|
||||||
&module
|
info.astNode = static_cast<void *>(module);
|
||||||
}
|
info.clangNode = MappedDecl->getClangNode();
|
||||||
);
|
|
||||||
|
sourceMgr.setGeneratedSourceInfo(bufferID, info);
|
||||||
|
|
||||||
// Create the source file.
|
// Create the source file.
|
||||||
auto sourceFile = new (SwiftContext)
|
auto sourceFile =
|
||||||
SourceFile(module, SourceFileKind::Library, bufferID);
|
new (SwiftContext) SourceFile(*module, SourceFileKind::Library, bufferID);
|
||||||
|
|
||||||
if (cached)
|
if (cached)
|
||||||
sourceFiles->push_back(sourceFile);
|
sourceFiles->push_back(sourceFile);
|
||||||
@@ -8703,8 +8700,8 @@ void ClangImporter::Implementation::importNontrivialAttribute(
|
|||||||
bool cached = true;
|
bool cached = true;
|
||||||
while (true) {
|
while (true) {
|
||||||
// Dig out a source file we can use for parsing.
|
// Dig out a source file we can use for parsing.
|
||||||
auto &sourceFile = getClangSwiftAttrSourceFile(
|
auto &sourceFile =
|
||||||
*MappedDecl->getDeclContext()->getParentModule(), AttrString, cached);
|
getClangSwiftAttrSourceFile(MappedDecl, AttrString, cached);
|
||||||
|
|
||||||
auto topLevelDecls = sourceFile.getTopLevelDecls();
|
auto topLevelDecls = sourceFile.getTopLevelDecls();
|
||||||
|
|
||||||
|
|||||||
@@ -1057,9 +1057,9 @@ public:
|
|||||||
StringRef getSwiftNameFromClangName(StringRef name);
|
StringRef getSwiftNameFromClangName(StringRef name);
|
||||||
|
|
||||||
/// Retrieve the placeholder source file for use in parsing Swift attributes
|
/// Retrieve the placeholder source file for use in parsing Swift attributes
|
||||||
/// in the given module.
|
/// of the given Decl.
|
||||||
SourceFile &getClangSwiftAttrSourceFile(
|
SourceFile &getClangSwiftAttrSourceFile(Decl *MappedDecl,
|
||||||
ModuleDecl &module, StringRef attributeText, bool cached);
|
StringRef attributeText, bool cached);
|
||||||
|
|
||||||
/// Create attribute with given text and attach it to decl, creating or
|
/// Create attribute with given text and attach it to decl, creating or
|
||||||
/// retrieving a chached source file as needed.
|
/// retrieving a chached source file as needed.
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/Support/ErrorHandling.h"
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
#include "llvm/Support/FileSystem.h"
|
#include "llvm/Support/FileSystem.h"
|
||||||
|
#include <optional>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
using namespace swift;
|
using namespace swift;
|
||||||
@@ -1093,12 +1094,14 @@ private:
|
|||||||
!SrcMgr.rangeContainsTokenLoc(SrcMgr.getRangeForBuffer(bufferID), loc);
|
!SrcMgr.rangeContainsTokenLoc(SrcMgr.getRangeForBuffer(bufferID), loc);
|
||||||
|
|
||||||
if (inGeneratedBuffer) {
|
if (inGeneratedBuffer) {
|
||||||
std::tie(bufferID, loc) = CurrentModule->getOriginalLocation(loc);
|
if (auto unexpandedRange = getUnexpandedMacroRange(SrcMgr, loc)) {
|
||||||
if (BufferID.value() != bufferID) {
|
loc = unexpandedRange.Start;
|
||||||
assert(false && "Location is not within file being indexed");
|
if (bufferID != SrcMgr.findBufferContainingLoc(loc)) {
|
||||||
|
assert(false && "Location should be within file being indexed");
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto [line, col] = SrcMgr.getLineAndColumnInBuffer(loc, bufferID);
|
auto [line, col] = SrcMgr.getLineAndColumnInBuffer(loc, bufferID);
|
||||||
return {{line, col, inGeneratedBuffer}};
|
return {{line, col, inGeneratedBuffer}};
|
||||||
|
|||||||
61
test/SourceKit/Macros/clang-overload-cursor-info.swift
Normal file
61
test/SourceKit/Macros/clang-overload-cursor-info.swift
Normal 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]]
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "swift/AST/ModuleNameLookup.h"
|
#include "swift/AST/ModuleNameLookup.h"
|
||||||
#include "swift/AST/NameLookup.h"
|
#include "swift/AST/NameLookup.h"
|
||||||
#include "swift/AST/SwiftNameTranslation.h"
|
#include "swift/AST/SwiftNameTranslation.h"
|
||||||
|
#include "swift/Basic/Assertions.h"
|
||||||
#include "swift/Basic/SourceManager.h"
|
#include "swift/Basic/SourceManager.h"
|
||||||
#include "swift/Frontend/Frontend.h"
|
#include "swift/Frontend/Frontend.h"
|
||||||
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
|
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
|
||||||
@@ -48,6 +49,7 @@
|
|||||||
#include "clang/Index/USRGeneration.h"
|
#include "clang/Index/USRGeneration.h"
|
||||||
#include "clang/Lex/Lexer.h"
|
#include "clang/Lex/Lexer.h"
|
||||||
|
|
||||||
|
#include "llvm/Support/Compiler.h"
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
|
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
@@ -877,56 +879,110 @@ static void setLocationInfoForClangNode(ClangNode ClangNode,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void setLocationInfoForRange(SourceManager &SM, SourceRange R,
|
||||||
|
unsigned BufID,
|
||||||
|
LocationInfo &Location,
|
||||||
|
bool Presumed = false) {
|
||||||
|
CONDITIONAL_ASSERT(BufID == SM.findBufferContainingLoc(R.Start) &&
|
||||||
|
"SourceRange R should be in BufID");
|
||||||
|
|
||||||
|
auto CR = Lexer::getCharSourceRangeFromSourceRange(SM, R);
|
||||||
|
|
||||||
|
Location.Filename = SM.getIdentifierForBuffer(BufID);
|
||||||
|
Location.Length = CR.getByteLength();
|
||||||
|
Location.Offset = SM.getLocOffsetInBuffer(CR.getStart(), BufID);
|
||||||
|
|
||||||
|
if (Presumed)
|
||||||
|
std::tie(Location.Line, Location.Column) =
|
||||||
|
SM.getPresumedLineAndColumnForLoc(CR.getStart(), BufID);
|
||||||
|
else
|
||||||
|
std::tie(Location.Line, Location.Column) =
|
||||||
|
SM.getLineAndColumnInBuffer(CR.getStart(), BufID);
|
||||||
|
}
|
||||||
|
|
||||||
static void setLocationInfo(const ValueDecl *VD,
|
static void setLocationInfo(const ValueDecl *VD,
|
||||||
LocationInfo &Location) {
|
LocationInfo &Location) {
|
||||||
ASTContext &Ctx = VD->getASTContext();
|
ASTContext &Ctx = VD->getASTContext();
|
||||||
SourceManager &SM = Ctx.SourceMgr;
|
SourceManager &SM = Ctx.SourceMgr;
|
||||||
|
auto *Importer = static_cast<ClangImporter *>(Ctx.getClangModuleLoader());
|
||||||
|
|
||||||
auto ClangNode = VD->getClangNode();
|
if (auto loc = VD->getLoc(/*SerializedOK=*/true)) {
|
||||||
|
// For most cases we just want the range of the name itself; it suffices to
|
||||||
|
// make Range from just Loc because Lexer::getCharSourceRangeFromSourceRange
|
||||||
|
// will grow the range to encompass the end of the token at Loc.
|
||||||
|
SourceRange range = loc;
|
||||||
|
|
||||||
auto Loc = VD->getLoc(/*SerializedOK=*/true);
|
// One exception is for functions, where we also want to include the range
|
||||||
if (Loc.isValid()) {
|
// of the parameter list.
|
||||||
// For most cases we just want the range of the name itself. One exception
|
|
||||||
// is for functions, where we also want to include the parameter list.
|
|
||||||
SourceRange Range = Loc;
|
|
||||||
if (auto *FD = dyn_cast<AbstractFunctionDecl>(VD)) {
|
if (auto *FD = dyn_cast<AbstractFunctionDecl>(VD)) {
|
||||||
if (auto R = FD->getParameterListSourceRange())
|
if (auto FDR = FD->getParameterListSourceRange())
|
||||||
Range = R;
|
range = FDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto [DeclBufID, DeclRange] =
|
unsigned bufID = SM.findBufferContainingLoc(range.Start);
|
||||||
VD->getModuleContext()->getOriginalRange(Range);
|
|
||||||
|
|
||||||
auto DeclCharRange =
|
// If this range is from a generated buffer, recursively "unexpand" macros
|
||||||
Lexer::getCharSourceRangeFromSourceRange(SM, DeclRange);
|
// to chase after where the macro was originally expanded from.
|
||||||
auto DeclLoc = DeclCharRange.getStart();
|
//
|
||||||
|
// However, we don't care about certain kinds of generated buffers, so save
|
||||||
|
// the original range and buffer ID so we can set location according to VD.
|
||||||
|
auto VDRange = range;
|
||||||
|
auto VDBufID = bufID;
|
||||||
|
while (auto *info = SM.getGeneratedSourceInfo(bufID)) {
|
||||||
|
switch (info->kind) {
|
||||||
|
#define MACRO_ROLE(Name, Description) \
|
||||||
|
case GeneratedSourceInfo::Name##MacroExpansion:
|
||||||
|
#include "swift/Basic/MacroRoles.def"
|
||||||
|
if (auto *customAttr = info->attachedMacroCustomAttr)
|
||||||
|
range = customAttr->getRange();
|
||||||
|
else
|
||||||
|
range = ASTNode::getFromOpaqueValue(info->astNode).getSourceRange();
|
||||||
|
bufID = SM.findBufferContainingLoc(range.Start);
|
||||||
|
continue; // Continue while-loop to recursively un-expand macros
|
||||||
|
|
||||||
Location.Filename = SM.getIdentifierForBuffer(DeclBufID);
|
case GeneratedSourceInfo::ReplacedFunctionBody:
|
||||||
Location.Offset = SM.getLocOffsetInBuffer(DeclLoc, DeclBufID);
|
if (bufID == VDBufID) {
|
||||||
Location.Length = DeclCharRange.getByteLength();
|
// The location was in a temporary source buffer that just contains
|
||||||
std::tie(Location.Line, Location.Column) =
|
// the function body, which we created while reusing the ASTContext
|
||||||
SM.getLineAndColumnInBuffer(DeclLoc, DeclBufID);
|
// for the rest of the file. Set the location so that it maps back to
|
||||||
if (auto GeneratedSourceInfo = SM.getGeneratedSourceInfo(DeclBufID)) {
|
// the original file.
|
||||||
if (GeneratedSourceInfo->kind ==
|
setLocationInfoForRange(SM, VDRange, VDBufID, Location,
|
||||||
GeneratedSourceInfo::ReplacedFunctionBody) {
|
/*Presumed=*/true);
|
||||||
// The location was in a temporary source buffer that just contains the
|
// Adjust offset according to generated buffer.
|
||||||
// function body and which we created while reusing the ASTContext for
|
auto originalLoc = info->originalSourceRange.getStart();
|
||||||
// the rest of the file. Map the location back to the original file.
|
auto originalBufID = SM.findBufferContainingLoc(originalLoc);
|
||||||
unsigned OriginalBufID = SM.findBufferContainingLoc(
|
auto generatedLoc = info->generatedSourceRange.getStart();
|
||||||
GeneratedSourceInfo->originalSourceRange.getStart());
|
auto generatedBufID = SM.findBufferContainingLoc(generatedLoc);
|
||||||
auto OriginalStartOffset = SM.getLocOffsetInBuffer(
|
Location.Offset +=
|
||||||
GeneratedSourceInfo->originalSourceRange.getStart(), OriginalBufID);
|
SM.getLocOffsetInBuffer(originalLoc, originalBufID) -
|
||||||
auto GeneratedStartOffset = SM.getLocOffsetInBuffer(
|
SM.getLocOffsetInBuffer(generatedLoc, generatedBufID);
|
||||||
GeneratedSourceInfo->generatedSourceRange.getStart(), DeclBufID);
|
} else {
|
||||||
Location.Offset += OriginalStartOffset - GeneratedStartOffset;
|
// We somehow encountered a replaced function body while looking
|
||||||
std::tie(Location.Line, Location.Column) =
|
// through other macro expansions. Fall back to setting location based
|
||||||
SM.getPresumedLineAndColumnForLoc(DeclLoc, DeclBufID);
|
// on VD's original source range because mapping location back to the
|
||||||
|
// original file might be tricky.
|
||||||
|
setLocationInfoForRange(SM, VDRange, VDBufID, Location);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
case GeneratedSourceInfo::AttributeFromClang:
|
||||||
|
// This buffer was generated for an imported ClangNode, so set location
|
||||||
|
// info according to that.
|
||||||
|
if (auto node = info->clangNode)
|
||||||
|
setLocationInfoForClangNode(node, Importer, Location);
|
||||||
|
else
|
||||||
|
setLocationInfoForRange(SM, VDRange, VDBufID, Location);
|
||||||
|
return;
|
||||||
|
case GeneratedSourceInfo::DefaultArgument:
|
||||||
|
case GeneratedSourceInfo::PrettyPrinted:
|
||||||
|
setLocationInfoForRange(SM, VDRange, VDBufID, Location);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else if (ClangNode) {
|
llvm_unreachable("All switch cases either explicitly continue or return");
|
||||||
ClangImporter *Importer =
|
}
|
||||||
static_cast<ClangImporter*>(Ctx.getClangModuleLoader());
|
|
||||||
setLocationInfoForClangNode(ClangNode, Importer, Location);
|
setLocationInfoForRange(SM, range, bufID, Location);
|
||||||
|
} else if (auto CNode = VD->getClangNode()) {
|
||||||
|
setLocationInfoForClangNode(CNode, Importer, Location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user