1919#include " TypeCheckConcurrency.h"
2020#include " TypeCheckInvertible.h"
2121#include " TypeChecker.h"
22+ #include " swift/AST/ASTBridging.h"
2223#include " swift/AST/ASTWalker.h"
2324#include " swift/AST/ConformanceLookup.h"
2425#include " swift/AST/DiagnosticsSema.h"
@@ -3160,6 +3161,9 @@ class VarDeclUsageChecker : public ASTWalker {
31603161 DeclContext *DC;
31613162
31623163 DiagnosticEngine &Diags;
3164+
3165+ SourceRange FullRange;
3166+
31633167 // Keep track of some information about a variable.
31643168 enum {
31653169 RK_Defined = 1 , // /< Whether it was ever defined in this scope.
@@ -3195,8 +3199,9 @@ class VarDeclUsageChecker : public ASTWalker {
31953199 void operator =(const VarDeclUsageChecker &) = delete ;
31963200
31973201public:
3198- VarDeclUsageChecker (DeclContext *DC,
3199- DiagnosticEngine &Diags) : DC(DC), Diags(Diags) {}
3202+ VarDeclUsageChecker (DeclContext *DC, DiagnosticEngine &Diags,
3203+ SourceRange range)
3204+ : DC(DC), Diags(Diags), FullRange(range) {}
32003205
32013206 // After we have scanned the entire region, diagnose variables that could be
32023207 // declared with a narrower usage kind.
@@ -3266,11 +3271,6 @@ class VarDeclUsageChecker : public ASTWalker {
32663271 if (isa<TypeDecl>(D))
32673272 return Action::SkipNode ();
32683273
3269- // The body of #if clauses are not walked into, we need custom processing
3270- // for them.
3271- if (auto *ICD = dyn_cast<IfConfigDecl>(D))
3272- handleIfConfig (ICD);
3273-
32743274 // If this is a VarDecl, then add it to our list of things to track.
32753275 if (auto *vd = dyn_cast<VarDecl>(D)) {
32763276 if (shouldTrackVarDecl (vd)) {
@@ -3354,9 +3354,6 @@ class VarDeclUsageChecker : public ASTWalker {
33543354 // / The heavy lifting happens when visiting expressions.
33553355 PreWalkResult<Expr *> walkToExprPre (Expr *E) override ;
33563356
3357- // / handle #if directives.
3358- void handleIfConfig (IfConfigDecl *ICD);
3359-
33603357 // / Custom handling for statements.
33613358 PreWalkResult<Stmt *> walkToStmtPre (Stmt *S) override {
33623359 // Keep track of an association between vardecls and the StmtCondition that
@@ -3864,6 +3861,16 @@ SourceLoc swift::getFixItLocForVarToLet(VarDecl *var) {
38643861 return SourceLoc ();
38653862}
38663863
3864+ extern " C" bool swift_ASTGen_inactiveCodeContainsReference (
3865+ BridgedASTContext ctx,
3866+ BridgedStringRef sourceFileBuffer,
3867+ BridgedStringRef searchRange,
3868+ BridgedStringRef name,
3869+ void **cache
3870+ );
3871+
3872+ extern " C" void swift_ASTGen_freeInactiveCodeContainsReferenceCache (void *cache);
3873+
38673874// After we have scanned the entire region, diagnose variables that could be
38683875// declared with a narrower usage kind.
38693876VarDeclUsageChecker::~VarDeclUsageChecker () {
@@ -3873,6 +3880,35 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
38733880 if (sawError)
38743881 return ;
38753882
3883+ // / Check whether the given variable might have been referenced from an
3884+ // / inactive region of the source code.
3885+ void *usedInInactiveCache = nullptr ;
3886+ auto isUsedInInactive = [&](VarDecl *var) -> bool {
3887+ #if SWIFT_BUILD_SWIFT_SYNTAX
3888+ // Extract the full buffer containing the source range.
3889+ ASTContext &ctx = DC->getASTContext ();
3890+ SourceManager &sourceMgr = ctx.SourceMgr ;
3891+ auto bufferID = sourceMgr.findBufferContainingLoc (FullRange.Start );
3892+ StringRef sourceFileText = sourceMgr.getEntireTextForBuffer (bufferID);
3893+
3894+ // Extract the search text from that buffer.
3895+ auto searchTextCharRange = Lexer::getCharSourceRangeFromSourceRange (
3896+ sourceMgr, FullRange);
3897+ StringRef searchText = sourceMgr.extractText (searchTextCharRange, bufferID);
3898+
3899+ return swift_ASTGen_inactiveCodeContainsReference (
3900+ ctx, sourceFileText, searchText, var->getName ().str (),
3901+ &usedInInactiveCache);
3902+ #else
3903+ return false ;
3904+ #endif
3905+ };
3906+ SWIFT_DEFER {
3907+ #if SWIFT_BUILD_SWIFT_SYNTAX
3908+ swift_ASTGen_freeInactiveCodeContainsReferenceCache (usedInInactiveCache);
3909+ #endif
3910+ };
3911+
38763912 for (auto p : VarDecls) {
38773913 VarDecl *var;
38783914 unsigned access;
@@ -3907,7 +3943,7 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
39073943 auto VD = dyn_cast<VarDecl>(FD->getStorage ());
39083944 if ((access & RK_Read) == 0 ) {
39093945 auto found = AssociatedGetterRefExpr.find (VD);
3910- if (found != AssociatedGetterRefExpr.end ()) {
3946+ if (found != AssociatedGetterRefExpr.end () && ! isUsedInInactive (VD) ) {
39113947 auto *DRE = found->second ;
39123948 Diags.diagnose (DRE->getLoc (), diag::unused_setter_parameter,
39133949 var->getName ());
@@ -3941,6 +3977,9 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
39413977 // produce a fixit hint with a parent map, but this is a lot of effort for
39423978 // a narrow case.
39433979 if (access & RK_CaptureList) {
3980+ if (isUsedInInactive (var))
3981+ continue ;
3982+
39443983 Diags.diagnose (var->getLoc (), diag::capture_never_used,
39453984 var->getName ());
39463985 continue ;
@@ -3954,6 +3993,9 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
39543993 if (auto *pbd = var->getParentPatternBinding ()) {
39553994 if (pbd->getSingleVar () == var && pbd->getInit (0 ) != nullptr &&
39563995 !isa<TypedPattern>(pbd->getPattern (0 ))) {
3996+ if (isUsedInInactive (var))
3997+ continue ;
3998+
39573999 unsigned varKind = var->isLet ();
39584000 SourceRange replaceRange (
39594001 pbd->getStartLoc (),
@@ -3984,6 +4026,9 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
39844026 if (isa<NamedPattern>(LP->getSubPattern ())) {
39854027 auto initExpr = SC->getCond ()[0 ].getInitializer ();
39864028 if (initExpr->getStartLoc ().isValid ()) {
4029+ if (isUsedInInactive (var))
4030+ continue ;
4031+
39874032 unsigned noParens = initExpr->canAppendPostfixExpression ();
39884033
39894034 // If the subexpr is an "as?" cast, we can rewrite it to
@@ -4051,6 +4096,9 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
40514096 });
40524097
40534098 if (foundVP) {
4099+ if (isUsedInInactive (var))
4100+ continue ;
4101+
40544102 unsigned varKind = var->isLet ();
40554103 Diags
40564104 .diagnose (var->getLoc (), diag::variable_never_used,
@@ -4062,6 +4110,9 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
40624110
40634111 // Otherwise, this is something more complex, perhaps
40644112 // let (a,b) = foo()
4113+ if (isUsedInInactive (var))
4114+ continue ;
4115+
40654116 if (isWrittenLet) {
40664117 Diags.diagnose (var->getLoc (),
40674118 diag::immutable_value_never_used_but_assigned,
@@ -4085,6 +4136,9 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
40854136 !isVarDeclPartOfPBDThatHadSomeMutation (var)) {
40864137 SourceLoc FixItLoc = getFixItLocForVarToLet (var);
40874138
4139+ if (isUsedInInactive (var))
4140+ continue ;
4141+
40884142 // If this is a parameter explicitly marked 'var', remove it.
40894143 if (FixItLoc.isInvalid ()) {
40904144 Diags.diagnose (var->getLoc (), diag::variable_never_mutated,
@@ -4113,6 +4167,9 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
41134167
41144168 // If this is a variable that was only written to, emit a warning.
41154169 if ((access & RK_Read) == 0 ) {
4170+ if (isUsedInInactive (var))
4171+ continue ;
4172+
41164173 Diags.diagnose (var->getLoc (), diag::variable_never_read, var->getName ());
41174174 continue ;
41184175 }
@@ -4334,56 +4391,12 @@ ASTWalker::PreWalkResult<Expr *> VarDeclUsageChecker::walkToExprPre(Expr *E) {
43344391 return Action::Continue (E);
43354392}
43364393
4337- // / handle #if directives. All of the active clauses are already walked by the
4338- // / AST walker, but we also want to handle the inactive ones to avoid false
4339- // / positives.
4340- void VarDeclUsageChecker::handleIfConfig (IfConfigDecl *ICD) {
4341- struct ConservativeDeclMarker : public ASTWalker {
4342- VarDeclUsageChecker &VDUC;
4343- SourceFile *SF;
4344-
4345- ConservativeDeclMarker (VarDeclUsageChecker &VDUC)
4346- : VDUC(VDUC), SF(VDUC.DC->getParentSourceFile ()) {}
4347-
4348- MacroWalking getMacroWalkingBehavior () const override {
4349- return MacroWalking::Arguments;
4350- }
4351-
4352- PostWalkResult<Expr *> walkToExprPost (Expr *E) override {
4353- // If we see a bound reference to a decl in an inactive #if block, then
4354- // conservatively mark it read and written. This will silence "variable
4355- // unused" and "could be marked let" warnings for it.
4356- if (auto *DRE = dyn_cast<DeclRefExpr>(E))
4357- VDUC.addMark (DRE->getDecl (), RK_Read | RK_Written);
4358- else if (auto *declRef = dyn_cast<UnresolvedDeclRefExpr>(E)) {
4359- auto name = declRef->getName ();
4360- auto loc = declRef->getLoc ();
4361- if (name.isSimpleName () && loc.isValid ()) {
4362- auto *varDecl = dyn_cast_or_null<VarDecl>(
4363- ASTScope::lookupSingleLocalDecl (SF, name.getFullName (), loc));
4364- if (varDecl)
4365- VDUC.addMark (varDecl, RK_Read|RK_Written);
4366- }
4367- }
4368- return Action::Continue (E);
4369- }
4370- };
4371-
4372- for (auto &clause : ICD->getClauses ()) {
4373- // Active clauses are handled by the normal AST walk.
4374- if (clause.isActive ) continue ;
4375-
4376- for (auto elt : clause.Elements )
4377- elt.walk (ConservativeDeclMarker (*this ));
4378- }
4379- }
4380-
43814394// / Apply the warnings managed by VarDeclUsageChecker to the top level
43824395// / code declarations that haven't been checked yet.
43834396void swift::
43844397performTopLevelDeclDiagnostics (TopLevelCodeDecl *TLCD) {
43854398 auto &ctx = TLCD->getDeclContext ()->getASTContext ();
4386- VarDeclUsageChecker checker (TLCD, ctx.Diags );
4399+ VarDeclUsageChecker checker (TLCD, ctx.Diags , TLCD-> getSourceRange () );
43874400 TLCD->walk (checker);
43884401}
43894402
@@ -4398,7 +4411,7 @@ void swift::performAbstractFuncDeclDiagnostics(AbstractFunctionDecl *AFD) {
43984411 // declared as constants. Skip local functions though, since they will
43994412 // be checked as part of their parent function or TopLevelCodeDecl.
44004413 auto &ctx = AFD->getDeclContext ()->getASTContext ();
4401- VarDeclUsageChecker checker (AFD, ctx.Diags );
4414+ VarDeclUsageChecker checker (AFD, ctx.Diags , AFD-> getBody ()-> getSourceRange () );
44024415 AFD->walk (checker);
44034416 }
44044417
0 commit comments