diff options
author | Jordan Rupprecht <rupprecht@google.com> | 2019-01-18 19:46:00 +0000 |
---|---|---|
committer | Jordan Rupprecht <rupprecht@google.com> | 2019-01-18 19:46:00 +0000 |
commit | 3748d41833787fcbf59cc5624e8d2b042a8991bc (patch) | |
tree | f3fcdba7decca7ee845a1bb3f885cb0baa1b4d83 /include/clang/StaticAnalyzer/Core | |
parent | 55c8788102d8fd203270fabd6513247b2d7fbd87 (diff) | |
parent | e054eb577a1f469b1a4a49fce08572c76e2dddf2 (diff) |
Creating branches/google/stable and tags/google/stable/2019-01-18 from r351319
git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/google/stable@351578 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include/clang/StaticAnalyzer/Core')
8 files changed, 116 insertions, 252 deletions
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def index 8e5d8d3ad3..3cd54df7b1 100644 --- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def +++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def @@ -275,7 +275,7 @@ ANALYZER_OPTION( ANALYZER_OPTION( bool, IsNaiveCTUEnabled, "experimental-enable-naive-ctu-analysis", "Whether naive cross translation unit analysis is enabled. This is an " - "experimental feature to inline functions from another translation units.", + "experimental feature to inline functions from other translation units.", false) ANALYZER_OPTION(bool, ShouldDisplayMacroExpansions, "expand-macros", @@ -344,8 +344,8 @@ ANALYZER_OPTION(StringRef, CTUDir, "ctu-dir", "The directory containing the CTU related files.", "") ANALYZER_OPTION(StringRef, CTUIndexName, "ctu-index-name", - "the name of the file containing the CTU index of functions.", - "externalFnMap.txt") + "the name of the file containing the CTU index of definitions.", + "externalDefMap.txt") ANALYZER_OPTION( StringRef, ModelPath, "model-path", diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h b/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h index 0e80e7bc19..d07525661a 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h @@ -16,7 +16,7 @@ namespace clang { namespace categories { extern const char * const CoreFoundationObjectiveC; extern const char * const LogicError; - extern const char * const MemoryCoreFoundationObjectiveC; + extern const char * const MemoryRefCount; extern const char * const MemoryError; extern const char * const UnixAPI; } diff --git a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h deleted file mode 100644 index 740754090d..0000000000 --- a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h +++ /dev/null @@ -1,145 +0,0 @@ -//===- CheckerRegistry.h - Maintains all available checkers -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H -#define LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H - -#include "clang/Basic/LLVM.h" -#include "clang/StaticAnalyzer/Core/CheckerManager.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include <cstddef> -#include <vector> - -// FIXME: move this information to an HTML file in docs/. -// At the very least, a checker plugin is a dynamic library that exports -// clang_analyzerAPIVersionString. This should be defined as follows: -// -// extern "C" -// const char clang_analyzerAPIVersionString[] = -// CLANG_ANALYZER_API_VERSION_STRING; -// -// This is used to check whether the current version of the analyzer is known to -// be incompatible with a plugin. Plugins with incompatible version strings, -// or without a version string at all, will not be loaded. -// -// To add a custom checker to the analyzer, the plugin must also define the -// function clang_registerCheckers. For example: -// -// extern "C" -// void clang_registerCheckers (CheckerRegistry ®istry) { -// registry.addChecker<MainCallChecker>("example.MainCallChecker", -// "Disallows calls to functions called main"); -// } -// -// The first method argument is the full name of the checker, including its -// enclosing package. By convention, the registered name of a checker is the -// name of the associated class (the template argument). -// The second method argument is a short human-readable description of the -// checker. -// -// The clang_registerCheckers function may add any number of checkers to the -// registry. If any checkers require additional initialization, use the three- -// argument form of CheckerRegistry::addChecker. -// -// To load a checker plugin, specify the full path to the dynamic library as -// the argument to the -load option in the cc1 frontend. You can then enable -// your custom checker using the -analyzer-checker: -// -// clang -cc1 -load </path/to/plugin.dylib> -analyze -// -analyzer-checker=<example.MainCallChecker> -// -// For a complete working example, see examples/analyzer-plugin. - -#ifndef CLANG_ANALYZER_API_VERSION_STRING -// FIXME: The Clang version string is not particularly granular; -// the analyzer infrastructure can change a lot between releases. -// Unfortunately, this string has to be statically embedded in each plugin, -// so we can't just use the functions defined in Version.h. -#include "clang/Basic/Version.h" -#define CLANG_ANALYZER_API_VERSION_STRING CLANG_VERSION_STRING -#endif - -namespace clang { - -class AnalyzerOptions; -class DiagnosticsEngine; - -namespace ento { - -/// Manages a set of available checkers for running a static analysis. -/// The checkers are organized into packages by full name, where including -/// a package will recursively include all subpackages and checkers within it. -/// For example, the checker "core.builtin.NoReturnFunctionChecker" will be -/// included if initializeManager() is called with an option of "core", -/// "core.builtin", or the full name "core.builtin.NoReturnFunctionChecker". -class CheckerRegistry { -public: - /// Initialization functions perform any necessary setup for a checker. - /// They should include a call to CheckerManager::registerChecker. - using InitializationFunction = void (*)(CheckerManager &); - - struct CheckerInfo { - InitializationFunction Initialize; - StringRef FullName; - StringRef Desc; - - CheckerInfo(InitializationFunction fn, StringRef name, StringRef desc) - : Initialize(fn), FullName(name), Desc(desc) {} - }; - - using CheckerInfoList = std::vector<CheckerInfo>; - -private: - template <typename T> - static void initializeManager(CheckerManager &mgr) { - mgr.registerChecker<T>(); - } - -public: - /// Adds a checker to the registry. Use this non-templated overload when your - /// checker requires custom initialization. - void addChecker(InitializationFunction fn, StringRef fullName, - StringRef desc); - - /// Adds a checker to the registry. Use this templated overload when your - /// checker does not require any custom initialization. - template <class T> - void addChecker(StringRef fullName, StringRef desc) { - // Avoid MSVC's Compiler Error C2276: - // http://msdn.microsoft.com/en-us/library/850cstw1(v=VS.80).aspx - addChecker(&CheckerRegistry::initializeManager<T>, fullName, desc); - } - - /// Initializes a CheckerManager by calling the initialization functions for - /// all checkers specified by the given CheckerOptInfo list. The order of this - /// list is significant; later options can be used to reverse earlier ones. - /// This can be used to exclude certain checkers in an included package. - void initializeManager(CheckerManager &mgr, const AnalyzerOptions &Opts, - DiagnosticsEngine &diags) const; - - /// Check if every option corresponds to a specific checker or package. - void validateCheckerOptions(const AnalyzerOptions &opts, - DiagnosticsEngine &diags) const; - - /// Prints the name and description of all checkers in this registry. - /// This output is not intended to be machine-parseable. - void printHelp(raw_ostream &out, size_t maxNameChars = 30) const; - void printList(raw_ostream &out, const AnalyzerOptions &opts) const; - -private: - mutable CheckerInfoList Checkers; - mutable llvm::StringMap<size_t> Packages; -}; - -} // namespace ento - -} // namespace clang - -#endif // LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index a53e8ee693..81dd83fc10 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -1138,9 +1138,16 @@ class CallEventManager { public: CallEventManager(llvm::BumpPtrAllocator &alloc) : Alloc(alloc) {} + /// Gets an outside caller given a callee context. CallEventRef<> getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State); + /// Gets a call event for a function call, Objective-C method call, + /// or a 'new' call. + CallEventRef<> + getCall(const Stmt *S, ProgramStateRef State, + const LocationContext *LC); + CallEventRef<> getSimpleCall(const CallExpr *E, ProgramStateRef State, const LocationContext *LCtx); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index bf01289a40..3d0ff4efa1 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -24,6 +24,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/Type.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index f544204497..c3a7028d87 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -555,15 +555,15 @@ public: MemRegionManager& getRegionManager() { return svalBuilder->getRegionManager(); } - const MemRegionManager& getRegionManager() const { + const MemRegionManager &getRegionManager() const { return svalBuilder->getRegionManager(); } CallEventManager &getCallEventManager() { return *CallEventMgr; } - StoreManager& getStoreManager() { return *StoreMgr; } - ConstraintManager& getConstraintManager() { return *ConstraintMgr; } - SubEngine* getOwningEngine() { return Eng; } + StoreManager &getStoreManager() { return *StoreMgr; } + ConstraintManager &getConstraintManager() { return *ConstraintMgr; } + SubEngine &getOwningEngine() { return *Eng; } ProgramStateRef removeDeadBindings(ProgramStateRef St, const StackFrameContext *LCtx, diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index 1b79bfc3f8..0efe96f67f 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -530,9 +530,7 @@ public: return PTMDataType::getFromOpaqueValue(const_cast<void *>(Data)); } - bool isNullMemberPointer() const { - return getPTMData().isNull(); - } + bool isNullMemberPointer() const; const DeclaratorDecl *getDecl() const; diff --git a/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h b/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h index de16a1781a..4fcaa794c1 100644 --- a/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h +++ b/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h @@ -36,9 +36,26 @@ using namespace ento; namespace clang { namespace ento { -/// An ArgEffect summarizes the retain count behavior on an argument or receiver -/// to a function or method. -enum ArgEffect { +/// Determines the object kind of a tracked object. +enum class ObjKind { + /// Indicates that the tracked object is a CF object. + CF, + + /// Indicates that the tracked object is an Objective-C object. + ObjC, + + /// Indicates that the tracked object could be a CF or Objective-C object. + AnyObj, + + /// Indicates that the tracked object is a generalized object. + Generalized, + + /// Indicates that the tracking object is a descendant of a + /// referenced-counted OSObject, used in the Darwin kernel. + OS +}; + +enum ArgEffectKind { /// There is no effect. DoNothing, @@ -46,44 +63,35 @@ enum ArgEffect { /// the referenced object. Autorelease, - /// The argument is treated as if an -dealloc message had been sent to - /// the referenced object. + /// The argument is treated as if the referenced object was deallocated. Dealloc, - /// The argument has its reference count decreased by 1. This is as - /// if CFRelease has been called on the argument. + /// The argument has its reference count decreased by 1. DecRef, - /// The argument has its reference count decreased by 1. This is as - /// if a -release message has been sent to the argument. This differs - /// in behavior from DecRef when ARC is enabled. - DecRefMsg, - /// The argument has its reference count decreased by 1 to model /// a transferred bridge cast under ARC. DecRefBridgedTransferred, - /// The argument has its reference count increased by 1. This is as - /// if a -retain message has been sent to the argument. This differs - /// in behavior from IncRef when ARC is enabled. - IncRefMsg, - - /// The argument has its reference count increased by 1. This is as - /// if CFRetain has been called on the argument. + /// The argument has its reference count increased by 1. IncRef, - /// The argument acts as if has been passed to CFMakeCollectable, which - /// transfers the object to the Garbage Collector under GC. - MakeCollectable, - /// The argument is a pointer to a retain-counted object; on exit, the new - /// value of the pointer is a +0 value or NULL. + /// value of the pointer is a +0 value. UnretainedOutParameter, /// The argument is a pointer to a retain-counted object; on exit, the new - /// value of the pointer is a +1 value or NULL. + /// value of the pointer is a +1 value. RetainedOutParameter, + /// The argument is a pointer to a retain-counted object; on exit, the new + /// value of the pointer is a +1 value iff the return code is zero. + RetainedOutParameterOnZero, + + /// The argument is a pointer to a retain-counted object; on exit, the new + /// value of the pointer is a +1 value iff the return code is non-zero. + RetainedOutParameterOnNonZero, + /// The argument is treated as potentially escaping, meaning that /// even when its reference count hits 0 it should be treated as still /// possibly being alive as someone else *may* be holding onto the object. @@ -108,13 +116,27 @@ enum ArgEffect { /// count of the argument and all typestate tracking on that argument /// should cease. DecRefAndStopTrackingHard, +}; - /// Performs the combined functionality of DecRefMsg and StopTrackingHard. - /// - /// The models the effect that the called function decrements the reference - /// count of the argument and all typestate tracking on that argument - /// should cease. - DecRefMsgAndStopTrackingHard +/// An ArgEffect summarizes the retain count behavior on an argument or receiver +/// to a function or method. +class ArgEffect { + ArgEffectKind K; + ObjKind O; +public: + explicit ArgEffect(ArgEffectKind K = DoNothing, ObjKind O = ObjKind::AnyObj) + : K(K), O(O) {} + + ArgEffectKind getKind() const { return K; } + ObjKind getObjKind() const { return O; } + + ArgEffect withKind(ArgEffectKind NewK) { + return ArgEffect(NewK, O); + } + + bool operator==(const ArgEffect &Other) const { + return K == Other.K && O == Other.O; + } }; /// RetEffect summarizes a call's retain/release behavior with respect @@ -125,18 +147,19 @@ public: /// Indicates that no retain count information is tracked for /// the return value. NoRet, + /// Indicates that the returned value is an owned (+1) symbol. OwnedSymbol, + /// Indicates that the returned value is an object with retain count /// semantics but that it is not owned (+0). This is the default /// for getters, etc. NotOwnedSymbol, - /// Indicates that the object is not owned and controlled by the - /// Garbage collector. - GCNotOwnedSymbol, + /// Indicates that the return value is an owned object when the /// receiver is also a tracked object. OwnedWhenTrackedReceiver, + // Treat this function as returning a non-tracked symbol even if // the function has been inlined. This is used where the call // site summary is more precise than the summary indirectly produced @@ -144,27 +167,11 @@ public: NoRetHard }; - /// Determines the object kind of a tracked object. - enum ObjKind { - /// Indicates that the tracked object is a CF object. This is - /// important between GC and non-GC code. - CF, - /// Indicates that the tracked object is an Objective-C object. - ObjC, - /// Indicates that the tracked object could be a CF or Objective-C object. - AnyObj, - /// Indicates that the tracked object is a generalized object. - Generalized, - - /// A descendant of OSObject. - OS - }; - private: Kind K; ObjKind O; - RetEffect(Kind k, ObjKind o = AnyObj) : K(k), O(o) {} + RetEffect(Kind k, ObjKind o = ObjKind::AnyObj) : K(k), O(o) {} public: Kind getKind() const { return K; } @@ -184,7 +191,7 @@ public: } static RetEffect MakeOwnedWhenTrackedReceiver() { - return RetEffect(OwnedWhenTrackedReceiver, ObjC); + return RetEffect(OwnedWhenTrackedReceiver, ObjKind::ObjC); } static RetEffect MakeOwned(ObjKind o) { @@ -193,9 +200,6 @@ public: static RetEffect MakeNotOwned(ObjKind o) { return RetEffect(NotOwnedSymbol, o); } - static RetEffect MakeGCNotOwned() { - return RetEffect(GCNotOwnedSymbol, ObjC); - } static RetEffect MakeNoRet() { return RetEffect(NoRet); } @@ -217,7 +221,9 @@ class CallEffects { RetEffect Ret; ArgEffect Receiver; - CallEffects(const RetEffect &R) : Ret(R) {} + CallEffects(const RetEffect &R, + ArgEffect Receiver = ArgEffect(DoNothing, ObjKind::AnyObj)) + : Ret(R), Receiver(Receiver) {} public: /// Returns the argument effects for a call. @@ -262,7 +268,8 @@ namespace llvm { template <> struct FoldingSetTrait<ArgEffect> { static inline void Profile(const ArgEffect X, FoldingSetNodeID &ID) { - ID.AddInteger((unsigned) X); + ID.AddInteger((unsigned) X.getKind()); + ID.AddInteger((unsigned) X.getObjKind()); } }; template <> struct FoldingSetTrait<RetEffect> { @@ -370,14 +377,15 @@ public: ArgEffect getReceiverEffect() const { return Receiver; } /// \return the effect on the "this" receiver of the method call. + /// This is only meaningful if the summary applies to CXXMethodDecl*. ArgEffect getThisEffect() const { return This; } /// Set the effect of the method on "this". void setThisEffect(ArgEffect e) { This = e; } bool isNoop() const { - return Ret == RetEffect::MakeNoRet() && Receiver == DoNothing - && DefaultArgEffect == MayEscape && This == DoNothing + return Ret == RetEffect::MakeNoRet() && Receiver.getKind() == DoNothing + && DefaultArgEffect.getKind() == MayEscape && This.getKind() == DoNothing && Args.isEmpty(); } @@ -508,9 +516,6 @@ class RetainSummaryManager { /// AF - A factory for ArgEffects objects. ArgEffects::Factory AF; - /// ScratchArgs - A holding buffer for construct ArgEffects. - ArgEffects ScratchArgs; - /// ObjCAllocRetE - Default return effect for methods returning Objective-C /// objects. RetEffect ObjCAllocRetE; @@ -523,10 +528,6 @@ class RetainSummaryManager { /// effects. llvm::FoldingSet<CachedSummaryNode> SimpleSummaries; - /// getArgEffects - Returns a persistent ArgEffects object based on the - /// data in ScratchArgs. - ArgEffects getArgEffects(); - /// Create an OS object at +1. const RetainSummary *getOSSummaryCreateRule(const FunctionDecl *FD); @@ -542,10 +543,8 @@ class RetainSummaryManager { /// Free the OS object. const RetainSummary *getOSSummaryFreeRule(const FunctionDecl *FD); - enum UnaryFuncKind { cfretain, cfrelease, cfautorelease, cfmakecollectable }; - const RetainSummary *getUnarySummary(const FunctionType* FT, - UnaryFuncKind func); + ArgEffectKind AE); const RetainSummary *getCFSummaryCreateRule(const FunctionDecl *FD); const RetainSummary *getCFSummaryGetRule(const FunctionDecl *FD); @@ -553,27 +552,31 @@ class RetainSummaryManager { const RetainSummary *getPersistentSummary(const RetainSummary &OldSumm); - const RetainSummary *getPersistentSummary(RetEffect RetEff, - ArgEffect ReceiverEff = DoNothing, - ArgEffect DefaultEff = MayEscape, - ArgEffect ThisEff = DoNothing) { - RetainSummary Summ(getArgEffects(), RetEff, DefaultEff, ReceiverEff, - ThisEff); + const RetainSummary * + getPersistentSummary(RetEffect RetEff, ArgEffects ScratchArgs, + ArgEffect ReceiverEff = ArgEffect(DoNothing), + ArgEffect DefaultEff = ArgEffect(MayEscape), + ArgEffect ThisEff = ArgEffect(DoNothing)) { + RetainSummary Summ(ScratchArgs, RetEff, DefaultEff, ReceiverEff, ThisEff); return getPersistentSummary(Summ); } const RetainSummary *getDoNothingSummary() { - return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); + return getPersistentSummary(RetEffect::MakeNoRet(), + ArgEffects(AF.getEmptyMap()), + ArgEffect(DoNothing), ArgEffect(DoNothing)); } const RetainSummary *getDefaultSummary() { return getPersistentSummary(RetEffect::MakeNoRet(), - DoNothing, MayEscape); + ArgEffects(AF.getEmptyMap()), + ArgEffect(DoNothing), ArgEffect(MayEscape)); } const RetainSummary *getPersistentStopSummary() { - return getPersistentSummary(RetEffect::MakeNoRet(), - StopTracking, StopTracking); + return getPersistentSummary( + RetEffect::MakeNoRet(), ArgEffects(AF.getEmptyMap()), + ArgEffect(StopTracking), ArgEffect(StopTracking)); } void InitializeClassMethodSummaries(); @@ -646,11 +649,9 @@ class RetainSummaryManager { /// Apply the annotation of {@code pd} in function {@code FD} /// to the resulting summary stored in out-parameter {@code Template}. /// \return whether an annotation was applied. - bool applyFunctionParamAnnotationEffect(const ParmVarDecl *pd, - unsigned parm_idx, - const FunctionDecl *FD, - ArgEffects::Factory &AF, - RetainSummaryTemplate &Template); + bool applyParamAnnotationEffect(const ParmVarDecl *pd, unsigned parm_idx, + const NamedDecl *FD, + RetainSummaryTemplate &Template); public: RetainSummaryManager(ASTContext &ctx, @@ -661,10 +662,10 @@ public: ARCEnabled(usesARC), TrackObjCAndCFObjects(trackObjCAndCFObjects), TrackOSObjects(trackOSObjects), - AF(BPAlloc), ScratchArgs(AF.getEmptyMap()), - ObjCAllocRetE(usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC) - : RetEffect::MakeOwned(RetEffect::ObjC)), - ObjCInitRetE(usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC) + AF(BPAlloc), + ObjCAllocRetE(usesARC ? RetEffect::MakeNotOwned(ObjKind::ObjC) + : RetEffect::MakeOwned(ObjKind::ObjC)), + ObjCInitRetE(usesARC ? RetEffect::MakeNotOwned(ObjKind::ObjC) : RetEffect::MakeOwnedWhenTrackedReceiver()) { InitializeClassMethodSummaries(); InitializeMethodSummaries(); @@ -745,16 +746,18 @@ public: RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; } - /// \return True if the declaration has an attribute {@code T}, - /// AND we are tracking that attribute. False otherwise. + /// Determine whether a declaration {@code D} of correspondent type (return + /// type for functions/methods) {@code QT} has any of the given attributes, + /// provided they pass necessary validation checks AND tracking the given + /// attribute is enabled. + /// Returns the object kind corresponding to the present attribute, or None, + /// if none of the specified attributes are present. + /// Crashes if passed an attribute which is not explicitly handled. template <class T> - bool hasEnabledAttr(const Decl *D) { - return isAttrEnabled<T>() && D->hasAttr<T>(); - } + Optional<ObjKind> hasAnyEnabledAttrOf(const Decl *D, QualType QT); - /// Check whether we are tracking properties specified by the attributes. - template <class T> - bool isAttrEnabled(); + template <class T1, class T2, class... Others> + Optional<ObjKind> hasAnyEnabledAttrOf(const Decl *D, QualType QT); friend class RetainSummaryTemplate; }; |