|
21 | 21 | #include "swift/AST/Decl.h"
|
22 | 22 | #include "swift/AST/DiagnosticSuppression.h"
|
23 | 23 | #include "swift/AST/DiagnosticsCommon.h"
|
| 24 | +#include "swift/AST/Expr.h" |
24 | 25 | #include "swift/AST/Module.h"
|
25 | 26 | #include "swift/AST/Pattern.h"
|
26 | 27 | #include "swift/AST/PrintOptions.h"
|
@@ -1267,10 +1268,83 @@ DiagnosticEngine::diagnosticInfoForDiagnostic(const Diagnostic &diagnostic) {
|
1267 | 1268 | diagnostic.isChildNote());
|
1268 | 1269 | }
|
1269 | 1270 |
|
| 1271 | +std::vector<Diagnostic> DiagnosticEngine::getGeneratedSourceBufferNotes( |
| 1272 | + SourceLoc loc, Optional<unsigned> &lastBufferID |
| 1273 | +) { |
| 1274 | + // The set of child notes we're building up. |
| 1275 | + std::vector<Diagnostic> childNotes; |
| 1276 | + |
| 1277 | + // If the location is invalid, there's nothing to do. |
| 1278 | + if (loc.isInvalid()) |
| 1279 | + return childNotes; |
| 1280 | + |
| 1281 | + // If we already emitted these notes for a prior part of the diagnostic, |
| 1282 | + // don't do so again. |
| 1283 | + auto currentBufferID = SourceMgr.findBufferContainingLoc(loc); |
| 1284 | + if (currentBufferID == lastBufferID) |
| 1285 | + return childNotes; |
| 1286 | + |
| 1287 | + // Keep track of the last buffer ID we considered. |
| 1288 | + lastBufferID = currentBufferID; |
| 1289 | + |
| 1290 | + SourceLoc currentLoc = loc; |
| 1291 | + do { |
| 1292 | + auto generatedInfo = SourceMgr.getGeneratedSourceInfo(currentBufferID); |
| 1293 | + if (!generatedInfo) |
| 1294 | + return childNotes; |
| 1295 | + |
| 1296 | + ASTNode expansionNode = |
| 1297 | + ASTNode::getFromOpaqueValue(generatedInfo->astNode); |
| 1298 | + |
| 1299 | + switch (generatedInfo->kind) { |
| 1300 | + case GeneratedSourceInfo::MacroExpansion: { |
| 1301 | + SourceRange origRange = expansionNode.getSourceRange(); |
| 1302 | + DeclName macroName; |
| 1303 | + if (auto expansionExpr = dyn_cast_or_null<MacroExpansionExpr>( |
| 1304 | + expansionNode.dyn_cast<Expr *>())) { |
| 1305 | + macroName = expansionExpr->getMacroName().getFullName(); |
| 1306 | + } else { |
| 1307 | + auto expansionDecl = |
| 1308 | + cast<MacroExpansionDecl>(expansionNode.get<Decl *>()); |
| 1309 | + macroName = expansionDecl->getMacro().getFullName(); |
| 1310 | + } |
| 1311 | + |
| 1312 | + Diagnostic expansionNote(diag::in_macro_expansion, macroName); |
| 1313 | + expansionNote.setLoc(origRange.Start); |
| 1314 | + expansionNote.addRange( |
| 1315 | + Lexer::getCharSourceRangeFromSourceRange(SourceMgr, origRange)); |
| 1316 | + expansionNote.setIsChildNote(true); |
| 1317 | + childNotes.push_back(std::move(expansionNote)); |
| 1318 | + break; |
| 1319 | + } |
| 1320 | + |
| 1321 | + case GeneratedSourceInfo::ReplacedFunctionBody: |
| 1322 | + return childNotes; |
| 1323 | + } |
| 1324 | + |
| 1325 | + // Walk up the stack. |
| 1326 | + currentLoc = expansionNode.getStartLoc(); |
| 1327 | + currentBufferID = SourceMgr.findBufferContainingLoc(currentLoc); |
| 1328 | + } while (true); |
| 1329 | +} |
| 1330 | + |
1270 | 1331 | void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) {
|
| 1332 | + Optional<unsigned> lastBufferID; |
| 1333 | + |
| 1334 | + ArrayRef<Diagnostic> childNotes = diagnostic.getChildNotes(); |
| 1335 | + std::vector<Diagnostic> extendedChildNotes; |
| 1336 | + |
1271 | 1337 | if (auto info = diagnosticInfoForDiagnostic(diagnostic)) {
|
| 1338 | + // If the diagnostic location is within a buffer containing generated |
| 1339 | + // source code, add child notes showing where the generation occurred. |
| 1340 | + extendedChildNotes = getGeneratedSourceBufferNotes(info->Loc, lastBufferID); |
| 1341 | + if (!extendedChildNotes.empty()) { |
| 1342 | + extendedChildNotes.insert(extendedChildNotes.end(), |
| 1343 | + childNotes.begin(), childNotes.end()); |
| 1344 | + childNotes = extendedChildNotes; |
| 1345 | + } |
| 1346 | + |
1272 | 1347 | SmallVector<DiagnosticInfo, 1> childInfo;
|
1273 |
| - auto childNotes = diagnostic.getChildNotes(); |
1274 | 1348 | for (unsigned i : indices(childNotes)) {
|
1275 | 1349 | auto child = diagnosticInfoForDiagnostic(childNotes[i]);
|
1276 | 1350 | assert(child);
|
@@ -1302,7 +1376,7 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) {
|
1302 | 1376 | // For compatibility with DiagnosticConsumers which don't know about child
|
1303 | 1377 | // notes. These can be ignored by consumers which do take advantage of the
|
1304 | 1378 | // grouping.
|
1305 |
| - for (auto &childNote : diagnostic.getChildNotes()) |
| 1379 | + for (auto &childNote : childNotes) |
1306 | 1380 | emitDiagnostic(childNote);
|
1307 | 1381 | }
|
1308 | 1382 |
|
|
0 commit comments