//===--- iwyu_ast_util.h - clang-AST utilities for include-what-you-use ---===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // Utilities that make it easier to work with Clang's AST. #ifndef INCLUDE_WHAT_YOU_USE_IWYU_AST_UTIL_H_ #define INCLUDE_WHAT_YOU_USE_IWYU_AST_UTIL_H_ #include // for map #include // for set #include // for string #include "iwyu_port.h" // for CHECK_ #include "iwyu_use_flags.h" #include "llvm/Support/Casting.h" #include "clang/AST/DeclBase.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Stmt.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/SourceLocation.h" namespace clang { class CXXConstructExpr; class CXXConstructorDecl; class CXXDeleteExpr; class CXXDestructorDecl; class CXXMethodDecl; class CXXRecordDecl; class CallExpr; class CastExpr; class ClassTemplateDecl; class Expr; class FunctionDecl; class NamedDecl; class TagDecl; class TemplateDecl; class TemplateName; class TranslationUnitDecl; class TypeDecl; class ValueDecl; struct ASTTemplateArgumentListInfo; } // namespace clang namespace include_what_you_use { using std::map; using std::set; using std::string; //------------------------------------------------------------ // ASTNode and friends. // ASTNode represents a single node of the AST tree. An AST node may be // a statement, declaration, type, template-name, etc. ASTNode keeps // track of its parent node, as we do AST traversal, allowing queries // on the "context" of a node. // // We also store some state that's useful for iwyu. For instance, // we store whether a node is in a 'forward-declarable' context // (such as a function parameter), meaning all types seen below // that node are legal to fowrard-declare according to c++. class ASTNode { public: // In each case, the caller owns the object, and must guarantee it // lives for at least as long as the ASTNode object does. ASTNode(const clang::Decl* decl) : kind_(kDeclKind), as_decl_(decl), parent_(nullptr), in_fwd_decl_context_(false) { } ASTNode(const clang::Stmt* stmt) : kind_(kStmtKind), as_stmt_(stmt), parent_(nullptr), in_fwd_decl_context_(false) { } ASTNode(const clang::Type* type) : kind_(kTypeKind), as_type_(type), parent_(nullptr), in_fwd_decl_context_(false) { } ASTNode(const clang::TypeLoc* typeloc) : kind_(kTypelocKind), as_typeloc_(typeloc), parent_(nullptr), in_fwd_decl_context_(false) { } ASTNode(const clang::NestedNameSpecifier* nns) : kind_(kNNSKind), as_nns_(nns), parent_(nullptr), in_fwd_decl_context_(false) { } ASTNode(const clang::NestedNameSpecifierLoc* nnsloc) : kind_(kNNSLocKind), as_nnsloc_(nnsloc), parent_(nullptr), in_fwd_decl_context_(false) { } ASTNode(const clang::TemplateName* template_name) : kind_(kTemplateNameKind), as_template_name_(template_name), parent_(nullptr), in_fwd_decl_context_(false) { } ASTNode(const clang::TemplateArgument* template_arg) : kind_(kTemplateArgumentKind), as_template_arg_(template_arg), parent_(nullptr), in_fwd_decl_context_(false) { } ASTNode(const clang::TemplateArgumentLoc* template_argloc) : kind_(kTemplateArgumentLocKind), as_template_argloc_(template_argloc), parent_(nullptr), in_fwd_decl_context_(false) { } // A 'forward-declare' context means some parent of us can be // forward-declared, which means we can be too. e.g. in // MyClass* x, Foo is fwd-declarable because MyClass is. bool in_forward_declare_context() const { return in_fwd_decl_context_; } void set_in_forward_declare_context(bool b) { in_fwd_decl_context_ = b; } const ASTNode* parent() const { return parent_; } void SetParent(const ASTNode* parent) { parent_ = parent; if (parent) // We inherit this from parent. set_in_forward_declare_context(parent->in_forward_declare_context()); } // The number of nodes above this node in the AST tree. int depth() const { int depth = 0; for (const ASTNode* node = this; node != nullptr; node = node->parent_) depth++; return depth - 1; // don't count "this" } // If this node knows its location, returns it. If not, and it's // likely its location is very close (say, within a few lines) of // its parent, ask its parent. Unfortunately, there's nothing which // tells us whether a parent's location is very close to its child. // We assume that they always are (empirically this is true) // *except* for the case the parent is in a macro: then it often // happens that the parent belongs at the spelling location, while // the child is a macro arg and hence belongs in the instantiation // location. Those could be far away, even in different files. For // example: '#define NEW_FUNC(cls) void Func(cls* x) {}'. Func is // at the spelling loc, but its child Type 'cls' is at the // instantiation loc. In that case, or if *no* ancestor of the // current node knows its location, returns an invalid SourceLocation. clang::SourceLocation GetLocation() const; // Returns true if this node points to the exact same // decl/typeloc/etc as the one you pass in. For Decl/Stmt/Type, the // pointer is canonical (every instance of type X has the same // clang::Type*). But for most, the value is canonical (each type // has the same QualType but not QualType*). The IsA<> checks are // needed to avoid false matches when target_node is nullptr. bool ContentIs(const clang::Decl* target_node) const { return IsA() && GetAs() == target_node; } bool ContentIs(const clang::Stmt* target_node) const { return IsA() && GetAs() == target_node; } bool ContentIs(const clang::Type* target_node) const { return IsA() && GetAs() == target_node; } bool ContentIs(const clang::TypeLoc* target_node) const { if (!IsA()) return false; const clang::TypeLoc* type_loc = GetAs(); if (type_loc == nullptr || target_node == nullptr) return type_loc == target_node; return *type_loc == *target_node; } // We don't define ContentIs() for other kinds of AST nodes // (e.g. TemplateName) as it's non-trivial (Clang doesn't define // equality comparison functions for them) and we don't need that // yet. // Returns true if the current node or any ancestor of it contains // the exact same thing as ptr. One use of this is to check for // recursion. template bool StackContainsContent(const T* ptr) const { for (const ASTNode* node = this; node != nullptr; node = node->parent_) { if (node->ContentIs(ptr)) return true; } return false; } // Generation 0 == you, 1 == parent, etc. template const To* GetAncestorAs(int generation) const { const ASTNode* target_node = this; for (; generation > 0; --generation) { if (target_node->parent_ == nullptr) return nullptr; target_node = target_node->parent_; } // DynCast needs a dummy argument of type To* to help its resolution. const To* dummy = nullptr; return target_node->DynCast(dummy); } // Convenience methods. template bool AncestorIsA(int generation) const { return GetAncestorAs(generation) != nullptr; } // Returns true if this node or any of its ancestors contains a T*. template bool HasAncestorOfType() const { for (const ASTNode* node = this; node != nullptr; node = node->parent_) { if (node->IsA()) return true; } return false; } template const To* GetParentAs() const { return GetAncestorAs(1); } template bool ParentIsA() const { return AncestorIsA(1); } template const To* GetAs() const { return GetAncestorAs(0); } template bool IsA() const { return AncestorIsA(0); } private: enum NodeKind { kDeclKind, kStmtKind, kTypeKind, kTypelocKind, kNNSKind, kNNSLocKind, kTemplateNameKind, kTemplateArgumentKind, kTemplateArgumentLocKind }; // Returns a casted pointer if this object actually is of the given // type (or a subclass of the given type), and nullptr otherwise. We // have to use overloading on To's kind_, in these helper // methods, in order to get llvm's dyn_cast to compile -- it gets // upset (at compile time, sadly) if from-type and to-type aren't in // the same type hierarchy. So To must be specified both in the // template arg and in the method parameter. template const To* DynCast(const clang::Decl*) const { if (kind_ != kDeclKind) return nullptr; return ::llvm::dyn_cast(as_decl_); } template const To* DynCast(const clang::Stmt*) const { if (kind_ != kStmtKind) return nullptr; return ::llvm::dyn_cast(as_stmt_); } template const To* DynCast(const clang::Type*) const { // We also will cast ourselves to a type if we're a typeloc. // This simplifies a lot of code lower down that doesn't care // to distinguish. For code that *does* care to distinguish, // it should check for typelocs first: // if (node.IsA()) ... else if (node.IsA()) ... if (kind_ == kTypelocKind) return ::llvm::dyn_cast(as_typeloc_->getTypePtr()); if (kind_ != kTypeKind) return nullptr; return ::llvm::dyn_cast(as_type_); } template const To* DynCast(const clang::TypeLoc*) const { if (kind_ != kTypelocKind) return nullptr; return ::llvm::dyn_cast(as_typeloc_); } template const To* DynCast( const clang::NestedNameSpecifier*) const { // Like Type, this will cast to NNS if we're an NNSLoc. For code // that cares to distinguish, it should check for nnslocs first. if (kind_ == kNNSLocKind) return as_nnsloc_->getNestedNameSpecifier(); if (kind_ != kNNSKind) return nullptr; return as_nns_; } template const To* DynCast( const clang::NestedNameSpecifierLoc*) const { if (kind_ != kNNSLocKind) return nullptr; return as_nnsloc_; } template const To* DynCast(const clang::TemplateName*) const { if (kind_ != kTemplateNameKind) return nullptr; return as_template_name_; } template const To* DynCast( const clang::TemplateArgument*) const { // We also will cast ourselves to a templateargument if we're a // templateargumentloc. This simplifies a lot of code lower down // that doesn't care to distinguish. For code that *does* care to // distinguish, it should check for typelocs first. if (kind_ == kTemplateArgumentLocKind) return &as_template_argloc_->getArgument(); if (kind_ != kTemplateArgumentKind) return nullptr; return as_template_arg_; } template const To* DynCast( const clang::TemplateArgumentLoc*) const { if (kind_ != kTemplateArgumentLocKind) return nullptr; return as_template_argloc_; } // We also allow casting to void* template const void* DynCast(const void*) const { switch (kind_) { // this is just to avoid aliasing violations. case kDeclKind: return as_decl_; case kStmtKind: return as_stmt_; case kTypeKind: return as_type_; case kTypelocKind: return as_typeloc_; case kNNSKind: return as_nns_; case kNNSLocKind: return as_nnsloc_; case kTemplateNameKind: return as_template_name_; case kTemplateArgumentKind: return as_template_arg_; case kTemplateArgumentLocKind: return as_template_argloc_; } CHECK_UNREACHABLE_("Unknown kind"); } // If this node is of a type that knows its location, sets loc and // returns true, otherwise returns false and leaves loc unchanged. bool FillLocationIfKnown(clang::SourceLocation* loc) const; const NodeKind kind_; union { const clang::Decl* as_decl_; const clang::Stmt* as_stmt_; const clang::Type* as_type_; const clang::TypeLoc* as_typeloc_; const clang::NestedNameSpecifier* as_nns_; const clang::NestedNameSpecifierLoc* as_nnsloc_; const clang::TemplateName* as_template_name_; const clang::TemplateArgument* as_template_arg_; const clang::TemplateArgumentLoc* as_template_argloc_; }; const ASTNode* parent_; bool in_fwd_decl_context_; }; // --- Helper classes for ASTNode. // An object of this type modifies a given variable in the constructor // and restores its original value in the destructor. template class ValueSaver { public: ValueSaver(T* p, const T& newval) : ptr_(p), oldval_(*ptr_) { *ptr_ = newval; } // The one-arg version just uses the current value as newval. explicit ValueSaver(T* p) : ptr_(p), oldval_(*ptr_) { } ~ValueSaver() { *ptr_ = oldval_; } private: T* const ptr_; const T oldval_; }; // An object of this type updates current_ast_node_ to be the given // node, and sets the given node's parent to be the old // current_ast_node_. It then undoes this work in its destructor. // The caller owns both old_current_node and new_current_node, and // must make sure each of them lives at least as long as this object. class CurrentASTNodeUpdater { public: CurrentASTNodeUpdater(ASTNode** old_current_node, ASTNode* new_current_node) : old_current_node_value_(*old_current_node), node_saver_(old_current_node, new_current_node) { new_current_node->SetParent(old_current_node_value_); } private: ASTNode* const old_current_node_value_; const ValueSaver node_saver_; }; // --- Utilities for ASTNode. // See if a given ast_node is a 'real' ElaboratedType(Loc). (An // elaboration is 'class Foo myvar' instead of just 'Foo myvar'.) // We avoid 'fake' elaborations that are caused because clang also // uses ElaboratedType for namespaces ('ns::Foo myvar'). bool IsElaboratedTypeSpecifier(const ASTNode* ast_node); // Walk up to parents of the given node so long as each parent is an // elaborated type node. // Can expand from a node representing 'X' to e.g. 'struct X' or 'mylib::X'. const ASTNode* MostElaboratedAncestor(const ASTNode* ast_node); // See if a given ast_node is a qualified name part of an ElaboratedType // node (e.g. 'class ns::Foo x', 'class ::Global x' or 'class Outer::Inner x'.) bool IsQualifiedNameNode(const ASTNode* ast_node); // Return true if the given ast_node is inside a C++ method body. Do // this by walking up the AST tree until you find a CXXMethodDecl, // then see if the node just before you reached it is the body. We // also check if the node is in an initializer (either explicitly or // implicitly), or the implicit (non-body) code of a destructor. bool IsNodeInsideCXXMethodBody(const ASTNode* ast_node); // Return UseFlags for the current node. // These flags provide context around the use to help later IWYU analysis, UseFlags ComputeUseFlags(const ASTNode* ast_node); // Return true if we're a nested tag type as written, that is, we're a // class or enum decl inside another class decl. The parent class may be // templated, but we should not be. (We could extend the function to // handle that case, but there's been no need yet.) bool IsNestedTagAsWritten(const ASTNode* ast_node); // Is ast_node the 'D' in the following: // template