|
40 | 40 | #include "swift/Basic/SourceManager.h"
|
41 | 41 | #include "swift/Basic/Statistic.h"
|
42 | 42 | #include "swift/Basic/StringExtras.h"
|
| 43 | +#include "swift/ClangImporter/ClangImporter.h" |
| 44 | +#include "swift/ClangImporter/ClangImporterRequests.h" |
43 | 45 | #include "swift/Parse/Lexer.h"
|
44 | 46 | #include "swift/Sema/ConstraintSystem.h"
|
45 | 47 | #include "swift/Sema/IDETypeChecking.h"
|
@@ -6392,6 +6394,132 @@ static void diagnoseMissingMemberImports(const Expr *E, const DeclContext *DC) {
|
6392 | 6394 | const_cast<Expr *>(E)->walk(walker);
|
6393 | 6395 | }
|
6394 | 6396 |
|
| 6397 | +static bool isReturningFRT(const clang::NamedDecl *ND, |
| 6398 | + clang::QualType &outReturnType, ASTContext &Ctx) { |
| 6399 | + if (auto *FD = dyn_cast<clang::FunctionDecl>(ND)) |
| 6400 | + outReturnType = FD->getReturnType(); |
| 6401 | + else if (auto *MD = dyn_cast<clang::ObjCMethodDecl>(ND)) |
| 6402 | + outReturnType = MD->getReturnType(); |
| 6403 | + else |
| 6404 | + return false; |
| 6405 | + |
| 6406 | + clang::QualType pointeeType = outReturnType; |
| 6407 | + if (outReturnType->isPointerType() || outReturnType->isReferenceType()) |
| 6408 | + pointeeType = outReturnType->getPointeeType(); |
| 6409 | + |
| 6410 | + const auto *recordDecl = pointeeType->getAsRecordDecl(); |
| 6411 | + if (!recordDecl) |
| 6412 | + return false; |
| 6413 | + |
| 6414 | + return !importer::hasImmortalAttrs(recordDecl) && |
| 6415 | + evaluateOrDefault(Ctx.evaluator, |
| 6416 | + CxxRecordSemantics({recordDecl, Ctx, nullptr}), |
| 6417 | + {}) == CxxRecordSemanticsKind::Reference; |
| 6418 | +} |
| 6419 | + |
| 6420 | +static bool shouldDiagnoseMissingReturnsRetained(const clang::NamedDecl *ND, |
| 6421 | + clang::QualType retType, |
| 6422 | + ASTContext &Ctx) { |
| 6423 | + if (!Ctx.LangOpts.hasFeature(Feature::WarnUnannotatedReturnOfCxxFrt)) |
| 6424 | + return false; |
| 6425 | + |
| 6426 | + auto attrInfo = importer::ReturnOwnershipInfo(ND); |
| 6427 | + if (attrInfo.hasRetainAttr()) |
| 6428 | + return false; |
| 6429 | + |
| 6430 | + if (importer::matchSwiftAttrOnRecordPtr<bool>( |
| 6431 | + retType, {{"returned_as_unretained_by_default", true}})) |
| 6432 | + return false; |
| 6433 | + |
| 6434 | + if (isa<clang::ObjCMethodDecl>(ND)) |
| 6435 | + // All ObjCMethods can be annotated with ownership attrs |
| 6436 | + return true; |
| 6437 | + |
| 6438 | + if (auto *FD = dyn_cast<clang::FunctionDecl>(ND)) { |
| 6439 | + if (isa<clang::CXXDeductionGuideDecl>(FD)) |
| 6440 | + // Deduction guides don't need ownership attrs because they aren't |
| 6441 | + // functions. |
| 6442 | + return false; |
| 6443 | + |
| 6444 | + if (const auto *methodDecl = dyn_cast<clang::CXXMethodDecl>(FD)) { |
| 6445 | + if (isa<clang::CXXConstructorDecl, clang::CXXDestructorDecl>(methodDecl)) |
| 6446 | + // Ownership attrs are not yet supported for ctors and dtors if FRTs |
| 6447 | + return false; |
| 6448 | + |
| 6449 | + if (methodDecl->isOverloadedOperator()) |
| 6450 | + // Ownership attrs are not yet supported for overloaded operators |
| 6451 | + return false; |
| 6452 | + |
| 6453 | + if (!methodDecl->isUserProvided()) |
| 6454 | + // Implicitly defined methods don't need ownership attrs since users |
| 6455 | + // can't annotate them. |
| 6456 | + return false; |
| 6457 | + } |
| 6458 | + |
| 6459 | + return true; |
| 6460 | + } |
| 6461 | + |
| 6462 | + // Decls that aren't functions or ObjCMethods don't need ownership attrs. |
| 6463 | + return false; |
| 6464 | +} |
| 6465 | + |
| 6466 | +// Diagnose calls to imported C++ functions that return `SWIFT_SHARED_REFERENCE` |
| 6467 | +// types without explicit ownership annotations SWIFT_RETURNS_(UN)RETAINED |
| 6468 | +static void diagnoseCxxFunctionCalls(const Expr *E, const DeclContext *DC) { |
| 6469 | + class DiagnoseWalker : public BaseDiagnosticWalker { |
| 6470 | + ASTContext &Ctx; |
| 6471 | + |
| 6472 | + public: |
| 6473 | + explicit DiagnoseWalker(ASTContext &ctx) : Ctx(ctx) {} |
| 6474 | + |
| 6475 | + PreWalkResult<Expr *> walkToExprPre(Expr *E) override { |
| 6476 | + if (!E) |
| 6477 | + return Action::SkipNode(E); |
| 6478 | + |
| 6479 | + auto *CE = dyn_cast<CallExpr>(E); |
| 6480 | + if (!CE) |
| 6481 | + return Action::Continue(E); |
| 6482 | + |
| 6483 | + auto *func = CE->getCalledValue(/*skipFunctionConversions=*/true); |
| 6484 | + if (!func) |
| 6485 | + return Action::Continue(E); |
| 6486 | + |
| 6487 | + auto *clangDecl = func->getClangDecl(); |
| 6488 | + if (!clangDecl) |
| 6489 | + return Action::Continue(E); |
| 6490 | + |
| 6491 | + auto *ND = dyn_cast<clang::NamedDecl>(clangDecl); |
| 6492 | + if (!ND) |
| 6493 | + return Action::Continue(E); |
| 6494 | + |
| 6495 | + clang::QualType retType; |
| 6496 | + if (!isReturningFRT(ND, retType, Ctx)) |
| 6497 | + return Action::Continue(E); |
| 6498 | + |
| 6499 | + if (shouldDiagnoseMissingReturnsRetained(ND, retType, Ctx)) { |
| 6500 | + SourceLoc diagnosticLoc = func->getLoc(); |
| 6501 | + if (diagnosticLoc.isInvalid() && func->getClangDecl()) { |
| 6502 | + // Fixme: Remove the diagnosticLoc once the source locations of the |
| 6503 | + // objc method declarations are imported correctly. |
| 6504 | + diagnosticLoc = Ctx.getClangModuleLoader()->importSourceLocation( |
| 6505 | + ND->getLocation()); |
| 6506 | + } |
| 6507 | + |
| 6508 | + Ctx.Diags.diagnose(CE->getLoc(), |
| 6509 | + diag::warn_unannotated_cxx_func_returning_frt, func); |
| 6510 | + |
| 6511 | + Ctx.Diags.diagnose(diagnosticLoc, |
| 6512 | + diag::note_unannotated_cxx_func_returning_frt, func); |
| 6513 | + } |
| 6514 | + |
| 6515 | + return Action::Continue(E); |
| 6516 | + } |
| 6517 | + }; |
| 6518 | + |
| 6519 | + DiagnoseWalker walker(DC->getASTContext()); |
| 6520 | + const_cast<Expr *>(E)->walk(walker); |
| 6521 | +} |
| 6522 | + |
6395 | 6523 | //===----------------------------------------------------------------------===//
|
6396 | 6524 | // High-level entry points.
|
6397 | 6525 | //===----------------------------------------------------------------------===//
|
@@ -6423,6 +6551,7 @@ void swift::performSyntacticExprDiagnostics(const Expr *E,
|
6423 | 6551 | diagUnqualifiedAccessToMethodNamedSelf(E, DC);
|
6424 | 6552 | diagnoseDictionaryLiteralDuplicateKeyEntries(E, DC);
|
6425 | 6553 | diagnoseMissingMemberImports(E, DC);
|
| 6554 | + diagnoseCxxFunctionCalls(E, DC); |
6426 | 6555 | }
|
6427 | 6556 |
|
6428 | 6557 | void swift::performStmtDiagnostics(const Stmt *S, DeclContext *DC) {
|
|
0 commit comments