18
18
#include "CSDiag.h"
19
19
#include "CalleeCandidateInfo.h"
20
20
#include "MiscDiagnostics.h"
21
+ #include "TypoCorrection.h"
21
22
#include "swift/AST/ASTWalker.h"
22
23
#include "swift/AST/GenericEnvironment.h"
23
24
#include "swift/AST/Initializer.h"
@@ -1330,25 +1331,20 @@ diagnoseTypeMemberOnInstanceLookup(Type baseObjTy,
1330
1331
/// lower case counterparts are identical.
1331
1332
/// - DeclName is valid when such a correct case is found; invalid otherwise.
1332
1333
static DeclName
1333
- findCorrectEnumCaseName(Type Ty, LookupResult &Result ,
1334
+ findCorrectEnumCaseName(Type Ty, TypoCorrectionResults &corrections ,
1334
1335
DeclName memberName) {
1335
1336
if (!memberName.isSimpleName())
1336
1337
return DeclName();
1337
1338
if (!Ty->is<EnumType>() &&
1338
1339
!Ty->is<BoundGenericEnumType>())
1339
1340
return DeclName();
1340
- llvm::SmallVector<DeclName, 4> candidates;
1341
- for (auto &correction : Result) {
1342
- DeclName correctName = correction.getValueDecl()->getFullName();
1343
- if (!isa<EnumElementDecl>(correction.getValueDecl()))
1344
- continue;
1345
- if (correctName.getBaseIdentifier().str().equals_lower(
1346
- memberName.getBaseIdentifier().str()))
1347
- candidates.push_back(correctName.getBaseName());
1348
- }
1349
- if (candidates.size() == 1)
1350
- return candidates.front();
1351
- return DeclName();
1341
+ auto candidate =
1342
+ corrections.getUniqueCandidateMatching([&](ValueDecl *candidate) {
1343
+ return (isa<EnumElementDecl>(candidate) &&
1344
+ candidate->getFullName().getBaseIdentifier().str()
1345
+ .equals_lower(memberName.getBaseIdentifier().str()));
1346
+ });
1347
+ return (candidate ? candidate->getFullName() : DeclName());
1352
1348
}
1353
1349
1354
1350
/// Given a result of name lookup that had no viable results, diagnose the
@@ -1362,12 +1358,10 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy,
1362
1358
1363
1359
// If we found no results at all, mention that fact.
1364
1360
if (result.UnviableCandidates.empty()) {
1365
- LookupResult correctionResults ;
1361
+ TypoCorrectionResults corrections(CS.TC, memberName, nameLoc) ;
1366
1362
auto tryTypoCorrection = [&] {
1367
1363
CS.TC.performTypoCorrection(CS.DC, DeclRefKind::Ordinary, baseObjTy,
1368
- memberName, nameLoc.getBaseNameLoc(),
1369
- defaultMemberLookupOptions,
1370
- correctionResults);
1364
+ defaultMemberLookupOptions, corrections);
1371
1365
};
1372
1366
1373
1367
// TODO: This should handle tuple member lookups, like x.1231 as well.
@@ -1382,48 +1376,69 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy,
1382
1376
tryTypoCorrection();
1383
1377
1384
1378
if (DeclName rightName = findCorrectEnumCaseName(instanceTy,
1385
- correctionResults ,
1379
+ corrections ,
1386
1380
memberName)) {
1387
1381
diagnose(loc, diag::could_not_find_enum_case, instanceTy,
1388
1382
memberName, rightName)
1389
1383
.fixItReplace(nameLoc.getBaseNameLoc(),
1390
1384
rightName.getBaseIdentifier().str());
1391
1385
return;
1392
1386
}
1393
- diagnose(loc, diag::could_not_find_type_member, instanceTy, memberName)
1394
- .highlight(baseRange).highlight(nameLoc.getSourceRange());
1387
+
1388
+ if (auto correction = corrections.claimUniqueCorrection()) {
1389
+ auto diagnostic =
1390
+ diagnose(loc, diag::could_not_find_type_member_corrected,
1391
+ instanceTy, memberName, correction->CorrectedName);
1392
+ diagnostic.highlight(baseRange).highlight(nameLoc.getSourceRange());
1393
+ correction->addFixits(diagnostic);
1394
+ } else {
1395
+ diagnose(loc, diag::could_not_find_type_member, instanceTy, memberName)
1396
+ .highlight(baseRange).highlight(nameLoc.getSourceRange());
1397
+ }
1395
1398
} else if (auto moduleTy = baseObjTy->getAs<ModuleType>()) {
1396
1399
diagnose(baseExpr->getLoc(), diag::no_member_of_module,
1397
1400
moduleTy->getModule()->getName(), memberName)
1398
1401
.highlight(baseRange)
1399
1402
.highlight(nameLoc.getSourceRange());
1400
1403
return;
1401
1404
} else {
1402
- diagnose(loc, diag::could_not_find_value_member,
1403
- baseObjTy, memberName)
1404
- .highlight(baseRange).highlight(nameLoc.getSourceRange());
1405
- tryTypoCorrection();
1405
+ auto emitBasicError = [&] {
1406
+ diagnose(loc, diag::could_not_find_value_member,
1407
+ baseObjTy, memberName)
1408
+ .highlight(baseRange).highlight(nameLoc.getSourceRange());
1409
+ };
1406
1410
1407
1411
// Check for a few common cases that can cause missing members.
1408
1412
if (baseObjTy->is<EnumType>() && memberName.isSimpleName("rawValue")) {
1409
1413
auto loc = baseObjTy->castTo<EnumType>()->getDecl()->getNameLoc();
1410
1414
if (loc.isValid()) {
1415
+ emitBasicError();
1411
1416
diagnose(loc, diag::did_you_mean_raw_type);
1412
- return; // Always prefer this over typo corrections.
1417
+ return;
1413
1418
}
1414
1419
} else if (baseObjTy->isAny()) {
1420
+ emitBasicError();
1415
1421
diagnose(loc, diag::any_as_anyobject_fixit)
1416
1422
.fixItInsert(baseExpr->getStartLoc(), "(")
1417
1423
.fixItInsertAfter(baseExpr->getEndLoc(), " as AnyObject)");
1418
1424
return;
1419
1425
}
1426
+
1427
+ tryTypoCorrection();
1428
+
1429
+ if (auto correction = corrections.claimUniqueCorrection()) {
1430
+ auto diagnostic =
1431
+ diagnose(loc, diag::could_not_find_value_member_corrected,
1432
+ baseObjTy, memberName, correction->CorrectedName);
1433
+ diagnostic.highlight(baseRange).highlight(nameLoc.getSourceRange());
1434
+ correction->addFixits(diagnostic);
1435
+ } else {
1436
+ emitBasicError();
1437
+ }
1420
1438
}
1421
1439
1422
1440
// Note all the correction candidates.
1423
- for (auto &correction : correctionResults) {
1424
- CS.TC.noteTypoCorrection(memberName, nameLoc,
1425
- correction.getValueDecl());
1426
- }
1441
+ corrections.noteAllCandidates();
1427
1442
1428
1443
// TODO: recover?
1429
1444
return;
@@ -6803,11 +6818,13 @@ static bool diagnoseKeyPathComponents(ConstraintSystem &CS, KeyPathExpr *KPE,
6803
6818
// If we didn't find anything, try to apply typo-correction.
6804
6819
bool resultsAreFromTypoCorrection = false;
6805
6820
if (!lookup) {
6821
+ TypoCorrectionResults corrections(TC, componentName,
6822
+ DeclNameLoc(componentNameLoc));
6823
+
6806
6824
TC.performTypoCorrection(CS.DC, DeclRefKind::Ordinary, lookupType,
6807
- componentName, componentNameLoc,
6808
6825
(lookupType ? defaultMemberTypeLookupOptions
6809
6826
: defaultUnqualifiedLookupOptions),
6810
- lookup );
6827
+ corrections );
6811
6828
6812
6829
if (currentType)
6813
6830
TC.diagnose(componentNameLoc, diag::could_not_find_type_member,
@@ -6817,10 +6834,8 @@ static bool diagnoseKeyPathComponents(ConstraintSystem &CS, KeyPathExpr *KPE,
6817
6834
componentName, false);
6818
6835
6819
6836
// Note all the correction candidates.
6820
- for (auto &result : lookup) {
6821
- TC.noteTypoCorrection(componentName, DeclNameLoc(componentNameLoc),
6822
- result.getValueDecl());
6823
- }
6837
+ corrections.noteAllCandidates();
6838
+ corrections.addAllCandidatesToLookup(lookup);
6824
6839
6825
6840
isInvalid = true;
6826
6841
if (!lookup)
0 commit comments