@@ -1416,35 +1416,59 @@ void TypeChecker::diagnoseDuplicateCaptureVars(CaptureListExpr *expr) {
1416
1416
diagnoseDuplicateDecls (captureListVars);
1417
1417
}
1418
1418
1419
- template <typename ...DiagIDAndArgs> InFlightDiagnostic
1420
- diagnoseAtAttrOrDecl (DeclAttribute *attr, ValueDecl *VD,
1421
- DiagIDAndArgs... idAndArgs) {
1422
- ASTContext &ctx = VD->getASTContext ();
1423
- if (attr->getLocation ().isValid ())
1424
- return ctx.Diags .diagnose (attr->getLocation (), idAndArgs...);
1425
- else
1426
- return ctx.Diags .diagnose (VD, idAndArgs...);
1419
+ static StringRef prettyPrintAttrs (const ValueDecl *VD,
1420
+ ArrayRef<const DeclAttribute *> attrs,
1421
+ SmallVectorImpl<char > &out) {
1422
+ llvm::raw_svector_ostream os (out);
1423
+ StreamPrinter printer (os);
1424
+
1425
+ PrintOptions opts = PrintOptions::printEverything ();
1426
+ VD->getAttrs ().print (printer, opts, attrs, VD);
1427
+ return StringRef (out.begin (), out.size ()).drop_back ();
1428
+ }
1429
+
1430
+ static void diagnoseChangesByAccessNote (
1431
+ ValueDecl *VD,
1432
+ ArrayRef<const DeclAttribute *> attrs,
1433
+ Diag<StringRef, StringRef, DescriptiveDeclKind> diagID,
1434
+ Diag<StringRef> fixItID,
1435
+ llvm::function_ref<void (InFlightDiagnostic, StringRef)> addFixIts) {
1436
+ if (!VD->getASTContext ().LangOpts .shouldRemarkOnAccessNoteSuccess () ||
1437
+ attrs.empty ())
1438
+ return ;
1439
+
1440
+ // Generate string containing all attributes.
1441
+ SmallString<64 > attrString;
1442
+ auto attrText = prettyPrintAttrs (VD, attrs, attrString);
1443
+
1444
+ SourceLoc fixItLoc;
1445
+
1446
+ auto reason = VD->getModuleContext ()->getAccessNotes ().Reason ;
1447
+ auto diag = VD->diagnose (diagID, reason, attrText, VD->getDescriptiveKind ());
1448
+ for (auto attr : attrs) {
1449
+ diag.highlight (attr->getRangeWithAt ());
1450
+ if (fixItLoc.isInvalid ())
1451
+ fixItLoc = attr->getRangeWithAt ().Start ;
1452
+ }
1453
+ diag.flush ();
1454
+
1455
+ if (!fixItLoc)
1456
+ fixItLoc = VD->getAttributeInsertionLoc (true );
1457
+
1458
+ addFixIts (VD->getASTContext ().Diags .diagnose (fixItLoc, fixItID, attrText),
1459
+ attrString);
1427
1460
}
1428
1461
1429
1462
template <typename Attr>
1430
1463
static void addOrRemoveAttr (ValueDecl *VD, const AccessNotesFile ¬es,
1431
1464
Optional<bool > expected,
1465
+ SmallVectorImpl<DeclAttribute *> &removedAttrs,
1432
1466
llvm::function_ref<Attr*()> willCreate) {
1433
1467
if (!expected) return ;
1434
1468
1435
1469
auto attr = VD->getAttrs ().getAttribute <Attr>();
1436
1470
if (*expected == (attr != nullptr )) return ;
1437
1471
1438
- auto diagnoseChangeByAccessNote =
1439
- [&](Diag<StringRef, bool , StringRef, DescriptiveDeclKind> diagID,
1440
- Diag<bool > fixitID) -> InFlightDiagnostic {
1441
- bool isModifier = attr->isDeclModifier ();
1442
-
1443
- diagnoseAtAttrOrDecl (attr, VD, diagID, notes.Reason , isModifier,
1444
- attr->getAttrName (), VD->getDescriptiveKind ());
1445
- return diagnoseAtAttrOrDecl (attr, VD, fixitID, isModifier);
1446
- };
1447
-
1448
1472
if (*expected) {
1449
1473
attr = willCreate ();
1450
1474
attr->setAddedByAccessNote ();
@@ -1453,77 +1477,80 @@ static void addOrRemoveAttr(ValueDecl *VD, const AccessNotesFile ¬es,
1453
1477
// Arrange for us to emit a remark about this attribute after type checking
1454
1478
// has ensured it's valid.
1455
1479
if (auto SF = VD->getDeclContext ()->getParentSourceFile ())
1456
- SF->AttrsAddedByAccessNotes . emplace_back (VD, attr);
1480
+ SF->AttrsAddedByAccessNotes [VD]. push_back ( attr);
1457
1481
} else {
1482
+ removedAttrs.push_back (attr);
1458
1483
VD->getAttrs ().removeAttribute (attr);
1459
- if (VD->getASTContext ().LangOpts .shouldRemarkOnAccessNoteSuccess ())
1460
- diagnoseChangeByAccessNote (diag::attr_removed_by_access_note,
1461
- diag::fixit_attr_removed_by_access_note)
1462
- .fixItRemove (attr->getRangeWithAt ());
1463
1484
}
1464
1485
}
1465
1486
1466
1487
InFlightDiagnostic
1467
1488
swift::softenIfAccessNote (const Decl *D, const DeclAttribute *attr,
1468
1489
InFlightDiagnostic &diag) {
1469
- if (!attr || !attr->getAddedByAccessNote ())
1490
+ const ValueDecl *VD = dyn_cast<ValueDecl>(D);
1491
+ if (!VD || !attr || !attr->getAddedByAccessNote ())
1470
1492
return std::move (diag);
1471
1493
1472
- auto behavior = D->getASTContext ().LangOpts .getAccessNoteFailureLimit ();
1494
+ SmallString<32 > attrString;
1495
+ auto attrText = prettyPrintAttrs (VD, makeArrayRef (attr), attrString);
1496
+
1497
+ ASTContext &ctx = D->getASTContext ();
1498
+ auto behavior = ctx.LangOpts .getAccessNoteFailureLimit ();
1473
1499
return std::move (diag.wrapIn (diag::wrap_invalid_attr_added_by_access_note,
1474
1500
D->getModuleContext ()->getAccessNotes ().Reason ,
1475
- attr-> isDeclModifier ( ), attr-> getAttrName ())
1501
+ ctx. AllocateCopy (attrText ), D-> getDescriptiveKind ())
1476
1502
.limitBehavior (behavior));
1477
1503
}
1478
1504
1479
1505
static void applyAccessNote (ValueDecl *VD, const AccessNote ¬e,
1480
1506
const AccessNotesFile ¬es) {
1481
1507
ASTContext &ctx = VD->getASTContext ();
1508
+ SmallVector<DeclAttribute *, 2 > removedAttrs;
1482
1509
1483
- addOrRemoveAttr<ObjCAttr>(VD, notes, note.ObjC , [&]{
1510
+ addOrRemoveAttr<ObjCAttr>(VD, notes, note.ObjC , removedAttrs, [&]{
1484
1511
return ObjCAttr::create (ctx, note.ObjCName , false );
1485
1512
});
1486
1513
1487
- addOrRemoveAttr<DynamicAttr>(VD, notes, note.Dynamic , [&]{
1514
+ addOrRemoveAttr<DynamicAttr>(VD, notes, note.Dynamic , removedAttrs, [&]{
1488
1515
return new (ctx) DynamicAttr (true );
1489
1516
});
1490
1517
1518
+ // FIXME: If we ever have more attributes, we'll need to sort removedAttrs by
1519
+ // SourceLoc. As it is, attrs are always before modifiers, so we're okay now.
1520
+
1521
+ diagnoseChangesByAccessNote (VD, removedAttrs,
1522
+ diag::attr_removed_by_access_note,
1523
+ diag::fixit_attr_removed_by_access_note,
1524
+ [&](InFlightDiagnostic diag, StringRef code) {
1525
+ for (auto attr : llvm::reverse (removedAttrs))
1526
+ diag.fixItRemove (attr->getRangeWithAt ());
1527
+ });
1528
+
1491
1529
if (note.ObjCName ) {
1492
1530
auto attr = VD->getAttrs ().getAttribute <ObjCAttr>();
1493
1531
assert (attr && " ObjCName set, but ObjCAttr not true or did not apply???" );
1494
1532
1495
1533
if (!attr->hasName ()) {
1534
+ auto oldName = attr->getName ();
1496
1535
attr->setName (*note.ObjCName , true );
1497
1536
1498
1537
if (!ctx.LangOpts .shouldRemarkOnAccessNoteSuccess ())
1499
1538
return ;
1500
1539
1501
- diagnoseAtAttrOrDecl (attr, VD,
1502
- diag::attr_objc_name_changed_by_access_note,
1503
- notes.Reason , VD->getDescriptiveKind (),
1504
- *note.ObjCName );
1505
-
1506
- SmallString<64 > newNameString;
1507
- llvm::raw_svector_ostream os (newNameString);
1508
- os << " (" ;
1509
- os << *note.ObjCName ;
1510
- os << " )" ;
1511
-
1512
- auto note = diagnoseAtAttrOrDecl (attr, VD,
1513
- diag::fixit_attr_objc_name_changed_by_access_note);
1540
+ VD->diagnose (diag::attr_objc_name_changed_by_access_note,
1541
+ notes.Reason , VD->getDescriptiveKind (), *note.ObjCName );
1514
1542
1515
- if (attr->getLParenLoc ().isValid ())
1516
- note.fixItReplace ({ attr->getLParenLoc (), attr->getRParenLoc () },
1517
- newNameString);
1518
- else
1519
- note.fixItInsertAfter (attr->getLocation (), newNameString);
1543
+ auto fixIt =
1544
+ VD->diagnose (diag::fixit_attr_objc_name_changed_by_access_note);
1545
+ fixDeclarationObjCName (fixIt, VD, oldName, *note.ObjCName );
1520
1546
}
1521
1547
else if (attr->getName () != *note.ObjCName ) {
1522
1548
auto behavior = ctx.LangOpts .getAccessNoteFailureLimit ();
1523
- diagnoseAtAttrOrDecl (attr, VD,
1524
- diag::attr_objc_name_conflicts_with_access_note,
1525
- notes.Reason , VD->getDescriptiveKind (),
1526
- *note.ObjCName , *attr->getName ())
1549
+
1550
+ VD->diagnose (diag::attr_objc_name_conflicts_with_access_note,
1551
+ notes.Reason , VD->getDescriptiveKind (), *attr->getName (),
1552
+ *note.ObjCName )
1553
+ .highlight (attr->getRangeWithAt ())
1527
1554
.limitBehavior (behavior);
1528
1555
}
1529
1556
}
@@ -1538,24 +1565,31 @@ void swift::diagnoseAttrsAddedByAccessNote(SourceFile &SF) {
1538
1565
if (!SF.getASTContext ().LangOpts .shouldRemarkOnAccessNoteSuccess ())
1539
1566
return ;
1540
1567
1541
- for (auto declAndAttr : SF.AttrsAddedByAccessNotes ) {
1542
- auto VD = std::get<0 >(declAndAttr);
1543
- auto attr = std::get<1 >(declAndAttr);
1544
-
1545
- if (attr->isInvalid ()) continue ;
1546
- assert (attr->getAddedByAccessNote ());
1547
-
1548
- bool isModifier = attr->isDeclModifier ();
1549
-
1550
- auto reason = VD->getModuleContext ()->getAccessNotes ().Reason ;
1551
- VD->diagnose (diag::attr_added_by_access_note, reason, isModifier,
1552
- attr->getAttrName (), VD->getDescriptiveKind ());
1568
+ for (auto declAndAttrs : SF.AttrsAddedByAccessNotes ) {
1569
+ auto D = declAndAttrs.getFirst ();
1570
+ SmallVector<DeclAttribute *, 4 > sortedAttrs;
1571
+ llvm::append_range (sortedAttrs, declAndAttrs.getSecond ());
1572
+
1573
+ // Filter out invalid attributes.
1574
+ sortedAttrs.erase (
1575
+ llvm::remove_if (sortedAttrs, [](DeclAttribute *attr) {
1576
+ assert (attr->getAddedByAccessNote ());
1577
+ return attr->isInvalid ();
1578
+ }), sortedAttrs.end ());
1579
+ if (sortedAttrs.empty ()) continue ;
1580
+
1581
+ // Sort attributes by name.
1582
+ llvm::sort (sortedAttrs, [](DeclAttribute * first, DeclAttribute * second) {
1583
+ return first->getAttrName () < second->getAttrName ();
1584
+ });
1585
+ sortedAttrs.erase (std::unique (sortedAttrs.begin (), sortedAttrs.end ()),
1586
+ sortedAttrs.end ());
1553
1587
1554
- SmallString< 64 > attrString;
1555
- llvm::raw_svector_ostream os (attrString);
1556
- attr-> print (os, VD);
1557
- VD-> diagnose (diag::fixit_attr_added_by_access_note, isModifier)
1558
- . fixItInsert (VD-> getAttributeInsertionLoc (isModifier), attrString );
1588
+ diagnoseChangesByAccessNote (D, sortedAttrs, diag::attr_added_by_access_note,
1589
+ diag::fixit_attr_added_by_access_note,
1590
+ [=](InFlightDiagnostic diag, StringRef code) {
1591
+ diag. fixItInsert (D-> getAttributeInsertionLoc ( /* isModifier= */ true ), code);
1592
+ } );
1559
1593
}
1560
1594
}
1561
1595
0 commit comments