Skip to content

Commit 043434d

Browse files
committed
[NFC] Add DiagnosticStateRAII
DiagnosticEngine tracks whether an error/warning was ignored so that it can also automatically ignore related notes. This can go rather poorly if you have logic between the warning/error and notes to determine which notes to emit, and this logic emits ignored diagnostics. Add an RAII type to handle this situation and use it at all entry points into TypeCheckDeclObjC.cpp, since this code is about to start using ignored diagnostics pretty heavily.
1 parent 5e68204 commit 043434d

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

include/swift/AST/DiagnosticEngine.h

+31
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "llvm/Support/Allocator.h"
3030
#include "llvm/Support/FileSystem.h"
3131
#include "llvm/Support/Path.h"
32+
#include "llvm/Support/SaveAndRestore.h"
3233
#include "llvm/Support/VersionTuple.h"
3334

3435
namespace swift {
@@ -640,6 +641,8 @@ namespace swift {
640641
/// Track which diagnostics should be ignored.
641642
llvm::BitVector ignoredDiagnostics;
642643

644+
friend class DiagnosticStateRAII;
645+
643646
public:
644647
DiagnosticState();
645648

@@ -740,6 +743,7 @@ namespace swift {
740743
friend class InFlightDiagnostic;
741744
friend class DiagnosticTransaction;
742745
friend class CompoundDiagnosticTransaction;
746+
friend class DiagnosticStateRAII;
743747

744748
public:
745749
explicit DiagnosticEngine(SourceManager &SourceMgr)
@@ -1053,6 +1057,33 @@ namespace swift {
10531057
}
10541058
};
10551059

1060+
/// Remember details about the state of a diagnostic engine and restore them
1061+
/// when the object is destroyed.
1062+
///
1063+
/// Diagnostic engines contain state about the most recent diagnostic emitted
1064+
/// which influences subsequent emissions; in particular, if you try to emit
1065+
/// a note and the previous diagnostic was ignored, the note will be ignored
1066+
/// too. This can be a problem in code structured like:
1067+
///
1068+
/// D->diagnose(diag::an_error);
1069+
/// if (conditionWhichMightEmitDiagnostics())
1070+
/// D->diagnose(diag::a_note); // might be affected by diagnostics from
1071+
/// // conditionWhichMightEmitDiagnostics()!
1072+
///
1073+
/// To prevent this, functions which are called for their return values but
1074+
/// may emit diagnostics as a side effect can use \c DiagnosticStateRAII to
1075+
/// ensure that their changes to diagnostic engine state don't leak out and
1076+
/// affect the caller's diagnostics.
1077+
class DiagnosticStateRAII {
1078+
llvm::SaveAndRestore<DiagnosticBehavior> previousBehavior;
1079+
1080+
public:
1081+
DiagnosticStateRAII(DiagnosticEngine &diags)
1082+
: previousBehavior(diags.state.previousBehavior) {}
1083+
1084+
~DiagnosticStateRAII() {}
1085+
};
1086+
10561087
class BufferIndirectlyCausingDiagnosticRAII {
10571088
private:
10581089
DiagnosticEngine &Diags;

lib/Sema/TypeCheckDeclObjC.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,7 @@ bool swift::isRepresentableInObjC(
553553

554554
// If you change this function, you must add or modify a test in PrintAsObjC.
555555
ASTContext &ctx = AFD->getASTContext();
556+
DiagnosticStateRAII diagState(ctx.Diags);
556557

557558
bool Diagnose = shouldDiagnoseObjCReason(Reason, ctx);
558559

@@ -985,6 +986,8 @@ bool swift::isRepresentableInObjC(const VarDecl *VD, ObjCReason Reason) {
985986
T = RST->getReferentType();
986987
}
987988
ASTContext &ctx = VD->getASTContext();
989+
DiagnosticStateRAII diagState(ctx.Diags);
990+
988991
bool Result = T->isRepresentableIn(ForeignLanguage::ObjectiveC,
989992
VD->getDeclContext());
990993
bool Diagnose = shouldDiagnoseObjCReason(Reason, ctx);
@@ -1018,6 +1021,7 @@ bool swift::isRepresentableInObjC(const VarDecl *VD, ObjCReason Reason) {
10181021
bool swift::isRepresentableInObjC(const SubscriptDecl *SD, ObjCReason Reason) {
10191022
// If you change this function, you must add or modify a test in PrintAsObjC.
10201023
ASTContext &ctx = SD->getASTContext();
1024+
DiagnosticStateRAII diagState(ctx.Diags);
10211025
bool Diagnose = shouldDiagnoseObjCReason(Reason, ctx);
10221026

10231027
if (checkObjCInForeignClassContext(SD, Reason))
@@ -1219,6 +1223,7 @@ static Optional<ObjCReason> shouldMarkClassAsObjC(const ClassDecl *CD) {
12191223
}
12201224

12211225
/// Figure out if a declaration should be exported to Objective-C.
1226+
static
12221227
Optional<ObjCReason> shouldMarkAsObjC(const ValueDecl *VD, bool allowImplicit) {
12231228
// If Objective-C interoperability is disabled, nothing gets marked as @objc.
12241229
if (!VD->getASTContext().LangOpts.EnableObjCInterop)
@@ -1472,6 +1477,8 @@ static void markAsObjC(ValueDecl *D, ObjCReason reason,
14721477

14731478

14741479
bool IsObjCRequest::evaluate(Evaluator &evaluator, ValueDecl *VD) const {
1480+
DiagnosticStateRAII diagState(VD->getASTContext().Diags);
1481+
14751482
// Access notes may add attributes that affect this calculus.
14761483
(void)evaluateOrDefault(evaluator, ApplyAccessNoteRequest{VD}, {});
14771484

@@ -2180,6 +2187,7 @@ lookupOverridenObjCMethod(ClassDecl *classDecl, AbstractFunctionDecl *method,
21802187

21812188
bool swift::diagnoseUnintendedObjCMethodOverrides(SourceFile &sf) {
21822189
auto &Ctx = sf.getASTContext();
2190+
DiagnosticStateRAII diagState(Ctx.Diags);
21832191
auto &methods = sf.ObjCMethodList;
21842192

21852193
// If no Objective-C methods were defined in this file, we're done.
@@ -2284,6 +2292,7 @@ bool swift::diagnoseObjCMethodConflicts(SourceFile &sf) {
22842292
return false;
22852293

22862294
auto &Ctx = sf.getASTContext();
2295+
DiagnosticStateRAII diagState(Ctx.Diags);
22872296
OrderDeclarations ordering;
22882297

22892298
// Sort the set of conflicts so we get a deterministic order for
@@ -2389,6 +2398,7 @@ bool swift::diagnoseObjCUnsatisfiedOptReqConflicts(SourceFile &sf) {
23892398
return false;
23902399

23912400
auto &Ctx = sf.getASTContext();
2401+
DiagnosticStateRAII diagState(Ctx.Diags);
23922402

23932403
// Sort the set of local unsatisfied requirements, so we get a
23942404
// deterministic order for diagnostics.

0 commit comments

Comments
 (0)