Skip to content

Commit bbecb33

Browse files
authored
Merge pull request #4532 from jtbandes/suggestions
[QoI] offer typo correction for platform conditionals
2 parents ca7021e + 49f5251 commit bbecb33

File tree

6 files changed

+85
-20
lines changed

6 files changed

+85
-20
lines changed

include/swift/AST/DiagnosticsCommon.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ ERROR(func_decl_without_brace,PointsToFirstBadToken,
7979
NOTE(convert_let_to_var,none,
8080
"change 'let' to 'var' to make it mutable", ())
8181

82+
NOTE(note_typo_candidate,none,
83+
"did you mean '%0'?", (StringRef))
8284

8385
#ifndef DIAG_NO_UNDEF
8486
# if defined(DIAG)

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -595,8 +595,6 @@ ERROR(use_undeclared_type,none,
595595
"use of undeclared type %0", (Identifier))
596596
ERROR(use_undeclared_type_did_you_mean,none,
597597
"use of undeclared type %0; did you mean to use '%1'?", (Identifier, StringRef))
598-
NOTE(note_typo_candidate,none,
599-
"did you mean '%0'?", (StringRef))
600598
NOTE(note_typo_candidate_implicit_member,none,
601599
"did you mean the implicitly-synthesized %1 '%0'?", (StringRef, StringRef))
602600
NOTE(note_remapped_type,none,

include/swift/Basic/LangOptions.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "llvm/ADT/StringRef.h"
2727
#include "llvm/ADT/Triple.h"
2828
#include <string>
29+
#include <vector>
2930

3031
namespace swift {
3132
/// \brief A collection of options that affect the language dialect and
@@ -239,15 +240,27 @@ namespace swift {
239240
///
240241
/// Note that this also canonicalizes the OS name if the check returns
241242
/// true.
242-
static bool checkPlatformConditionOS(StringRef &OSName);
243+
///
244+
/// \param suggestions Populated with suggested replacements
245+
/// if a match is not found.
246+
static bool checkPlatformConditionOS(
247+
StringRef &OSName, std::vector<StringRef> &suggestions);
243248

244249
/// Returns true if the 'arch' platform condition argument represents
245250
/// a supported target architecture.
246-
static bool isPlatformConditionArchSupported(StringRef ArchName);
251+
///
252+
/// \param suggestions Populated with suggested replacements
253+
/// if a match is not found.
254+
static bool isPlatformConditionArchSupported(
255+
StringRef ArchName, std::vector<StringRef> &suggestions);
247256

248257
/// Returns true if the 'endian' platform condition argument represents
249258
/// a supported target endianness.
250-
static bool isPlatformConditionEndiannessSupported(StringRef endianness);
259+
///
260+
/// \param suggestions Populated with suggested replacements
261+
/// if a match is not found.
262+
static bool isPlatformConditionEndiannessSupported(
263+
StringRef endianness, std::vector<StringRef> &suggestions);
251264

252265
private:
253266
llvm::SmallVector<std::pair<std::string, std::string>, 3>

lib/Basic/LangOptions.cpp

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@
2020
#include "swift/Config.h"
2121
#include "llvm/ADT/SmallString.h"
2222
#include "llvm/Support/raw_ostream.h"
23+
#include <limits.h>
2324

2425
using namespace swift;
2526

2627
static const StringRef SupportedConditionalCompilationOSs[] = {
2728
"OSX",
29+
"macOS",
2830
"tvOS",
2931
"watchOS",
3032
"iOS",
@@ -50,25 +52,52 @@ static const StringRef SupportedConditionalCompilationEndianness[] = {
5052
"big"
5153
};
5254

53-
template <typename Type, size_t N>
54-
bool contains(const Type (&Array)[N], const Type &V) {
55-
return std::find(std::begin(Array), std::end(Array), V) != std::end(Array);
55+
template <size_t N>
56+
bool contains(const StringRef (&Array)[N], const StringRef &V,
57+
std::vector<StringRef> &suggestions) {
58+
// Compare against known values, ignoring case to avoid penalizing
59+
// characters with incorrect case.
60+
unsigned minDistance = std::numeric_limits<unsigned>::max();
61+
std::string lower = V.lower();
62+
for (const StringRef& candidate : Array) {
63+
if (candidate == V) {
64+
suggestions.clear();
65+
return true;
66+
}
67+
unsigned distance = StringRef(lower).edit_distance(candidate.lower());
68+
if (distance < minDistance) {
69+
suggestions.clear();
70+
minDistance = distance;
71+
}
72+
if (distance == minDistance)
73+
suggestions.emplace_back(candidate);
74+
}
75+
return false;
5676
}
5777

58-
bool LangOptions::checkPlatformConditionOS(StringRef &OSName) {
78+
bool LangOptions::checkPlatformConditionOS(
79+
StringRef &OSName, std::vector<StringRef> &suggestions) {
5980
if (OSName == "macOS")
6081
OSName = "OSX";
61-
return contains(SupportedConditionalCompilationOSs, OSName);
82+
return contains(SupportedConditionalCompilationOSs,
83+
OSName,
84+
suggestions);
6285
}
6386

6487
bool
65-
LangOptions::isPlatformConditionArchSupported(StringRef ArchName) {
66-
return contains(SupportedConditionalCompilationArches, ArchName);
88+
LangOptions::isPlatformConditionArchSupported(
89+
StringRef ArchName, std::vector<StringRef> &suggestions) {
90+
return contains(SupportedConditionalCompilationArches,
91+
ArchName,
92+
suggestions);
6793
}
6894

6995
bool
70-
LangOptions::isPlatformConditionEndiannessSupported(StringRef Endianness) {
71-
return contains(SupportedConditionalCompilationEndianness, Endianness);
96+
LangOptions::isPlatformConditionEndiannessSupported(
97+
StringRef Endianness, std::vector<StringRef> &suggestions) {
98+
return contains(SupportedConditionalCompilationEndianness,
99+
Endianness,
100+
suggestions);
72101
}
73102

74103
StringRef

lib/Parse/ParseStmt.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/Parse/Parser.h"
1818
#include "swift/AST/Attr.h"
1919
#include "swift/AST/Decl.h"
20+
#include "swift/Basic/Defer.h"
2021
#include "swift/Basic/Fallthrough.h"
2122
#include "swift/Basic/Version.h"
2223
#include "swift/Parse/Lexer.h"
@@ -1709,20 +1710,32 @@ Parser::classifyConditionalCompilationExpr(Expr *condition,
17091710
diag::unsupported_platform_runtime_condition_argument);
17101711
return ConditionalCompilationExprState::error();
17111712
}
1713+
1714+
std::vector<StringRef> suggestions;
1715+
SWIFT_DEFER {
1716+
for (const StringRef& suggestion : suggestions) {
1717+
D.diagnose(UDRE->getLoc(), diag::note_typo_candidate,
1718+
suggestion)
1719+
.fixItReplace(UDRE->getSourceRange(), suggestion);
1720+
}
1721+
};
17121722
if (fnName == "os") {
1713-
if (!LangOptions::checkPlatformConditionOS(argument)) {
1723+
if (!LangOptions::checkPlatformConditionOS(argument,
1724+
suggestions)) {
17141725
D.diagnose(UDRE->getLoc(), diag::unknown_platform_condition_argument,
17151726
"operating system", fnName);
17161727
return ConditionalCompilationExprState::error();
17171728
}
17181729
} else if (fnName == "arch") {
1719-
if (!LangOptions::isPlatformConditionArchSupported(argument)) {
1730+
if (!LangOptions::isPlatformConditionArchSupported(argument,
1731+
suggestions)) {
17201732
D.diagnose(UDRE->getLoc(), diag::unknown_platform_condition_argument,
17211733
"architecture", fnName);
17221734
return ConditionalCompilationExprState::error();
17231735
}
17241736
} else if (fnName == "_endian") {
1725-
if (!LangOptions::isPlatformConditionEndiannessSupported(argument)) {
1737+
if (!LangOptions::isPlatformConditionEndiannessSupported(argument,
1738+
suggestions)) {
17261739
D.diagnose(UDRE->getLoc(), diag::unknown_platform_condition_argument,
17271740
"endianness", fnName);
17281741
}

test/Parse/ConditionalCompilation/basicParseErrors.swift

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,23 @@ struct S {
5656
#else
5757
#endif
5858

59-
#if os(youOS) // expected-warning {{unknown operating system for build configuration 'os'}}
59+
#if os(ios) // expected-warning {{unknown operating system for build configuration 'os'}} expected-note{{did you mean 'iOS'?}} {{8-11=iOS}}
6060
#endif
6161

62-
#if arch(leg) // expected-warning {{unknown architecture for build configuration 'arch'}}
62+
#if os(uOS) // expected-warning {{unknown operating system for build configuration 'os'}} expected-note{{did you mean 'iOS'?}} {{8-11=iOS}}
6363
#endif
6464

65-
#if _endian(mid) // expected-warning {{unknown endianness for build configuration '_endian'}}
65+
#if os(xxxxxxd) // expected-warning {{unknown operating system for build configuration 'os'}}
66+
// expected-note@-1{{did you mean 'Linux'?}} {{8-15=Linux}}
67+
// expected-note@-2{{did you mean 'FreeBSD'?}} {{8-15=FreeBSD}}
68+
// expected-note@-3{{did you mean 'Android'?}} {{8-15=Android}}
69+
// expected-note@-4{{did you mean 'OSX'?}} {{8-15=OSX}}
70+
#endif
71+
72+
#if arch(leg) // expected-warning {{unknown architecture for build configuration 'arch'}} expected-note{{did you mean 'arm'?}} {{10-13=arm}}
73+
#endif
74+
75+
#if _endian(mid) // expected-warning {{unknown endianness for build configuration '_endian'}} expected-note{{did you mean 'big'?}} {{13-16=big}}
6676
#endif
6777

6878
LABEL: #if true // expected-error {{expected statement}}

0 commit comments

Comments
 (0)