Mercurial > hg > CbC > CbC_llvm
view clang-tools-extra/clang-tidy/objc/NSInvocationArgumentLifetimeCheck.cpp @ 265:31d058e83c98 current
fix llvm again
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Sat, 14 Oct 2023 10:13:49 +0900 |
parents | 1f2b6ac9f198 |
children |
line wrap: on
line source
//===--- NSInvocationArgumentLifetimeCheck.cpp - clang-tidy ---------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "NSInvocationArgumentLifetimeCheck.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ComputeDependence.h" #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchersMacros.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/StringRef.h" #include <optional> using namespace clang::ast_matchers; namespace clang::tidy::objc { namespace { static constexpr StringRef WeakText = "__weak"; static constexpr StringRef StrongText = "__strong"; static constexpr StringRef UnsafeUnretainedText = "__unsafe_unretained"; /// Matches ObjCIvarRefExpr, DeclRefExpr, or MemberExpr that reference /// Objective-C object (or block) variables or fields whose object lifetimes /// are not __unsafe_unretained. AST_POLYMORPHIC_MATCHER(isObjCManagedLifetime, AST_POLYMORPHIC_SUPPORTED_TYPES(ObjCIvarRefExpr, DeclRefExpr, MemberExpr)) { QualType QT = Node.getType(); return QT->isScalarType() && (QT->getScalarTypeKind() == Type::STK_ObjCObjectPointer || QT->getScalarTypeKind() == Type::STK_BlockPointer) && QT.getQualifiers().getObjCLifetime() > Qualifiers::OCL_ExplicitNone; } static std::optional<FixItHint> fixItHintReplacementForOwnershipString(StringRef Text, CharSourceRange Range, StringRef Ownership) { size_t Index = Text.find(Ownership); if (Index == StringRef::npos) return std::nullopt; SourceLocation Begin = Range.getBegin().getLocWithOffset(Index); SourceLocation End = Begin.getLocWithOffset(Ownership.size()); return FixItHint::CreateReplacement(SourceRange(Begin, End), UnsafeUnretainedText); } static std::optional<FixItHint> fixItHintForVarDecl(const VarDecl *VD, const SourceManager &SM, const LangOptions &LangOpts) { assert(VD && "VarDecl parameter must not be null"); // Don't provide fix-its for any parameter variables at this time. if (isa<ParmVarDecl>(VD)) return std::nullopt; // Currently there is no way to directly get the source range for the // __weak/__strong ObjC lifetime qualifiers, so it's necessary to string // search in the source code. CharSourceRange Range = Lexer::makeFileCharRange( CharSourceRange::getTokenRange(VD->getSourceRange()), SM, LangOpts); if (Range.isInvalid()) { // An invalid range likely means inside a macro, in which case don't supply // a fix-it. return std::nullopt; } StringRef VarDeclText = Lexer::getSourceText(Range, SM, LangOpts); if (std::optional<FixItHint> Hint = fixItHintReplacementForOwnershipString(VarDeclText, Range, WeakText)) return Hint; if (std::optional<FixItHint> Hint = fixItHintReplacementForOwnershipString( VarDeclText, Range, StrongText)) return Hint; return FixItHint::CreateInsertion(Range.getBegin(), "__unsafe_unretained "); } } // namespace void NSInvocationArgumentLifetimeCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( traverse( TK_AsIs, objcMessageExpr( hasReceiverType(asString("NSInvocation *")), anyOf(hasSelector("getArgument:atIndex:"), hasSelector("getReturnValue:")), hasArgument( 0, anyOf(hasDescendant(memberExpr(isObjCManagedLifetime())), hasDescendant(objcIvarRefExpr(isObjCManagedLifetime())), hasDescendant( // Reference to variables, but when dereferencing // to ivars/fields a more-descendent variable // reference (e.g. self) may match with strong // object lifetime, leading to an incorrect match. // Exclude these conditions. declRefExpr(to(varDecl().bind("var")), unless(hasParent(implicitCastExpr())), isObjCManagedLifetime()))))) .bind("call")), this); } void NSInvocationArgumentLifetimeCheck::check( const MatchFinder::MatchResult &Result) { const auto *MatchedExpr = Result.Nodes.getNodeAs<ObjCMessageExpr>("call"); auto Diag = diag(MatchedExpr->getArg(0)->getBeginLoc(), "NSInvocation %objcinstance0 should only pass pointers to " "objects with ownership __unsafe_unretained") << MatchedExpr->getSelector(); // Only provide fix-it hints for references to local variables; fixes for // instance variable references don't have as clear an automated fix. const auto *VD = Result.Nodes.getNodeAs<VarDecl>("var"); if (!VD) return; if (auto Hint = fixItHintForVarDecl(VD, *Result.SourceManager, Result.Context->getLangOpts())) Diag << *Hint; } } // namespace clang::tidy::objc