diff options
Diffstat (limited to 'include/clang/StaticAnalyzer')
15 files changed, 142 insertions, 87 deletions
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index 6dbdbbf..fb35f51 100644 --- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -232,6 +232,7 @@ private: /// \sa getMaxNodesPerTopLevelFunction Optional<unsigned> MaxNodesPerTopLevelFunction; +public: /// Interprets an option's string value as a boolean. /// /// Accepts the strings "true" and "false". @@ -244,7 +245,6 @@ private: /// Interprets an option's string value as an integer value. int getOptionAsInteger(StringRef Name, int DefaultVal); -public: /// \brief Retrieves and sets the UserMode. This is a high-level option, /// which is used to set other low-level options. It is not accessible /// outside of AnalyzerOptions. diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 7a87e47..5c560b2 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -406,11 +406,6 @@ private: /// A vector of BugReports for tracking the allocated pointers and cleanup. std::vector<BugReportEquivClass *> EQClassesVector; - /// A map from PathDiagnosticPiece to the LocationContext of the inlined - /// function call it represents. - llvm::DenseMap<const PathDiagnosticCallPiece*, - const LocationContext*> LocationContextMap; - protected: BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k), D(d) {} @@ -482,10 +477,6 @@ public: EmitBasicReport(DeclWithIssue, BugName, Category, BugStr, Loc, &R, 1); } - void addCallPieceLocationContextPair(const PathDiagnosticCallPiece *C, - const LocationContext *LC) { - LocationContextMap[C] = LC; - } private: llvm::StringMap<BugType *> StrBugTypes; diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h index 2e5f207..2e67180 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h @@ -134,10 +134,15 @@ class TrackConstraintBRVisitor bool IsSatisfied; bool IsZeroCheck; + /// We should start tracking from the last node along the path in which the + /// value is constrained. + bool IsTrackingTurnedOn; + public: TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption) : Constraint(constraint), Assumption(assumption), IsSatisfied(false), - IsZeroCheck(!Assumption && Constraint.getAs<Loc>()) {} + IsZeroCheck(!Assumption && Constraint.getAs<Loc>()), + IsTrackingTurnedOn(false) {} void Profile(llvm::FoldingSetNodeID &ID) const; diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index 3f0a1b1..a80b5a7 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -21,6 +21,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerUnion.h" #include <deque> +#include <list> #include <iterator> #include <string> #include <vector> @@ -93,7 +94,7 @@ public: void HandlePathDiagnostic(PathDiagnostic *D); - enum PathGenerationScheme { None, Minimal, Extensive }; + enum PathGenerationScheme { None, Minimal, Extensive, AlternateExtensive }; virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } virtual bool supportsLogicalOpControlFlow() const { return false; } virtual bool supportsAllBlockEdges() const { return false; } @@ -283,6 +284,13 @@ public: const SourceManager& getManager() const { assert(isValid()); return *SM; } void Profile(llvm::FoldingSetNodeID &ID) const; + + /// \brief Given an exploded node, retrieve the statement that should be used + /// for the diagnostic location. + static const Stmt *getStmt(const ExplodedNode *N); + + /// \brief Retrieve the statement corresponding to the sucessor node. + static const Stmt *getNextStmt(const ExplodedNode *N); }; class PathDiagnosticLocationPair { @@ -296,6 +304,9 @@ public: const PathDiagnosticLocation &getStart() const { return Start; } const PathDiagnosticLocation &getEnd() const { return End; } + void setStart(const PathDiagnosticLocation &L) { Start = L; } + void setEnd(const PathDiagnosticLocation &L) { End = L; } + void flatten() { Start.flatten(); End.flatten(); @@ -381,7 +392,7 @@ public: }; -class PathPieces : public std::deque<IntrusiveRefCntPtr<PathDiagnosticPiece> > { +class PathPieces : public std::list<IntrusiveRefCntPtr<PathDiagnosticPiece> > { void flattenTo(PathPieces &Primary, PathPieces &Current, bool ShouldFlattenMacros) const; public: @@ -608,6 +619,14 @@ public: return LPairs[0].getEnd(); } + void setStartLocation(const PathDiagnosticLocation &L) { + LPairs[0].setStart(L); + } + + void setEndLocation(const PathDiagnosticLocation &L) { + LPairs[0].setEnd(L); + } + void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); } virtual PathDiagnosticLocation getLocation() const { diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index 6f99fc1..b2411e6 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -17,6 +17,7 @@ #include "clang/Analysis/ProgramPoint.h" #include "clang/Basic/LangOptions.h" #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallVector.h" @@ -134,9 +135,13 @@ enum PointerEscapeKind { class CheckerManager { const LangOptions LangOpts; - + AnalyzerOptionsRef AOptions; public: - CheckerManager(const LangOptions &langOpts) : LangOpts(langOpts) { } + CheckerManager(const LangOptions &langOpts, + AnalyzerOptionsRef AOptions) + : LangOpts(langOpts), + AOptions(AOptions) {} + ~CheckerManager(); bool hasPathSensitiveCheckers() const; @@ -144,6 +149,7 @@ public: void finishedCheckerRegistration(); const LangOptions &getLangOpts() const { return LangOpts; } + AnalyzerOptions &getAnalyzerOptions() { return *AOptions; } typedef CheckerBase *CheckerRef; typedef const void *CheckerTag; @@ -170,6 +176,20 @@ public: return checker; } + template <typename CHECKER> + CHECKER *registerChecker(AnalyzerOptions &AOpts) { + CheckerTag tag = getTag<CHECKER>(); + CheckerRef &ref = CheckerTags[tag]; + if (ref) + return static_cast<CHECKER *>(ref); // already registered. + + CHECKER *checker = new CHECKER(AOpts); + CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>)); + CHECKER::_register(checker, *this); + ref = checker; + return checker; + } + //===----------------------------------------------------------------------===// // Functions for running checkers for AST traversing.. //===----------------------------------------------------------------------===// diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h index 1135b51..2c799c0 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h @@ -93,7 +93,7 @@ public: /// Returns the type of the APSInt used to store values of the given QualType. APSIntType getAPSIntType(QualType T) const { - assert(T->isIntegerType() || Loc::isLocType(T)); + assert(T->isIntegralOrEnumerationType() || Loc::isLocType(T)); return APSIntType(Ctx.getTypeSize(T), !T->isSignedIntegerOrEnumerationType()); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h index cda1366..0b9762a 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -110,10 +110,6 @@ public: StoreManager &getStoreManager() { return Eng.getStoreManager(); } - - const AnalyzerOptions::ConfigTable &getConfig() const { - return Eng.getAnalysisManager().options.Config; - } /// \brief Returns the previous node in the exploded graph, which includes /// the state of the program before the checker ran. Note, checkers should diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index 5211916..edcfc8a 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -196,6 +196,10 @@ public: return const_cast<ExplodedNode*>(this)->getFirstPred(); } + const ExplodedNode *getFirstSucc() const { + return succ_empty() ? NULL : *(succ_begin()); + } + // Iterators over successor and predecessor vertices. typedef ExplodedNode* const * succ_iterator; typedef const ExplodedNode* const * const_succ_iterator; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index af2f365..9b4f77d 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -37,11 +37,12 @@ class StackFrameContext; namespace ento { +class CodeTextRegion; class MemRegionManager; class MemSpaceRegion; class SValBuilder; +class SymbolicRegion; class VarRegion; -class CodeTextRegion; /// Represent a region's offset within the top level base region. class RegionOffset { @@ -145,6 +146,10 @@ public: const MemRegion *StripCasts(bool StripBaseCasts = true) const; + /// \brief If this is a symbolic region, returns the region. Otherwise, + /// goes up the base chain looking for the first symbolic base region. + const SymbolicRegion *getSymbolicBase() const; + bool hasGlobalsOrParametersStorage() const; bool hasStackStorage() const; @@ -169,6 +174,16 @@ public: /// \brief Print the region for use in diagnostics. virtual void printPretty(raw_ostream &os) const; + /// \brief Returns true if this region's textual representation can be used + /// as part of a larger expression. + virtual bool canPrintPrettyAsExpr() const; + + /// \brief Print the region as expression. + /// + /// When this region represents a subexpression, the method is for printing + /// an expression containing it. + virtual void printPrettyAsExpr(raw_ostream &os) const; + Kind getKind() const { return kind; } template<typename RegionTy> const RegionTy* getAs() const; @@ -874,8 +889,9 @@ public: return R->getKind() == VarRegionKind; } - bool canPrintPretty() const; - void printPretty(raw_ostream &os) const; + bool canPrintPrettyAsExpr() const; + + void printPrettyAsExpr(raw_ostream &os) const; }; /// CXXThisRegion - Represents the region for the implicit 'this' parameter @@ -937,6 +953,8 @@ public: bool canPrintPretty() const; void printPretty(raw_ostream &os) const; + bool canPrintPrettyAsExpr() const; + void printPrettyAsExpr(raw_ostream &os) const; }; class ObjCIvarRegion : public DeclRegion { @@ -952,8 +970,8 @@ public: const ObjCIvarDecl *getDecl() const; QualType getValueType() const; - bool canPrintPretty() const; - void printPretty(raw_ostream &os) const; + bool canPrintPrettyAsExpr() const; + void printPrettyAsExpr(raw_ostream &os) const; void dumpToStream(raw_ostream &os) const; @@ -1082,6 +1100,10 @@ public: static bool classof(const MemRegion *region) { return region->getKind() == CXXBaseObjectRegionKind; } + + bool canPrintPrettyAsExpr() const; + + void printPrettyAsExpr(raw_ostream &os) const; }; template<typename RegionTy> diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index 6ea7211..42ef1db 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -201,14 +201,6 @@ public: // Binding and retrieving values to/from the environment and symbolic store. //==---------------------------------------------------------------------==// - /// \brief Create a new state with the specified CompoundLiteral binding. - /// \param CL the compound literal expression (the binding key) - /// \param LC the LocationContext of the binding - /// \param V the value to bind. - ProgramStateRef bindCompoundLiteral(const CompoundLiteralExpr *CL, - const LocationContext *LC, - SVal V) const; - /// Create a new state by binding the value 'V' to the statement 'S' in the /// state's environment. ProgramStateRef BindExpr(const Stmt *S, const LocationContext *LCtx, @@ -711,7 +703,8 @@ ProgramState::getSValAsScalarOrLoc(const Stmt *S, const LocationContext *LCtx) const { if (const Expr *Ex = dyn_cast<Expr>(S)) { QualType T = Ex->getType(); - if (Ex->isGLValue() || Loc::isLocType(T) || T->isIntegerType()) + if (Ex->isGLValue() || Loc::isLocType(T) || + T->isIntegralOrEnumerationType()) return getSVal(S, LCtx); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index f7e49a3..bbb5688 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -78,7 +78,8 @@ public: // FIXME: Remove the second disjunct when we support symbolic // truncation/extension. return (Context.getCanonicalType(Ty1) == Context.getCanonicalType(Ty2) || - (Ty1->isIntegerType() && Ty2->isIntegerType())); + (Ty1->isIntegralOrEnumerationType() && + Ty2->isIntegralOrEnumerationType())); } SVal evalCast(SVal val, QualType castTy, QualType originalType); @@ -201,6 +202,12 @@ public: DefinedSVal getBlockPointer(const BlockDecl *block, CanQualType locTy, const LocationContext *locContext); + /// Returns the value of \p E, if it can be determined in a non-path-sensitive + /// manner. + /// + /// If \p E is not a constant or cannot be modeled, returns \c None. + Optional<SVal> getConstantVal(const Expr *E); + NonLoc makeCompoundVal(QualType type, llvm::ImmutableList<SVal> vals) { return nonloc::CompoundVal(BasicVals.getCompoundValData(type, vals)); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index 1c5519e..326e784 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -144,16 +144,24 @@ public: /// Otherwise return 0. const FunctionDecl *getAsFunctionDecl() const; - /// If this SVal is a location (subclasses Loc) and - /// wraps a symbol, return that SymbolRef. Otherwise return 0. - SymbolRef getAsLocSymbol() const; + /// \brief If this SVal is a location and wraps a symbol, return that + /// SymbolRef. Otherwise return 0. + /// + /// Casts are ignored during lookup. + /// \param IncludeBaseRegions The boolean that controls whether the search + /// should continue to the base regions if the region is not symbolic. + SymbolRef getAsLocSymbol(bool IncludeBaseRegions = false) const; /// Get the symbol in the SVal or its base region. SymbolRef getLocSymbolInBase() const; - /// If this SVal wraps a symbol return that SymbolRef. + /// \brief If this SVal wraps a symbol return that SymbolRef. /// Otherwise, return 0. - SymbolRef getAsSymbol() const; + /// + /// Casts are ignored during lookup. + /// \param IncludeBaseRegions The boolean that controls whether the search + /// should continue to the base regions if the region is not symbolic. + SymbolRef getAsSymbol(bool IncludeBaseRegions = false) const; /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then /// return that expression. Otherwise return NULL. diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index bbfd579..b219495 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -76,21 +76,6 @@ public: /// \param L the location whose binding should be removed. virtual StoreRef killBinding(Store ST, Loc L) = 0; - /// \brief Create a new store that binds a value to a compound literal. - /// - /// \param ST The original store whose bindings are the basis for the new - /// store. - /// - /// \param CL The compound literal to bind (the binding key). - /// - /// \param LC The LocationContext for the binding. - /// - /// \param V The value to bind to the compound literal. - virtual StoreRef bindCompoundLiteral(Store ST, - const CompoundLiteralExpr *CL, - const LocationContext *LC, - SVal V) = 0; - /// getInitialStore - Returns the initial "empty" store representing the /// value bindings upon entry to an analyzed function. virtual StoreRef getInitialStore(const LocationContext *InitLoc) = 0; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h index 56afca2..914b2be 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -49,7 +49,10 @@ public: MetadataKind, BEGIN_SYMBOLS = RegionValueKind, END_SYMBOLS = MetadataKind, - SymIntKind, IntSymKind, SymSymKind, CastSymbolKind }; + SymIntKind, IntSymKind, SymSymKind, + BEGIN_BINARYSYMEXPRS = SymIntKind, + END_BINARYSYMEXPRS = SymSymKind, + CastSymbolKind }; private: Kind K; @@ -341,24 +344,39 @@ public: } }; -/// SymIntExpr - Represents symbolic expression like 'x' + 3. -class SymIntExpr : public SymExpr { - const SymExpr *LHS; +/// \brief Represents a symbolic expression involving a binary operator +class BinarySymExpr : public SymExpr { BinaryOperator::Opcode Op; - const llvm::APSInt& RHS; QualType T; -public: - SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, - const llvm::APSInt& rhs, QualType t) - : SymExpr(SymIntKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} +protected: + BinarySymExpr(Kind k, BinaryOperator::Opcode op, QualType t) + : SymExpr(k), Op(op), T(t) {} +public: // FIXME: We probably need to make this out-of-line to avoid redundant // generation of virtual functions. QualType getType() const { return T; } BinaryOperator::Opcode getOpcode() const { return Op; } + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + Kind k = SE->getKind(); + return k >= BEGIN_BINARYSYMEXPRS && k <= END_BINARYSYMEXPRS; + } +}; + +/// \brief Represents a symbolic expression like 'x' + 3. +class SymIntExpr : public BinarySymExpr { + const SymExpr *LHS; + const llvm::APSInt& RHS; + +public: + SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t) + : BinarySymExpr(SymIntKind, op, t), LHS(lhs), RHS(rhs) {} + virtual void dumpToStream(raw_ostream &os) const; const SymExpr *getLHS() const { return LHS; } @@ -375,7 +393,7 @@ public: } void Profile(llvm::FoldingSetNodeID& ID) { - Profile(ID, LHS, Op, RHS, T); + Profile(ID, LHS, getOpcode(), RHS, getType()); } // Implement isa<T> support. @@ -384,21 +402,15 @@ public: } }; -/// IntSymExpr - Represents symbolic expression like 3 - 'x'. -class IntSymExpr : public SymExpr { +/// \brief Represents a symbolic expression like 3 - 'x'. +class IntSymExpr : public BinarySymExpr { const llvm::APSInt& LHS; - BinaryOperator::Opcode Op; const SymExpr *RHS; - QualType T; public: IntSymExpr(const llvm::APSInt& lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) - : SymExpr(IntSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} - - QualType getType() const { return T; } - - BinaryOperator::Opcode getOpcode() const { return Op; } + : BinarySymExpr(IntSymKind, op, t), LHS(lhs), RHS(rhs) {} virtual void dumpToStream(raw_ostream &os) const; @@ -416,7 +428,7 @@ public: } void Profile(llvm::FoldingSetNodeID& ID) { - Profile(ID, LHS, Op, RHS, T); + Profile(ID, LHS, getOpcode(), RHS, getType()); } // Implement isa<T> support. @@ -425,26 +437,19 @@ public: } }; -/// SymSymExpr - Represents symbolic expression like 'x' + 'y'. -class SymSymExpr : public SymExpr { +/// \brief Represents a symbolic expression like 'x' + 'y'. +class SymSymExpr : public BinarySymExpr { const SymExpr *LHS; - BinaryOperator::Opcode Op; const SymExpr *RHS; - QualType T; public: SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) - : SymExpr(SymSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} + : BinarySymExpr(SymSymKind, op, t), LHS(lhs), RHS(rhs) {} - BinaryOperator::Opcode getOpcode() const { return Op; } const SymExpr *getLHS() const { return LHS; } const SymExpr *getRHS() const { return RHS; } - // FIXME: We probably need to make this out-of-line to avoid redundant - // generation of virtual functions. - QualType getType() const { return T; } - virtual void dumpToStream(raw_ostream &os) const; static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, @@ -457,7 +462,7 @@ public: } void Profile(llvm::FoldingSetNodeID& ID) { - Profile(ID, LHS, Op, RHS, T); + Profile(ID, LHS, getOpcode(), RHS, getType()); } // Implement isa<T> support. diff --git a/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h b/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h index 492edd4..1df8c09 100644 --- a/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h +++ b/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h @@ -21,7 +21,7 @@ namespace clang { namespace ento { class CheckerManager; -CheckerManager *createCheckerManager(const AnalyzerOptions &opts, +CheckerManager *createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts, ArrayRef<std::string> plugins, DiagnosticsEngine &diags); |