mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Turn pretty-printing of a declaration into a request
The diagnostics engine has some code to pretty-print a declaration when there is no source location for that declaration. The declaration is pretty-printed into a source buffer, and a source location into that buffer is synthesizes. This applies to synthesized declarations as well as those imported from Swift modules (without source code) or from Clang. Reimplement this pretty-printing for declarations as a request. In doing so, change the manner in which we do the printing: the diagnostics engine printed the entire enclosing type into a buffer whose name was the module + that type. This meant that the buffer was shared by every member of that type, but also meant that we would end up deserializing a lot of declarations just for printing and potentially doing a lot more work for these diagnostics.
This commit is contained in:
@@ -1052,10 +1052,6 @@ namespace swift {
|
||||
/// been emitted due to an open transaction.
|
||||
SmallVector<Diagnostic, 4> TentativeDiagnostics;
|
||||
|
||||
/// The set of declarations for which we have pretty-printed
|
||||
/// results that we can point to on the command line.
|
||||
llvm::DenseMap<const Decl *, SourceLoc> PrettyPrintedDeclarations;
|
||||
|
||||
llvm::BumpPtrAllocator TransactionAllocator;
|
||||
/// A set of all strings involved in current transactional chain.
|
||||
/// This is required because diagnostics are not directly emitted
|
||||
@@ -1108,6 +1104,7 @@ namespace swift {
|
||||
friend class CompoundDiagnosticTransaction;
|
||||
friend class DiagnosticStateRAII;
|
||||
friend class DiagnosticQueue;
|
||||
friend class PrettyPrintDeclRequest;
|
||||
|
||||
public:
|
||||
explicit DiagnosticEngine(SourceManager &SourceMgr)
|
||||
|
||||
@@ -754,6 +754,27 @@ public:
|
||||
|
||||
void simple_display(llvm::raw_ostream &out, const KnownProtocolKind);
|
||||
|
||||
/// Pretty-print the given declaration into a buffer and return a source
|
||||
/// location that refers to the declaration in that buffer.
|
||||
class PrettyPrintDeclRequest
|
||||
: public SimpleRequest<PrettyPrintDeclRequest,
|
||||
SourceLoc(const Decl *),
|
||||
RequestFlags::Cached>
|
||||
{
|
||||
public:
|
||||
using SimpleRequest::SimpleRequest;
|
||||
|
||||
private:
|
||||
friend SimpleRequest;
|
||||
|
||||
// Evaluation.
|
||||
SourceLoc evaluate(Evaluator &eval, const Decl *d) const;
|
||||
|
||||
public:
|
||||
// Caching
|
||||
bool isCached() const { return true; }
|
||||
};
|
||||
|
||||
// Find the type in the cache or look it up
|
||||
class DefaultTypeRequest
|
||||
: public SimpleRequest<DefaultTypeRequest,
|
||||
|
||||
@@ -76,6 +76,8 @@ SWIFT_REQUEST(TypeChecker, DefaultDefinitionTypeRequest,
|
||||
SWIFT_REQUEST(TypeChecker, DefaultTypeRequest,
|
||||
Type(KnownProtocolKind, const DeclContext *), SeparatelyCached,
|
||||
NoLocationInfo)
|
||||
SWIFT_REQUEST(TypeChecker, PrettyPrintDeclRequest,
|
||||
SourceLoc(const Decl *), Cached, NoLocationInfo)
|
||||
SWIFT_REQUEST(TypeChecker, DifferentiableAttributeTypeCheckRequest,
|
||||
IndexSubset *(DifferentiableAttr *),
|
||||
SeparatelyCached, NoLocationInfo)
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "swift/AST/PrintOptions.h"
|
||||
#include "swift/AST/SourceFile.h"
|
||||
#include "swift/AST/Stmt.h"
|
||||
#include "swift/AST/TypeCheckRequests.h"
|
||||
#include "swift/AST/TypeRepr.h"
|
||||
#include "swift/Basic/Assertions.h"
|
||||
#include "swift/Basic/SourceManager.h"
|
||||
@@ -1306,20 +1307,6 @@ void DiagnosticEngine::forwardTentativeDiagnosticsTo(
|
||||
clearTentativeDiagnostics();
|
||||
}
|
||||
|
||||
/// Returns the access level of the least accessible PrettyPrintedDeclarations
|
||||
/// buffer that \p decl should appear in.
|
||||
///
|
||||
/// This is always \c Public unless \p decl is a \c ValueDecl and its
|
||||
/// access level is below \c Public. (That can happen with @testable and
|
||||
/// @_private imports.)
|
||||
static AccessLevel getBufferAccessLevel(const Decl *decl) {
|
||||
AccessLevel level = AccessLevel::Public;
|
||||
if (auto *VD = dyn_cast<ValueDecl>(decl))
|
||||
level = VD->getFormalAccessScope().accessLevelForDiagnostics();
|
||||
if (level > AccessLevel::Public) level = AccessLevel::Public;
|
||||
return level;
|
||||
}
|
||||
|
||||
std::optional<DiagnosticInfo>
|
||||
DiagnosticEngine::diagnosticInfoForDiagnostic(const Diagnostic &diagnostic) {
|
||||
auto behavior = state.determineBehavior(diagnostic);
|
||||
@@ -1334,154 +1321,12 @@ DiagnosticEngine::diagnosticInfoForDiagnostic(const Diagnostic &diagnostic) {
|
||||
// has a location we can point to, use that location.
|
||||
loc = decl->getLoc();
|
||||
|
||||
// If the location of the decl is invalid still, try to pretty-print the
|
||||
// declaration into a buffer and capture the source location there.
|
||||
if (loc.isInvalid()) {
|
||||
// There is no location we can point to. Pretty-print the declaration
|
||||
// so we can point to it.
|
||||
SourceLoc ppLoc = PrettyPrintedDeclarations[decl];
|
||||
if (ppLoc.isInvalid()) {
|
||||
class TrackingPrinter : public StreamPrinter {
|
||||
SmallVectorImpl<std::pair<const Decl *, uint64_t>> &Entries;
|
||||
AccessLevel bufferAccessLevel;
|
||||
|
||||
public:
|
||||
TrackingPrinter(
|
||||
SmallVectorImpl<std::pair<const Decl *, uint64_t>> &Entries,
|
||||
raw_ostream &OS, AccessLevel bufferAccessLevel) :
|
||||
StreamPrinter(OS), Entries(Entries),
|
||||
bufferAccessLevel(bufferAccessLevel) {}
|
||||
|
||||
void printDeclLoc(const Decl *D) override {
|
||||
if (getBufferAccessLevel(D) == bufferAccessLevel)
|
||||
Entries.push_back({ D, OS.tell() });
|
||||
}
|
||||
};
|
||||
SmallVector<std::pair<const Decl *, uint64_t>, 8> entries;
|
||||
llvm::SmallString<128> buffer;
|
||||
llvm::SmallString<128> bufferName;
|
||||
const Decl *ppDecl = decl;
|
||||
{
|
||||
// The access level of the buffer we want to print. Declarations below
|
||||
// this access level will be omitted from the buffer; declarations
|
||||
// above it will be printed, but (except for Open declarations in the
|
||||
// Public buffer) will not be recorded in PrettyPrintedDeclarations as
|
||||
// the "true" SourceLoc for the declaration.
|
||||
AccessLevel bufferAccessLevel = getBufferAccessLevel(decl);
|
||||
|
||||
// Figure out which declaration to print. It's the top-most
|
||||
// declaration (not a module).
|
||||
auto dc = decl->getDeclContext();
|
||||
|
||||
// FIXME: Horrible, horrible hackaround. We're not getting a
|
||||
// DeclContext everywhere we should.
|
||||
if (!dc) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
while (!dc->isModuleContext()) {
|
||||
switch (dc->getContextKind()) {
|
||||
case DeclContextKind::Package:
|
||||
llvm_unreachable("Not in a package context!");
|
||||
break;
|
||||
case DeclContextKind::Module:
|
||||
llvm_unreachable("Not in a module context!");
|
||||
break;
|
||||
|
||||
case DeclContextKind::FileUnit:
|
||||
case DeclContextKind::TopLevelCodeDecl:
|
||||
case DeclContextKind::SerializedTopLevelCodeDecl:
|
||||
break;
|
||||
|
||||
case DeclContextKind::ExtensionDecl:
|
||||
ppDecl = cast<ExtensionDecl>(dc);
|
||||
break;
|
||||
|
||||
case DeclContextKind::GenericTypeDecl:
|
||||
ppDecl = cast<GenericTypeDecl>(dc);
|
||||
break;
|
||||
|
||||
case DeclContextKind::Initializer:
|
||||
case DeclContextKind::AbstractClosureExpr:
|
||||
case DeclContextKind::SerializedAbstractClosure:
|
||||
case DeclContextKind::AbstractFunctionDecl:
|
||||
case DeclContextKind::SubscriptDecl:
|
||||
case DeclContextKind::EnumElementDecl:
|
||||
case DeclContextKind::MacroDecl:
|
||||
break;
|
||||
}
|
||||
|
||||
dc = dc->getParent();
|
||||
}
|
||||
|
||||
// Build the module name path (in reverse), which we use to
|
||||
// build the name of the buffer.
|
||||
SmallVector<StringRef, 4> nameComponents;
|
||||
while (dc) {
|
||||
auto publicName = cast<ModuleDecl>(dc)->
|
||||
getPublicModuleName(/*onlyIfImported*/true);
|
||||
nameComponents.push_back(publicName.str());
|
||||
dc = dc->getParent();
|
||||
}
|
||||
|
||||
for (unsigned i = nameComponents.size(); i; --i) {
|
||||
bufferName += nameComponents[i-1];
|
||||
bufferName += '.';
|
||||
}
|
||||
|
||||
if (auto value = dyn_cast<ValueDecl>(ppDecl)) {
|
||||
bufferName += value->getBaseName().userFacingName();
|
||||
} else if (auto ext = dyn_cast<ExtensionDecl>(ppDecl)) {
|
||||
bufferName += ext->getExtendedType().getString();
|
||||
}
|
||||
|
||||
// If we're using a lowered access level, give the buffer a distinct
|
||||
// name.
|
||||
if (bufferAccessLevel != AccessLevel::Public) {
|
||||
assert(bufferAccessLevel < AccessLevel::Public
|
||||
&& "Above-public access levels should use public buffer");
|
||||
bufferName += " (";
|
||||
bufferName += getAccessLevelSpelling(bufferAccessLevel);
|
||||
bufferName += ")";
|
||||
}
|
||||
|
||||
// Pretty-print the declaration we've picked.
|
||||
llvm::raw_svector_ostream out(buffer);
|
||||
TrackingPrinter printer(entries, out, bufferAccessLevel);
|
||||
llvm::SaveAndRestore<bool> isPrettyPrinting(
|
||||
IsPrettyPrintingDecl, true);
|
||||
ppDecl->print(
|
||||
printer,
|
||||
PrintOptions::printForDiagnostics(
|
||||
bufferAccessLevel,
|
||||
decl->getASTContext().TypeCheckerOpts.PrintFullConvention));
|
||||
}
|
||||
|
||||
// Build a buffer with the pretty-printed declaration.
|
||||
auto bufferID = SourceMgr.addMemBufferCopy(buffer, bufferName);
|
||||
auto memBufferStartLoc = SourceMgr.getLocForBufferStart(bufferID);
|
||||
|
||||
SourceMgr.setGeneratedSourceInfo(
|
||||
bufferID,
|
||||
GeneratedSourceInfo{
|
||||
GeneratedSourceInfo::PrettyPrinted,
|
||||
CharSourceRange(),
|
||||
CharSourceRange(memBufferStartLoc, buffer.size()),
|
||||
ASTNode(const_cast<Decl *>(ppDecl)).getOpaqueValue(),
|
||||
nullptr
|
||||
}
|
||||
);
|
||||
|
||||
// Go through all of the pretty-printed entries and record their
|
||||
// locations.
|
||||
for (auto entry : entries) {
|
||||
PrettyPrintedDeclarations[entry.first] =
|
||||
memBufferStartLoc.getAdvancedLoc(entry.second);
|
||||
}
|
||||
|
||||
// Grab the pretty-printed location.
|
||||
ppLoc = PrettyPrintedDeclarations[decl];
|
||||
}
|
||||
|
||||
loc = ppLoc;
|
||||
loc = evaluateOrDefault(
|
||||
decl->getASTContext().evaluator, PrettyPrintDeclRequest{decl},
|
||||
SourceLoc());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "TypeCheckObjC.h"
|
||||
#include "TypeCheckType.h"
|
||||
#include "TypeChecker.h"
|
||||
#include "swift/AST/ASTMangler.h"
|
||||
#include "swift/AST/ASTPrinter.h"
|
||||
#include "swift/AST/ASTVisitor.h"
|
||||
#include "swift/AST/ASTWalker.h"
|
||||
@@ -3209,3 +3210,176 @@ bool IsUnsafeRequest::evaluate(Evaluator &evaluator, Decl *decl) const {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// PrettyPrintDeclRequest
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
/// Returns the access level for pretty-printed declarations.
|
||||
///
|
||||
/// This is always \c Public unless \p decl is a \c ValueDecl and its
|
||||
/// access level is below \c Public. (That can happen with @testable and
|
||||
/// @_private imports.)
|
||||
static AccessLevel getBufferAccessLevel(const Decl *decl) {
|
||||
AccessLevel level = AccessLevel::Public;
|
||||
if (auto *VD = dyn_cast<ValueDecl>(decl))
|
||||
level = VD->getFormalAccessScope().accessLevelForDiagnostics();
|
||||
if (level > AccessLevel::Public) level = AccessLevel::Public;
|
||||
return level;
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// Keep track of the offsets at which a given target declaration is printed.
|
||||
class TrackingPrinter : public StreamPrinter {
|
||||
const Decl *targetDecl;
|
||||
|
||||
public:
|
||||
std::optional<uint64_t> targetDeclOffset;
|
||||
|
||||
TrackingPrinter(const Decl *targetDecl, raw_ostream &out)
|
||||
: StreamPrinter(out), targetDecl(targetDecl) { }
|
||||
|
||||
void printDeclLoc(const Decl *D) override {
|
||||
if (D == targetDecl)
|
||||
targetDeclOffset = OS.tell();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SourceLoc PrettyPrintDeclRequest::evaluate(Evaluator &eval, const Decl *decl) const {
|
||||
// Conjure a buffer name for this declaration.
|
||||
SmallVector<std::string, 4> nameComponents;
|
||||
DeclContext *dc;
|
||||
if (auto valueDecl = dyn_cast<ValueDecl>(decl)) {
|
||||
nameComponents.push_back(valueDecl->getBaseName().userFacingName().str());
|
||||
dc = valueDecl->getDeclContext();
|
||||
} else {
|
||||
dc = decl->getInnermostDeclContext();
|
||||
}
|
||||
|
||||
// Collect context information for the buffer name.
|
||||
while (dc) {
|
||||
switch (dc->getContextKind()) {
|
||||
case DeclContextKind::Package:
|
||||
break;
|
||||
case DeclContextKind::Module:
|
||||
nameComponents.push_back(
|
||||
cast<ModuleDecl>(dc)->getPublicModuleName(/*onlyIfImported=*/true
|
||||
).str().str());
|
||||
break;
|
||||
|
||||
case DeclContextKind::FileUnit:
|
||||
case DeclContextKind::TopLevelCodeDecl:
|
||||
case DeclContextKind::SerializedTopLevelCodeDecl:
|
||||
break;
|
||||
|
||||
case DeclContextKind::ExtensionDecl:
|
||||
nameComponents.push_back(
|
||||
cast<ExtensionDecl>(dc)->getExtendedType().getString());
|
||||
break;
|
||||
|
||||
case DeclContextKind::GenericTypeDecl:
|
||||
case DeclContextKind::Initializer:
|
||||
case DeclContextKind::AbstractClosureExpr:
|
||||
case DeclContextKind::SerializedAbstractClosure:
|
||||
case DeclContextKind::AbstractFunctionDecl:
|
||||
case DeclContextKind::SubscriptDecl:
|
||||
case DeclContextKind::EnumElementDecl:
|
||||
case DeclContextKind::MacroDecl:
|
||||
if (auto valueDecl = dyn_cast_or_null<ValueDecl>(dc->getAsDecl())) {
|
||||
nameComponents.push_back(
|
||||
valueDecl->getBaseName().userFacingName().str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dc = dc->getParent();
|
||||
}
|
||||
|
||||
|
||||
std::string bufferName;
|
||||
{
|
||||
llvm::raw_string_ostream out(bufferName);
|
||||
for (auto iter = nameComponents.rbegin(); iter != nameComponents.rend(); ++iter) {
|
||||
out << *iter;
|
||||
|
||||
if (iter + 1 != nameComponents.rend())
|
||||
out << ".";
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the name of the enclosing type(s), if there is one. We'll embed the
|
||||
// printed declaration in the type definition to establish the lexical
|
||||
// context.
|
||||
std::vector<std::string> enclosingTypes;
|
||||
for (auto dc = decl->getDeclContext(); dc; dc = dc->getParent()) {
|
||||
if (auto nominal = dc->getSelfNominalTypeDecl()) {
|
||||
// The name of this enclosing type.
|
||||
auto nominalKindName =
|
||||
Decl::getDescriptiveKindName(nominal->getDescriptiveKind());
|
||||
enclosingTypes.push_back(
|
||||
(nominalKindName + " " +
|
||||
nominal->getBaseName().userFacingName()).str());
|
||||
|
||||
// Jump from an extension over to the extended type.
|
||||
dc = nominal;
|
||||
}
|
||||
}
|
||||
std::reverse(enclosingTypes.begin(), enclosingTypes.end());
|
||||
|
||||
// Render the buffer contents.
|
||||
ASTContext &ctx = decl->getASTContext();
|
||||
llvm::SmallString<128> bufferContents;
|
||||
uint64_t targetDeclOffsetInBuffer;
|
||||
{
|
||||
llvm::raw_svector_ostream out(bufferContents);
|
||||
|
||||
// Produce the enclosing types.
|
||||
unsigned indent = 0;
|
||||
for (const auto &enclosingType : enclosingTypes) {
|
||||
out << std::string(indent, ' ') << enclosingType << " {\n";
|
||||
indent += 2;
|
||||
}
|
||||
|
||||
// Print this declaration.
|
||||
TrackingPrinter printer(decl, out);
|
||||
printer.setIndent(indent);
|
||||
llvm::SaveAndRestore<bool> isPrettyPrinting(
|
||||
ctx.Diags.IsPrettyPrintingDecl, true);
|
||||
auto options = PrintOptions::printForDiagnostics(
|
||||
getBufferAccessLevel(decl),
|
||||
ctx.TypeCheckerOpts.PrintFullConvention);
|
||||
decl->print(printer, options);
|
||||
// Close all of the enclosing types.
|
||||
for (const auto & enclosingType: enclosingTypes) {
|
||||
(void)enclosingType;
|
||||
indent -= 2;
|
||||
out << std::string(indent, ' ') << "}\n";
|
||||
}
|
||||
assert(indent == 0);
|
||||
|
||||
if (!printer.targetDeclOffset)
|
||||
return SourceLoc();
|
||||
|
||||
targetDeclOffsetInBuffer = *printer.targetDeclOffset;
|
||||
}
|
||||
|
||||
// Build a buffer with the pretty-printed declaration.
|
||||
SourceManager &sourceMgr = ctx.SourceMgr;
|
||||
auto bufferID = sourceMgr.addMemBufferCopy(bufferContents, bufferName);
|
||||
auto memBufferStartLoc = sourceMgr.getLocForBufferStart(bufferID);
|
||||
|
||||
// Note that this is a pretty-printed buffer.
|
||||
sourceMgr.setGeneratedSourceInfo(
|
||||
bufferID,
|
||||
GeneratedSourceInfo{
|
||||
GeneratedSourceInfo::PrettyPrinted,
|
||||
CharSourceRange(),
|
||||
CharSourceRange(memBufferStartLoc, bufferContents.size()),
|
||||
ASTNode(const_cast<Decl *>(decl)).getOpaqueValue(),
|
||||
nullptr
|
||||
}
|
||||
);
|
||||
|
||||
return memBufferStartLoc.getAdvancedLoc(targetDeclOffsetInBuffer);
|
||||
}
|
||||
|
||||
@@ -60,10 +60,10 @@ s.c = 5
|
||||
// CHECK-NEXT: ctypes.h:{{[0-9]+}}:{{[0-9]+}}: note: built-in type 'Complex' not supported
|
||||
// CHECK-NEXT: int _Complex c;
|
||||
// CHECK-NEXT: ^
|
||||
// CHECK-NEXT: ctypes.PartialImport:{{[0-9]+}}:{{[0-9]+}}: note: did you mean 'a'?
|
||||
// CHECK-NEXT: ctypes.PartialImport.a:{{[0-9]+}}:{{[0-9]+}}: note: did you mean 'a'?
|
||||
// CHECK-NEXT: public var a: Int32
|
||||
// CHECK-NEXT: ^
|
||||
// CHECK-NEXT: ctypes.PartialImport:{{[0-9]+}}:{{[0-9]+}}: note: did you mean 'b'?
|
||||
// CHECK-NEXT: ctypes.PartialImport.b:{{[0-9]+}}:{{[0-9]+}}: note: did you mean 'b'?
|
||||
// CHECK-NEXT: public var b: Int32
|
||||
// CHECK-NEXT: ^
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ _ = bar.methodReturningForwardDeclaredInterface()
|
||||
let s: PartialImport
|
||||
s.c = 5
|
||||
// CHECK: experimental_diagnostics_opt_out.swift:{{[0-9]+}}:{{[0-9]+}}: error: value of type 'PartialImport' has no member 'c'
|
||||
// CHECK: ctypes.PartialImport:{{[0-9]+}}:{{[0-9]+}}: note: did you mean 'a'?
|
||||
// CHECK: ctypes.PartialImport:{{[0-9]+}}:{{[0-9]+}}: note: did you mean 'b'?
|
||||
// CHECK: ctypes.PartialImport.a:{{[0-9]+}}:{{[0-9]+}}: note: did you mean 'a'?
|
||||
// CHECK: ctypes.PartialImport.b:{{[0-9]+}}:{{[0-9]+}}: note: did you mean 'b'?
|
||||
// CHECK-NOT: warning
|
||||
// CHECK-NOT: error
|
||||
// CHECK-NOT: note
|
||||
|
||||
@@ -14,6 +14,6 @@ final class MyImage : Image {
|
||||
// CHECK: non-@objc initializer 'init(imageLiteralResourceName:)' is declared in extension of 'Image' and cannot be overridden
|
||||
// Make sure we aren't emitting a fixit into the extant module...
|
||||
// CHECK-NOT: add '@objc' to make this declaration overridable
|
||||
// CHECK: ImageInitializers.Image:{{.*}}: note: overridden declaration is here
|
||||
// CHECK: ImageInitializers.Image.init:{{.*}}: note: overridden declaration is here
|
||||
override required convenience init(imageLiteralResourceName name: String) { }
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
var x = String.init // expected-error{{ambiguous use of 'init'}}
|
||||
// CHECK: {{.*[/\\]}}serialized-diagnostics-prettyprint.swift:[[@LINE-1]]:16: error: ambiguous use of 'init'
|
||||
|
||||
// CHECK: Swift.String:2:23: note: found this candidate
|
||||
// CHECK: CONTENTS OF FILE Swift.String:
|
||||
// CHECK: extension String {
|
||||
// CHECK: Swift.String.init:2:19: note: found this candidate
|
||||
// CHECK: CONTENTS OF FILE Swift.String.init:
|
||||
// CHECK: struct String {
|
||||
// CHECK: public init(_ content: Substring.UnicodeScalarView)
|
||||
|
||||
@@ -49,7 +49,7 @@ open class SubClass: ParentClass {
|
||||
// Removed the underlying file, so should use the generated source instead
|
||||
// RUN: mv %t/moda.swift %t/moda.swift-moved
|
||||
// RUN: not %target-swift-frontend -typecheck -I %t/mods -D MODB %s 2>&1 | %FileCheck -check-prefix=CHECK-GENERATED %s
|
||||
// CHECK-GENERATED: moda.ParentClass:{{.*}}: note:
|
||||
// CHECK-GENERATED: moda.ParentClass.overridableMethodA:{{.*}}: note:
|
||||
|
||||
// Underlying file has changed, so the locations in .swiftsourceinfo may not
|
||||
// make sense any more. Ignored for now (ie. it is used regardless)
|
||||
@@ -65,7 +65,7 @@ open class SubClass: ParentClass {
|
||||
// RUN: rm %t/moda.swift
|
||||
// RUN: touch %t/moda.swift
|
||||
// RUN: not %target-swift-frontend -typecheck -I %t/mods -D MODB %s 2>&1 | %FileCheck -check-prefix=CHECK-EMPTY %s
|
||||
// CHECK-EMPTY: moda.ParentClass:{{.*}}: note:
|
||||
// CHECK-EMPTY: moda.ParentClass.overridableMethodA:{{.*}}: note:
|
||||
|
||||
// The file and line from a location directive should be used whether or not it
|
||||
// exists - the actual source still comes from the original file, so that's what
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
ambiguous()
|
||||
|
||||
// CHECK: testable-printast-locations.swift:[[@LINE-2]]:1: error: ambiguous use of 'ambiguous()'
|
||||
// CHECK: ModuleA.ambiguous (internal):1:15: note: found this candidate in module 'ModuleA'
|
||||
// CHECK: ModuleB.ambiguous (internal):1:15: note: found this candidate in module 'ModuleB'
|
||||
// CHECK: ModuleA.ambiguous:1:15: note: found this candidate in module 'ModuleA'
|
||||
// CHECK: ModuleB.ambiguous:1:15: note: found this candidate in module 'ModuleB'
|
||||
|
||||
Reference in New Issue
Block a user