Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -569,26 +569,6 @@ IntrusiveRefCntPtr ExternalSource; ASTMutationListener *Listener = nullptr; - /// Contains parents of a node. - using ParentVector = llvm::SmallVector; - - /// Maps from a node to its parents. This is used for nodes that have - /// pointer identity only, which are more common and we can save space by - /// only storing a unique pointer to them. - using ParentMapPointers = - llvm::DenseMap>; - - /// Parent map for nodes without pointer identity. We store a full - /// DynTypedNode for all keys. - using ParentMapOtherNodes = - llvm::DenseMap>; - /// Container for either a single DynTypedNode or for an ArrayRef to /// DynTypedNode. For use with ParentMap. class DynTypedNodeList { @@ -630,6 +610,12 @@ } }; + class Bounds; + std::unique_ptr FullBounds; + Bounds& fullBounds() { return *FullBounds;} + std::unique_ptr + bounds(const std::vector &TopLevelDecls); + std::vector topLevelDecls(const Bounds&); /// Returns the parents of the given node. /// /// Note that this will lazily compute the parents of all nodes @@ -654,11 +640,11 @@ /// /// 'NodeT' can be one of Decl, Stmt, Type, TypeLoc, /// NestedNameSpecifier or NestedNameSpecifierLoc. - template DynTypedNodeList getParents(const NodeT &Node) { - return getParents(ast_type_traits::DynTypedNode::create(Node)); + template + DynTypedNodeList getParents(const NodeT &Node, Bounds &B) { + return getParents(ast_type_traits::DynTypedNode::create(Node), B); } - - DynTypedNodeList getParents(const ast_type_traits::DynTypedNode &Node); + DynTypedNodeList getParents(const ast_type_traits::DynTypedNode &, Bounds &); const clang::PrintingPolicy &getPrintingPolicy() const { return PrintingPolicy; @@ -2921,13 +2907,9 @@ // but we include it here so that ASTContext can quickly deallocate them. llvm::PointerIntPair LastSDM; - std::unique_ptr PointerParents; - std::unique_ptr OtherParents; - std::unique_ptr VTContext; void ReleaseDeclContextMaps(); - void ReleaseParentMapEntries(); public: enum PragmaSectionFlag : unsigned { Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -195,6 +195,14 @@ /// \returns false if the visitation was terminated early, true otherwise. bool dataTraverseStmtPost(Stmt *S) { return true; } + /// Recursively visit an AST, calling TraverseDecl() on its top-level decls. + bool TraverseAST(ASTContext &Ctx, ASTContext::Bounds &B) { + for (Decl *D : Ctx.topLevelDecls(B)) + if (!TraverseDecl(D)) + return false; + return true; + } + /// Recursively visit a type, by dispatching to /// Traverse*Type() based on the argument's getTypeClass() property. /// Index: include/clang/ASTMatchers/ASTMatchFinder.h =================================================================== --- include/clang/ASTMatchers/ASTMatchFinder.h +++ include/clang/ASTMatchers/ASTMatchFinder.h @@ -73,7 +73,8 @@ /// Every time a match is found, the MatchFinder will invoke the registered /// MatchCallback with a MatchResult containing information about the match. struct MatchResult { - MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context); + MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context, + clang::ASTContext::Bounds *Bounds); /// Contains the nodes bound on the current match. /// @@ -83,6 +84,7 @@ /// Utilities for interpreting the matched AST structures. /// @{ clang::ASTContext * const Context; + clang::ASTContext::Bounds *Bounds; clang::SourceManager * const SourceManager; /// @} }; @@ -182,15 +184,16 @@ /// example when using decl(forEachDescendant(stmt())). /// /// @{ - template void match(const T &Node, ASTContext &Context) { - match(clang::ast_type_traits::DynTypedNode::create(Node), Context); + template + void match(const T &Node, ASTContext &Context, ASTContext::Bounds &Bounds) { + match(clang::ast_type_traits::DynTypedNode::create(Node), Context, Bounds); } void match(const clang::ast_type_traits::DynTypedNode &Node, - ASTContext &Context); + ASTContext &Context, ASTContext::Bounds &); /// @} /// Finds all matches in the given AST. - void matchAST(ASTContext &Context); + void matchAST(ASTContext &, ASTContext::Bounds &); /// Registers a callback to notify the end of parsing. /// @@ -239,19 +242,20 @@ /// \see selectFirst /// @{ template -SmallVector -match(MatcherT Matcher, const NodeT &Node, ASTContext &Context); +SmallVector match(MatcherT Matcher, const NodeT &Node, + ASTContext &Context, ASTContext::Bounds &); template -SmallVector -match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node, - ASTContext &Context); +SmallVector match(MatcherT Matcher, + const ast_type_traits::DynTypedNode &Node, + ASTContext &Context, ASTContext::Bounds &); /// @} /// Returns the results of matching \p Matcher on the translation unit of /// \p Context and collects the \c BoundNodes of all callback invocations. template -SmallVector match(MatcherT Matcher, ASTContext &Context); +SmallVector match(MatcherT Matcher, ASTContext &Context, + ASTContext::Bounds &); /// Returns the first result of type \c NodeT bound to \p BoundTo. /// @@ -286,27 +290,29 @@ template SmallVector match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node, - ASTContext &Context) { + ASTContext &Context, ASTContext::Bounds &Bounds) { internal::CollectMatchesCallback Callback; MatchFinder Finder; Finder.addMatcher(Matcher, &Callback); - Finder.match(Node, Context); + Finder.match(Node, Context, Bounds); return std::move(Callback.Nodes); } template -SmallVector -match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) { - return match(Matcher, ast_type_traits::DynTypedNode::create(Node), Context); +SmallVector match(MatcherT Matcher, const NodeT &Node, + ASTContext &Context, + ASTContext::Bounds &Bounds) { + return match(Matcher, ast_type_traits::DynTypedNode::create(Node), Context, + Bounds); } template -SmallVector -match(MatcherT Matcher, ASTContext &Context) { +SmallVector match(MatcherT Matcher, ASTContext &Context, + ASTContext::Bounds &Bounds) { internal::CollectMatchesCallback Callback; MatchFinder Finder; Finder.addMatcher(Matcher, &Callback); - Finder.matchAST(Context); + Finder.matchAST(Context, Bounds); return std::move(Callback.Nodes); } Index: include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -6121,7 +6121,8 @@ /// but does match 'return > 0' AST_MATCHER_P(Stmt, forFunction, internal::Matcher, InnerMatcher) { - const auto &Parents = Finder->getASTContext().getParents(Node); + const auto &Parents = + Finder->getASTContext().getParents(Node, Finder->getASTBounds()); llvm::SmallVector Stack(Parents.begin(), Parents.end()); @@ -6138,7 +6139,8 @@ return true; } } else { - for(const auto &Parent: Finder->getASTContext().getParents(CurNode)) + for (const auto &Parent : + Finder->getASTContext().getParents(CurNode, Finder->getASTBounds())) Stack.push_back(Parent); } } Index: include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- include/clang/ASTMatchers/ASTMatchersInternal.h +++ include/clang/ASTMatchers/ASTMatchersInternal.h @@ -1038,6 +1038,7 @@ } virtual ASTContext &getASTContext() const = 0; + virtual ASTContext::Bounds &getASTBounds() const = 0; protected: virtual bool matchesChildOf(const ast_type_traits::DynTypedNode &Node, Index: include/clang/Analysis/Analyses/ExprMutationAnalyzer.h =================================================================== --- include/clang/Analysis/Analyses/ExprMutationAnalyzer.h +++ include/clang/Analysis/Analyses/ExprMutationAnalyzer.h @@ -23,8 +23,9 @@ /// a given statement. class ExprMutationAnalyzer { public: - ExprMutationAnalyzer(const Stmt &Stm, ASTContext &Context) - : Stm(Stm), Context(Context) {} + ExprMutationAnalyzer(const Stmt &Stm, ASTContext &Context, + ASTContext::Bounds &Bounds) + : Stm(Stm), Context(Context), Bounds(Bounds) {} bool isMutated(const Expr *Exp) { return findMutation(Exp) != nullptr; } bool isMutated(const Decl *Dec) { return findMutation(Dec) != nullptr; } @@ -68,6 +69,7 @@ const Stmt &Stm; ASTContext &Context; + ASTContext::Bounds &Bounds; llvm::DenseMap> FuncParmAnalyzer; @@ -79,7 +81,8 @@ // params. class FunctionParmMutationAnalyzer { public: - FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context); + FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context, + ASTContext::Bounds &Bounds); bool isMutated(const ParmVarDecl *Parm) { return findMutation(Parm) != nullptr; Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -781,6 +781,96 @@ llvm_unreachable("getAddressSpaceMapMangling() doesn't cover anything."); } +class ASTContext::Bounds { + /// Contains parents of a node. + using ParentVector = llvm::SmallVector; + + /// Maps from a node to its parents. This is used for nodes that have + /// pointer identity only, which are more common and we can save space by + /// only storing a unique pointer to them. + using ParentMapPointers = llvm::DenseMap< + const void *, + llvm::PointerUnion4>; + + /// Parent map for nodes without pointer identity. We store a full + /// DynTypedNode for all keys. + using ParentMapOtherNodes = llvm::DenseMap< + ast_type_traits::DynTypedNode, + llvm::PointerUnion4>; + + ASTContext &Ctx; + std::vector TopLevelDecls; + + // Parent map cache. + class ParentMapASTVisitor; + std::unique_ptr PointerParents; + std::unique_ptr OtherParents; + + static ast_type_traits::DynTypedNode + getSingleDynTypedNodeFromParentMap(ParentMapPointers::mapped_type U) { + if (const auto *D = U.dyn_cast()) + return ast_type_traits::DynTypedNode::create(*D); + if (const auto *S = U.dyn_cast()) + return ast_type_traits::DynTypedNode::create(*S); + return *U.get(); + } + template + static ASTContext::DynTypedNodeList getDynNodeFromMap(const NodeTy &Node, + const MapTy &Map) { + auto I = Map.find(Node); + if (I == Map.end()) { + return llvm::ArrayRef(); + } + if (const auto *V = I->second.template dyn_cast()) { + return llvm::makeArrayRef(*V); + } + return getSingleDynTypedNodeFromParentMap(I->second); + } + +public: + Bounds(ASTContext &Ctx, llvm::ArrayRef TopLevelDecls) + : Ctx(Ctx), TopLevelDecls(TopLevelDecls) {} + ~Bounds() { + if (!PointerParents) + return; + for (const auto &Entry : *PointerParents) { + if (Entry.second.is()) { + delete Entry.second.get(); + } else if (Entry.second.is()) { + delete Entry.second.get(); + } + } + for (const auto &Entry : *OtherParents) { + if (Entry.second.is()) { + delete Entry.second.get(); + } else if (Entry.second.is()) { + delete Entry.second.get(); + } + } + } + + DynTypedNodeList getParents(const ast_type_traits::DynTypedNode &Node); + std::vector topLevelDecls() const { return TopLevelDecls; } + ASTContext &getASTContext() { return Ctx; } +}; + +ASTContext::DynTypedNodeList +ASTContext::getParents(const ast_type_traits::DynTypedNode &N, Bounds &B) { + assert(&B.getASTContext() == this); + return B.getParents(N); +} + +std::unique_ptr +ASTContext::bounds(const std::vector &TopLevelDecls) { + return {new Bounds(*this, TopLevelDecls), [](Bounds *P) { delete P; }}; +} + +std::vector ASTContext::topLevelDecls(const Bounds& B) { + return B.topLevelDecls(); +} + ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, IdentifierTable &idents, SelectorTable &sels, Builtin::Context &builtins) @@ -796,11 +886,10 @@ CommentCommandTraits(BumpAlloc, LOpts.CommentOpts), CompCategories(this_()), LastSDM(nullptr, 0) { TUDecl = TranslationUnitDecl::Create(*this); + FullBounds = llvm::make_unique(*this, std::vector{TUDecl}); } ASTContext::~ASTContext() { - ReleaseParentMapEntries(); - // Release the DenseMaps associated with DeclContext objects. // FIXME: Is this the ideal solution? ReleaseDeclContextMaps(); @@ -838,24 +927,6 @@ Value.second->~PerModuleInitializers(); } -void ASTContext::ReleaseParentMapEntries() { - if (!PointerParents) return; - for (const auto &Entry : *PointerParents) { - if (Entry.second.is()) { - delete Entry.second.get(); - } else if (Entry.second.is()) { - delete Entry.second.get(); - } - } - for (const auto &Entry : *OtherParents) { - if (Entry.second.is()) { - delete Entry.second.get(); - } else if (Entry.second.is()) { - delete Entry.second.get(); - } - } -} - void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) { Deallocations.push_back({Callback, Data}); } @@ -10094,21 +10165,10 @@ return (Size != Align || toBits(sizeChars) > MaxInlineWidthInBits); } -static ast_type_traits::DynTypedNode getSingleDynTypedNodeFromParentMap( - ASTContext::ParentMapPointers::mapped_type U) { - if (const auto *D = U.dyn_cast()) - return ast_type_traits::DynTypedNode::create(*D); - if (const auto *S = U.dyn_cast()) - return ast_type_traits::DynTypedNode::create(*S); - return *U.get(); -} - -namespace { - /// Template specializations to abstract away from pointers and TypeLocs. /// @{ template -ast_type_traits::DynTypedNode createDynTypedNode(const T &Node) { +static ast_type_traits::DynTypedNode createDynTypedNode(const T &Node) { return ast_type_traits::DynTypedNode::create(*Node); } template <> @@ -10122,154 +10182,132 @@ } /// @} - /// A \c RecursiveASTVisitor that builds a map from nodes to their - /// parents as defined by the \c RecursiveASTVisitor. - /// - /// Note that the relationship described here is purely in terms of AST - /// traversal - there are other relationships (for example declaration context) - /// in the AST that are better modeled by special matchers. +/// A \c RecursiveASTVisitor that builds a map from nodes to their +/// parents as defined by the \c RecursiveASTVisitor. +/// +/// Note that the relationship described here is purely in terms of AST +/// traversal - there are other relationships (for example declaration context) +/// in the AST that are better modeled by special matchers. +/// +/// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes. +class ASTContext::Bounds::ParentMapASTVisitor + : public RecursiveASTVisitor { +public: + /// Builds and returns the translation unit's parent map. /// - /// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes. - class ParentMapASTVisitor : public RecursiveASTVisitor { - public: - /// Builds and returns the translation unit's parent map. - /// - /// The caller takes ownership of the returned \c ParentMap. - static std::pair - buildMap(TranslationUnitDecl &TU) { - ParentMapASTVisitor Visitor(new ASTContext::ParentMapPointers, - new ASTContext::ParentMapOtherNodes); - Visitor.TraverseDecl(&TU); - return std::make_pair(Visitor.Parents, Visitor.OtherParents); - } + /// The caller takes ownership of the returned \c ParentMap. + static std::pair + buildMap(const std::vector &TopLevelDecls) { + ParentMapASTVisitor Visitor(new ParentMapPointers, + new ParentMapOtherNodes); + for (Decl *D : TopLevelDecls) + Visitor.TraverseDecl(D); + return std::make_pair(Visitor.Parents, Visitor.OtherParents); + } - private: - friend class RecursiveASTVisitor; +private: + friend class RecursiveASTVisitor; - using VisitorBase = RecursiveASTVisitor; + using VisitorBase = RecursiveASTVisitor; - ParentMapASTVisitor(ASTContext::ParentMapPointers *Parents, - ASTContext::ParentMapOtherNodes *OtherParents) - : Parents(Parents), OtherParents(OtherParents) {} + ParentMapASTVisitor(ParentMapPointers *Parents, + ParentMapOtherNodes *OtherParents) + : Parents(Parents), OtherParents(OtherParents) {} - bool shouldVisitTemplateInstantiations() const { - return true; - } + bool shouldVisitTemplateInstantiations() const { return true; } - bool shouldVisitImplicitCode() const { - return true; - } + bool shouldVisitImplicitCode() const { return true; } - template - bool TraverseNode(T Node, MapNodeTy MapNode, - BaseTraverseFn BaseTraverse, MapTy *Parents) { - if (!Node) - return true; - if (ParentStack.size() > 0) { - // FIXME: Currently we add the same parent multiple times, but only - // when no memoization data is available for the type. - // For example when we visit all subexpressions of template - // instantiations; this is suboptimal, but benign: the only way to - // visit those is with hasAncestor / hasParent, and those do not create - // new matches. - // The plan is to enable DynTypedNode to be storable in a map or hash - // map. The main problem there is to implement hash functions / - // comparison operators for all types that DynTypedNode supports that - // do not have pointer identity. - auto &NodeOrVector = (*Parents)[MapNode]; - if (NodeOrVector.isNull()) { - if (const auto *D = ParentStack.back().get()) - NodeOrVector = D; - else if (const auto *S = ParentStack.back().get()) - NodeOrVector = S; - else - NodeOrVector = - new ast_type_traits::DynTypedNode(ParentStack.back()); - } else { - if (!NodeOrVector.template is()) { - auto *Vector = new ASTContext::ParentVector( - 1, getSingleDynTypedNodeFromParentMap(NodeOrVector)); - delete NodeOrVector - .template dyn_cast(); - NodeOrVector = Vector; - } - - auto *Vector = - NodeOrVector.template get(); - // Skip duplicates for types that have memoization data. - // We must check that the type has memoization data before calling - // std::find() because DynTypedNode::operator== can't compare all - // types. - bool Found = ParentStack.back().getMemoizationData() && - std::find(Vector->begin(), Vector->end(), - ParentStack.back()) != Vector->end(); - if (!Found) - Vector->push_back(ParentStack.back()); + template + bool TraverseNode(T Node, MapNodeTy MapNode, BaseTraverseFn BaseTraverse, + MapTy *Parents) { + if (!Node) + return true; + if (ParentStack.size() > 0) { + // FIXME: Currently we add the same parent multiple times, but only + // when no memoization data is available for the type. + // For example when we visit all subexpressions of template + // instantiations; this is suboptimal, but benign: the only way to + // visit those is with hasAncestor / hasParent, and those do not create + // new matches. + // The plan is to enable DynTypedNode to be storable in a map or hash + // map. The main problem there is to implement hash functions / + // comparison operators for all types that DynTypedNode supports that + // do not have pointer identity. + auto &NodeOrVector = (*Parents)[MapNode]; + if (NodeOrVector.isNull()) { + if (const auto *D = ParentStack.back().get()) + NodeOrVector = D; + else if (const auto *S = ParentStack.back().get()) + NodeOrVector = S; + else + NodeOrVector = new ast_type_traits::DynTypedNode(ParentStack.back()); + } else { + if (!NodeOrVector.template is()) { + auto *Vector = new ParentVector( + 1, getSingleDynTypedNodeFromParentMap(NodeOrVector)); + delete NodeOrVector + .template dyn_cast(); + NodeOrVector = Vector; } - } - ParentStack.push_back(createDynTypedNode(Node)); - bool Result = BaseTraverse(); - ParentStack.pop_back(); - return Result; - } - bool TraverseDecl(Decl *DeclNode) { - return TraverseNode(DeclNode, DeclNode, - [&] { return VisitorBase::TraverseDecl(DeclNode); }, - Parents); - } - - bool TraverseStmt(Stmt *StmtNode) { - return TraverseNode(StmtNode, StmtNode, - [&] { return VisitorBase::TraverseStmt(StmtNode); }, - Parents); - } - - bool TraverseTypeLoc(TypeLoc TypeLocNode) { - return TraverseNode( - TypeLocNode, ast_type_traits::DynTypedNode::create(TypeLocNode), - [&] { return VisitorBase::TraverseTypeLoc(TypeLocNode); }, - OtherParents); - } - - bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLocNode) { - return TraverseNode( - NNSLocNode, ast_type_traits::DynTypedNode::create(NNSLocNode), - [&] { - return VisitorBase::TraverseNestedNameSpecifierLoc(NNSLocNode); - }, - OtherParents); + auto *Vector = NodeOrVector.template get(); + // Skip duplicates for types that have memoization data. + // We must check that the type has memoization data before calling + // std::find() because DynTypedNode::operator== can't compare all + // types. + bool Found = ParentStack.back().getMemoizationData() && + std::find(Vector->begin(), Vector->end(), + ParentStack.back()) != Vector->end(); + if (!Found) + Vector->push_back(ParentStack.back()); + } } + ParentStack.push_back(createDynTypedNode(Node)); + bool Result = BaseTraverse(); + ParentStack.pop_back(); + return Result; + } - ASTContext::ParentMapPointers *Parents; - ASTContext::ParentMapOtherNodes *OtherParents; - llvm::SmallVector ParentStack; - }; + bool TraverseDecl(Decl *DeclNode) { + return TraverseNode( + DeclNode, DeclNode, [&] { return VisitorBase::TraverseDecl(DeclNode); }, + Parents); + } -} // namespace + bool TraverseStmt(Stmt *StmtNode) { + return TraverseNode( + StmtNode, StmtNode, [&] { return VisitorBase::TraverseStmt(StmtNode); }, + Parents); + } -template -static ASTContext::DynTypedNodeList getDynNodeFromMap(const NodeTy &Node, - const MapTy &Map) { - auto I = Map.find(Node); - if (I == Map.end()) { - return llvm::ArrayRef(); + bool TraverseTypeLoc(TypeLoc TypeLocNode) { + return TraverseNode( + TypeLocNode, ast_type_traits::DynTypedNode::create(TypeLocNode), + [&] { return VisitorBase::TraverseTypeLoc(TypeLocNode); }, + OtherParents); } - if (const auto *V = - I->second.template dyn_cast()) { - return llvm::makeArrayRef(*V); + + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLocNode) { + return TraverseNode( + NNSLocNode, ast_type_traits::DynTypedNode::create(NNSLocNode), + [&] { return VisitorBase::TraverseNestedNameSpecifierLoc(NNSLocNode); }, + OtherParents); } - return getSingleDynTypedNodeFromParentMap(I->second); -} + + ParentMapPointers *Parents; + ParentMapOtherNodes *OtherParents; + llvm::SmallVector ParentStack; +}; ASTContext::DynTypedNodeList -ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) { +ASTContext::Bounds::getParents(const ast_type_traits::DynTypedNode &Node) { if (!PointerParents) { // We always need to run over the whole translation unit, as // hasAncestor can escape any subtree. - auto Maps = ParentMapASTVisitor::buildMap(*getTranslationUnitDecl()); + auto Maps = ParentMapASTVisitor::buildMap(TopLevelDecls); PointerParents.reset(Maps.first); OtherParents.reset(Maps.second); } Index: lib/ASTMatchers/ASTMatchFinder.cpp =================================================================== --- lib/ASTMatchers/ASTMatchFinder.cpp +++ lib/ASTMatchers/ASTMatchFinder.cpp @@ -340,8 +340,10 @@ } } - void set_active_ast_context(ASTContext *NewActiveASTContext) { + void set_active_ast_context(ASTContext *NewActiveASTContext, + ASTContext::Bounds *Bounds) { ActiveASTContext = NewActiveASTContext; + ActiveBounds = Bounds; } // The following Visit*() and Traverse*() functions "override" @@ -501,6 +503,7 @@ // Implements ASTMatchFinder::getASTContext. ASTContext &getASTContext() const override { return *ActiveASTContext; } + ASTContext::Bounds &getASTBounds() const override { return *ActiveBounds; } bool shouldVisitTemplateInstantiations() const { return true; } bool shouldVisitImplicitCode() const { return true; } @@ -546,7 +549,7 @@ Timer.setBucket(&TimeByBucket[MP.second->getID()]); BoundNodesTreeBuilder Builder; if (MP.first.matches(Node, this, &Builder)) { - MatchVisitor Visitor(ActiveASTContext, MP.second); + MatchVisitor Visitor(ActiveASTContext, ActiveBounds,MP.second); Builder.visitMatches(&Visitor); } } @@ -570,7 +573,7 @@ Timer.setBucket(&TimeByBucket[MP.second->getID()]); BoundNodesTreeBuilder Builder; if (MP.first.matchesNoKindCheck(DynNode, this, &Builder)) { - MatchVisitor Visitor(ActiveASTContext, MP.second); + MatchVisitor Visitor(ActiveASTContext, ActiveBounds, MP.second); Builder.visitMatches(&Visitor); } } @@ -635,8 +638,7 @@ bool memoizedMatchesAncestorOfRecursively( const ast_type_traits::DynTypedNode &Node, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) { - if (Node.get() == - ActiveASTContext->getTranslationUnitDecl()) + if (Node.get() != nullptr) return false; // For AST-nodes that don't have an identity, we can't memoize. @@ -672,7 +674,7 @@ const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) { - const auto &Parents = ActiveASTContext->getParents(Node); + const auto &Parents = ActiveASTContext->getParents(Node, *ActiveBounds); assert(!Parents.empty() && "Found node that is not in the parent map."); if (Parents.size() == 1) { // Only one parent - do recursive memoization. @@ -701,7 +703,7 @@ } if (MatchMode != ASTMatchFinder::AMM_ParentOnly) { for (const auto &Parent : - ActiveASTContext->getParents(Queue.front())) { + ActiveASTContext->getParents(Queue.front(), *ActiveBounds)) { // Make sure we do not visit the same node twice. // Otherwise, we'll visit the common ancestors as often as there // are splits on the way down. @@ -719,17 +721,18 @@ // the aggregated bound nodes for each match. class MatchVisitor : public BoundNodesTreeBuilder::Visitor { public: - MatchVisitor(ASTContext* Context, - MatchFinder::MatchCallback* Callback) - : Context(Context), - Callback(Callback) {} + MatchVisitor(ASTContext *Context, ASTContext::Bounds *Bounds, + MatchFinder::MatchCallback *Callback) + : Context(Context), Bounds(Bounds), Callback(Callback) {} void visitMatch(const BoundNodes& BoundNodesView) override { - Callback->run(MatchFinder::MatchResult(BoundNodesView, Context)); + Callback->run( + MatchFinder::MatchResult(BoundNodesView, Context, Bounds)); } private: ASTContext* Context; + ASTContext::Bounds* Bounds; MatchFinder::MatchCallback* Callback; }; @@ -772,6 +775,7 @@ const MatchFinder::MatchFinderOptions &Options; ASTContext *ActiveASTContext; + ASTContext::Bounds *ActiveBounds; // Maps a canonical type to its TypedefDecls. llvm::DenseMap > TypeAliases; @@ -912,7 +916,7 @@ if (ParsingDone != nullptr) { ParsingDone->run(); } - Finder->matchAST(Context); + Finder->matchAST(Context, Context.fullBounds()); } MatchFinder *Finder; @@ -923,9 +927,10 @@ } // end namespace internal MatchFinder::MatchResult::MatchResult(const BoundNodes &Nodes, - ASTContext *Context) - : Nodes(Nodes), Context(Context), - SourceManager(&Context->getSourceManager()) {} + ASTContext *Context, + ASTContext::Bounds *Bounds) + : Nodes(Nodes), Context(Context), Bounds(Bounds), + SourceManager(&Context->getSourceManager()) {} MatchFinder::MatchCallback::~MatchCallback() {} MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {} @@ -1009,17 +1014,18 @@ } void MatchFinder::match(const clang::ast_type_traits::DynTypedNode &Node, - ASTContext &Context) { + ASTContext &Context, ASTContext::Bounds &Bounds) { internal::MatchASTVisitor Visitor(&Matchers, Options); - Visitor.set_active_ast_context(&Context); + Visitor.set_active_ast_context(&Context, &Bounds); Visitor.match(Node); } -void MatchFinder::matchAST(ASTContext &Context) { +void MatchFinder::matchAST(ASTContext &Context, ASTContext::Bounds &Bounds) { internal::MatchASTVisitor Visitor(&Matchers, Options); - Visitor.set_active_ast_context(&Context); + Visitor.set_active_ast_context(&Context, &Bounds); Visitor.onStartOfTranslationUnit(); - Visitor.TraverseDecl(Context.getTranslationUnitDecl()); + for (Decl* D : Context.topLevelDecls(Bounds)) + Visitor.TraverseDecl(D); Visitor.onEndOfTranslationUnit(); } Index: lib/Analysis/ExprMutationAnalyzer.cpp =================================================================== --- lib/Analysis/ExprMutationAnalyzer.cpp +++ lib/Analysis/ExprMutationAnalyzer.cpp @@ -129,7 +129,7 @@ MutationFinder Finder) { const auto Refs = match(findAll(declRefExpr(to(equalsNode(Dec))).bind(NodeID::value)), - Stm, Context); + Stm, Context, Bounds); for (const auto &RefNodes : Refs) { const auto *E = RefNodes.getNodeAs(NodeID::value); if ((this->*Finder)(E)) @@ -166,7 +166,7 @@ hasDescendant(equalsNode(Exp)))), cxxNoexceptExpr()))))) .bind(NodeID::value)), - Stm, Context)) != nullptr; + Stm, Context, Bounds)) != nullptr; } const Stmt * @@ -270,7 +270,7 @@ AsOperatorArrowThis, AsNonConstRefArg, AsLambdaRefCaptureInit, AsNonConstRefReturn)) .bind("stmt")), - Stm, Context); + Stm, Context, Bounds); return selectFirst("stmt", Matches); } @@ -281,7 +281,7 @@ cxxDependentScopeMemberExpr( hasObjectExpression(equalsNode(Exp))))) .bind(NodeID::value)), - Stm, Context); + Stm, Context, Bounds); return findExprMutation(MemberExprs); } @@ -290,7 +290,7 @@ const auto SubscriptExprs = match( findAll(arraySubscriptExpr(hasBase(ignoringImpCasts(equalsNode(Exp)))) .bind(NodeID::value)), - Stm, Context); + Stm, Context, Bounds); return findExprMutation(SubscriptExprs); } @@ -303,7 +303,7 @@ implicitCastExpr(hasImplicitDestinationType( nonConstReferenceType())))) .bind(NodeID::value)), - Stm, Context); + Stm, Context, Bounds); if (const Stmt *S = findExprMutation(Casts)) return S; // Treat std::{move,forward} as cast. @@ -312,7 +312,7 @@ hasAnyName("::std::move", "::std::forward"))), hasArgument(0, equalsNode(Exp))) .bind("expr")), - Stm, Context); + Stm, Context, Bounds); return findExprMutation(Calls); } @@ -324,7 +324,7 @@ hasLoopVariable(varDecl(hasType(nonConstReferenceType())) .bind(NodeID::value)), hasRangeInit(equalsNode(Exp)))), - Stm, Context); + Stm, Context, Bounds); return findDeclMutation(LoopVars); } @@ -339,7 +339,7 @@ returns(nonConstReferenceType()))), argumentCountIs(1), hasArgument(0, equalsNode(Exp))) .bind(NodeID::value)), - Stm, Context); + Stm, Context, Bounds); if (const Stmt *S = findExprMutation(Ref)) return S; @@ -358,7 +358,7 @@ unless(hasParent(declStmt(hasParent( cxxForRangeStmt(hasRangeStmt(equalsBoundNode("stmt")))))))) .bind(NodeID::value))), - Stm, Context); + Stm, Context, Bounds); return findDeclMutation(Refs); } @@ -375,7 +375,7 @@ cxxConstructExpr(NonConstRefParam, IsInstantiated, FuncDecl))) .bind(NodeID::value)), - Stm, Context); + Stm, Context, Bounds); for (const auto &Nodes : Matches) { const auto *Exp = Nodes.getNodeAs(NodeID::value); const auto *Func = Nodes.getNodeAs("func"); @@ -400,7 +400,8 @@ std::unique_ptr &Analyzer = FuncParmAnalyzer[Func]; if (!Analyzer) - Analyzer.reset(new FunctionParmMutationAnalyzer(*Func, Context)); + Analyzer.reset( + new FunctionParmMutationAnalyzer(*Func, Context, Bounds)); if (Analyzer->findMutation(Parm)) return Exp; continue; @@ -413,13 +414,13 @@ } FunctionParmMutationAnalyzer::FunctionParmMutationAnalyzer( - const FunctionDecl &Func, ASTContext &Context) - : BodyAnalyzer(*Func.getBody(), Context) { + const FunctionDecl &Func, ASTContext &Context, ASTContext::Bounds &Bounds) + : BodyAnalyzer(*Func.getBody(), Context, Bounds) { if (const auto *Ctor = dyn_cast(&Func)) { // CXXCtorInitializer might also mutate Param but they're not part of // function body, check them eagerly here since they're typically trivial. for (const CXXCtorInitializer *Init : Ctor->inits()) { - ExprMutationAnalyzer InitAnalyzer(*Init->getInit(), Context); + ExprMutationAnalyzer InitAnalyzer(*Init->getInit(), Context, Bounds); for (const ParmVarDecl *Parm : Ctor->parameters()) { if (Results.find(Parm) != Results.end()) continue; Index: lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp +++ lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp @@ -212,12 +212,14 @@ AnalysisDeclContext *ADC = AM.getAnalysisDeclContext(D); auto SemaphoreMatcherM = findGCDAntiPatternWithSemaphore(); - auto Matches = match(SemaphoreMatcherM, *D->getBody(), AM.getASTContext()); + auto Matches = match(SemaphoreMatcherM, *D->getBody(), AM.getASTContext(), + AM.getASTContext().fullBounds()); for (BoundNodes Match : Matches) emitDiagnostics(Match, "semaphore", BR, ADC, this); auto GroupMatcherM = findGCDAntiPatternWithGroup(); - Matches = match(GroupMatcherM, *D->getBody(), AM.getASTContext()); + Matches = match(GroupMatcherM, *D->getBody(), AM.getASTContext(), + AM.getASTContext().fullBounds()); for (BoundNodes Match : Matches) emitDiagnostics(Match, "group", BR, ADC, this); } Index: lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp +++ lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp @@ -339,7 +339,7 @@ Callback CB(this, BR, AM.getAnalysisDeclContext(D)); F.addMatcher(stmt(forEachDescendant(FinalM)), &CB); - F.match(*D->getBody(), AM.getASTContext()); + F.match(*D->getBody(), AM.getASTContext(), AM.getASTContext().fullBounds()); } void ento::registerNumberObjectConversionChecker(CheckerManager &Mgr) { Index: lib/StaticAnalyzer/Checkers/ObjCAutoreleaseWriteChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/ObjCAutoreleaseWriteChecker.cpp +++ lib/StaticAnalyzer/Checkers/ObjCAutoreleaseWriteChecker.cpp @@ -199,7 +199,8 @@ functionDecl(HasParamAndWritesInMarkedFuncM), blockDecl(HasParamAndWritesInMarkedFuncM))); - auto Matches = match(MatcherM, *D, AM.getASTContext()); + auto Matches = + match(MatcherM, *D, AM.getASTContext(), AM.getASTContext().fullBounds()); for (BoundNodes Match : Matches) emitDiagnostics(Match, D, BR, AM, this); } Index: lib/StaticAnalyzer/Checkers/RunLoopAutoreleaseLeakChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/RunLoopAutoreleaseLeakChecker.cpp +++ lib/StaticAnalyzer/Checkers/RunLoopAutoreleaseLeakChecker.cpp @@ -184,7 +184,8 @@ DeclarationMatcher GroupM = decl(hasDescendant(RunLoopInAutorelease)); - auto Matches = match(GroupM, *D, AM.getASTContext()); + auto Matches = + match(GroupM, *D, AM.getASTContext(), AM.getASTContext().fullBounds()); for (BoundNodes Match : Matches) emitDiagnostics(Match, D, BR, AM, Chkr); } @@ -204,7 +205,8 @@ hasDescendant(OtherMessageSentM) ); - auto Matches = match(GroupM, *D, AM.getASTContext()); + auto Matches = + match(GroupM, *D, AM.getASTContext(), AM.getASTContext().fullBounds()); for (BoundNodes Match : Matches) emitDiagnostics(Match, D, BR, AM, Chkr); Index: lib/StaticAnalyzer/Core/BugReporterVisitors.cpp =================================================================== --- lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -431,7 +431,8 @@ hasLHS(ignoringParenImpCasts( objcIvarRefExpr(hasDeclaration(equalsNode(Ivar))).bind(IvarBind)))); StatementMatcher ParentM = stmt(hasDescendant(WriteIntoIvarM)); - auto Matches = match(ParentM, *Parent->getBody(), Parent->getASTContext()); + auto Matches = match(ParentM, *Parent->getBody(), Parent->getASTContext(), + Parent->getASTContext().fullBounds()); for (BoundNodes &Match : Matches) { auto IvarRef = Match.getNodeAs(IvarBind); if (IvarRef->isFreeIvar()) Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp =================================================================== --- lib/StaticAnalyzer/Core/LoopUnrolling.cpp +++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp @@ -186,7 +186,7 @@ auto Match = match(stmt(anyOf(callByRef(equalsNode(VD)), getAddrTo(equalsNode(VD)), assignedToRef(equalsNode(VD)))), - *S, ASTCtx); + *S, ASTCtx, ASTCtx.fullBounds()); if (!Match.empty()) return true; @@ -203,7 +203,8 @@ // TODO: Match the cases where the bound is not a concrete literal but an // integer with known value - auto Matches = match(forLoopMatcher(), *LoopStmt, ASTCtx); + auto Matches = + match(forLoopMatcher(), *LoopStmt, ASTCtx, ASTCtx.fullBounds()); if (Matches.empty()) return false; Index: lib/StaticAnalyzer/Core/LoopWidening.cpp =================================================================== --- lib/StaticAnalyzer/Core/LoopWidening.cpp +++ lib/StaticAnalyzer/Core/LoopWidening.cpp @@ -68,8 +68,10 @@ } // References should not be invalidated. - auto Matches = match(findAll(stmt(hasDescendant(varDecl(hasType(referenceType())).bind(MatchRef)))), - *LCtx->getDecl()->getBody(), ASTCtx); + auto Matches = + match(findAll(stmt(hasDescendant( + varDecl(hasType(referenceType())).bind(MatchRef)))), + *LCtx->getDecl()->getBody(), ASTCtx, ASTCtx.fullBounds()); for (BoundNodes Match : Matches) { const VarDecl *VD = Match.getNodeAs(MatchRef); assert(VD); Index: lib/StaticAnalyzer/Core/RegionStore.cpp =================================================================== --- lib/StaticAnalyzer/Core/RegionStore.cpp +++ lib/StaticAnalyzer/Core/RegionStore.cpp @@ -1049,7 +1049,7 @@ to(varDecl(hasStaticStorageDuration()).bind(DeclBind))))); auto Matches = match(RefToStatic, *RD->getLambdaCallOperator()->getBody(), - RD->getASTContext()); + RD->getASTContext(), RD->getASTContext().fullBounds()); for (BoundNodes &Match : Matches) { auto *VD = Match.getNodeAs(DeclBind); Index: lib/StaticAnalyzer/Core/RetainSummaryManager.cpp =================================================================== --- lib/StaticAnalyzer/Core/RetainSummaryManager.cpp +++ lib/StaticAnalyzer/Core/RetainSummaryManager.cpp @@ -58,7 +58,9 @@ StringRef ClassName) { using namespace ast_matchers; DeclarationMatcher SubclassM = cxxRecordDecl(isSameOrDerivedFrom(ClassName)); - return !(match(SubclassM, *D, D->getASTContext()).empty()); + return !( + match(SubclassM, *D, D->getASTContext(), D->getASTContext().fullBounds()) + .empty()); } static bool isOSObjectSubclass(const Decl *D) { Index: lib/Tooling/ASTDiff/ASTDiff.cpp =================================================================== --- lib/Tooling/ASTDiff/ASTDiff.cpp +++ lib/Tooling/ASTDiff/ASTDiff.cpp @@ -384,7 +384,7 @@ static const DeclContext *getEnclosingDeclContext(ASTContext &AST, const Stmt *S) { while (S) { - const auto &Parents = AST.getParents(*S); + const auto &Parents = AST.getParents(*S, AST.fullBounds()); if (Parents.empty()) return nullptr; const auto &P = Parents[0]; Index: lib/Tooling/Refactoring/Rename/USRLocFinder.cpp =================================================================== --- lib/Tooling/Refactoring/Rename/USRLocFinder.cpp +++ lib/Tooling/Refactoring/Rename/USRLocFinder.cpp @@ -155,8 +155,9 @@ // given USRs' set. class RenameLocFinder : public RecursiveASTVisitor { public: - RenameLocFinder(llvm::ArrayRef USRs, ASTContext &Context) - : USRSet(USRs.begin(), USRs.end()), Context(Context) {} + RenameLocFinder(llvm::ArrayRef USRs, ASTContext &Context, + ASTContext::Bounds &Bounds) + : USRSet(USRs.begin(), USRs.end()), Context(Context), Bounds(Bounds) {} // A structure records all information of a symbol reference being renamed. // We try to add as few prefix qualifiers as possible. @@ -351,7 +352,7 @@ } bool VisitTypeLoc(TypeLoc Loc) { - auto Parents = Context.getParents(Loc); + auto Parents = Context.getParents(Loc, Bounds); TypeLoc ParentTypeLoc; if (!Parents.empty()) { // Handle cases of nested name specificier locations. @@ -463,7 +464,7 @@ // Get the closest ancester which is a declaration of a given AST node. template const Decl *getClosestAncestorDecl(const ASTNodeType &Node) { - auto Parents = Context.getParents(Node); + auto Parents = Context.getParents(Node, Bounds); // FIXME: figure out how to handle it when there are multiple parents. if (Parents.size() != 1) return nullptr; @@ -476,7 +477,7 @@ // Get the parent typeLoc of a given typeLoc. If there is no such parent, // return nullptr. const TypeLoc *getParentTypeLoc(TypeLoc Loc) const { - auto Parents = Context.getParents(Loc); + auto Parents = Context.getParents(Loc, Bounds); // FIXME: figure out how to handle it when there are multiple parents. if (Parents.size() != 1) return nullptr; @@ -493,6 +494,7 @@ const std::set USRSet; ASTContext &Context; + ASTContext::Bounds &Bounds; std::vector RenameInfos; // Record all interested using declarations which contains the using-shadow // declarations of the symbol declarations being renamed. @@ -511,8 +513,9 @@ std::vector createRenameAtomicChanges(llvm::ArrayRef USRs, llvm::StringRef NewName, Decl *TranslationUnitDecl) { - RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext()); - Finder.TraverseDecl(TranslationUnitDecl); + ASTContext &Ctx = TranslationUnitDecl->getASTContext(); + RenameLocFinder Finder(USRs, Ctx, Ctx.fullBounds()); + Finder.TraverseAST(Ctx, Ctx.fullBounds()); const SourceManager &SM = TranslationUnitDecl->getASTContext().getSourceManager(); Index: lib/Tooling/RefactoringCallbacks.cpp =================================================================== --- lib/Tooling/RefactoringCallbacks.cpp +++ lib/Tooling/RefactoringCallbacks.cpp @@ -47,7 +47,7 @@ for (const auto &Callback : Refactoring.Callbacks) { Callback->getReplacements().clear(); } - Refactoring.MatchFinder.matchAST(Context); + Refactoring.MatchFinder.matchAST(Context, Context.fullBounds()); for (const auto &Callback : Refactoring.Callbacks) { for (const auto &Replacement : Callback->getReplacements()) { llvm::Error Err = Index: unittests/AST/ASTImporterTest.cpp =================================================================== --- unittests/AST/ASTImporterTest.cpp +++ unittests/AST/ASTImporterTest.cpp @@ -122,7 +122,7 @@ ASTImporter Importer(ToCtx, ToAST->getFileManager(), FromCtx, FromAST->getFileManager(), false); - auto FoundNodes = match(SearchMatcher, FromCtx); + auto FoundNodes = match(SearchMatcher, FromCtx, FromCtx.fullBounds()); if (FoundNodes.size() != 1) return testing::AssertionFailure() << "Multiple potential nodes were found!"; @@ -254,8 +254,9 @@ From->getFileManager(), false)); // Find the declaration and import it. - auto FoundDecl = match(Action.ImportPredicate.bind(DeclToImportID), - From->getASTContext()); + auto FoundDecl = + match(Action.ImportPredicate.bind(DeclToImportID), + From->getASTContext(), From->getASTContext().fullBounds()); EXPECT_TRUE(FoundDecl.size() == 1); const Decl *ToImport = selectFirst(DeclToImportID, FoundDecl); auto Imported = importNode(From, To, *ImporterRef, ToImport); @@ -263,8 +264,9 @@ } // Find the declaration and import it. - auto FoundDecl = match(FinalSelectPredicate.bind(DeclToVerifyID), - AllASTs[FileForFinalCheck]->getASTContext()); + auto &Ctx = AllASTs[FileForFinalCheck]->getASTContext(); + auto FoundDecl = + match(FinalSelectPredicate.bind(DeclToVerifyID), Ctx, Ctx.fullBounds()); EXPECT_TRUE(FoundDecl.size() == 1); const Decl *ToVerify = selectFirst(DeclToVerifyID, FoundDecl); MatchVerifier Verifier; Index: unittests/AST/DeclMatcher.h =================================================================== --- unittests/AST/DeclMatcher.h +++ unittests/AST/DeclMatcher.h @@ -33,7 +33,7 @@ NodeType *match(const Decl *D, const MatcherType &AMatcher) { MatchFinder Finder; Finder.addMatcher(AMatcher.bind(""), this); - Finder.matchAST(D->getASTContext()); + Finder.matchAST(D->getASTContext(), D->getASTContext().fullBounds()); assert(Node); return Node; } @@ -65,7 +65,7 @@ unsigned match(const Decl *D, const MatcherType &AMatcher) { MatchFinder Finder; Finder.addMatcher(AMatcher.bind(""), this); - Finder.matchAST(D->getASTContext()); + Finder.matchAST(D->getASTContext(), D->getASTContext().fullBounds()); return Count; } }; Index: unittests/AST/MatchVerifier.h =================================================================== --- unittests/AST/MatchVerifier.h +++ unittests/AST/MatchVerifier.h @@ -135,7 +135,7 @@ Finder.addMatcher(AMatcher.bind(""), this); setFailure("Could not find match"); - Finder.match(*D, D->getASTContext()); + Finder.match(*D, D->getASTContext(), D->getASTContext().fullBounds()); if (!Verified) return testing::AssertionFailure() << VerifyResult; Index: unittests/ASTMatchers/ASTMatchersInternalTest.cpp =================================================================== --- unittests/ASTMatchers/ASTMatchersInternalTest.cpp +++ unittests/ASTMatchers/ASTMatchersInternalTest.cpp @@ -141,7 +141,7 @@ VerifyCallback.Called = false; std::unique_ptr AST(tooling::buildASTFromCode("int x;")); ASSERT_TRUE(AST.get()); - Finder.matchAST(AST->getASTContext()); + Finder.matchAST(AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_TRUE(VerifyCallback.Called); } @@ -167,7 +167,7 @@ VerifyCallback.Called = false; std::unique_ptr AST(tooling::buildASTFromCode("int x;")); ASSERT_TRUE(AST.get()); - Finder.matchAST(AST->getASTContext()); + Finder.matchAST(AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_TRUE(VerifyCallback.Called); } @@ -176,7 +176,8 @@ clang::tooling::buildASTFromCode("struct { int *foo; };"); ASSERT_TRUE(AST.get()); auto PT = selectFirst( - "x", match(pointerType().bind("x"), AST->getASTContext())); + "x", match(pointerType().bind("x"), AST->getASTContext(), + AST->getASTContext().fullBounds())); EXPECT_NE(nullptr, PT); } Index: unittests/ASTMatchers/ASTMatchersNodeTest.cpp =================================================================== --- unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -1504,7 +1504,7 @@ return selectFirst( "", match(stmt(hasParent( stmt(has(stmt(equalsNode(TypedNode)))).bind(""))), - *Node, Context)) != nullptr; + *Node, Context, Context.fullBounds())) != nullptr; } bool verify(const BoundNodes &Nodes, ASTContext &Context, const Decl *Node) { // Use the original typed pointer to verify we can pass pointers to subtypes @@ -1513,7 +1513,7 @@ return selectFirst( "", match(decl(hasParent( decl(has(decl(equalsNode(TypedNode)))).bind(""))), - *Node, Context)) != nullptr; + *Node, Context, Context.fullBounds())) != nullptr; } bool verify(const BoundNodes &Nodes, ASTContext &Context, const Type *Node) { // Use the original typed pointer to verify we can pass pointers to subtypes @@ -1523,7 +1523,7 @@ return selectFirst( "", match(fieldDecl(hasParent(decl(has(fieldDecl( hasType(type(equalsNode(TypedNode)).bind(""))))))), - *Dec, Context)) != nullptr; + *Dec, Context, Context.fullBounds())) != nullptr; } }; Index: unittests/ASTMatchers/ASTMatchersTest.h =================================================================== --- unittests/ASTMatchers/ASTMatchersTest.h +++ unittests/ASTMatchers/ASTMatchersTest.h @@ -265,7 +265,7 @@ if (!AST.get()) return testing::AssertionFailure() << "Parsing error in \"" << Code << "\" while building AST"; - Finder.matchAST(AST->getASTContext()); + Finder.matchAST(AST->getASTContext(), AST->getASTContext().fullBounds()); // XXX if (!VerifiedResult && ExpectResult) { return testing::AssertionFailure() << "Could not verify result in \"" << Code << "\" with AST"; Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -2006,7 +2006,8 @@ bool run(const BoundNodes *Nodes, ASTContext *Context) override { const Stmt *Node = Nodes->getNodeAs("node"); std::set Parents; - for (const auto &Parent : Context->getParents(*Node)) { + for (const auto &Parent : + Context->getParents(*Node, Context->fullBounds())) { if (!Parents.insert(Parent.getMemoizationData()).second) { return true; } @@ -2188,8 +2189,8 @@ bool run(const BoundNodes *Nodes, ASTContext *Context) override { const T *Node = Nodes->getNodeAs(Id); - return selectFirst(InnerId, match(InnerMatcher, *Node, *Context)) != - nullptr; + return selectFirst(InnerId, match(InnerMatcher, *Node, *Context, + Context->fullBounds())) != nullptr; } private: std::string Id; Index: unittests/Analysis/ExprMutationAnalyzerTest.cpp =================================================================== --- unittests/Analysis/ExprMutationAnalyzerTest.cpp +++ unittests/Analysis/ExprMutationAnalyzerTest.cpp @@ -52,14 +52,14 @@ bool isMutated(const SmallVectorImpl &Results, ASTUnit *AST) { const auto *const S = selectFirst("stmt", Results); const auto *const E = selectFirst("expr", Results); - return ExprMutationAnalyzer(*S, AST->getASTContext()).isMutated(E); + return ExprMutationAnalyzer(*S, AST->getASTContext(), AST->getASTContext().fullBounds()).isMutated(E); } SmallVector mutatedBy(const SmallVectorImpl &Results, ASTUnit *AST) { const auto *const S = selectFirst("stmt", Results); SmallVector Chain; - ExprMutationAnalyzer Analyzer(*S, AST->getASTContext()); + ExprMutationAnalyzer Analyzer(*S, AST->getASTContext(), AST->getASTContext().fullBounds()); for (const auto *E = selectFirst("expr", Results); E != nullptr;) { const Stmt *By = Analyzer.findMutation(E); std::string buffer; @@ -102,7 +102,8 @@ TEST(ExprMutationAnalyzerTest, Trivial) { const auto AST = buildASTFromCode("void f() { int x; x; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), + AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } @@ -112,7 +113,7 @@ const std::string ModExpr = "x " + GetParam() + " 10"; const auto AST = buildASTFromCode("void f() { int x; " + ModExpr + "; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr)); } @@ -126,7 +127,7 @@ const std::string ModExpr = GetParam(); const auto AST = buildASTFromCode("void f() { int x; " + ModExpr + "; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr)); } @@ -137,7 +138,7 @@ const auto AST = buildASTFromCode( "void f() { struct Foo { void mf(); }; Foo x; x.mf(); }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()")); } @@ -147,19 +148,19 @@ "template void f() { X x; x.mf(); }", {"-fno-delayed-template-parsing"}); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()")); AST = buildASTFromCodeWithArgs("template void f() { T x; x.mf(); }", {"-fno-delayed-template-parsing"}); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()")); AST = buildASTFromCodeWithArgs( "template struct X;" "template void f() { X x; x.mf(); }", {"-fno-delayed-template-parsing"}); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()")); } @@ -167,7 +168,7 @@ const auto AST = buildASTFromCode( "void f() { struct Foo { void mf() const; }; Foo x; x.mf(); }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } @@ -175,7 +176,7 @@ const auto AST = buildASTFromCode( "void f() { struct Foo { Foo& operator=(int); }; Foo x; x = 10; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x = 10")); } @@ -183,145 +184,145 @@ const auto AST = buildASTFromCode( "void f() { struct Foo { int operator()() const; }; Foo x; x(); }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } TEST(ExprMutationAnalyzerTest, ByValueArgument) { auto AST = buildASTFromCode("void g(int); void f() { int x; g(x); }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("void g(int*); void f() { int* x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("typedef int* IntPtr;" "void g(IntPtr); void f() { int* x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode( "struct A {}; A operator+(A, int); void f() { A x; x + 1; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("void f() { struct A { A(int); }; int x; A y(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("struct A { A(); A& operator=(A); };" "void f() { A x, y; y = x; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode( "template struct A { A(); A(const A&); static void mf(A) {} };" "void f() { A<0> x; A<0>::mf(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } TEST(ExprMutationAnalyzerTest, ByConstValueArgument) { auto AST = buildASTFromCode("void g(const int); void f() { int x; g(x); }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("void g(int* const); void f() { int* x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("typedef int* const CIntPtr;" "void g(CIntPtr); void f() { int* x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode( "struct A {}; A operator+(const A, int); void f() { A x; x + 1; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode( "void f() { struct A { A(const int); }; int x; A y(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("template struct A { A(); A(const A&);" "static void mf(const A&) {} };" "void f() { A<0> x; A<0>::mf(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } TEST(ExprMutationAnalyzerTest, ByNonConstRefArgument) { auto AST = buildASTFromCode("void g(int&); void f() { int x; g(x); }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); AST = buildASTFromCode("typedef int& IntRef;" "void g(IntRef); void f() { int x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); AST = buildASTFromCode("template using TRef = T&;" "void g(TRef); void f() { int x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); AST = buildASTFromCode( "template struct identity { using type = T; };" "template void g(typename identity::type);" "void f() { int x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); AST = buildASTFromCode("typedef int* IntPtr;" "void g(IntPtr&); void f() { int* x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); AST = buildASTFromCode("typedef int* IntPtr; typedef IntPtr& IntPtrRef;" "void g(IntPtrRef); void f() { int* x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); AST = buildASTFromCode( "struct A {}; A operator+(A&, int); void f() { A x; x + 1; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x + 1")); AST = buildASTFromCode("void f() { struct A { A(int&); }; int x; A y(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); AST = buildASTFromCode("void f() { struct A { A(); A(A&); }; A x; A y(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); AST = buildASTFromCode( "template struct A { A(); A(const A&); static void mf(A&) {} };" "void f() { A<0> x; A<0>::mf(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("A<0>::mf(x)")); } TEST(ExprMutationAnalyzerTest, ByConstRefArgument) { auto AST = buildASTFromCode("void g(const int&); void f() { int x; g(x); }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("typedef const int& CIntRef;" "void g(CIntRef); void f() { int x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("template using CTRef = const T&;" "void g(CTRef); void f() { int x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = @@ -329,22 +330,22 @@ "template " "void g(typename identity::type);" "void f() { int x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode( "struct A {}; A operator+(const A&, int); void f() { A x; x + 1; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode( "void f() { struct A { A(const int&); }; int x; A y(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode( "void f() { struct A { A(); A(const A&); }; A x; A y(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } @@ -352,25 +353,25 @@ auto AST = buildASTFromCode( "void g(int&&); void f() { int x; g(static_cast(x)); }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(static_cast(x))")); AST = buildASTFromCode("struct A {}; A operator+(A&&, int);" "void f() { A x; static_cast(x) + 1; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("static_cast(x) + 1")); AST = buildASTFromCode("void f() { struct A { A(int&&); }; " "int x; A y(static_cast(x)); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("static_cast(x)")); AST = buildASTFromCode("void f() { struct A { A(); A(A&&); }; " "A x; A y(static_cast(x)); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("static_cast(x)")); } @@ -379,22 +380,22 @@ auto AST = buildASTFromCode( "void g(const int&&); void f() { int x; g(static_cast(x)); }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("struct A {}; A operator+(const A&&, int);" "void f() { A x; static_cast(x) + 1; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("void f() { struct A { A(const int&&); }; " "int x; A y(static_cast(x)); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("void f() { struct A { A(); A(const A&&); }; " "A x; A y(static_cast(x)); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } @@ -402,61 +403,61 @@ auto AST = buildASTFromCode(StdRemoveReference + StdMove + "void f() { struct A {}; A x; std::move(x); }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode(StdRemoveReference + StdMove + "void f() { struct A {}; A x, y; std::move(x) = y; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("std::move(x) = y")); AST = buildASTFromCode(StdRemoveReference + StdMove + "void f() { int x, y; y = std::move(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode(StdRemoveReference + StdMove + "struct S { S(); S(const S&); S& operator=(const S&); };" "void f() { S x, y; y = std::move(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode(StdRemoveReference + StdMove + "struct S { S(); S(S&&); S& operator=(S&&); };" "void f() { S x, y; y = std::move(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("y = std::move(x)")); AST = buildASTFromCode(StdRemoveReference + StdMove + "struct S { S(); S(const S&); S(S&&);" "S& operator=(const S&); S& operator=(S&&); };" "void f() { S x, y; y = std::move(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("y = std::move(x)")); AST = buildASTFromCode(StdRemoveReference + StdMove + "struct S { S(); S(const S&); S(S&&);" "S& operator=(const S&); S& operator=(S&&); };" "void f() { const S x; S y; y = std::move(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode(StdRemoveReference + StdMove + "struct S { S(); S& operator=(S); };" "void f() { S x, y; y = std::move(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode(StdRemoveReference + StdMove + "struct S{}; void f() { S x, y; y = std::move(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("y = std::move(x)")); AST = buildASTFromCode( StdRemoveReference + StdMove + "struct S{}; void f() { const S x; S y; y = std::move(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } @@ -465,13 +466,13 @@ buildASTFromCode(StdRemoveReference + StdForward + "void f() { struct A {}; A x; std::forward(x); }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode( StdRemoveReference + StdForward + "void f() { struct A {}; A x, y; std::forward(x) = y; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("std::forward(x) = y")); } @@ -481,81 +482,81 @@ buildASTFromCodeWithArgs("template void f() { T x; g(x); }", {"-fno-delayed-template-parsing"}); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); AST = buildASTFromCodeWithArgs("template void f() { char x[N]; g(x); }", {"-fno-delayed-template-parsing"}); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); AST = buildASTFromCodeWithArgs( "template void f(T t) { int x; g(t, x); }", {"-fno-delayed-template-parsing"}); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(t, x)")); AST = buildASTFromCodeWithArgs( "template void f(T t) { int x; t.mf(x); }", {"-fno-delayed-template-parsing"}); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("t.mf(x)")); AST = buildASTFromCodeWithArgs( "template struct S;" "template void f() { S s; int x; s.mf(x); }", {"-fno-delayed-template-parsing"}); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("s.mf(x)")); AST = buildASTFromCodeWithArgs( "struct S { template void mf(); };" "template void f(S s) { int x; s.mf(x); }", {"-fno-delayed-template-parsing"}); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("s.mf(x)")); AST = buildASTFromCodeWithArgs("template " "void g(F f) { int x; f(x); } ", {"-fno-delayed-template-parsing"}); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("f(x)")); AST = buildASTFromCodeWithArgs( "template void f() { int x; (void)T(x); }", {"-fno-delayed-template-parsing"}); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("T(x)")); } TEST(ExprMutationAnalyzerTest, ReturnAsValue) { auto AST = buildASTFromCode("int f() { int x; return x; }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("int* f() { int* x; return x; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("typedef int* IntPtr;" "IntPtr f() { int* x; return x; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } TEST(ExprMutationAnalyzerTest, ReturnAsNonConstRef) { const auto AST = buildASTFromCode("int& f() { int x; return x; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("return x;")); } TEST(ExprMutationAnalyzerTest, ReturnAsConstRef) { const auto AST = buildASTFromCode("const int& f() { int x; return x; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } @@ -563,7 +564,7 @@ const auto AST = buildASTFromCode("int&& f() { int x; return static_cast(x); }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("return static_cast(x);")); } @@ -572,14 +573,14 @@ const auto AST = buildASTFromCode( "const int&& f() { int x; return static_cast(x); }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } TEST(ExprMutationAnalyzerTest, TakeAddress) { const auto AST = buildASTFromCode("void g(int*); void f() { int x; g(&x); }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("&x")); } @@ -587,7 +588,7 @@ const auto AST = buildASTFromCode("void g(int*); void f() { int x[2]; g(x); }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); } @@ -600,10 +601,10 @@ "template <> void f() { char y[S::v]; g(y); }", {"-fno-delayed-template-parsing"}); const auto ResultsX = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(ResultsX, AST.get()), ElementsAre("g(x)")); const auto ResultsY = - match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("y")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(ResultsY, AST.get()), ElementsAre("y")); } @@ -612,7 +613,7 @@ "void f() { int x; int& r0 = x; int& r1 = r0; int& r2 = r1; " "int& r3 = r2; r3 = 10; }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("r0", "r1", "r2", "r3", "r3 = 10")); @@ -620,7 +621,7 @@ "using IntRefY = int&;" "void f() { int x; IntRefX r0 = x; IntRefY r1 = r0;" "decltype((x)) r2 = r1; r2 = 10; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("r0", "r1", "r2", "r2 = 10")); } @@ -630,18 +631,18 @@ "void f() { int x; int& r0 = x; int& r1 = r0; int& r2 = r1; " "int& r3 = r2; int& r4 = r3; int& r5 = r4;}"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("void f() { int x; int& r0 = x; const int& r1 = r0;}"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("typedef const int& CIntRefX;" "using CIntRefY = const int&;" "void f() { int x; int& r0 = x; CIntRefX r1 = r0;" "CIntRefY r2 = r1; decltype((r1)) r3 = r2;}"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } @@ -649,7 +650,7 @@ const auto AST = buildASTFromCode( "void f() { int x, y; bool b; int &r = b ? x : y; r = 10; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("r", "r = 10")); } @@ -657,7 +658,7 @@ const auto AST = buildASTFromCode("void f() { int x, y; bool b; int& r = b ? x : y; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } @@ -665,49 +666,49 @@ auto AST = buildASTFromCode("template void g(T&& t) { t = 10; }" "void f() { int x; g(x); }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); AST = buildASTFromCode( "void h(int&);" "template void g(Args&&... args) { h(args...); }" "void f() { int x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); AST = buildASTFromCode( "void h(int&, int);" "template void g(Args&&... args) { h(args...); }" "void f() { int x, y; g(x, y); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x, y)")); - Results = match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("y")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode( "void h(int, int&);" "template void g(Args&&... args) { h(args...); }" "void f() { int x, y; g(y, x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(y, x)")); - Results = match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("y")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("struct S { template S(T&& t) { t = 10; } };" "void f() { int x; S s(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); AST = buildASTFromCode( "struct S { template S(T&& t) : m(++t) { } int m; };" "void f() { int x; S s(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); AST = buildASTFromCode("template struct S {" "template S(T&& t) : m(++t) { } U m; };" "void f() { int x; S s(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); AST = buildASTFromCode(StdRemoveReference + StdForward + @@ -717,7 +718,7 @@ "template void g(Args&&... args)" "{ h(std::forward(args)...); }" "void f() { int x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); } @@ -725,46 +726,46 @@ auto AST = buildASTFromCode("template void g(T&&) {}" "void f() { int x; g(x); }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("template void g(T&& t) { t; }" "void f() { int x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("template void g(Args&&...) {}" "void f() { int x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("template void g(Args&&...) {}" "void f() { int y, x; g(y, x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode( "void h(int, int&);" "template void g(Args&&... args) { h(args...); }" "void f() { int x, y; g(x, y); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("struct S { template S(T&& t) { t; } };" "void f() { int x; S s(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode( "struct S { template S(T&& t) : m(t) { } int m; };" "void f() { int x; S s(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("template struct S {" "template S(T&& t) : m(t) { } U m; };" "void f() { int x; S s(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode(StdRemoveReference + StdForward + @@ -774,21 +775,21 @@ "template void g(Args&&... args)" "{ h(std::forward(args)...); }" "void f() { int x; g(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } TEST(ExprMutationAnalyzerTest, ArrayElementModified) { const auto AST = buildASTFromCode("void f() { int x[2]; x[0] = 10; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x[0] = 10")); } TEST(ExprMutationAnalyzerTest, ArrayElementNotModified) { const auto AST = buildASTFromCode("void f() { int x[2]; x[0]; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } @@ -797,20 +798,20 @@ buildASTFromCode("void f() { struct A { int vi; }; struct B { A va; }; " "struct C { B vb; }; C x; x.vb.va.vi = 10; }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.vb.va.vi = 10")); AST = buildASTFromCodeWithArgs( "template void f() { T x; x.y.z = 10; }", {"-fno-delayed-template-parsing"}); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.y.z = 10")); AST = buildASTFromCodeWithArgs( "template struct S;" "template void f() { S x; x.y.z = 10; }", {"-fno-delayed-template-parsing"}); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.y.z = 10")); } @@ -819,19 +820,19 @@ buildASTFromCode("void f() { struct A { int vi; }; struct B { A va; }; " "struct C { B vb; }; C x; x.vb.va.vi; }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCodeWithArgs("template void f() { T x; x.y.z; }", {"-fno-delayed-template-parsing"}); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCodeWithArgs("template struct S;" "template void f() { S x; x.y.z; }", {"-fno-delayed-template-parsing"}); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } @@ -839,7 +840,7 @@ const auto AST = buildASTFromCode("void f() { int x; static_cast(x); }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } @@ -847,13 +848,13 @@ auto AST = buildASTFromCode("void f() { int x; static_cast(x) = 10; }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("static_cast(x) = 10")); AST = buildASTFromCode("typedef int& IntRef;" "void f() { int x; static_cast(x) = 10; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("static_cast(x) = 10")); } @@ -862,7 +863,7 @@ const auto AST = buildASTFromCode("void f() { int x; static_cast(x); }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } @@ -870,33 +871,33 @@ auto AST = buildASTFromCode("void f() { int x; static_cast(x); }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("typedef const int& CIntRef;" "void f() { int x; static_cast(x); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByValue) { const auto AST = buildASTFromCode("void f() { int x; [=]() { x; }; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByValue) { const auto AST = buildASTFromCode("void f() { int x; [x]() { x; }; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByRef) { const auto AST = buildASTFromCode("void f() { int x; [&]() { x = 10; }; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ResultOf(removeSpace, "[&](){x=10;}"))); } @@ -904,7 +905,7 @@ TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByRef) { const auto AST = buildASTFromCode("void f() { int x; [&x]() { x = 10; }; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ResultOf(removeSpace, "[&x](){x=10;}"))); } @@ -913,12 +914,12 @@ auto AST = buildASTFromCode("void f() { int x[2]; for (int& e : x) e = 10; }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10")); AST = buildASTFromCode("typedef int& IntRef;" "void f() { int x[2]; for (IntRef e : x) e = 10; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10")); } @@ -926,25 +927,25 @@ const auto AST = buildASTFromCode("void f() { int x[2]; for (int& e : x) e; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } TEST(ExprMutationAnalyzerTest, RangeForArrayByValue) { auto AST = buildASTFromCode("void f() { int x[2]; for (int e : x) e = 10; }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("void f() { int* x[2]; for (int* e : x) e = nullptr; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode( "typedef int* IntPtr;" "void f() { int* x[2]; for (IntPtr e : x) e = nullptr; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } @@ -952,12 +953,12 @@ auto AST = buildASTFromCode("void f() { int x[2]; for (const int& e : x) e; }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("typedef const int& CIntRef;" "void f() { int x[2]; for (CIntRef e : x) e; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } @@ -966,7 +967,7 @@ buildASTFromCode("struct V { int* begin(); int* end(); };" "void f() { V x; for (int& e : x) e = 10; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10")); } @@ -974,7 +975,7 @@ const auto AST = buildASTFromCode("struct V { int* begin(); int* end(); };" "void f() { V x; for (int& e : x) e; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } @@ -983,7 +984,7 @@ "struct V { const int* begin() const; const int* end() const; };" "void f() { V x; for (int e : x) e; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } @@ -992,52 +993,52 @@ "struct V { const int* begin() const; const int* end() const; };" "void f() { V x; for (const int& e : x) e; }"); const auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } TEST(ExprMutationAnalyzerTest, UnevaluatedExpressions) { auto AST = buildASTFromCode("void f() { int x, y; decltype(x = 10) z = y; }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("void f() { int x, y; __typeof(x = 10) z = y; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("void f() { int x, y; __typeof__(x = 10) z = y; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("void f() { int x; sizeof(x = 10); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("void f() { int x; alignof(x = 10); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode("void f() { int x; noexcept(x = 10); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCodeWithArgs("namespace std { class type_info; }" "void f() { int x; typeid(x = 10); }", {"-frtti"}); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode( "void f() { int x; _Generic(x = 10, int: 0, default: 1); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); } TEST(ExprMutationAnalyzerTest, NotUnevaluatedExpressions) { auto AST = buildASTFromCode("void f() { int x; sizeof(int[x++]); }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x++")); AST = buildASTFromCodeWithArgs( @@ -1045,7 +1046,7 @@ "struct A { virtual ~A(); }; struct B : A {};" "struct X { A& f(); }; void f() { X x; typeid(x.f()); }", {"-frtti"}); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.f()")); } @@ -1064,45 +1065,45 @@ auto AST = buildASTFromCode(UniquePtrDef + "void f() { UniquePtr x; *x = 10; }"); auto Results = - match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("* x = 10")); AST = buildASTFromCode(UniquePtrDef + "void f() { UniquePtr x; *x; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode(UniquePtrDef + "void f() { UniquePtr x; *x; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode(UniquePtrDef + "struct S { int v; };" "void f() { UniquePtr x; x->v; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); AST = buildASTFromCode(UniquePtrDef + "struct S { int v; };" "void f() { UniquePtr x; x->v; }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCode(UniquePtrDef + "struct S { void mf(); };" "void f() { UniquePtr x; x->mf(); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); AST = buildASTFromCode(UniquePtrDef + "struct S { void mf() const; };" "void f() { UniquePtr x; x->mf(); }"); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_FALSE(isMutated(Results, AST.get())); AST = buildASTFromCodeWithArgs( UniquePtrDef + "template void f() { UniquePtr x; x->mf(); }", {"-fno-delayed-template-parsing"}); - Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext(), AST->getASTContext().fullBounds()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x->mf()")); }