diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2012-08-19 10:33:04 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2012-08-19 10:33:04 +0000 |
commit | 657bc3d9848e3be92029b2416031340988cd0111 (patch) | |
tree | 5b9c2fa9d79942fbdce3d618e37e27c18263af9a /include/clang | |
parent | 56d91b49b13fe55c918afbda19f6165b5fbff87a (diff) |
Notes
Diffstat (limited to 'include/clang')
29 files changed, 542 insertions, 162 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 8fd7d6ef42330..cad3ad2b5f9c3 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -474,8 +474,17 @@ public: Data.setPointer(RC); } + const Decl *getOriginalDecl() const LLVM_READONLY { + return OriginalDecl; + } + + void setOriginalDecl(const Decl *Orig) { + OriginalDecl = Orig; + } + private: llvm::PointerIntPair<const RawComment *, 2, Kind> Data; + const Decl *OriginalDecl; }; /// \brief Mapping from declarations to comments attached to any @@ -485,6 +494,10 @@ public: /// lazily. mutable llvm::DenseMap<const Decl *, RawCommentAndCacheFlags> RedeclComments; + /// \brief Mapping from declarations to parsed comments attached to any + /// redeclaration. + mutable llvm::DenseMap<const Decl *, comments::FullComment *> ParsedComments; + /// \brief Return the documentation comment attached to a given declaration, /// without looking into cache. RawComment *getRawCommentForDeclNoCache(const Decl *D) const; @@ -500,7 +513,12 @@ public: /// \brief Return the documentation comment attached to a given declaration. /// Returns NULL if no comment is attached. - const RawComment *getRawCommentForAnyRedecl(const Decl *D) const; + /// + /// \param OriginalDecl if not NULL, is set to declaration AST node that had + /// the comment, if the comment we found comes from a redeclaration. + const RawComment *getRawCommentForAnyRedecl( + const Decl *D, + const Decl **OriginalDecl = NULL) const; /// Return parsed documentation comment attached to a given declaration. /// Returns NULL if no comment is attached. diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 27b44d4bd97b0..b17bd48b7d03c 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -105,7 +105,8 @@ public: virtual bool isLateParsed() const { return false; } // Pretty print this attribute. - virtual void printPretty(llvm::raw_ostream &OS, ASTContext &C) const = 0; + virtual void printPretty(llvm::raw_ostream &OS, + const PrintingPolicy &Policy) const = 0; // Implement isa/cast/dyncast/etc. static bool classof(const Attr *) { return true; } diff --git a/include/clang/AST/CommentCommandTraits.h b/include/clang/AST/CommentCommandTraits.h index f1883755e5202..5f0269a4650b1 100644 --- a/include/clang/AST/CommentCommandTraits.h +++ b/include/clang/AST/CommentCommandTraits.h @@ -35,14 +35,14 @@ public: /// A verbatim-like block command eats every character (except line starting /// decorations) until matching end command is seen or comment end is hit. /// - /// \param BeginName name of the command that starts the verbatim block. + /// \param StartName name of the command that starts the verbatim block. /// \param [out] EndName name of the command that ends the verbatim block. /// /// \returns true if a given command is a verbatim block command. bool isVerbatimBlockCommand(StringRef StartName, StringRef &EndName) const; /// \brief Register a new verbatim block command. - void addVerbatimBlockCommand(StringRef BeginName, StringRef EndName); + void addVerbatimBlockCommand(StringRef StartName, StringRef EndName); /// \brief Check if a given command is a verbatim line command. /// @@ -90,7 +90,7 @@ public: private: struct VerbatimBlockCommand { - StringRef BeginName; + StringRef StartName; StringRef EndName; }; diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index ac2cc9ec4d271..0f596095f74a2 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -858,10 +858,10 @@ public: raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation = 0); // Debuggers don't usually respect default arguments. - LLVM_ATTRIBUTE_USED void dump() const { dump(llvm::errs()); } + LLVM_ATTRIBUTE_USED void dump() const; void dump(raw_ostream &Out) const; // Debuggers don't usually respect default arguments. - LLVM_ATTRIBUTE_USED void dumpXML() const { dumpXML(llvm::errs()); } + LLVM_ATTRIBUTE_USED void dumpXML() const; void dumpXML(raw_ostream &OS) const; private: diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 851e3105bc0df..2d95f038dfd47 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1646,14 +1646,17 @@ public: /// \brief Find the method in RD that corresponds to this one. /// /// Find if RD or one of the classes it inherits from override this method. - /// If so, return it. RD is assumed to be a base class of the class defining - /// this method (or be the class itself). + /// If so, return it. RD is assumed to be a subclass of the class defining + /// this method (or be the class itself), unless MayBeBase is set to true. CXXMethodDecl * - getCorrespondingMethodInClass(const CXXRecordDecl *RD); + getCorrespondingMethodInClass(const CXXRecordDecl *RD, + bool MayBeBase = false); const CXXMethodDecl * - getCorrespondingMethodInClass(const CXXRecordDecl *RD) const { - return const_cast<CXXMethodDecl*>(this)->getCorrespondingMethodInClass(RD); + getCorrespondingMethodInClass(const CXXRecordDecl *RD, + bool MayBeBase = false) const { + return const_cast<CXXMethodDecl *>(this) + ->getCorrespondingMethodInClass(RD, MayBeBase); } // Implement isa/cast/dyncast/etc. diff --git a/include/clang/AST/DeclGroup.h b/include/clang/AST/DeclGroup.h index 63cdac594920a..cda6ae520af4e 100644 --- a/include/clang/AST/DeclGroup.h +++ b/include/clang/AST/DeclGroup.h @@ -26,7 +26,11 @@ class DeclGroupIterator; class DeclGroup { // FIXME: Include a TypeSpecifier object. - unsigned NumDecls; + union { + unsigned NumDecls; + + Decl *Aligner; + }; private: DeclGroup() : NumDecls(0) {} diff --git a/include/clang/AST/DeclLookups.h b/include/clang/AST/DeclLookups.h index b8abe97be1fbc..867b465257533 100644 --- a/include/clang/AST/DeclLookups.h +++ b/include/clang/AST/DeclLookups.h @@ -67,7 +67,7 @@ public: DeclContext::all_lookups_iterator DeclContext::lookups_begin() const { DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext(); - if (hasExternalVisibleStorage()) + if (Primary->hasExternalVisibleStorage()) getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary); if (StoredDeclsMap *Map = Primary->buildLookup()) return all_lookups_iterator(Map->begin(), Map->end()); @@ -76,7 +76,7 @@ DeclContext::all_lookups_iterator DeclContext::lookups_begin() const { DeclContext::all_lookups_iterator DeclContext::lookups_end() const { DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext(); - if (hasExternalVisibleStorage()) + if (Primary->hasExternalVisibleStorage()) getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary); if (StoredDeclsMap *Map = Primary->buildLookup()) return all_lookups_iterator(Map->end(), Map->end()); diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h index 2e34dc8cbd5c3..f2c015fffe946 100644 --- a/include/clang/AST/PrettyPrinter.h +++ b/include/clang/AST/PrettyPrinter.h @@ -34,19 +34,19 @@ public: struct PrintingPolicy { /// \brief Create a default printing policy for C. PrintingPolicy(const LangOptions &LO) - : Indentation(2), LangOpts(LO), SuppressSpecifiers(false), + : LangOpts(LO), Indentation(2), SuppressSpecifiers(false), SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false), SuppressUnwrittenScope(false), SuppressInitializers(false), - Dump(false), ConstantArraySizeAsWritten(false), - AnonymousTagLocations(true), SuppressStrongLifetime(false), - Bool(LO.Bool) { } - - /// \brief The number of spaces to use to indent each line. - unsigned Indentation : 8; + ConstantArraySizeAsWritten(false), AnonymousTagLocations(true), + SuppressStrongLifetime(false), Bool(LO.Bool), + DumpSourceManager(0) { } /// \brief What language we're printing. LangOptions LangOpts; + /// \brief The number of spaces to use to indent each line. + unsigned Indentation : 8; + /// \brief Whether we should suppress printing of the actual specifiers for /// the given type or declaration. /// @@ -103,12 +103,6 @@ struct PrintingPolicy { /// internal initializer constructed for x will not be printed. bool SuppressInitializers : 1; - /// \brief True when we are "dumping" rather than "pretty-printing", - /// where dumping involves printing the internal details of the AST - /// and pretty-printing involves printing something similar to - /// source code. - bool Dump : 1; - /// \brief Whether we should print the sizes of constant array expressions /// as written in the sources. /// @@ -139,6 +133,12 @@ struct PrintingPolicy { /// \brief Whether we can use 'bool' rather than '_Bool', even if the language /// doesn't actually have 'bool' (because, e.g., it is defined as a macro). unsigned Bool : 1; + + /// \brief If we are "dumping" rather than "pretty-printing", this points to + /// a SourceManager which will be used to dump SourceLocations. Dumping + /// involves printing the internal details of the AST and pretty-printing + /// involves printing something similar to source code. + SourceManager *DumpSourceManager; }; } // end namespace clang diff --git a/include/clang/AST/RawCommentList.h b/include/clang/AST/RawCommentList.h index 4901d07c3cdc9..630626b438ee5 100644 --- a/include/clang/AST/RawCommentList.h +++ b/include/clang/AST/RawCommentList.h @@ -55,16 +55,11 @@ public: /// Is this comment attached to any declaration? bool isAttached() const LLVM_READONLY { - return !DeclOrParsedComment.isNull(); + return IsAttached; } - /// Return the declaration that this comment is attached to. - const Decl *getDecl() const; - - /// Set the declaration that this comment is attached to. - void setDecl(const Decl *D) { - assert(DeclOrParsedComment.isNull()); - DeclOrParsedComment = D; + void setAttached() { + IsAttached = true; } /// Returns true if it is a comment that should be put after a member: @@ -118,28 +113,23 @@ public: return extractBriefText(Context); } - /// Returns a \c FullComment AST node, parsing the comment if needed. - comments::FullComment *getParsed(const ASTContext &Context) const { - if (comments::FullComment *FC = - DeclOrParsedComment.dyn_cast<comments::FullComment *>()) - return FC; - - return parse(Context); - } + /// Parse the comment, assuming it is attached to decl \c D. + comments::FullComment *parse(const ASTContext &Context, const Decl *D) const; private: SourceRange Range; mutable StringRef RawText; mutable const char *BriefText; - mutable llvm::PointerUnion<const Decl *, comments::FullComment *> - DeclOrParsedComment; mutable bool RawTextValid : 1; ///< True if RawText is valid mutable bool BriefTextValid : 1; ///< True if BriefText is valid unsigned Kind : 3; + /// True if comment is attached to a declaration in ASTContext. + bool IsAttached : 1; + bool IsTrailingComment : 1; bool IsAlmostTrailingComment : 1; @@ -152,7 +142,7 @@ private: RawComment(SourceRange SR, CommentKind K, bool IsTrailingComment, bool IsAlmostTrailingComment) : Range(SR), RawTextValid(false), BriefTextValid(false), Kind(K), - IsTrailingComment(IsTrailingComment), + IsAttached(false), IsTrailingComment(IsTrailingComment), IsAlmostTrailingComment(IsAlmostTrailingComment), BeginLineValid(false), EndLineValid(false) { } @@ -161,8 +151,6 @@ private: const char *extractBriefText(const ASTContext &Context) const; - comments::FullComment *parse(const ASTContext &Context) const; - friend class ASTReader; }; diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 79e1920159cd7..35fb69312b6e9 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -373,15 +373,9 @@ public: /// dumpPretty/printPretty - These two methods do a "pretty print" of the AST /// back to its original source language syntax. - void dumpPretty(ASTContext& Context) const; + void dumpPretty(ASTContext &Context) const; void printPretty(raw_ostream &OS, PrinterHelper *Helper, const PrintingPolicy &Policy, - unsigned Indentation = 0) const { - printPretty(OS, *(ASTContext*)0, Helper, Policy, Indentation); - } - void printPretty(raw_ostream &OS, ASTContext &Context, - PrinterHelper *Helper, - const PrintingPolicy &Policy, unsigned Indentation = 0) const; /// viewAST - Visualize an AST rooted at this Stmt* using GraphViz. Only @@ -1620,36 +1614,40 @@ public: /// MSAsmStmt - This represents a MS inline-assembly statement extension. /// class MSAsmStmt : public Stmt { - SourceLocation AsmLoc, EndLoc; + SourceLocation AsmLoc, LBraceLoc, EndLoc; std::string AsmStr; bool IsSimple; bool IsVolatile; unsigned NumAsmToks; - unsigned NumLineEnds; + unsigned NumInputs; + unsigned NumOutputs; unsigned NumClobbers; Token *AsmToks; - unsigned *LineEnds; + IdentifierInfo **Names; Stmt **Exprs; StringRef *Clobbers; public: - MSAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, - bool isvolatile, ArrayRef<Token> asmtoks, - ArrayRef<unsigned> lineends, StringRef asmstr, - ArrayRef<StringRef> clobbers, SourceLocation endloc); + MSAsmStmt(ASTContext &C, SourceLocation asmloc, SourceLocation lbraceloc, + bool issimple, bool isvolatile, ArrayRef<Token> asmtoks, + ArrayRef<IdentifierInfo*> inputs, ArrayRef<IdentifierInfo*> outputs, + StringRef asmstr, ArrayRef<StringRef> clobbers, + SourceLocation endloc); SourceLocation getAsmLoc() const { return AsmLoc; } void setAsmLoc(SourceLocation L) { AsmLoc = L; } + SourceLocation getLBraceLoc() const { return LBraceLoc; } + void setLBraceLoc(SourceLocation L) { LBraceLoc = L; } SourceLocation getEndLoc() const { return EndLoc; } void setEndLoc(SourceLocation L) { EndLoc = L; } + bool hasBraces() const { return LBraceLoc.isValid(); } + unsigned getNumAsmToks() { return NumAsmToks; } Token *getAsmToks() { return AsmToks; } - unsigned getNumLineEnds() { return NumLineEnds; } - unsigned *getLineEnds() { return LineEnds; } bool isVolatile() const { return IsVolatile; } void setVolatile(bool V) { IsVolatile = V; } @@ -1665,7 +1663,7 @@ public: //===--- Other ---===// unsigned getNumClobbers() const { return NumClobbers; } - StringRef getClobber(unsigned i) { return Clobbers[i]; } + StringRef getClobber(unsigned i) const { return Clobbers[i]; } SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(AsmLoc, EndLoc); diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h index 54c9f2c534d2c..5047028e5eac4 100644 --- a/include/clang/AST/TemplateBase.h +++ b/include/clang/AST/TemplateBase.h @@ -510,17 +510,23 @@ public: /// This is safe to be used inside an AST node, in contrast with /// TemplateArgumentListInfo. struct ASTTemplateArgumentListInfo { - /// \brief The source location of the left angle bracket ('<'); + /// \brief The source location of the left angle bracket ('<'). SourceLocation LAngleLoc; - /// \brief The source location of the right angle bracket ('>'); + /// \brief The source location of the right angle bracket ('>'). SourceLocation RAngleLoc; - /// \brief The number of template arguments in TemplateArgs. - /// The actual template arguments (if any) are stored after the - /// ExplicitTemplateArgumentList structure. - unsigned NumTemplateArgs; - + union { + /// \brief The number of template arguments in TemplateArgs. + /// The actual template arguments (if any) are stored after the + /// ExplicitTemplateArgumentList structure. + unsigned NumTemplateArgs; + + /// Force ASTTemplateArgumentListInfo to the right alignment + /// for the following array of TemplateArgumentLocs. + void *Aligner; + }; + /// \brief Retrieve the template arguments TemplateArgumentLoc *getTemplateArgs() { return reinterpret_cast<TemplateArgumentLoc *> (this + 1); diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 1d1c1d172573f..11a878d6b0f34 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -1061,7 +1061,6 @@ public: struct FunctionLocInfo { SourceLocation LocalRangeBegin; SourceLocation LocalRangeEnd; - bool TrailingReturn; }; /// \brief Wrapper for source info for functions. @@ -1084,13 +1083,6 @@ public: getLocalData()->LocalRangeEnd = L; } - bool getTrailingReturn() const { - return getLocalData()->TrailingReturn; - } - void setTrailingReturn(bool Trailing) { - getLocalData()->TrailingReturn = Trailing; - } - ArrayRef<ParmVarDecl *> getParams() const { return ArrayRef<ParmVarDecl *>(getParmArray(), getNumArgs()); } @@ -1119,7 +1111,6 @@ public: void initializeLocal(ASTContext &Context, SourceLocation Loc) { setLocalRangeBegin(Loc); setLocalRangeEnd(Loc); - setTrailingReturn(false); for (unsigned i = 0, e = getNumArgs(); i != e; ++i) setArg(i, NULL); } diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index 37e82e8318dde..33ef3dc8d6e0c 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -50,6 +50,7 @@ #include "clang/ASTMatchers/ASTMatchersMacros.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Regex.h" +#include <iterator> namespace clang { namespace ast_matchers { @@ -195,6 +196,75 @@ AST_MATCHER_P(ClassTemplateSpecializationDecl, hasAnyTemplateArgument, return false; } +/// \brief Matches expressions that match InnerMatcher after any implicit casts +/// are stripped off. +/// +/// Parentheses and explicit casts are not discarded. +/// Given +/// int arr[5]; +/// int a = 0; +/// char b = 0; +/// const int c = a; +/// int *d = arr; +/// long e = (long) 0l; +/// The matchers +/// variable(hasInitializer(ignoringImpCasts(integerLiteral()))) +/// variable(hasInitializer(ignoringImpCasts(declarationReference()))) +/// would match the declarations for a, b, c, and d, but not e. +/// while +/// variable(hasInitializer(integerLiteral())) +/// variable(hasInitializer(declarationReference())) +/// only match the declarations for b, c, and d. +AST_MATCHER_P(Expr, ignoringImpCasts, + internal::Matcher<Expr>, InnerMatcher) { + return InnerMatcher.matches(*Node.IgnoreImpCasts(), Finder, Builder); +} + +/// \brief Matches expressions that match InnerMatcher after parentheses and +/// casts are stripped off. +/// +/// Implicit and non-C Style casts are also discarded. +/// Given +/// int a = 0; +/// char b = (0); +/// void* c = reinterpret_cast<char*>(0); +/// char d = char(0); +/// The matcher +/// variable(hasInitializer(ignoringParenCasts(integerLiteral()))) +/// would match the declarations for a, b, c, and d. +/// while +/// variable(hasInitializer(integerLiteral())) +/// only match the declaration for a. +AST_MATCHER_P(Expr, ignoringParenCasts, internal::Matcher<Expr>, InnerMatcher) { + return InnerMatcher.matches(*Node.IgnoreParenCasts(), Finder, Builder); +} + +/// \brief Matches expressions that match InnerMatcher after implicit casts and +/// parentheses are stripped off. +/// +/// Explicit casts are not discarded. +/// Given +/// int arr[5]; +/// int a = 0; +/// char b = (0); +/// const int c = a; +/// int *d = (arr); +/// long e = ((long) 0l); +/// The matchers +/// variable(hasInitializer(ignoringParenImpCasts( +/// integerLiteral()))) +/// variable(hasInitializer(ignoringParenImpCasts( +/// declarationReference()))) +/// would match the declarations for a, b, c, and d, but not e. +/// while +/// variable(hasInitializer(integerLiteral())) +/// variable(hasInitializer(declarationReference())) +/// would only match the declaration for a. +AST_MATCHER_P(Expr, ignoringParenImpCasts, + internal::Matcher<Expr>, InnerMatcher) { + return InnerMatcher.matches(*Node.IgnoreParenImpCasts(), Finder, Builder); +} + /// \brief Matches classTemplateSpecializations where the n'th TemplateArgument /// matches the given Matcher. /// @@ -691,6 +761,19 @@ const internal::VariadicDynCastAllOfMatcher< Expr, ImplicitCastExpr> implicitCast; +/// \brief Matches any cast nodes of Clang's AST. +/// +/// Example: castExpr() matches each of the following: +/// (int) 3; +/// const_cast<Expr *>(SubExpr); +/// char c = 0; +/// but does not match +/// int i = (0); +/// int k = 0; +const internal::VariadicDynCastAllOfMatcher< + Expr, + CastExpr> castExpr; + /// \brief Matches functional cast expressions /// /// Example: Matches Foo(bar); @@ -1193,6 +1276,21 @@ AST_MATCHER_P(DeclRefExpr, throughUsingDecl, return false; } +/// \brief Matches the Decl of a DeclStmt which has a single declaration. +/// +/// Given +/// int a, b; +/// int c; +/// declarationStatement(hasSingleDecl(anything())) +/// matches 'int c;' but not 'int a, b;'. +AST_MATCHER_P(DeclStmt, hasSingleDecl, internal::Matcher<Decl>, InnerMatcher) { + if (Node.isSingleDecl()) { + const Decl *FoundDecl = Node.getSingleDecl(); + return InnerMatcher.matches(*FoundDecl, Finder, Builder); + } + return false; +} + /// \brief Matches a variable declaration that has an initializer expression /// that matches the given matcher. /// @@ -1238,6 +1336,44 @@ AST_POLYMORPHIC_MATCHER_P2( *Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder)); } +/// \brief Matches declaration statements that contain a specific number of +/// declarations. +/// +/// Example: Given +/// int a, b; +/// int c; +/// int d = 2, e; +/// declCountIs(2) +/// matches 'int a, b;' and 'int d = 2, e;', but not 'int c;'. +AST_MATCHER_P(DeclStmt, declCountIs, unsigned, N) { + return std::distance(Node.decl_begin(), Node.decl_end()) == N; +} + +/// \brief Matches the n'th declaration of a declaration statement. +/// +/// Note that this does not work for global declarations because the AST +/// breaks up multiple-declaration DeclStmt's into multiple single-declaration +/// DeclStmt's. +/// Example: Given non-global declarations +/// int a, b = 0; +/// int c; +/// int d = 2, e; +/// declarationStatement(containsDeclaration( +/// 0, variable(hasInitializer(anything())))) +/// matches only 'int d = 2, e;', and +/// declarationStatement(containsDeclaration(1, variable())) +/// matches 'int a, b = 0' as well as 'int d = 2, e;' +/// but 'int c;' is not matched. +AST_MATCHER_P2(DeclStmt, containsDeclaration, unsigned, N, + internal::Matcher<Decl>, InnerMatcher) { + const unsigned NumDecls = std::distance(Node.decl_begin(), Node.decl_end()); + if (N >= NumDecls) + return false; + DeclStmt::const_decl_iterator Iterator = Node.decl_begin(); + std::advance(Iterator, N); + return InnerMatcher.matches(**Iterator, Finder, Builder); +} + /// \brief Matches a constructor initializer. /// /// Given @@ -1385,6 +1521,18 @@ AST_MATCHER_P(FunctionDecl, returns, internal::Matcher<QualType>, Matcher) { return Matcher.matches(Node.getResultType(), Finder, Builder); } +/// \brief Matches extern "C" function declarations. +/// +/// Given: +/// extern "C" void f() {} +/// extern "C" { void g() {} } +/// void h() {} +/// function(isExternC()) +/// matches the declaration of f and g, but not the declaration h +AST_MATCHER(FunctionDecl, isExternC) { + return Node.isExternC(); +} + /// \brief Matches the condition expression of an if statement, for loop, /// or conditional operator. /// diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 99180e450e65a..fade83ef9361c 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -826,6 +826,27 @@ def SharedLocksRequired : InheritableAttr { let TemplateDependent = 1; } +// Type safety attributes for `void *' pointers and type tags. + +def ArgumentWithTypeTag : InheritableAttr { + let Spellings = [GNU<"argument_with_type_tag">, + GNU<"pointer_with_type_tag">]; + let Args = [IdentifierArgument<"ArgumentKind">, + UnsignedArgument<"ArgumentIdx">, + UnsignedArgument<"TypeTagIdx">, + BoolArgument<"IsPointer">]; + let Subjects = [Function]; +} + +def TypeTagForDatatype : InheritableAttr { + let Spellings = [GNU<"type_tag_for_datatype">]; + let Args = [IdentifierArgument<"ArgumentKind">, + TypeArgument<"MatchingCType">, + BoolArgument<"LayoutCompatible">, + BoolArgument<"MustBeNull">]; + let Subjects = [Var]; +} + // Microsoft-related attributes def MsStruct : InheritableAttr { diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index 1b060a509232c..84b28811728ef 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -376,9 +376,9 @@ BUILTIN(__builtin_ctz , "iUi" , "nc") BUILTIN(__builtin_ctzl , "iULi" , "nc") BUILTIN(__builtin_ctzll, "iULLi", "nc") // TODO: int ctzimax(uintmax_t) -BUILTIN(__builtin_ffs , "iUi" , "nc") -BUILTIN(__builtin_ffsl , "iULi" , "nc") -BUILTIN(__builtin_ffsll, "iULLi", "nc") +BUILTIN(__builtin_ffs , "ii" , "nc") +BUILTIN(__builtin_ffsl , "iLi" , "nc") +BUILTIN(__builtin_ffsll, "iLLi", "nc") BUILTIN(__builtin_parity , "iUi" , "nc") BUILTIN(__builtin_parityl , "iULi" , "nc") BUILTIN(__builtin_parityll, "iULLi", "nc") diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index b95a90bd21c3d..d8632dd8c39d6 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -155,6 +155,8 @@ def MethodAccess : DiagGroup<"objc-method-access">; def ObjCReceiver : DiagGroup<"receiver-expr">; def OverlengthStrings : DiagGroup<"overlength-strings">; def OverloadedVirtual : DiagGroup<"overloaded-virtual">; +def PrivateExtern : DiagGroup<"private-extern">; +def SelTypeCast : DiagGroup<"cast-of-sel-type">; def ObjCPropertyImpl : DiagGroup<"objc-property-implementation">; def ObjCPropertyNoAttribute : DiagGroup<"objc-property-no-attribute">; def ObjCMissingSuperCalls : DiagGroup<"objc-missing-super-calls">; @@ -341,6 +343,8 @@ def FormatNonLiteral : DiagGroup<"format-nonliteral", [FormatSecurity]>; def Format2 : DiagGroup<"format=2", [FormatNonLiteral, FormatSecurity, FormatY2K]>; +def TypeSafety : DiagGroup<"type-safety">; + def Extra : DiagGroup<"extra", [ MissingFieldInitializers, IgnoredQualifiers, @@ -371,7 +375,9 @@ def Most : DiagGroup<"most", [ Unused, VolatileRegisterVar, ObjCMissingSuperCalls, - OverloadedVirtual + OverloadedVirtual, + PrivateExtern, + SelTypeCast ]>; // Thread Safety warnings diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 8cb82fd4a9149..b1c16fa8529f1 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -677,6 +677,10 @@ def warn_availability_and_unavailable : Warning< "'unavailable' availability overrides all other availability information">, InGroup<Availability>; +// Type safety attributes +def err_type_safety_unknown_flag : Error< + "invalid comparison flag %0; use 'layout_compatible' or 'must_be_null'">; + // Language specific pragmas // - Generic warnings def warn_pragma_expected_lparen : Warning< diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 6d7b52e55f58f..2d63dc42fd94a 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -815,7 +815,7 @@ def err_friend_def_in_local_class : Error< "friend function cannot be defined in a local class">; def err_abstract_type_in_decl : Error< - "%select{return|parameter|variable|field}0 type %1 is an abstract class">; + "%select{return|parameter|variable|field|ivar}0 type %1 is an abstract class">; def err_allocation_of_abstract_type : Error< "allocating an object of abstract class type %0">; def err_throw_abstract_type : Error< @@ -1489,6 +1489,11 @@ def note_non_literal_user_provided_dtor : Note< "%0 is not literal because it has a user-provided destructor">; def note_non_literal_nontrivial_dtor : Note< "%0 is not literal because it has a non-trivial destructor">; +def warn_private_extern : Warning< + "Use of __private_extern__ on tentative definition has unexpected" + " behaviour - use __attribute__((visibility(\"hidden\"))) on extern" + " declaration or definition instead">, + InGroup<PrivateExtern>, DefaultIgnore; // C++11 char16_t/char32_t def warn_cxx98_compat_unicode_type : Warning< @@ -1542,6 +1547,8 @@ def err_attribute_argument_n_not_int : Error< "'%0' attribute requires parameter %1 to be an integer constant">; def err_attribute_argument_n_not_string : Error< "'%0' attribute requires parameter %1 to be a string">; +def err_attribute_argument_n_not_identifier : Error< + "'%0' attribute requires parameter %1 to be an identifier">; def err_attribute_argument_out_of_bounds : Error< "'%0' attribute parameter %1 is out of bounds">; def err_attribute_requires_objc_interface : Error< @@ -1550,6 +1557,8 @@ def err_attribute_uuid_malformed_guid : Error< "uuid attribute contains a malformed GUID">; def warn_nonnull_pointers_only : Warning< "nonnull attribute only applies to pointer arguments">; +def err_attribute_pointers_only : Error< + "'%0' attribute only applies to pointer arguments">; def err_attribute_invalid_implicit_this_argument : Error< "'%0' attribute is invalid for the implicit this argument">; def err_ownership_type : Error< @@ -1765,7 +1774,6 @@ def err_attribute_can_be_applied_only_to_value_decl : Error< def warn_attribute_not_on_decl : Error< "%0 attribute ignored when parsing type">; - // Availability attribute def warn_availability_unknown_platform : Warning< "unknown platform %0 in availability macro">, InGroup<Availability>; @@ -3677,6 +3685,10 @@ def err_illegal_decl_array_of_references : Error< "'%0' declared as array of references of type %1">; def err_decl_negative_array_size : Error< "'%0' declared as an array with a negative size">; +def err_array_static_outside_prototype : Error< + "%0 used in array declarator outside of function prototype">; +def err_array_static_not_outermost : Error< + "%0 used in non-outermost array type derivation">; def err_array_star_outside_prototype : Error< "star modifier used outside of function prototype">; def err_illegal_decl_pointer_to_reference : Error< @@ -4953,6 +4965,9 @@ def err_typecheck_cast_to_union_no_type : Error< "cast to union type from type %0 not present in union">; def err_cast_pointer_from_non_pointer_int : Error< "operand of type %0 cannot be cast to a pointer type">; +def warn_cast_pointer_from_sel : Warning< + "cast of type %0 to %1 is deprecated; use sel_getName instead">, + InGroup<SelTypeCast>; def err_cast_pointer_to_non_pointer_int : Error< "pointer cannot be cast to type %0">; def err_typecheck_expect_scalar_operand : Error< @@ -5467,6 +5482,23 @@ def warn_identity_field_assign : Warning< "assigning %select{field|instance variable}0 to itself">, InGroup<SelfAssignmentField>; +// Type safety attributes +def err_type_tag_for_datatype_not_ice : Error< + "'type_tag_for_datatype' attribute requires the initializer to be " + "an %select{integer|integral}0 constant expression">; +def err_type_tag_for_datatype_too_large : Error< + "'type_tag_for_datatype' attribute requires the initializer to be " + "an %select{integer|integral}0 constant expression " + "that can be represented by a 64 bit integer">; +def warn_type_tag_for_datatype_wrong_kind : Warning< + "this type tag was not designed to be used with this function">, + InGroup<TypeSafety>; +def warn_type_safety_type_mismatch : Warning< + "argument type %0 doesn't match specified '%1' type tag " + "%select{that requires %3|}2">, InGroup<TypeSafety>; +def warn_type_safety_null_pointer_required : Warning< + "specified %0 type tag requires a null pointer">, InGroup<TypeSafety>; + // Generic selections. def err_assoc_type_incomplete : Error< "type %0 in generic association incomplete">; diff --git a/include/clang/Lex/PTHManager.h b/include/clang/Lex/PTHManager.h index 25a49038a863d..44f9ab39f3216 100644 --- a/include/clang/Lex/PTHManager.h +++ b/include/clang/Lex/PTHManager.h @@ -101,7 +101,7 @@ class PTHManager : public IdentifierInfoLookup { public: // The current PTH version. - enum { Version = 9 }; + enum { Version = 10 }; ~PTHManager(); diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 353b59e0ae324..4ef92f7dbc69f 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1834,6 +1834,10 @@ private: ParsedAttributes &Attrs, SourceLocation *EndLoc); + void ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc); void ParseTypeofSpecifier(DeclSpec &DS); SourceLocation ParseDecltypeSpecifier(DeclSpec &DS); diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index 5239044e67080..bf358862b09eb 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -19,6 +19,7 @@ #include "llvm/ADT/SmallVector.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/VersionTuple.h" +#include "clang/Sema/Ownership.h" #include <cassert> namespace clang { @@ -87,6 +88,10 @@ private: /// availability attribute. unsigned IsAvailability : 1; + /// True if this has extra information associated with a + /// type_tag_for_datatype attribute. + unsigned IsTypeTagForDatatype : 1; + unsigned AttrKind : 8; /// \brief The location of the 'unavailable' keyword in an @@ -119,6 +124,22 @@ private: return reinterpret_cast<const AvailabilityChange*>(this+1)[index]; } +public: + struct TypeTagForDatatypeData { + ParsedType *MatchingCType; + unsigned LayoutCompatible : 1; + unsigned MustBeNull : 1; + }; + +private: + TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() { + return *reinterpret_cast<TypeTagForDatatypeData *>(this + 1); + } + + const TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() const { + return *reinterpret_cast<const TypeTagForDatatypeData *>(this + 1); + } + AttributeList(const AttributeList &); // DO NOT IMPLEMENT void operator=(const AttributeList &); // DO NOT IMPLEMENT void operator delete(void *); // DO NOT IMPLEMENT @@ -126,6 +147,7 @@ private: size_t allocated_size() const; + /// Constructor for attributes with expression arguments. AttributeList(IdentifierInfo *attrName, SourceRange attrRange, IdentifierInfo *scopeName, SourceLocation scopeLoc, IdentifierInfo *parmName, SourceLocation parmLoc, @@ -134,12 +156,13 @@ private: : AttrName(attrName), ScopeName(scopeName), ParmName(parmName), AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), NumArgs(numArgs), SyntaxUsed(syntaxUsed), Invalid(false), - UsedAsTypeAttr(false), IsAvailability(false), - NextInPosition(0), NextInPool(0) { + UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(false), NextInPosition(0), NextInPool(0) { if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(Expr*)); AttrKind = getKind(getName(), getScopeName(), syntaxUsed); } + /// Constructor for availability attributes. AttributeList(IdentifierInfo *attrName, SourceRange attrRange, IdentifierInfo *scopeName, SourceLocation scopeLoc, IdentifierInfo *parmName, SourceLocation parmLoc, @@ -153,6 +176,7 @@ private: AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), NumArgs(0), SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false), IsAvailability(true), + IsTypeTagForDatatype(false), UnavailableLoc(unavailable), MessageExpr(messageExpr), NextInPosition(0), NextInPool(0) { new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced); @@ -161,6 +185,25 @@ private: AttrKind = getKind(getName(), getScopeName(), syntaxUsed); } + /// Constructor for type_tag_for_datatype attribute. + AttributeList(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *argumentKindName, + SourceLocation argumentKindLoc, + ParsedType matchingCType, bool layoutCompatible, + bool mustBeNull, Syntax syntaxUsed) + : AttrName(attrName), ScopeName(scopeName), ParmName(argumentKindName), + AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(argumentKindLoc), + NumArgs(0), SyntaxUsed(syntaxUsed), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(true), NextInPosition(NULL), NextInPool(NULL) { + TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot(); + new (&ExtraData.MatchingCType) ParsedType(matchingCType); + ExtraData.LayoutCompatible = layoutCompatible; + ExtraData.MustBeNull = mustBeNull; + AttrKind = getKind(getName(), getScopeName(), syntaxUsed); + } + friend class AttributePool; friend class AttributeFactory; @@ -279,6 +322,24 @@ public: assert(getKind() == AT_Availability && "Not an availability attribute"); return MessageExpr; } + + const ParsedType &getMatchingCType() const { + assert(getKind() == AT_TypeTagForDatatype && + "Not a type_tag_for_datatype attribute"); + return *getTypeTagForDatatypeDataSlot().MatchingCType; + } + + bool getLayoutCompatible() const { + assert(getKind() == AT_TypeTagForDatatype && + "Not a type_tag_for_datatype attribute"); + return getTypeTagForDatatypeDataSlot().LayoutCompatible; + } + + bool getMustBeNull() const { + assert(getKind() == AT_TypeTagForDatatype && + "Not a type_tag_for_datatype attribute"); + return getTypeTagForDatatypeDataSlot().MustBeNull; + } }; /// A factory, from which one makes pools, from which one creates @@ -294,7 +355,11 @@ public: AvailabilityAllocSize = sizeof(AttributeList) + ((3 * sizeof(AvailabilityChange) + sizeof(void*) - 1) - / sizeof(void*) * sizeof(void*)) + / sizeof(void*) * sizeof(void*)), + TypeTagForDatatypeAllocSize = + sizeof(AttributeList) + + (sizeof(AttributeList::TypeTagForDatatypeData) + sizeof(void *) - 1) + / sizeof(void*) * sizeof(void*) }; private: @@ -411,6 +476,21 @@ public: AttributeList *createIntegerAttribute(ASTContext &C, IdentifierInfo *Name, SourceLocation TokLoc, int Arg); + + AttributeList *createTypeTagForDatatype( + IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *argumentKindName, + SourceLocation argumentKindLoc, + ParsedType matchingCType, bool layoutCompatible, + bool mustBeNull, AttributeList::Syntax syntax) { + void *memory = allocate(AttributeFactory::TypeTagForDatatypeAllocSize); + return add(new (memory) AttributeList(attrName, attrRange, + scopeName, scopeLoc, + argumentKindName, argumentKindLoc, + matchingCType, layoutCompatible, + mustBeNull, syntax)); + } }; /// addAttributeLists - Add two AttributeLists together @@ -503,7 +583,7 @@ public: /// dependencies on this method, it may not be long-lived. AttributeList *&getListRef() { return list; } - + /// Add attribute with expression arguments. AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange, IdentifierInfo *scopeName, SourceLocation scopeLoc, IdentifierInfo *parmName, SourceLocation parmLoc, @@ -516,6 +596,7 @@ public: return attr; } + /// Add availability attribute. AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange, IdentifierInfo *scopeName, SourceLocation scopeLoc, IdentifierInfo *parmName, SourceLocation parmLoc, @@ -533,6 +614,24 @@ public: return attr; } + /// Add type_tag_for_datatype attribute. + AttributeList *addNewTypeTagForDatatype( + IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *argumentKindName, + SourceLocation argumentKindLoc, + ParsedType matchingCType, bool layoutCompatible, + bool mustBeNull, AttributeList::Syntax syntax) { + AttributeList *attr = + pool.createTypeTagForDatatype(attrName, attrRange, + scopeName, scopeLoc, + argumentKindName, argumentKindLoc, + matchingCType, layoutCompatible, + mustBeNull, syntax); + add(attr); + return attr; + } + AttributeList *addNewInteger(ASTContext &C, IdentifierInfo *name, SourceLocation loc, int arg) { AttributeList *attr = diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 058e0d9d39206..acc88c0578ed7 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2498,13 +2498,11 @@ public: ExprResult CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection); StmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, - SourceLocation LParenLoc, Stmt *First, Expr *collection, SourceLocation RParenLoc); StmtResult FinishObjCForCollectionStmt(Stmt *ForCollection, Stmt *Body); - StmtResult ActOnCXXForRangeStmt(SourceLocation ForLoc, - SourceLocation LParenLoc, Stmt *LoopVar, + StmtResult ActOnCXXForRangeStmt(SourceLocation ForLoc, Stmt *LoopVar, SourceLocation ColonLoc, Expr *Collection, SourceLocation RParenLoc); StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc, @@ -2542,8 +2540,8 @@ public: bool MSAsm = false); StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, + SourceLocation LBraceLoc, ArrayRef<Token> AsmToks, - ArrayRef<unsigned> LineEnds, SourceLocation EndLoc); VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, @@ -4463,6 +4461,7 @@ public: AbstractParamType, AbstractVariableType, AbstractFieldType, + AbstractIvarType, AbstractArrayType }; @@ -7146,6 +7145,42 @@ private: void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field, Expr *Init); +public: + /// \brief Register a magic integral constant to be used as a type tag. + void RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, + uint64_t MagicValue, QualType Type, + bool LayoutCompatible, bool MustBeNull); + + struct TypeTagData { + TypeTagData() {} + + TypeTagData(QualType Type, bool LayoutCompatible, bool MustBeNull) : + Type(Type), LayoutCompatible(LayoutCompatible), + MustBeNull(MustBeNull) + {} + + QualType Type; + + /// If true, \c Type should be compared with other expression's types for + /// layout-compatibility. + unsigned LayoutCompatible : 1; + unsigned MustBeNull : 1; + }; + + /// A pair of ArgumentKind identifier and magic value. This uniquely + /// identifies the magic value. + typedef std::pair<const IdentifierInfo *, uint64_t> TypeTagMagicValue; + +private: + /// \brief A map from magic value to type information. + OwningPtr<llvm::DenseMap<TypeTagMagicValue, TypeTagData> > + TypeTagForDatatypeMagicValues; + + /// \brief Peform checks on a call of a function with argument_with_type_tag + /// or pointer_with_type_tag attributes. + void CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, + const Expr * const *ExprArgs); + /// \brief The parser's current scope. /// /// The parser maintains this state here. diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 5ee52cc615890..48393a379b39e 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -81,15 +81,19 @@ protected: typedef llvm::DenseSet<SymbolRef> Symbols; typedef llvm::DenseSet<const MemRegion *> Regions; - /// A set of symbols that are registered with this report as being + /// A (stack of) a set of symbols that are registered with this + /// report as being "interesting", and thus used to help decide which + /// diagnostics to include when constructing the final path diagnostic. + /// The stack is largely used by BugReporter when generating PathDiagnostics + /// for multiple PathDiagnosticConsumers. + llvm::SmallVector<Symbols *, 2> interestingSymbols; + + /// A (stack of) set of regions that are registered with this report as being /// "interesting", and thus used to help decide which diagnostics /// to include when constructing the final path diagnostic. - Symbols interestingSymbols; - - /// A set of regions that are registered with this report as being - /// "interesting", and thus used to help decide which diagnostics - /// to include when constructing the final path diagnostic. - Regions interestingRegions; + /// The stack is largely used by BugReporter when generating PathDiagnostics + /// for multiple PathDiagnosticConsumers. + llvm::SmallVector<Regions *, 2> interestingRegions; /// A set of custom visitors which generate "event" diagnostics at /// interesting points in the path. @@ -107,6 +111,15 @@ protected: /// when reporting an issue. bool DoNotPrunePath; +private: + // Used internally by BugReporter. + Symbols &getInterestingSymbols(); + Regions &getInterestingRegions(); + + void lazyInitializeInterestingSets(); + void pushInterestingSymbolsAndRegions(); + void popInterestingSymbolsAndRegions(); + public: BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode) : BT(bt), DeclWithIssue(0), Description(desc), ErrorNode(errornode), @@ -160,9 +173,9 @@ public: void markInteresting(const MemRegion *R); void markInteresting(SVal V); - bool isInteresting(SymbolRef sym) const; - bool isInteresting(const MemRegion *R) const; - bool isInteresting(SVal V) const; + bool isInteresting(SymbolRef sym); + bool isInteresting(const MemRegion *R); + bool isInteresting(SVal V); unsigned getConfigurationChangeToken() const { return ConfigurationChangeToken; @@ -295,7 +308,7 @@ class BugReporterData { public: virtual ~BugReporterData(); virtual DiagnosticsEngine& getDiagnostic() = 0; - virtual PathDiagnosticConsumer* getPathDiagnosticConsumer() = 0; + virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0; virtual ASTContext &getASTContext() = 0; virtual SourceManager& getSourceManager() = 0; }; @@ -318,6 +331,12 @@ private: /// Generate and flush the diagnostics for the given bug report. void FlushReport(BugReportEquivClass& EQ); + /// Generate and flush the diagnostics for the given bug report + /// and PathDiagnosticConsumer. + void FlushReport(BugReport *exampleReport, + PathDiagnosticConsumer &PD, + ArrayRef<BugReport*> BugReports); + /// The set of bug reports tracked by the BugReporter. llvm::FoldingSet<BugReportEquivClass> EQClasses; /// A vector of BugReports for tracking the allocated pointers and cleanup. @@ -341,8 +360,8 @@ public: return D.getDiagnostic(); } - PathDiagnosticConsumer* getPathDiagnosticConsumer() { - return D.getPathDiagnosticConsumer(); + ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() { + return D.getPathDiagnosticConsumers(); } /// \brief Iterator over the set of BugTypes tracked by the BugReporter. @@ -360,7 +379,8 @@ public: SourceManager& getSourceManager() { return D.getSourceManager(); } virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic, - SmallVectorImpl<BugReport *> &bugReports) {} + PathDiagnosticConsumer &PC, + ArrayRef<BugReport *> &bugReports) {} void Register(BugType *BT); @@ -421,7 +441,8 @@ public: ProgramStateManager &getStateManager(); virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic, - SmallVectorImpl<BugReport*> &bugReports); + PathDiagnosticConsumer &PC, + ArrayRef<BugReport*> &bugReports); /// classof - Used by isa<>, cast<>, and dyn_cast<>. static bool classof(const BugReporter* R) { diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index 2e7abfa5cc3bb..973cfb109c050 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -51,22 +51,25 @@ typedef const SymExpr* SymbolRef; class PathDiagnostic; class PathDiagnosticConsumer { +public: + typedef std::vector<std::pair<StringRef, std::string> > FilesMade; + +private: virtual void anchor(); public: PathDiagnosticConsumer() : flushed(false) {} virtual ~PathDiagnosticConsumer(); - void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade); + void FlushDiagnostics(FilesMade *FilesMade); virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, - SmallVectorImpl<std::string> *FilesMade) - = 0; + FilesMade *filesMade) = 0; virtual StringRef getName() const = 0; void HandlePathDiagnostic(PathDiagnostic *D); - enum PathGenerationScheme { Minimal, Extensive }; + enum PathGenerationScheme { None, Minimal, Extensive }; virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } virtual bool supportsLogicalOpControlFlow() const { return false; } virtual bool supportsAllBlockEdges() const { return false; } @@ -332,15 +335,8 @@ public: ranges.push_back(SourceRange(B,E)); } - typedef const SourceRange* range_iterator; - - range_iterator ranges_begin() const { - return ranges.empty() ? NULL : &ranges[0]; - } - - range_iterator ranges_end() const { - return ranges_begin() + ranges.size(); - } + /// Return the SourceRanges associated with this PathDiagnosticPiece. + ArrayRef<SourceRange> getRanges() const { return ranges; } static inline bool classof(const PathDiagnosticPiece *P) { return true; diff --git a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h index 65be3a406b433..3aab648dc5741 100644 --- a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h +++ b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLIENTS_H #include <string> +#include <vector> namespace clang { @@ -23,24 +24,25 @@ class Preprocessor; namespace ento { class PathDiagnosticConsumer; +typedef std::vector<PathDiagnosticConsumer*> PathDiagnosticConsumers; -PathDiagnosticConsumer* -createHTMLDiagnosticConsumer(const std::string& prefix, const Preprocessor &PP); +void createHTMLDiagnosticConsumer(PathDiagnosticConsumers &C, + const std::string& prefix, + const Preprocessor &PP); -PathDiagnosticConsumer* -createPlistDiagnosticConsumer(const std::string& prefix, const Preprocessor &PP, - PathDiagnosticConsumer *SubPD = 0); +void createPlistDiagnosticConsumer(PathDiagnosticConsumers &C, + const std::string& prefix, + const Preprocessor &PP); -PathDiagnosticConsumer* -createPlistMultiFileDiagnosticConsumer(const std::string& prefix, - const Preprocessor &PP); +void createPlistMultiFileDiagnosticConsumer(PathDiagnosticConsumers &C, + const std::string& prefix, + const Preprocessor &PP); -PathDiagnosticConsumer* -createTextPathDiagnosticConsumer(const std::string& prefix, - const Preprocessor &PP); +void createTextPathDiagnosticConsumer(PathDiagnosticConsumers &C, + const std::string& prefix, + const Preprocessor &PP); -} // end GR namespace - -} // end clang namespace +} // end 'ento' namespace +} // end 'clang' namespace #endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h index 1cc53d4423dac..876196ba4f7fd 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h @@ -19,6 +19,7 @@ #include "clang/Frontend/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" +#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" namespace clang { @@ -32,8 +33,7 @@ class AnalysisManager : public BugReporterData { ASTContext &Ctx; DiagnosticsEngine &Diags; const LangOptions &LangOpts; - - OwningPtr<PathDiagnosticConsumer> PD; + PathDiagnosticConsumers PathConsumers; // Configurable components creators. StoreManagerCreator CreateStoreMgr; @@ -82,8 +82,9 @@ public: bool NoRetryExhausted; public: - AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, - const LangOptions &lang, PathDiagnosticConsumer *pd, + AnalysisManager(ASTContext &ctx,DiagnosticsEngine &diags, + const LangOptions &lang, + const PathDiagnosticConsumers &Consumers, StoreManagerCreator storemgr, ConstraintManagerCreator constraintmgr, CheckerManager *checkerMgr, @@ -99,12 +100,7 @@ public: AnalysisInliningMode inliningMode, bool NoRetry); - /// Construct a clone of the given AnalysisManager with the given ASTContext - /// and DiagnosticsEngine. - AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, - AnalysisManager &ParentAM); - - ~AnalysisManager() { FlushDiagnostics(); } + ~AnalysisManager(); void ClearContexts() { AnaCtxMgr.clear(); @@ -140,15 +136,12 @@ public: return LangOpts; } - virtual PathDiagnosticConsumer *getPathDiagnosticConsumer() { - return PD.get(); - } - - void FlushDiagnostics() { - if (PD.get()) - PD->FlushDiagnostics(0); + ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() { + return PathConsumers; } + void FlushDiagnostics(); + unsigned getMaxNodes() const { return MaxNodes; } unsigned getMaxVisit() const { return MaxVisit; } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index 47edfe9fca91e..f6c5830c2955f 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -328,7 +328,7 @@ public: // For debugging purposes only void dump(raw_ostream &Out) const; - LLVM_ATTRIBUTE_USED void dump() const { dump(llvm::errs()); } + LLVM_ATTRIBUTE_USED void dump() const; static bool classof(const CallEvent *) { return true; } }; @@ -804,8 +804,12 @@ public: return getOriginExpr()->getReceiverInterface(); } + /// Returns how the message was written in the source (property access, + /// subscript, or explicit message send). ObjCMessageKind getMessageKind() const; + /// Returns true if this property access or subscript is a setter (has the + /// form of an assignment). bool isSetter() const { switch (getMessageKind()) { case OCM_Message: diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index 01218effff90d..8044ed839a75e 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -52,7 +52,9 @@ class RegionOffset { int64_t Offset; public: - enum { Symbolic = INT64_MAX }; + // We're using a const instead of an enumeration due to the size required; + // Visual Studio will only create enumerations of size int, not long long. + static const int64_t Symbolic = INT64_MAX; RegionOffset() : R(0) {} RegionOffset(const MemRegion *r, int64_t off) : R(r), Offset(off) {} diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index d36aa1bd1bcbe..b0c51dd5b9285 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -65,10 +65,14 @@ class DynamicTypeInfo { public: DynamicTypeInfo() : T(QualType()) {} - DynamicTypeInfo(QualType WithType, bool CanBeSub = true): - T(WithType), CanBeASubClass(CanBeSub) {} - QualType getType() { return T; } - bool canBeASubClass() { return CanBeASubClass; } + DynamicTypeInfo(QualType WithType, bool CanBeSub = true) + : T(WithType), CanBeASubClass(CanBeSub) {} + + bool isValid() const { return !T.isNull(); } + + QualType getType() const { return T; } + bool canBeASubClass() const { return CanBeASubClass; } + void Profile(llvm::FoldingSetNodeID &ID) const { T.Profile(ID); ID.AddInteger((unsigned)CanBeASubClass); |