Skip to content

Commit cac979a

Browse files
authored
Merge pull request swiftlang#25977 from roop/sr11037_fixit_platform_condition_kind
[Parser][QoI] Offer fixit for changing the platform condition kind
2 parents 0c9bfaa + cf9bb32 commit cac979a

File tree

5 files changed

+141
-38
lines changed

5 files changed

+141
-38
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//===--- PlatformConditionKinds.def - Kinds of Platform Conditions - C++ ---*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines macros used for macro-metaprogramming with the kinds of
14+
// platform conditions that can be used for conditional compilation.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef PLATFORM_CONDITION
19+
#define PLATFORM_CONDITION(LABEL, IDENTIFIER)
20+
#endif
21+
#ifndef PLATFORM_CONDITION_
22+
#define PLATFORM_CONDITION_(LABEL, IDENTIFIER) PLATFORM_CONDITION(LABEL, "_" IDENTIFIER)
23+
#endif
24+
25+
/// The active os target (OSX, iOS, Linux, etc.)
26+
PLATFORM_CONDITION(OS, "os")
27+
28+
/// The active arch target (x86_64, i386, arm, arm64, etc.)
29+
PLATFORM_CONDITION(Arch, "arch")
30+
31+
/// The active endianness target (big or little)
32+
PLATFORM_CONDITION_(Endianness, "endian")
33+
34+
/// Runtime support (_ObjC or _Native)
35+
PLATFORM_CONDITION_(Runtime, "runtime")
36+
37+
/// Conditional import of module
38+
PLATFORM_CONDITION(CanImport, "canImport")
39+
40+
/// Target Environment (currently just 'simulator' or absent)
41+
PLATFORM_CONDITION(TargetEnvironment, "targetEnvironment")
42+
43+
#undef PLATFORM_CONDITION
44+
#undef PLATFORM_CONDITION_

