diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-12-17 20:41:09 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-12-17 20:41:09 +0000 |
commit | 312c0ed19cc5276a17bacf2120097bec4515b0f1 (patch) | |
tree | e6e4a4163840b73ba54bb0d3b70ee4899e4b7434 /clang/lib/StaticAnalyzer | |
parent | b1c73532ee8997fe5dfbeb7d223027bdf99758a0 (diff) | |
download | src-312c0ed19cc5276a17bacf2120097bec4515b0f1.tar.gz src-312c0ed19cc5276a17bacf2120097bec4515b0f1.zip |
Diffstat (limited to 'clang/lib/StaticAnalyzer')
17 files changed, 224 insertions, 40 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp index bd6655cc1e3f..fedc6db3723a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp @@ -1045,8 +1045,8 @@ bool ObjCDeallocChecker::isReleasedByCIFilterDealloc( StringRef IvarName = PropImpl->getPropertyIvarDecl()->getName(); const char *ReleasePrefix = "input"; - if (!(PropName.startswith(ReleasePrefix) || - IvarName.startswith(ReleasePrefix))) { + if (!(PropName.starts_with(ReleasePrefix) || + IvarName.starts_with(ReleasePrefix))) { return false; } diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp index dbba12bb4355..afc5e6b48008 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -140,7 +140,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { if (!II) // if no identifier, not a simple C function return; StringRef Name = II->getName(); - if (Name.startswith("__builtin_")) + if (Name.starts_with("__builtin_")) Name = Name.substr(10); // Set the evaluation function by switching on the callee name. @@ -763,7 +763,7 @@ void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE, enum { DEPR_ONLY = -1, UNKNOWN_CALL = -2 }; StringRef Name = FD->getIdentifier()->getName(); - if (Name.startswith("__builtin_")) + if (Name.starts_with("__builtin_")) Name = Name.substr(10); int ArgIndex = diff --git a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index 5f44c9476928..86f446fc411c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -183,7 +183,7 @@ public: // Files autogenerated by DriverKit IIG contain some dead stores that // we don't want to report. - if (Data.startswith("/* iig")) + if (Data.starts_with("/* iig")) return true; return false; diff --git a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp index 14433d06c2d0..7c51673422a0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp @@ -159,6 +159,9 @@ void EnumCastOutOfRangeChecker::checkPreStmt(const CastExpr *CE, // Every initialization an enum with a fixed underlying type but without any // enumerators would produce a warning if we were to continue at this point. // The most notable example is std::byte in the C++17 standard library. + // TODO: Create heuristics to bail out when the enum type is intended to be + // used to store combinations of flag values (to mitigate the limitation + // described in the docs). if (DeclValues.size() == 0) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp index 8e02ef74c668..5637941a58f0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp @@ -73,7 +73,7 @@ decltype(auto) bindAssignmentToDecl(const char *DeclName) { static bool isTest(const Decl *D) { if (const auto* ND = dyn_cast<NamedDecl>(D)) { std::string DeclName = ND->getNameAsString(); - if (StringRef(DeclName).startswith("test")) + if (StringRef(DeclName).starts_with("test")) return true; } if (const auto *OD = dyn_cast<ObjCMethodDecl>(D)) { diff --git a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp index b77e9bf09a33..70f911fc66ab 100644 --- a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp @@ -817,9 +817,9 @@ void NonLocalizedStringChecker::checkPreObjCMessage(const ObjCMethodCall &msg, // Handle the case where the receiver is an NSString // These special NSString methods draw to the screen - if (!(SelectorName.startswith("drawAtPoint") || - SelectorName.startswith("drawInRect") || - SelectorName.startswith("drawWithRect"))) + if (!(SelectorName.starts_with("drawAtPoint") || + SelectorName.starts_with("drawInRect") || + SelectorName.starts_with("drawWithRect"))) return; SVal svTitle = msg.getReceiverSVal(); diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index c5e4add50188..79ab05f2c786 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -3150,16 +3150,16 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly( // transferred. Again, though, we can't be sure that the object will use // free() to deallocate the memory, so we can't model it explicitly. StringRef FirstSlot = Msg->getSelector().getNameForSlot(0); - if (FirstSlot.endswith("NoCopy")) + if (FirstSlot.ends_with("NoCopy")) return true; // If the first selector starts with addPointer, insertPointer, // or replacePointer, assume we are dealing with NSPointerArray or similar. // This is similar to C++ containers (vector); we still might want to check // that the pointers get freed by following the container itself. - if (FirstSlot.startswith("addPointer") || - FirstSlot.startswith("insertPointer") || - FirstSlot.startswith("replacePointer") || + if (FirstSlot.starts_with("addPointer") || + FirstSlot.starts_with("insertPointer") || + FirstSlot.starts_with("replacePointer") || FirstSlot.equals("valueWithPointer")) { return true; } @@ -3199,7 +3199,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly( // White list the 'XXXNoCopy' CoreFoundation functions. // We specifically check these before - if (FName.endswith("NoCopy")) { + if (FName.ends_with("NoCopy")) { // Look for the deallocator argument. We know that the memory ownership // is not transferred only if the deallocator argument is // 'kCFAllocatorNull'. diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp index 627b51af6bd4..06f1ad00eaf2 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp @@ -890,7 +890,7 @@ void NullabilityChecker::checkPostCall(const CallEvent &Call, // of CG calls. const SourceManager &SM = C.getSourceManager(); StringRef FilePath = SM.getFilename(SM.getSpellingLoc(Decl->getBeginLoc())); - if (llvm::sys::path::filename(FilePath).startswith("CG")) { + if (llvm::sys::path::filename(FilePath).starts_with("CG")) { State = State->set<NullabilityMap>(Region, Nullability::Contradicted); C.addTransition(State); return; @@ -992,7 +992,7 @@ void NullabilityChecker::checkPostObjCMessage(const ObjCMethodCall &M, // In order to reduce the noise in the diagnostics generated by this checker, // some framework and programming style based heuristics are used. These // heuristics are for Cocoa APIs which have NS prefix. - if (Name.startswith("NS")) { + if (Name.starts_with("NS")) { // Developers rely on dynamic invariants such as an item should be available // in a collection, or a collection is not empty often. Those invariants can // not be inferred by any static analysis tool. To not to bother the users diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp index 4636fd160511..08ad6877cbe6 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp @@ -50,7 +50,7 @@ void ObjCPropertyChecker::checkCopyMutable(const ObjCPropertyDecl *D, const std::string &PropTypeName(T->getPointeeType().getCanonicalType() .getUnqualifiedType() .getAsString()); - if (!StringRef(PropTypeName).startswith("NSMutable")) + if (!StringRef(PropTypeName).starts_with("NSMutable")) return; const ObjCImplDecl *ImplD = nullptr; diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index 9532254e3c45..f3e0a5f9f314 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -12,12 +12,15 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/AST/ASTTypeTraits.h" +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ParentMap.h" +#include "clang/AST/ParentMapContext.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" @@ -2139,15 +2142,14 @@ PathSensitiveBugReport::PathSensitiveBugReport( "checkers to emit warnings, because checkers should depend on " "*modeling*, not *diagnostics*."); - assert( - (bt.getCheckerName().startswith("debug") || - !isHidden(ErrorNode->getState() - ->getAnalysisManager() - .getCheckerManager() - ->getCheckerRegistryData(), - bt.getCheckerName())) && - "Hidden checkers musn't emit diagnostics as they are by definition " - "non-user facing!"); + assert((bt.getCheckerName().starts_with("debug") || + !isHidden(ErrorNode->getState() + ->getAnalysisManager() + .getCheckerManager() + ->getCheckerRegistryData(), + bt.getCheckerName())) && + "Hidden checkers musn't emit diagnostics as they are by definition " + "non-user facing!"); } void PathSensitiveBugReport::addVisitor( @@ -2425,6 +2427,12 @@ PathSensitiveBugReport::getLocation() const { } if (S) { + // Attributed statements usually have corrupted begin locations, + // it's OK to ignore attributes for our purposes and deal with + // the actual annotated statement. + if (const auto *AS = dyn_cast<AttributedStmt>(S)) + S = AS->getSubStmt(); + // For member expressions, return the location of the '.' or '->'. if (const auto *ME = dyn_cast<MemberExpr>(S)) return PathDiagnosticLocation::createMemberLoc(ME, SM); @@ -2897,6 +2905,10 @@ void BugReporter::emitReport(std::unique_ptr<BugReport> R) { if (!ValidSourceLoc) return; + // If the user asked to suppress this report, we should skip it. + if (UserSuppressions.isSuppressed(*R)) + return; + // Compute the bug report's hash to determine its equivalence class. llvm::FoldingSetNodeID ID; R->Profile(ID); @@ -3064,8 +3076,7 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { // See whether we need to silence the checker/package. for (const std::string &CheckerOrPackage : getAnalyzerOptions().SilencedCheckersAndPackages) { - if (report->getBugType().getCheckerName().startswith( - CheckerOrPackage)) + if (report->getBugType().getCheckerName().starts_with(CheckerOrPackage)) return; } diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 4a9d130c240a..2f9965036b9e 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -3372,7 +3372,7 @@ void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor( FullSourceLoc Loc = BR.getLocation().asLocation(); while (Loc.isMacroID()) { Loc = Loc.getSpellingLoc(); - if (SM.getFilename(Loc).endswith("sys/queue.h")) { + if (SM.getFilename(Loc).ends_with("sys/queue.h")) { BR.markInvalid(getTag(), nullptr); return; } diff --git a/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp b/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp new file mode 100644 index 000000000000..b5991e47a538 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp @@ -0,0 +1,169 @@ +//===- BugSuppression.cpp - Suppression interface -------------------------===// +// +// 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 "clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" + +using namespace clang; +using namespace ento; + +namespace { + +using Ranges = llvm::SmallVectorImpl<SourceRange>; + +inline bool hasSuppression(const Decl *D) { + // FIXME: Implement diagnostic identifier arguments + // (checker names, "hashtags"). + if (const auto *Suppression = D->getAttr<SuppressAttr>()) + return !Suppression->isGSL() && + (Suppression->diagnosticIdentifiers().empty()); + return false; +} +inline bool hasSuppression(const AttributedStmt *S) { + // FIXME: Implement diagnostic identifier arguments + // (checker names, "hashtags"). + return llvm::any_of(S->getAttrs(), [](const Attr *A) { + const auto *Suppression = dyn_cast<SuppressAttr>(A); + return Suppression && !Suppression->isGSL() && + (Suppression->diagnosticIdentifiers().empty()); + }); +} + +template <class NodeType> inline SourceRange getRange(const NodeType *Node) { + return Node->getSourceRange(); +} +template <> inline SourceRange getRange(const AttributedStmt *S) { + // Begin location for attributed statement node seems to be ALWAYS invalid. + // + // It is unlikely that we ever report any warnings on suppression + // attribute itself, but even if we do, we wouldn't want that warning + // to be suppressed by that same attribute. + // + // Long story short, we can use inner statement and it's not going to break + // anything. + return getRange(S->getSubStmt()); +} + +inline bool isLessOrEqual(SourceLocation LHS, SourceLocation RHS, + const SourceManager &SM) { + // SourceManager::isBeforeInTranslationUnit tests for strict + // inequality, when we need a non-strict comparison (bug + // can be reported directly on the annotated note). + // For this reason, we use the following equivalence: + // + // A <= B <==> !(B < A) + // + return !SM.isBeforeInTranslationUnit(RHS, LHS); +} + +inline bool fullyContains(SourceRange Larger, SourceRange Smaller, + const SourceManager &SM) { + // Essentially this means: + // + // Larger.fullyContains(Smaller) + // + // However, that method has a very trivial implementation and couldn't + // compare regular locations and locations from macro expansions. + // We could've converted everything into regular locations as a solution, + // but the following solution seems to be the most bulletproof. + return isLessOrEqual(Larger.getBegin(), Smaller.getBegin(), SM) && + isLessOrEqual(Smaller.getEnd(), Larger.getEnd(), SM); +} + +class CacheInitializer : public RecursiveASTVisitor<CacheInitializer> { +public: + static void initialize(const Decl *D, Ranges &ToInit) { + CacheInitializer(ToInit).TraverseDecl(const_cast<Decl *>(D)); + } + + bool VisitVarDecl(VarDecl *VD) { + // Bug location could be somewhere in the init value of + // a freshly declared variable. Even though it looks like the + // user applied attribute to a statement, it will apply to a + // variable declaration, and this is where we check for it. + return VisitAttributedNode(VD); + } + + bool VisitAttributedStmt(AttributedStmt *AS) { + // When we apply attributes to statements, it actually creates + // a wrapper statement that only contains attributes and the wrapped + // statement. + return VisitAttributedNode(AS); + } + +private: + template <class NodeType> bool VisitAttributedNode(NodeType *Node) { + if (hasSuppression(Node)) { + // TODO: In the future, when we come up with good stable IDs for checkers + // we can return a list of kinds to ignore, or all if no arguments + // were provided. + addRange(getRange(Node)); + } + // We should keep traversing AST. + return true; + } + + void addRange(SourceRange R) { + if (R.isValid()) { + Result.push_back(R); + } + } + + CacheInitializer(Ranges &R) : Result(R) {} + Ranges &Result; +}; + +} // end anonymous namespace + +// TODO: Introduce stable IDs for checkers and check for those here +// to be more specific. Attribute without arguments should still +// be considered as "suppress all". +// It is already much finer granularity than what we have now +// (i.e. removing the whole function from the analysis). +bool BugSuppression::isSuppressed(const BugReport &R) { + PathDiagnosticLocation Location = R.getLocation(); + PathDiagnosticLocation UniqueingLocation = R.getUniqueingLocation(); + const Decl *DeclWithIssue = R.getDeclWithIssue(); + + return isSuppressed(Location, DeclWithIssue, {}) || + isSuppressed(UniqueingLocation, DeclWithIssue, {}); +} + +bool BugSuppression::isSuppressed(const PathDiagnosticLocation &Location, + const Decl *DeclWithIssue, + DiagnosticIdentifierList Hashtags) { + if (!Location.isValid() || DeclWithIssue == nullptr) + return false; + + // While some warnings are attached to AST nodes (mostly path-sensitive + // checks), others are simply associated with a plain source location + // or range. Figuring out the node based on locations can be tricky, + // so instead, we traverse the whole body of the declaration and gather + // information on ALL suppressions. After that we can simply check if + // any of those suppressions affect the warning in question. + // + // Traversing AST of a function is not a heavy operation, but for + // large functions with a lot of bugs it can make a dent in performance. + // In order to avoid this scenario, we cache traversal results. + auto InsertionResult = CachedSuppressionLocations.insert( + std::make_pair(DeclWithIssue, CachedRanges{})); + Ranges &SuppressionRanges = InsertionResult.first->second; + if (InsertionResult.second) { + // We haven't checked this declaration for suppressions yet! + CacheInitializer::initialize(DeclWithIssue, SuppressionRanges); + } + + SourceRange BugRange = Location.asRange(); + const SourceManager &SM = Location.getManager(); + + return llvm::any_of(SuppressionRanges, + [BugRange, &SM](SourceRange Suppression) { + return fullyContains(Suppression, BugRange, SM); + }); +} diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index d004c12bf2c1..0ac1d91b79be 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -659,17 +659,17 @@ bool AnyFunctionCall::argumentsMayEscape() const { // - CoreFoundation functions that end with "NoCopy" can free a passed-in // buffer even if it is const. - if (FName.endswith("NoCopy")) + if (FName.ends_with("NoCopy")) return true; // - NSXXInsertXX, for example NSMapInsertIfAbsent, since they can // be deallocated by NSMapRemove. - if (FName.startswith("NS") && FName.contains("Insert")) + if (FName.starts_with("NS") && FName.contains("Insert")) return true; // - Many CF containers allow objects to escape through custom // allocators/deallocators upon container construction. (PR12101) - if (FName.startswith("CF") || FName.startswith("CG")) { + if (FName.starts_with("CF") || FName.starts_with("CG")) { return StrInStrNoCase(FName, "InsertValue") != StringRef::npos || StrInStrNoCase(FName, "AddValue") != StringRef::npos || StrInStrNoCase(FName, "SetValue") != StringRef::npos || diff --git a/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp b/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp index c25165cce128..d6d4cec9dd3d 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp @@ -105,10 +105,11 @@ bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD, if (FName.equals(Name)) return true; - if (FName.startswith("__inline") && FName.contains(Name)) + if (FName.starts_with("__inline") && FName.contains(Name)) return true; - if (FName.startswith("__") && FName.endswith("_chk") && FName.contains(Name)) + if (FName.starts_with("__") && FName.ends_with("_chk") && + FName.contains(Name)) return true; return false; diff --git a/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp b/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp index 1b3e8b11549d..b9c6278991f4 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp @@ -82,7 +82,7 @@ static constexpr char PackageSeparator = '.'; static bool isInPackage(const CheckerInfo &Checker, StringRef PackageName) { // Does the checker's full name have the package as a prefix? - if (!Checker.FullName.startswith(PackageName)) + if (!Checker.FullName.starts_with(PackageName)) return false; // Is the package actually just the name of a specific checker? @@ -158,7 +158,7 @@ void CheckerRegistryData::printCheckerWithDescList( continue; } - if (Checker.FullName.startswith("alpha")) { + if (Checker.FullName.starts_with("alpha")) { if (AnOpts.ShowCheckerHelpAlpha) Print(Out, Checker, ("(Enable only for development!) " + Checker.Desc).str()); @@ -228,7 +228,7 @@ void CheckerRegistryData::printCheckerOptionList(const AnalyzerOptions &AnOpts, } if (Option.DevelopmentStatus == "alpha" || - Entry.first.startswith("alpha")) { + Entry.first.starts_with("alpha")) { if (AnOpts.ShowCheckerOptionAlphaList) Print(Out, FullOption, llvm::Twine("(Enable only for development!) " + Desc).str()); diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 142acab7cd08..b6ef40595e3c 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -308,7 +308,7 @@ public: bool VisitFunctionDecl(FunctionDecl *FD) { IdentifierInfo *II = FD->getIdentifier(); - if (II && II->getName().startswith("__inline")) + if (II && II->getName().starts_with("__inline")) return true; // We skip function template definitions, as their semantics is diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp index f0d3f43c414c..317df90a7781 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp @@ -310,8 +310,8 @@ template <bool IsWeak> void CheckerRegistry::resolveDependencies() { "Failed to find the dependency of a checker!"); // We do allow diagnostics from unit test/example dependency checkers. - assert((DependencyIt->FullName.startswith("test") || - DependencyIt->FullName.startswith("example") || IsWeak || + assert((DependencyIt->FullName.starts_with("test") || + DependencyIt->FullName.starts_with("example") || IsWeak || DependencyIt->IsHidden) && "Strong dependencies are modeling checkers, and as such " "non-user facing! Mark them hidden in Checkers.td!"); |