Skip to content

Commit 5df96a7

Browse files
committedOct 1, 2024··
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.
1 parent c9b0a2a commit 5df96a7

11 files changed

+216
-177
lines changed
 

‎include/swift/AST/DiagnosticEngine.h

+1-4
Original file line numberDiff line numberDiff line change
@@ -1052,10 +1052,6 @@ namespace swift {
10521052
/// been emitted due to an open transaction.
10531053
SmallVector<Diagnostic, 4> TentativeDiagnostics;
10541054

1055-
/// The set of declarations for which we have pretty-printed
1056-
/// results that we can point to on the command line.
1057-
llvm::DenseMap<const Decl *, SourceLoc> PrettyPrintedDeclarations;
1058-
10591055
llvm::BumpPtrAllocator TransactionAllocator;
10601056
/// A set of all strings involved in current transactional chain.
10611057
/// This is required because diagnostics are not directly emitted
@@ -1108,6 +1104,7 @@ namespace swift {
11081104
friend class CompoundDiagnosticTransaction;
11091105
friend class DiagnosticStateRAII;
11101106
friend class DiagnosticQueue;
1107+
friend class PrettyPrintDeclRequest;
11111108

11121109
public:
11131110
explicit DiagnosticEngine(SourceManager &SourceMgr)

‎include/swift/AST/TypeCheckRequests.h

+21
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,27 @@ class MangleLocalTypeDeclRequest :
754754

755755
void simple_display(llvm::raw_ostream &out, const KnownProtocolKind);
756756

757+
/// Pretty-print the given declaration into a buffer and return a source
758+
/// location that refers to the declaration in that buffer.
759+
class PrettyPrintDeclRequest
760+
: public SimpleRequest<PrettyPrintDeclRequest,
761+
SourceLoc(const Decl *),
762+
RequestFlags::Cached>
763+
{
764+
public:
765+
using SimpleRequest::SimpleRequest;
766+
767+
private:
768+
friend SimpleRequest;
769+
770+
// Evaluation.
771+
SourceLoc evaluate(Evaluator &eval, const Decl *d) const;
772+
773+
public:
774+
// Caching
775+
bool isCached() const { return true; }
776+
};
777+
757778
// Find the type in the cache or look it up
758779
class DefaultTypeRequest
759780
: public SimpleRequest<DefaultTypeRequest,

‎include/swift/AST/TypeCheckerTypeIDZone.def

+2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ SWIFT_REQUEST(TypeChecker, DefaultDefinitionTypeRequest,
7676
SWIFT_REQUEST(TypeChecker, DefaultTypeRequest,
7777
Type(KnownProtocolKind, const DeclContext *), SeparatelyCached,
7878
NoLocationInfo)
79+
SWIFT_REQUEST(TypeChecker, PrettyPrintDeclRequest,
80+
SourceLoc(const Decl *), Cached, NoLocationInfo)
7981
SWIFT_REQUEST(TypeChecker, DifferentiableAttributeTypeCheckRequest,
8082
IndexSubset *(DifferentiableAttr *),
8183
SeparatelyCached, NoLocationInfo)

‎lib/AST/DiagnosticEngine.cpp

+6-161
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "swift/AST/PrintOptions.h"
3030
#include "swift/AST/SourceFile.h"
3131
#include "swift/AST/Stmt.h"
32+
#include "swift/AST/TypeCheckRequests.h"
3233
#include "swift/AST/TypeRepr.h"
3334
#include "swift/Basic/Assertions.h"
3435
#include "swift/Basic/SourceManager.h"
@@ -1306,20 +1307,6 @@ void DiagnosticEngine::forwardTentativeDiagnosticsTo(
13061307
clearTentativeDiagnostics();
13071308
}
13081309

1309-
/// Returns the access level of the least accessible PrettyPrintedDeclarations
1310-
/// buffer that \p decl should appear in.
1311-
///
1312-
/// This is always \c Public unless \p decl is a \c ValueDecl and its
1313-
/// access level is below \c Public. (That can happen with @testable and
1314-
/// @_private imports.)
1315-
static AccessLevel getBufferAccessLevel(const Decl *decl) {
1316-
AccessLevel level = AccessLevel::Public;
1317-
if (auto *VD = dyn_cast<ValueDecl>(decl))
1318-
level = VD->getFormalAccessScope().accessLevelForDiagnostics();
1319-
if (level > AccessLevel::Public) level = AccessLevel::Public;
1320-
return level;
1321-
}
1322-
13231310
std::optional<DiagnosticInfo>
13241311
DiagnosticEngine::diagnosticInfoForDiagnostic(const Diagnostic &diagnostic) {
13251312
auto behavior = state.determineBehavior(diagnostic);
@@ -1334,154 +1321,12 @@ DiagnosticEngine::diagnosticInfoForDiagnostic(const Diagnostic &diagnostic) {
13341321
// has a location we can point to, use that location.
13351322
loc = decl->getLoc();
13361323

1324+
// If the location of the decl is invalid still, try to pretty-print the
1325+
// declaration into a buffer and capture the source location there.
13371326
if (loc.isInvalid()) {
1338-
// There is no location we can point to. Pretty-print the declaration
1339-
// so we can point to it.
1340-
SourceLoc ppLoc = PrettyPrintedDeclarations[decl];
1341-
if (ppLoc.isInvalid()) {
1342-
class TrackingPrinter : public StreamPrinter {
1343-
SmallVectorImpl<std::pair<const Decl *, uint64_t>> &Entries;
1344-
AccessLevel bufferAccessLevel;
1345-
1346-
public:
1347-
TrackingPrinter(
1348-
SmallVectorImpl<std::pair<const Decl *, uint64_t>> &Entries,
1349-
raw_ostream &OS, AccessLevel bufferAccessLevel) :
1350-
StreamPrinter(OS), Entries(Entries),
1351-
bufferAccessLevel(bufferAccessLevel) {}
1352-
1353-
void printDeclLoc(const Decl *D) override {
1354-
if (getBufferAccessLevel(D) == bufferAccessLevel)
1355-
Entries.push_back({ D, OS.tell() });
1356-
}
1357-
};
1358-
SmallVector<std::pair<const Decl *, uint64_t>, 8> entries;
1359-
llvm::SmallString<128> buffer;
1360-
llvm::SmallString<128> bufferName;
1361-
const Decl *ppDecl = decl;
1362-
{
1363-
// The access level of the buffer we want to print. Declarations below
1364-
// this access level will be omitted from the buffer; declarations
1365-
// above it will be printed, but (except for Open declarations in the
1366-
// Public buffer) will not be recorded in PrettyPrintedDeclarations as
1367-
// the "true" SourceLoc for the declaration.
1368-
AccessLevel bufferAccessLevel = getBufferAccessLevel(decl);
1369-
1370-
// Figure out which declaration to print. It's the top-most
1371-
// declaration (not a module).
1372-
auto dc = decl->getDeclContext();
1373-
1374-
// FIXME: Horrible, horrible hackaround. We're not getting a
1375-
// DeclContext everywhere we should.
1376-
if (!dc) {
1377-
return std::nullopt;
1378-
}
1379-
1380-
while (!dc->isModuleContext()) {
1381-
switch (dc->getContextKind()) {
1382-
case DeclContextKind::Package:
1383-
llvm_unreachable("Not in a package context!");
1384-
break;
1385-
case DeclContextKind::Module:
1386-
llvm_unreachable("Not in a module context!");
1387-
break;
1388-
1389-
case DeclContextKind::FileUnit:
1390-
case DeclContextKind::TopLevelCodeDecl:
1391-
case DeclContextKind::SerializedTopLevelCodeDecl:
1392-
break;
1393-
1394-
case DeclContextKind::ExtensionDecl:
1395-
ppDecl = cast<ExtensionDecl>(dc);
1396-
break;
1397-
1398-
case DeclContextKind::GenericTypeDecl:
1399-
ppDecl = cast<GenericTypeDecl>(dc);
1400-
break;
1401-
1402-
case DeclContextKind::Initializer:
1403-
case DeclContextKind::AbstractClosureExpr:
1404-
case DeclContextKind::SerializedAbstractClosure:
1405-
case DeclContextKind::AbstractFunctionDecl:
1406-
case DeclContextKind::SubscriptDecl:
1407-
case DeclContextKind::EnumElementDecl:
1408-
case DeclContextKind::MacroDecl:
1409-
break;
1410-
}
1411-
1412-
dc = dc->getParent();
1413-
}
1414-
1415-
// Build the module name path (in reverse), which we use to
1416-
// build the name of the buffer.
1417-
SmallVector<StringRef, 4> nameComponents;
1418-
while (dc) {
1419-
auto publicName = cast<ModuleDecl>(dc)->
1420-
getPublicModuleName(/*onlyIfImported*/true);
1421-
nameComponents.push_back(publicName.str());
1422-
dc = dc->getParent();
1423-
}
1424-
1425-
for (unsigned i = nameComponents.size(); i; --i) {
1426-
bufferName += nameComponents[i-1];
1427-
bufferName += '.';
1428-
}
1429-
1430-
if (auto value = dyn_cast<ValueDecl>(ppDecl)) {
1431-
bufferName += value->getBaseName().userFacingName();
1432-
} else if (auto ext = dyn_cast<ExtensionDecl>(ppDecl)) {
1433-
bufferName += ext->getExtendedType().getString();
1434-
}
1435-
1436-
// If we're using a lowered access level, give the buffer a distinct
1437-
// name.
1438-
if (bufferAccessLevel != AccessLevel::Public) {
1439-
assert(bufferAccessLevel < AccessLevel::Public
1440-
&& "Above-public access levels should use public buffer");
1441-
bufferName += " (";
1442-
bufferName += getAccessLevelSpelling(bufferAccessLevel);
1443-
bufferName += ")";
1444-
}
1445-
1446-
// Pretty-print the declaration we've picked.
1447-
llvm::raw_svector_ostream out(buffer);
1448-
TrackingPrinter printer(entries, out, bufferAccessLevel);
1449-
llvm::SaveAndRestore<bool> isPrettyPrinting(
1450-
IsPrettyPrintingDecl, true);
1451-
ppDecl->print(
1452-
printer,
1453-
PrintOptions::printForDiagnostics(
1454-
bufferAccessLevel,
1455-
decl->getASTContext().TypeCheckerOpts.PrintFullConvention));
1456-
}
1457-
1458-
// Build a buffer with the pretty-printed declaration.
1459-
auto bufferID = SourceMgr.addMemBufferCopy(buffer, bufferName);
1460-
auto memBufferStartLoc = SourceMgr.getLocForBufferStart(bufferID);
1461-
1462-
SourceMgr.setGeneratedSourceInfo(
1463-
bufferID,
1464-
GeneratedSourceInfo{
1465-
GeneratedSourceInfo::PrettyPrinted,
1466-
CharSourceRange(),
1467-
CharSourceRange(memBufferStartLoc, buffer.size()),
1468-
ASTNode(const_cast<Decl *>(ppDecl)).getOpaqueValue(),
1469-
nullptr
1470-
}
1471-
);
1472-
1473-
// Go through all of the pretty-printed entries and record their
1474-
// locations.
1475-
for (auto entry : entries) {
1476-
PrettyPrintedDeclarations[entry.first] =
1477-
memBufferStartLoc.getAdvancedLoc(entry.second);
1478-
}
1479-
1480-
// Grab the pretty-printed location.
1481-
ppLoc = PrettyPrintedDeclarations[decl];
1482-
}
1483-
1484-
loc = ppLoc;
1327+
loc = evaluateOrDefault(
1328+
decl->getASTContext().evaluator, PrettyPrintDeclRequest{decl},
1329+
SourceLoc());
14851330
}
14861331
}
14871332

0 commit comments

Comments
 (0)
Please sign in to comment.