include/swift/Basic/LangOptions.h

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,8 @@ namespace swift {
3737

3838
/// Kind of implicit platform conditions.
3939
enum class PlatformConditionKind {
40-
/// The active os target (OSX, iOS, Linux, etc.)
41-
OS,
42-
/// The active arch target (x86_64, i386, arm, arm64, etc.)
43-
Arch,
44-
/// The active endianness target (big or little)
45-
Endianness,
46-
/// Runtime support (_ObjC or _Native)
47-
Runtime,
48-
/// Conditional import of module
49-
CanImport,
50-
/// Target Environment (currently just 'simulator' or absent)
51-
TargetEnvironment,
40+
#define PLATFORM_CONDITION(LABEL, IDENTIFIER) LABEL,
41+
#include "swift/AST/PlatformConditionKinds.def"
5242
};
5343

5444
/// Describes which Swift 3 Objective-C inference warnings should be
@@ -437,11 +427,13 @@ namespace swift {
437427
/// Returns true if the given platform condition argument represents
438428
/// a supported target operating system.
439429
///
440-
/// \param suggestions Populated with suggested replacements
430+
/// \param suggestedKind Populated with suggested replacement platform condition
431+
/// \param suggestedValues Populated with suggested replacement values
441432
/// if a match is not found.
442433
static bool checkPlatformConditionSupported(
443434
PlatformConditionKind Kind, StringRef Value,
444-
std::vector<StringRef> &suggestions);
435+
PlatformConditionKind &suggestedKind,
436+
std::vector<StringRef> &suggestedValues);
445437

446438
/// Return a hash code of any components from these options that should
447439
/// contribute to a Swift Bridging PCH hash.

lib/Basic/LangOptions.cpp

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,59 @@ static const StringRef SupportedConditionalCompilationTargetEnvironments[] = {
6565
"simulator",
6666
};
6767

68-
template <size_t N>
69-
bool contains(const StringRef (&Array)[N], const StringRef &V,
70-
std::vector<StringRef> &suggestions) {
68+
static const PlatformConditionKind AllPublicPlatformConditionKinds[] = {
69+
#define PLATFORM_CONDITION(LABEL, IDENTIFIER) PlatformConditionKind::LABEL,
70+
#define PLATFORM_CONDITION_(LABEL, IDENTIFIER)
71+
#include "swift/AST/PlatformConditionKinds.def"
72+
};
73+
74+
ArrayRef<StringRef> getSupportedConditionalCompilationValues(const PlatformConditionKind &Kind) {
75+
switch (Kind) {
76+
case PlatformConditionKind::OS:
77+
return SupportedConditionalCompilationOSs;
78+
case PlatformConditionKind::Arch:
79+
return SupportedConditionalCompilationArches;
80+
case PlatformConditionKind::Endianness:
81+
return SupportedConditionalCompilationEndianness;
82+
case PlatformConditionKind::Runtime:
83+
return SupportedConditionalCompilationRuntimes;
84+
case PlatformConditionKind::CanImport:
85+
return { };
86+
case PlatformConditionKind::TargetEnvironment:
87+
return SupportedConditionalCompilationTargetEnvironments;
88+
}
89+
}
90+
91+
PlatformConditionKind suggestedPlatformConditionKind(PlatformConditionKind Kind, const StringRef &V,
92+
std::vector<StringRef> &suggestedValues) {
93+
std::string lower = V.lower();
94+
for (const PlatformConditionKind& candidateKind : AllPublicPlatformConditionKinds) {
95+
if (candidateKind != Kind) {
96+
auto supportedValues = getSupportedConditionalCompilationValues(candidateKind);
97+
for (const StringRef& candidateValue : supportedValues) {
98+
if (candidateValue.lower() == lower) {
99+
suggestedValues.clear();
100+
if (candidateValue != V) {
101+
suggestedValues.emplace_back(candidateValue);
102+
}
103+
return candidateKind;
104+
}
105+
}
106+
}
107+
}
108+
return Kind;
109+
}
110+
111+
bool isMatching(PlatformConditionKind Kind, const StringRef &V,
112+
PlatformConditionKind &suggestedKind, std::vector<StringRef> &suggestions) {
71113
// Compare against known values, ignoring case to avoid penalizing
72114
// characters with incorrect case.
73115
unsigned minDistance = std::numeric_limits<unsigned>::max();
74116
std::string lower = V.lower();
75-
for (const StringRef& candidate : Array) {
117+
auto supportedValues = getSupportedConditionalCompilationValues(Kind);
118+
for (const StringRef& candidate : supportedValues) {
76119
if (candidate == V) {
120+
suggestedKind = Kind;
77121
suggestions.clear();
78122
return true;
79123
}
@@ -85,28 +129,21 @@ bool contains(const StringRef (&Array)[N], const StringRef &V,
85129
if (distance == minDistance)
86130
suggestions.emplace_back(candidate);
87131
}
132+
suggestedKind = suggestedPlatformConditionKind(Kind, V, suggestions);
88133
return false;
89134
}
90135

91136
bool LangOptions::
92137
checkPlatformConditionSupported(PlatformConditionKind Kind, StringRef Value,
93-
std::vector<StringRef> &suggestions) {
138+
PlatformConditionKind &suggestedKind,
139+
std::vector<StringRef> &suggestedValues) {
94140
switch (Kind) {
95141
case PlatformConditionKind::OS:
96-
return contains(SupportedConditionalCompilationOSs, Value,
97-
suggestions);
98142
case PlatformConditionKind::Arch:
99-
return contains(SupportedConditionalCompilationArches, Value,
100-
suggestions);
101143
case PlatformConditionKind::Endianness:
102-
return contains(SupportedConditionalCompilationEndianness, Value,
103-
suggestions);
104144
case PlatformConditionKind::Runtime:
105-
return contains(SupportedConditionalCompilationRuntimes, Value,
106-
suggestions);
107145
case PlatformConditionKind::TargetEnvironment:
108-
return contains(SupportedConditionalCompilationTargetEnvironments, Value,
109-
suggestions);
146+
return isMatching(Kind, Value, suggestedKind, suggestedValues);
110147
case PlatformConditionKind::CanImport:
111148
// All importable names are valid.
112149
// FIXME: Perform some kind of validation of the string?

lib/Parse/ParseIfConfig.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,21 @@ namespace {
3838
static
3939
Optional<PlatformConditionKind> getPlatformConditionKind(StringRef Name) {
4040
return llvm::StringSwitch<Optional<PlatformConditionKind>>(Name)
41-
.Case("os", PlatformConditionKind::OS)
42-
.Case("arch", PlatformConditionKind::Arch)
43-
.Case("_endian", PlatformConditionKind::Endianness)
44-
.Case("_runtime", PlatformConditionKind::Runtime)
45-
.Case("canImport", PlatformConditionKind::CanImport)
46-
.Case("targetEnvironment", PlatformConditionKind::TargetEnvironment)
41+
#define PLATFORM_CONDITION(LABEL, IDENTIFIER) \
42+
.Case(IDENTIFIER, PlatformConditionKind::LABEL)
43+
#include "swift/AST/PlatformConditionKinds.def"
4744
.Default(None);
4845
}
4946

47+
/// Get platform condition name from PlatformConditionKind.
48+
static StringRef getPlatformConditionName(PlatformConditionKind Kind) {
49+
switch (Kind) {
50+
#define PLATFORM_CONDITION(LABEL, IDENTIFIER) \
51+
case PlatformConditionKind::LABEL: return IDENTIFIER;
52+
#include "swift/AST/PlatformConditionKinds.def"
53+
}
54+
}
55+
5056
/// Extract source text of the expression.
5157
static StringRef extractExprSource(SourceManager &SM, Expr *E) {
5258
CharSourceRange Range =
@@ -265,9 +271,10 @@ class ValidateIfConfigCondition :
265271
return nullptr;
266272
}
267273

268-
std::vector<StringRef> suggestions;
274+
PlatformConditionKind suggestedKind = *Kind;
275+
std::vector<StringRef> suggestedValues;
269276
if (!LangOptions::checkPlatformConditionSupported(*Kind, *ArgStr,
270-
suggestions)) {
277+
suggestedKind, suggestedValues)) {
271278
if (Kind == PlatformConditionKind::Runtime) {
272279
// Error for _runtime()
273280
D.diagnose(Arg->getLoc(),
@@ -294,7 +301,12 @@ class ValidateIfConfigCondition :
294301
auto Loc = Arg->getLoc();
295302
D.diagnose(Loc, diag::unknown_platform_condition_argument,
296303
DiagName, *KindName);
297-
for (auto suggestion : suggestions)
304+
if (suggestedKind != *Kind) {
305+
auto suggestedKindName = getPlatformConditionName(suggestedKind);
306+
D.diagnose(Loc, diag::note_typo_candidate, suggestedKindName)
307+
.fixItReplace(E->getFn()->getSourceRange(), suggestedKindName);
308+
}
309+
for (auto suggestion : suggestedValues)
298310
D.diagnose(Loc, diag::note_typo_candidate, suggestion)
299311
.fixItReplace(Arg->getSourceRange(), suggestion);
300312
}

test/Parse/ConditionalCompilation/basicParseErrors.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,24 @@ func undefinedFunc() // ignored.
139139
#endif
140140
undefinedFunc() // expected-error {{use of unresolved identifier 'undefinedFunc'}}
141141

142+
#if os(simulator) // expected-warning {{unknown operating system for build configuration 'os'}} expected-note {{did you mean 'targetEnvironment'}} {{5-7=targetEnvironment}}
143+
#endif
144+
145+
#if arch(iOS) // expected-warning {{unknown architecture for build configuration 'arch'}} expected-note {{did you mean 'os'}} {{5-9=os}}
146+
#endif
147+
148+
#if _endian(arm64) // expected-warning {{unknown endianness for build configuration '_endian'}} expected-note {{did you mean 'arch'}} {{5-12=arch}}
149+
#endif
150+
151+
#if targetEnvironment(_ObjC) // expected-warning {{unknown target environment for build configuration 'targetEnvironment'}} expected-note {{did you mean 'simulator'}} {{23-28=simulator}}
152+
#endif
153+
154+
#if os(iOS) || os(simulator) // expected-warning {{unknown operating system for build configuration 'os'}} expected-note {{did you mean 'targetEnvironment'}} {{16-18=targetEnvironment}}
155+
#endif
156+
157+
#if arch(ios) // expected-warning {{unknown architecture for build configuration 'arch'}} expected-note {{did you mean 'os'}} {{5-9=os}} expected-note {{did you mean 'iOS'}} {{10-13=iOS}}
158+
#endif
159+
142160
#if FOO
143161
#else if BAR
144162
// expected-error@-1 {{unexpected 'if' keyword following '#else' conditional compilation directive; did you mean '#elseif'?}} {{1-9=#elseif}}

0 commit comments

Comments
 (0)