-
Notifications
You must be signed in to change notification settings - Fork 10.6k
warn on empty OptionSet static constants #27089
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
1a5a47f
acb99fb
9c9a327
6152f8e
5ae0484
76a8fa6
a665524
bc109fd
1ba47ff
cc0afc0
13acf10
2104984
bc308e0
06c0571
c6063b2
2d5438d
4250d7f
b7e059d
f7f9086
138d731
d70b0a4
b276a7e
1da9215
67cd809
9cc2d65
d04663a
0ba2980
9090d7f
cba8684
3d9573f
3dba00f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2360,6 +2360,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> { | |
|
|
||
| TC.checkDeclAttributes(VD); | ||
|
|
||
| checkForEmptyOptionSet(VD); | ||
|
|
||
| triggerAccessorSynthesis(TC, VD); | ||
|
|
||
| // Under the Swift 3 inference rules, if we have @IBInspectable or | ||
|
|
@@ -2383,6 +2385,42 @@ class DeclChecker : public DeclVisitor<DeclChecker> { | |
| if (VD->getAttrs().hasAttribute<DynamicReplacementAttr>()) | ||
| TC.checkDynamicReplacementAttribute(VD); | ||
| } | ||
|
|
||
| void checkForEmptyOptionSet(VarDecl *VD) { | ||
|
||
| if (!VD->isStatic()) | ||
| return; | ||
|
||
| auto DC = VD->getDeclContext(); | ||
| auto protocols = DC->getLocalProtocols(); | ||
|
||
| auto conformsToOptionSet = false; | ||
| for (auto protocol : protocols) { | ||
| if (protocol->isSpecificProtocol(KnownProtocolKind::OptionSet)) { | ||
| conformsToOptionSet = true; | ||
| break; | ||
| } | ||
| } | ||
| if (!conformsToOptionSet) | ||
| return; | ||
| auto type = VD->getType(); | ||
| if (!type->isEqual(DC->getSelfTypeInContext())) | ||
| return; | ||
| auto PBD = VD->getParentPatternBinding(); | ||
| if (!PBD) | ||
| return; | ||
| for (auto entry : PBD->getPatternList()) { | ||
|
||
| auto ctor = dyn_cast<CallExpr>(entry.getInit()); | ||
| if (!ctor) continue; | ||
|
||
| auto argLabels = ctor->getArgumentLabels(); | ||
| if (!argLabels.front().is(StringRef("rawValue"))) continue; | ||
|
||
| auto *args = cast<TupleExpr>(ctor->getArg()); | ||
| auto intArg = dyn_cast<IntegerLiteralExpr>(args->getElement(0)); | ||
| if (!intArg) continue; | ||
| auto val = intArg->getValue(); | ||
| if (val == 0) { | ||
| auto loc = VD->getLoc(); | ||
| TC.diagnose(loc, diag::option_set_zero_constant, type); | ||
|
||
| } | ||
| } | ||
| } | ||
|
|
||
| void visitBoundVars(Pattern *P) { | ||
| P->forEachVariable([&] (VarDecl *VD) { this->visitBoundVariable(VD); }); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| struct MyOptions: OptionSet { | ||
| var rawValue: Int | ||
| static let none = MyOptions(rawValue: 0) // expected-warning {{'static let' constant inside 'MyOptions' that conforms to OptionSet produces an empty option set}} | ||
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can drop "that conforms to OptionSet". You've already got "option set" in the diagnostic text, and the type name probably has to do with options already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be simpler to say
%0 %1 produces an empty option setwhere%0isDescriptiveDeclKindand%1is anIdentifier(property name). Example:static property 'foo' produces an empty option set.