2011-02-04 22:28:15 +00:00
|
|
|
//===--- 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 DEVTOOLS_MAINTENANCE_INCLUDE_WHAT_YOU_USE_IWYU_AST_UTIL_H_
|
|
|
|
#define DEVTOOLS_MAINTENANCE_INCLUDE_WHAT_YOU_USE_IWYU_AST_UTIL_H_
|
|
|
|
|
|
|
|
#include <set>
|
|
|
|
#include <string>
|
|
|
|
|
2011-02-08 06:12:32 +00:00
|
|
|
#include "port.h"
|
2011-02-04 22:28:15 +00:00
|
|
|
#include "iwyu_globals.h"
|
|
|
|
#include "iwyu_location_util.h"
|
|
|
|
#include "iwyu_output.h"
|
|
|
|
#include "iwyu_string_util.h"
|
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include "clang/AST/DeclBase.h"
|
|
|
|
#include "clang/AST/DeclCXX.h"
|
|
|
|
#include "clang/AST/DeclFriend.h"
|
|
|
|
#include "clang/AST/DeclTemplate.h"
|
|
|
|
#include "clang/AST/ExprCXX.h"
|
|
|
|
#include "clang/AST/NestedNameSpecifier.h"
|
|
|
|
#include "clang/AST/Stmt.h"
|
|
|
|
#include "clang/AST/TemplateBase.h"
|
|
|
|
#include "clang/AST/TemplateName.h"
|
|
|
|
#include "clang/AST/Type.h"
|
|
|
|
#include "clang/AST/TypeLoc.h"
|
|
|
|
#include "clang/Basic/FileManager.h"
|
|
|
|
#include "clang/Basic/SourceLocation.h"
|
|
|
|
|
|
|
|
namespace include_what_you_use {
|
|
|
|
|
|
|
|
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, const clang::SourceManager& sm)
|
|
|
|
: kind_(kDeclKind), as_decl_(decl),
|
|
|
|
parent_(NULL), in_fwd_decl_context_(false), source_manager_(sm) { }
|
|
|
|
ASTNode(const clang::Stmt* stmt, const clang::SourceManager& sm)
|
|
|
|
: kind_(kStmtKind), as_stmt_(stmt),
|
|
|
|
parent_(NULL), in_fwd_decl_context_(false), source_manager_(sm) { }
|
|
|
|
ASTNode(const clang::Type* type, const clang::SourceManager& sm)
|
|
|
|
: kind_(kTypeKind), as_type_(type),
|
|
|
|
parent_(NULL), in_fwd_decl_context_(false), source_manager_(sm) { }
|
|
|
|
ASTNode(const clang::TypeLoc* typeloc, const clang::SourceManager& sm)
|
|
|
|
: kind_(kTypelocKind), as_typeloc_(typeloc),
|
|
|
|
parent_(NULL), in_fwd_decl_context_(false), source_manager_(sm) { }
|
|
|
|
ASTNode(const clang::NestedNameSpecifier* nns, const clang::SourceManager& sm)
|
|
|
|
: kind_(kNNSKind), as_nns_(nns),
|
|
|
|
parent_(NULL), in_fwd_decl_context_(false), source_manager_(sm) { }
|
|
|
|
ASTNode(const clang::TemplateName* template_name,
|
|
|
|
const clang::SourceManager& sm)
|
|
|
|
: kind_(kTemplateNameKind), as_template_name_(template_name),
|
|
|
|
parent_(NULL), in_fwd_decl_context_(false), source_manager_(sm) { }
|
|
|
|
ASTNode(const clang::TemplateArgument* template_arg,
|
|
|
|
const clang::SourceManager& sm)
|
|
|
|
: kind_(kTemplateArgumentKind), as_template_arg_(template_arg),
|
|
|
|
parent_(NULL), in_fwd_decl_context_(false), source_manager_(sm) { }
|
|
|
|
ASTNode(const clang::TemplateArgumentLoc* template_argloc,
|
|
|
|
const clang::SourceManager& sm)
|
|
|
|
: kind_(kTemplateArgumentLocKind), as_template_argloc_(template_argloc),
|
|
|
|
parent_(NULL), in_fwd_decl_context_(false), source_manager_(sm) { }
|
|
|
|
|
|
|
|
// A 'forward-declare' context means some parent of us can be
|
|
|
|
// forward-declared, which means we can be too. e.g. in
|
|
|
|
// MyClass<Foo>* x, Foo is fwd-declarable because MyClass<Foo> 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 != NULL; 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 {
|
|
|
|
clang::SourceLocation retval;
|
|
|
|
if (FillLocationIfKnown(&retval))
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
// OK, let's ask a parent node.
|
|
|
|
for (const ASTNode* node = parent_; node != NULL; node = node->parent_) {
|
|
|
|
if (node->FillLocationIfKnown(&retval))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// If the parent node shows the spelling and instantiation
|
|
|
|
// locations are in a different file, then we're uncertain of our
|
|
|
|
// own location. Return an invalid location.
|
|
|
|
if (retval.isValid()) {
|
|
|
|
clang::FullSourceLoc full_loc(retval, source_manager_);
|
|
|
|
const clang::FileEntry* spelling_file =
|
|
|
|
source_manager_.getFileEntryForID(
|
|
|
|
source_manager_.getFileID(full_loc.getSpellingLoc()));
|
|
|
|
const clang::FileEntry* instantiation_file =
|
|
|
|
source_manager_.getFileEntryForID(
|
|
|
|
source_manager_.getFileID(full_loc.getInstantiationLoc()));
|
|
|
|
if (spelling_file != instantiation_file)
|
|
|
|
return clang::SourceLocation();
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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*).
|
|
|
|
bool ContentIs(const clang::Decl* target_node) const {
|
|
|
|
return GetAs<clang::Decl>() == target_node;
|
|
|
|
}
|
|
|
|
bool ContentIs(const clang::Stmt* target_node) const {
|
|
|
|
return GetAs<clang::Stmt>() == target_node;
|
|
|
|
}
|
|
|
|
bool ContentIs(const clang::Type* target_node) const {
|
|
|
|
return GetAs<clang::Type>() == target_node;
|
|
|
|
}
|
|
|
|
bool ContentIs(const clang::TypeLoc* target_node) const {
|
|
|
|
const clang::TypeLoc* type_loc = GetAs<clang::TypeLoc>();
|
|
|
|
if (type_loc == NULL || target_node == NULL)
|
|
|
|
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<typename T> bool StackContainsContent(const T* ptr) const {
|
|
|
|
for (const ASTNode* node = this; node != NULL; node = node->parent_) {
|
|
|
|
if (node->ContentIs(ptr))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generation 0 == you, 1 == parent, etc.
|
|
|
|
template<typename To> const To* GetAncestorAs(int generation) const {
|
|
|
|
const ASTNode* target_node = this;
|
|
|
|
for (; generation > 0; --generation) {
|
|
|
|
if (target_node->parent_ == NULL)
|
|
|
|
return NULL;
|
|
|
|
target_node = target_node->parent_;
|
|
|
|
}
|
|
|
|
// DynCast needs a dummy argument of type To* to help its resolution.
|
|
|
|
const To* dummy = NULL;
|
|
|
|
return target_node->DynCast<To>(dummy);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convenience methods.
|
|
|
|
|
|
|
|
template<typename To> bool AncestorIsA(int generation) const {
|
|
|
|
return GetAncestorAs<To>(generation) != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true if this node or any of its ancestors contains a T*.
|
|
|
|
template<typename T> bool HasAncestorOfType() const {
|
|
|
|
for (const ASTNode* node = this; node != NULL; node = node->parent_) {
|
|
|
|
if (node->IsA<T>())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename To> const To* GetParentAs() const {
|
|
|
|
return GetAncestorAs<To>(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename To> bool ParentIsA() const {
|
|
|
|
return AncestorIsA<To>(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename To> const To* GetAs() const {
|
|
|
|
return GetAncestorAs<To>(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename To> bool IsA() const {
|
|
|
|
return AncestorIsA<To>(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
enum NodeKind {
|
|
|
|
kDeclKind, kStmtKind, kTypeKind, kTypelocKind, kNNSKind,
|
|
|
|
kTemplateNameKind, kTemplateArgumentKind, kTemplateArgumentLocKind
|
|
|
|
};
|
|
|
|
|
|
|
|
// Returns a casted pointer if this object actually is of the given
|
|
|
|
// type (or a subclass of the given type), and NULL 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<typename To> const To* DynCast(const clang::Decl*) const {
|
|
|
|
if (kind_ != kDeclKind) return NULL;
|
|
|
|
return dyn_cast<To>(as_decl_);
|
|
|
|
}
|
|
|
|
template<typename To> const To* DynCast(const clang::Stmt*) const {
|
|
|
|
if (kind_ != kStmtKind) return NULL;
|
|
|
|
return dyn_cast<To>(as_stmt_);
|
|
|
|
}
|
|
|
|
template<typename To> 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<FooTypeLoc>()) ... else if (node.IsA<FooType>()) ...
|
|
|
|
if (kind_ == kTypelocKind)
|
|
|
|
return dyn_cast<To>(as_typeloc_->getTypePtr());
|
|
|
|
if (kind_ != kTypeKind) return NULL;
|
|
|
|
return dyn_cast<To>(as_type_);
|
|
|
|
}
|
|
|
|
template<typename To> const To* DynCast(const clang::TypeLoc*) const {
|
|
|
|
if (kind_ != kTypelocKind) return NULL;
|
|
|
|
return dyn_cast<To>(as_typeloc_);
|
|
|
|
}
|
|
|
|
template<typename To> const To* DynCast(
|
|
|
|
const clang::NestedNameSpecifier*) const {
|
|
|
|
if (kind_ != kNNSKind) return NULL;
|
|
|
|
return as_nns_;
|
|
|
|
}
|
|
|
|
template<typename To> const To* DynCast(const clang::TemplateName*) const {
|
|
|
|
if (kind_ != kTemplateNameKind) return NULL;
|
|
|
|
return as_template_name_;
|
|
|
|
}
|
|
|
|
template<typename To> 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 NULL;
|
|
|
|
return as_template_arg_;
|
|
|
|
}
|
|
|
|
template<typename To> const To* DynCast(
|
|
|
|
const clang::TemplateArgumentLoc*) const {
|
|
|
|
if (kind_ != kTemplateArgumentLocKind) return NULL;
|
|
|
|
return as_template_argloc_;
|
|
|
|
}
|
|
|
|
// We also allow casting to void*
|
|
|
|
template<typename Ignored> 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 kTemplateNameKind: return as_template_name_;
|
|
|
|
case kTemplateArgumentKind: return as_template_arg_;
|
|
|
|
case kTemplateArgumentLocKind: return as_template_argloc_;
|
|
|
|
default: assert(false && "Unknown kind"); return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
using include_what_you_use::GetLocation;
|
|
|
|
switch (kind_) {
|
|
|
|
case kDeclKind:
|
|
|
|
*loc = GetLocation(as_decl_); // in iwyu_location_util.h
|
|
|
|
return true;
|
|
|
|
case kStmtKind:
|
|
|
|
*loc = GetLocation(as_stmt_);
|
|
|
|
return true;
|
|
|
|
case kTypelocKind:
|
|
|
|
*loc = GetLocation(as_typeloc_);
|
|
|
|
return true;
|
|
|
|
case kTemplateArgumentLocKind:
|
|
|
|
*loc = GetLocation(as_template_argloc_);
|
|
|
|
return true;
|
|
|
|
case kTypeKind:
|
|
|
|
case kNNSKind:
|
|
|
|
case kTemplateNameKind:
|
|
|
|
case kTemplateArgumentKind:
|
|
|
|
return false;
|
|
|
|
default:
|
|
|
|
assert(false && "Unexpected kind of ASTNode");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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::TemplateName* as_template_name_;
|
|
|
|
const clang::TemplateArgument* as_template_arg_;
|
|
|
|
const clang::TemplateArgumentLoc* as_template_argloc_;
|
|
|
|
};
|
|
|
|
const ASTNode* parent_;
|
|
|
|
bool in_fwd_decl_context_;
|
|
|
|
const clang::SourceManager& source_manager_;
|
|
|
|
};
|
|
|
|
|
|
|
|
// --- 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<typename T> 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<ASTNode*> 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').
|
|
|
|
inline bool IsElaborationNode(const ASTNode* ast_node) {
|
|
|
|
if (ast_node == NULL)
|
|
|
|
return false;
|
|
|
|
const clang::ElaboratedType* elaborated_type =
|
|
|
|
ast_node->GetAs<clang::ElaboratedType>();
|
|
|
|
return elaborated_type && elaborated_type->getKeyword() != clang::ETK_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
// See if a given ast_node is a namespace-qualified ElaboratedType
|
|
|
|
// node. (E.g. 'class ns::Foo myyvar'.)
|
|
|
|
inline bool IsNamespaceQualifiedNode(const ASTNode* ast_node) {
|
|
|
|
if (ast_node == NULL)
|
|
|
|
return false;
|
|
|
|
const clang::ElaboratedType* elaborated_type =
|
|
|
|
ast_node->GetAs<clang::ElaboratedType>();
|
|
|
|
return (elaborated_type && elaborated_type->getQualifier()
|
|
|
|
&& elaborated_type->getQualifier()->getKind() ==
|
|
|
|
clang::NestedNameSpecifier::Namespace);
|
|
|
|
}
|
|
|
|
|
|
|
|
// See if the given ast_node is the decl of a class or function that
|
|
|
|
// occurs in a friend context. That is, for 'friend class Foo', this
|
|
|
|
// function matches the decl for 'class Foo'. (It does not match the
|
|
|
|
// FriendDecl 'friend class Foo' -- we're looking to say whether we're
|
|
|
|
// the decl *inside* the friend decl.)
|
|
|
|
inline bool IsDeclNodeInsideFriend(const ASTNode* ast_node) {
|
|
|
|
if (ast_node->ParentIsA<clang::FriendDecl>() ||
|
|
|
|
ast_node->ParentIsA<clang::FriendTemplateDecl>())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// For 'template<class Foo> friend class X', 'class X's parent is
|
|
|
|
// a ClassTemplateDecl.
|
|
|
|
if (ast_node->ParentIsA<clang::ClassTemplateDecl>() &&
|
|
|
|
(ast_node->AncestorIsA<clang::FriendDecl>(2) ||
|
|
|
|
ast_node->AncestorIsA<clang::FriendTemplateDecl>(2)))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Is ast_node the 'D' in the following:
|
|
|
|
// template<template <typename A> class T = D> class C { ... }
|
|
|
|
// ('D' might be something like 'vector').
|
|
|
|
inline bool IsDefaultTemplateTemplateArg(const ASTNode* ast_node) {
|
|
|
|
// D is a TemplateName, since it's a template, and its parent
|
|
|
|
// is a TemplateArgument, since D is inside a template argument.
|
|
|
|
// The only way a template name can be in a template argument
|
|
|
|
// is if it's a default parameter.
|
|
|
|
return (ast_node->IsA<clang::TemplateName>() &&
|
|
|
|
ast_node->ParentIsA<clang::TemplateArgument>());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true if this node is a ConstructExpr that is being used to
|
|
|
|
// construct a field in a class (that is, it's part of a constructor
|
|
|
|
// initializer list).
|
|
|
|
inline bool IsCXXConstructExprInInitializer(const ASTNode* ast_node) {
|
|
|
|
if (!ast_node->IsA<clang::CXXConstructExpr>())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
assert(ast_node->parent() && "Constructor should not be a top-level node!");
|
|
|
|
|
|
|
|
// Typically, you can tell an initializer because its parent is a
|
|
|
|
// constructor decl. But sometimes -- I'm not exactly sure when --
|
|
|
|
// there can be an ExprWithCleanups in the middle.
|
|
|
|
return ((ast_node->ParentIsA<clang::CXXConstructorDecl>()) ||
|
|
|
|
(ast_node->ParentIsA<clang::ExprWithCleanups>() &&
|
|
|
|
ast_node->AncestorIsA<clang::CXXConstructorDecl>(2)));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
inline clang::NestedNameSpecifier* TryGetQualifier(const ASTNode* ast_node) {
|
|
|
|
if (ast_node->IsA<T>())
|
|
|
|
return ast_node->GetAs<T>()->getQualifier();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If ASTNode is of a kind that has a qualifier (something that
|
|
|
|
// comes before the ::), return that, else return NULL.
|
|
|
|
inline const clang::NestedNameSpecifier* GetQualifier(const ASTNode* ast_node) {
|
|
|
|
const clang::NestedNameSpecifier* nns = NULL;
|
|
|
|
if (ast_node->IsA<clang::TemplateName>()) {
|
|
|
|
const clang::TemplateName* tn = ast_node->GetAs<clang::TemplateName>();
|
|
|
|
if (const clang::DependentTemplateName* dtn
|
|
|
|
= tn->getAsDependentTemplateName())
|
|
|
|
nns = dtn->getQualifier();
|
|
|
|
else if (const clang::QualifiedTemplateName* qtn
|
|
|
|
= tn->getAsQualifiedTemplateName())
|
|
|
|
nns = qtn->getQualifier();
|
|
|
|
}
|
|
|
|
if (!nns) nns = TryGetQualifier<clang::ElaboratedType>(ast_node);
|
|
|
|
if (!nns) nns = TryGetQualifier<clang::DependentNameType>(ast_node);
|
|
|
|
if (!nns)
|
|
|
|
nns = TryGetQualifier<clang::DependentTemplateSpecializationType>(ast_node);
|
|
|
|
if (!nns) nns = TryGetQualifier<clang::UsingDirectiveDecl>(ast_node);
|
|
|
|
if (!nns) nns = TryGetQualifier<clang::EnumDecl>(ast_node);
|
|
|
|
if (!nns) nns = TryGetQualifier<clang::RecordDecl>(ast_node);
|
|
|
|
if (!nns) nns = TryGetQualifier<clang::DeclaratorDecl>(ast_node);
|
|
|
|
if (!nns) nns = TryGetQualifier<clang::FunctionDecl>(ast_node);
|
|
|
|
if (!nns) nns = TryGetQualifier<clang::CXXDependentScopeMemberExpr>(ast_node);
|
|
|
|
if (!nns) nns = TryGetQualifier<clang::DeclRefExpr>(ast_node);
|
|
|
|
if (!nns) nns = TryGetQualifier<clang::DependentScopeDeclRefExpr>(ast_node);
|
|
|
|
if (!nns) nns = TryGetQualifier<clang::MemberExpr>(ast_node);
|
|
|
|
return nns;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true if any parent is a typedef: my_typedef.a, or
|
|
|
|
// MyTypedef::a, or MyTypedef::subclass::a, etc. Note it does
|
|
|
|
// *not* return true if the ast_node itself is a typedef.
|
|
|
|
inline bool IsMemberOfATypedef(const ASTNode* ast_node) {
|
|
|
|
// TODO(csilvers): is this ever triggered in practice?
|
|
|
|
if (ast_node->ParentIsA<clang::TypedefType>()) { // my_typedef.a
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we're one of those objects that exposes its qualifier
|
|
|
|
// (stuff before the ::), use that.
|
|
|
|
const clang::NestedNameSpecifier* nns = GetQualifier(ast_node);
|
|
|
|
|
|
|
|
// If that doesn't work, see if our parent in the tree is an nns
|
|
|
|
// node. We have to be a bit careful here: 1) If we're a typedef
|
|
|
|
// ourselves, the nns-parent is just us. We have to go a level up
|
|
|
|
// to see our 'real' qualifier. 2) Often the parent will be an
|
|
|
|
// elaborated type, and we get to the qualifier that way.
|
|
|
|
if (!nns) {
|
|
|
|
nns = ast_node->GetParentAs<clang::NestedNameSpecifier>();
|
|
|
|
if (nns && ast_node->IsA<clang::TypedefType>()) {
|
|
|
|
nns = nns->getPrefix();
|
|
|
|
} else if (!nns) {
|
|
|
|
// nns will be non-NULL when processing 'a' in MyTypedef::a::b
|
|
|
|
// But typically, such as processing 'a' in MyTypedef::a or 'b' in
|
|
|
|
// MyTypedef::a::b, the parent will be an ElaboratedType.
|
|
|
|
if (const clang::ElaboratedType* elab_type =
|
|
|
|
ast_node->GetParentAs<clang::ElaboratedType>())
|
|
|
|
nns = elab_type->getQualifier();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; nns; nns = nns->getPrefix()) {
|
|
|
|
if (nns->getAsType() && isa<clang::TypedefType>(nns->getAsType()))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------
|
|
|
|
// Helper functions for working with raw Clang AST nodes.
|
|
|
|
|
|
|
|
// --- Printers.
|
|
|
|
|
|
|
|
inline string PrintableLoc(clang::SourceLocation loc) {
|
|
|
|
if (loc.isInvalid()) {
|
|
|
|
return "Invalid location";
|
|
|
|
} else {
|
|
|
|
std::string buffer; // llvm wants regular string, not our versa-string
|
|
|
|
llvm::raw_string_ostream ostream(buffer);
|
|
|
|
loc.print(ostream, *GlobalSourceManager());
|
|
|
|
return NormalizeFilePath(ostream.str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline string PrintableSourceRange(clang::SourceRange range) {
|
|
|
|
return PrintableLoc(range.getBegin()) + " - " + PrintableLoc(range.getEnd());
|
|
|
|
}
|
|
|
|
|
|
|
|
inline string PrintableDecl(const clang::Decl* decl) {
|
|
|
|
std::string buffer; // llvm wants regular string, not our versa-string
|
|
|
|
llvm::raw_string_ostream ostream(buffer);
|
|
|
|
decl->print(ostream); // Note: can also set indentation and printingpolicy
|
|
|
|
return ostream.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void PrintStmt(const clang::Stmt* stmt) {
|
|
|
|
stmt->dump(*GlobalSourceManager()); // This prints to errs().
|
|
|
|
}
|
|
|
|
|
|
|
|
inline string PrintableType(const clang::Type* type) {
|
|
|
|
return clang::QualType(type, 0).getAsString();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline string PrintableTypeLoc(const clang::TypeLoc& typeloc) {
|
|
|
|
return PrintableType(typeloc.getTypePtr());
|
|
|
|
}
|
|
|
|
|
|
|
|
inline string PrintableNestedNameSpecifier(
|
|
|
|
const clang::NestedNameSpecifier* nns) {
|
|
|
|
std::string buffer; // llvm wants regular string, not our versa-string
|
|
|
|
llvm::raw_string_ostream ostream(buffer);
|
|
|
|
nns->print(ostream, DefaultPrintPolicy());
|
|
|
|
return ostream.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline string PrintableTemplateName(const clang::TemplateName& tpl_name) {
|
|
|
|
std::string buffer; // llvm wants regular string, not our versa-string
|
|
|
|
llvm::raw_string_ostream ostream(buffer);
|
|
|
|
tpl_name.print(ostream, DefaultPrintPolicy());
|
|
|
|
return ostream.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline string PrintableTemplateArgument(const clang::TemplateArgument& arg) {
|
|
|
|
return clang::TemplateSpecializationType::PrintTemplateArgumentList(
|
|
|
|
&arg, 1, DefaultPrintPolicy());
|
|
|
|
}
|
|
|
|
|
|
|
|
inline string PrintableTemplateArgumentLoc(
|
|
|
|
const clang::TemplateArgumentLoc& arg) {
|
|
|
|
return clang::TemplateSpecializationType::PrintTemplateArgumentList(
|
|
|
|
&arg, 1, DefaultPrintPolicy());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- Type conversion utilities.
|
|
|
|
|
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
// For implementing DynCastFrom() -- don't use directly.
|
|
|
|
template <typename T>
|
|
|
|
class DynCastPtr {
|
|
|
|
public:
|
|
|
|
explicit DynCastPtr(T* ptr) : ptr_(ptr) { }
|
|
|
|
|
|
|
|
template <typename U> operator U*() const {
|
|
|
|
return ::llvm::dyn_cast_or_null<U>(ptr_);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
T* ptr_;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace internal
|
|
|
|
|
|
|
|
// dyn_cast<> and dyn_cast_or_null<> require the user to write the
|
|
|
|
// type of the target pointer, which is redundant when the result is
|
|
|
|
// immediately assigned to a newly declared pointer variable of the
|
|
|
|
// target type (the typical case). DynCastFrom() lets us omit the
|
|
|
|
// target type, e.g.
|
|
|
|
//
|
|
|
|
// if (const CXXConstructExpr* expr = DynCastFrom(source_expr)) ...
|
|
|
|
//
|
|
|
|
// instead of
|
|
|
|
//
|
|
|
|
// if (const CXXConstructExpr* expr =
|
|
|
|
// dyn_cast_or_null<CXXConstructExpr>(source_expr)) ...
|
|
|
|
//
|
|
|
|
// For readability, DynCastFrom() should only be used as the
|
|
|
|
// initializer of a variable declaration, where the target type is
|
|
|
|
// obvious.
|
|
|
|
template <typename T>
|
|
|
|
inline internal::DynCastPtr<T> DynCastFrom(T* ptr) {
|
|
|
|
return internal::DynCastPtr<T>(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// --- Utilities for Template Arguments.
|
|
|
|
|
|
|
|
// These utilities figure out the template arguments that are
|
|
|
|
// specified in various contexts: TemplateSpecializationType (for
|
|
|
|
// template classes) and FunctionDecl (for template functions).
|
|
|
|
//
|
|
|
|
// For classes, we care only about explicitly specified template args,
|
|
|
|
// not implicit, default args. For functions, we care about all
|
|
|
|
// template args, since if not specified they're derived from the
|
|
|
|
// function arguments. In either case, we only care about template
|
|
|
|
// arguments that are types (including template types), not other
|
|
|
|
// kinds of arguments such as built-in types.
|
|
|
|
|
|
|
|
// Helper function to the functions below.
|
|
|
|
// TODO(csilvers): come up with a better name? Or refactor?
|
|
|
|
inline void AddTypelikeTemplateArgTo(const clang::TemplateArgument& tpl_arg,
|
|
|
|
set<const clang::Type*>* argset) {
|
|
|
|
if (tpl_arg.getKind() == clang::TemplateArgument::Type) {
|
|
|
|
set<const clang::Type*> argtypes;
|
|
|
|
argtypes.insert(tpl_arg.getAsType().getTypePtr());
|
|
|
|
// If the type is a function (a rare case, but happens in code like
|
|
|
|
// TplClass<char(int, int, int)> c), then the parameters are types
|
|
|
|
// we have to consider as well.
|
|
|
|
if (const clang::FunctionProtoType* fn_type
|
|
|
|
= DynCastFrom(tpl_arg.getAsType().getTypePtr())) {
|
|
|
|
argtypes.insert(fn_type->getResultType().getTypePtr());
|
|
|
|
for (unsigned i = 0; i < fn_type->getNumArgs(); ++i) {
|
|
|
|
argtypes.insert(fn_type->getArgType(i).getTypePtr());
|
|
|
|
}
|
|
|
|
// I *think* it's correct to ignore the exception specs here.
|
|
|
|
}
|
|
|
|
|
|
|
|
for (Each<const clang::Type*> it(&argtypes); !it.AtEnd(); ++it) {
|
|
|
|
VERRS(6) << "Adding a template type of interest: "
|
|
|
|
<< PrintableType(*it) << "\n";
|
|
|
|
argset->insert(*it);
|
|
|
|
// Recurse if we ourself are a template type.
|
|
|
|
if (const clang::TemplateSpecializationType* tpl_type
|
|
|
|
= DynCastFrom(*it)) {
|
|
|
|
for (unsigned i = 0; i < tpl_type->getNumArgs(); ++i)
|
|
|
|
AddTypelikeTemplateArgTo(tpl_type->getArg(i), argset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (tpl_arg.getKind() == clang::TemplateArgument::Template) {
|
|
|
|
const clang::TemplateName& tpl_name = tpl_arg.getAsTemplate();
|
|
|
|
VERRS(6) << "Noticing (but ignoring) a template template of interest: "
|
|
|
|
<< PrintableTemplateName(tpl_name) << "\n";
|
|
|
|
// TODO(csilvers): add tpl_name to argset somehow. This is a
|
|
|
|
// lower-priority TODO, since for the moment we just always
|
|
|
|
// assume template template args needs to be fully instantiated.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// --- Utilities for Decl.
|
|
|
|
|
|
|
|
// Returns true if the decl is for a templatized function.
|
|
|
|
inline bool IsTemplatizedFunctionDecl(const clang::FunctionDecl* decl) {
|
|
|
|
return decl && decl->getTemplateSpecializationArgs() != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true if the given class has at least one implicit
|
|
|
|
// conversion constructor.
|
|
|
|
inline bool HasImplicitConversionCtor(const clang::CXXRecordDecl* cxx_class) {
|
|
|
|
for (clang::CXXRecordDecl::ctor_iterator ctor = cxx_class->ctor_begin();
|
|
|
|
ctor != cxx_class->ctor_end(); ++ctor) {
|
|
|
|
if ((*ctor)->isExplicit() || (*ctor)->getNumParams() != 1 ||
|
|
|
|
(*ctor)->isCopyConstructor())
|
|
|
|
continue;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this decl is a (possibly templatized) class, return the decl
|
|
|
|
// that defines the class, if present. Otherwise return NULL.
|
|
|
|
inline const clang::RecordDecl* GetDefinitionForClass(const clang::Decl* decl) {
|
|
|
|
const clang::RecordDecl* as_record = DynCastFrom(decl);
|
|
|
|
const clang::ClassTemplateDecl* as_tpl = DynCastFrom(decl);
|
|
|
|
if (as_tpl) // Convert the template to its underlying class defn.
|
|
|
|
as_record = dyn_cast_or_null<clang::RecordDecl>(as_tpl->getTemplatedDecl());
|
|
|
|
if (as_record) {
|
|
|
|
if (const clang::RecordDecl* record_dfn = as_record->getDefinition())
|
|
|
|
return record_dfn;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Given a class, returns a SourceRange that encompasses the beginning
|
|
|
|
// of the class declaration (including template<> prefix, etc) to the
|
|
|
|
// class name. Used to determine where forward-declares are.
|
|
|
|
inline clang::SourceRange GetSourceRangeOfClassDecl(const clang::Decl* decl) {
|
|
|
|
// If we're a templatized class, go 'up' a level to get the
|
|
|
|
// template<...> prefix as well.
|
|
|
|
if (const clang::CXXRecordDecl* cxx_decl = DynCastFrom(decl)) {
|
|
|
|
if (cxx_decl->getDescribedClassTemplate())
|
|
|
|
return cxx_decl->getDescribedClassTemplate()->getSourceRange();
|
|
|
|
}
|
|
|
|
// We can get source ranges of classes and template classes.
|
|
|
|
if (const clang::TagDecl* tag_decl = DynCastFrom(decl))
|
|
|
|
return tag_decl->getSourceRange();
|
|
|
|
if (const clang::TemplateDecl* tpl_decl = DynCastFrom(decl))
|
|
|
|
return tpl_decl->getSourceRange();
|
|
|
|
assert(!"Cannot get source range for this decl type");
|
|
|
|
return clang::SourceRange();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Luckily, one can't have partial template specialization or
|
|
|
|
// default template args for function templates.
|
|
|
|
inline set<const clang::Type*> GetTplTypeArgsOfFunction(
|
|
|
|
const clang::FunctionDecl* decl) {
|
|
|
|
set<const clang::Type*> retval;
|
|
|
|
if (!decl)
|
|
|
|
return retval;
|
|
|
|
const clang::TemplateArgumentList* tpl_list =
|
|
|
|
decl->getTemplateSpecializationArgs();
|
|
|
|
if (tpl_list) {
|
|
|
|
for (unsigned i = 0; i < tpl_list->size(); ++i) {
|
|
|
|
AddTypelikeTemplateArgTo(tpl_list->get(i), &retval);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If class_decl is instantiated from a class template,
|
|
|
|
// returns the decl for that template; otherwise returns class_decl.
|
|
|
|
// As an example, consider this code:
|
|
|
|
// template<class T> class Foo { ... }; // template decl
|
|
|
|
// template<> class Foo<int> { ... }; // explicit specialization
|
|
|
|
// template class Foo<char>; // note: no body specified
|
|
|
|
// Foo<int> v1;
|
|
|
|
// Foo<float> v2;
|
|
|
|
// Foo<char> v3;
|
|
|
|
// The types Foo<int>, Foo<float>, and Foo<char> all have a
|
|
|
|
// corresponding decl. In the case of Foo<int>, the decl is the
|
|
|
|
// explicit specialization. This is *not* a decl that this routine
|
|
|
|
// deals with; the routine will just return its argument in this case.
|
|
|
|
// But in the case of Foo<float>, the decl is an implicit
|
|
|
|
// instantiation of Foo<T>, and this routine will return the decl for
|
|
|
|
// Foo<T>. Foo<char> is a rarer corner case: an explicit
|
|
|
|
// instantiation definition (it just causes code for that template
|
|
|
|
// case to be generated). It is treated the same as Foo<float>: we
|
|
|
|
// return the template decl, which provides the actual class body.
|
|
|
|
// We try to return a decl that's also a definition, when possible.
|
|
|
|
inline const clang::NamedDecl* GetInstantiatedFromDecl(
|
|
|
|
const clang::CXXRecordDecl* class_decl) {
|
|
|
|
if (const clang::ClassTemplateSpecializationDecl* tpl_sp_decl =
|
|
|
|
DynCastFrom(class_decl)) { // an instantiated class template
|
|
|
|
llvm::PointerUnion<clang::ClassTemplateDecl*,
|
|
|
|
clang::ClassTemplatePartialSpecializationDecl*>
|
|
|
|
instantiated_from = tpl_sp_decl->getInstantiatedFrom();
|
|
|
|
if (const clang::ClassTemplateDecl* tpl_decl =
|
|
|
|
instantiated_from.dyn_cast<clang::ClassTemplateDecl*>()) {
|
|
|
|
// class_decl is instantiated from a non-specialized template.
|
|
|
|
return tpl_decl;
|
|
|
|
} else if (const clang::ClassTemplatePartialSpecializationDecl*
|
|
|
|
partial_spec_decl =
|
|
|
|
instantiated_from.dyn_cast<
|
|
|
|
clang::ClassTemplatePartialSpecializationDecl*>()) {
|
|
|
|
// class_decl is instantiated from a template partial specialization.
|
|
|
|
return partial_spec_decl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// class_decl is not instantiated from a template.
|
|
|
|
return class_decl;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For an implicitly instantiated templated c++ class -- that is, a
|
|
|
|
// class like vector<int> that isn't explicitly written in the source
|
|
|
|
// code but instead derived from vector<T> -- returns the
|
|
|
|
// class-as-written (vector<T>, in this case). For an implicitly
|
|
|
|
// instantiated template function -- Fn<int> when all that is written
|
|
|
|
// in the source code is Fn<T> -- returns the function-as-written.
|
|
|
|
// (In each case, prefers the definition of the class or function
|
|
|
|
// as-written, rather than a forward-declaration.) Otherwise, returns
|
|
|
|
// the original input.
|
|
|
|
inline const clang::NamedDecl* GetDefinitionAsWritten(
|
|
|
|
const clang::NamedDecl* decl) {
|
|
|
|
// First, get to decl-as-written.
|
|
|
|
if (const clang::CXXRecordDecl* class_decl = DynCastFrom(decl)) {
|
|
|
|
decl = GetInstantiatedFromDecl(class_decl);
|
|
|
|
if (const clang::ClassTemplateDecl* tpl_decl = DynCastFrom(decl))
|
|
|
|
decl = tpl_decl->getTemplatedDecl(); // convert back to CXXRecordDecl
|
|
|
|
} else if (const clang::FunctionDecl* func_decl = DynCastFrom(decl)) {
|
|
|
|
if (const clang::FunctionDecl* tpl_pattern =
|
|
|
|
func_decl->getTemplateInstantiationPattern())
|
|
|
|
decl = tpl_pattern;
|
|
|
|
}
|
|
|
|
// Then, get to definition.
|
|
|
|
if (const clang::RecordDecl* class_dfn = GetDefinitionForClass(decl)) {
|
|
|
|
return class_dfn;
|
|
|
|
} else if (const clang::FunctionDecl* fn_decl = DynCastFrom(decl)) {
|
|
|
|
for (clang::FunctionDecl::redecl_iterator it = fn_decl->redecls_begin();
|
|
|
|
it != fn_decl->redecls_end(); ++it) {
|
|
|
|
if ((*it)->isThisDeclarationADefinition())
|
|
|
|
return *it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Couldn't find a definition, just return the original declaration.
|
|
|
|
return decl;
|
|
|
|
}
|
|
|
|
|
|
|
|
// True if this decl is for default (not placement-new)
|
|
|
|
// new/delete/new[]/delete[] from <new>. The second argument
|
|
|
|
// is the quoted form of the file the decl comes from, e.g. '<new>'.
|
|
|
|
inline bool IsDefaultNewOrDelete(const clang::FunctionDecl* decl,
|
|
|
|
const string& decl_loc_as_quoted_include) {
|
|
|
|
// Clang will report <new> as the location of the default new and
|
|
|
|
// delete operators if <new> is included. Otherwise, it reports the
|
|
|
|
// (fake) file "<built_in>".
|
|
|
|
if (decl_loc_as_quoted_include != "<new>" &&
|
|
|
|
!IsBuiltinFile(GetFileEntry(decl)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const string decl_name = decl->getNameAsString();
|
|
|
|
if (!StartsWith(decl_name, "operator new") &&
|
|
|
|
!StartsWith(decl_name, "operator delete"))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Placement-new/delete has 2 args, second is void*. The only other
|
|
|
|
// 2-arg overloads of new/delete in <new> take a const nothrow_t&.
|
|
|
|
if (decl->getNumParams() == 2 &&
|
|
|
|
!decl->getParamDecl(1)->getType().isConstQualified())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true if this decl is part of a friend decl.
|
|
|
|
inline bool IsFriendDecl(const clang::Decl* decl) {
|
|
|
|
// For 'template<...> friend class T', the decl will just be 'class T'.
|
|
|
|
// We need to go 'up' a level to check friendship in the right place.
|
|
|
|
if (const clang::CXXRecordDecl* cxx_decl = DynCastFrom(decl))
|
|
|
|
if (cxx_decl->getDescribedClassTemplate())
|
|
|
|
decl = cxx_decl->getDescribedClassTemplate();
|
|
|
|
return decl->getFriendObjectKind() != clang::Decl::FOK_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool HasDefaultTemplateParameters(const clang::TemplateDecl* decl) {
|
|
|
|
clang::TemplateParameterList* tpl_params = decl->getTemplateParameters();
|
|
|
|
return tpl_params->getMinRequiredArguments() < tpl_params->size();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline set<const clang::RecordDecl*> GetClassRedecls(
|
|
|
|
const clang::RecordDecl* decl) {
|
|
|
|
set<const clang::RecordDecl*> redecls;
|
|
|
|
for (clang::TagDecl::redecl_iterator it = decl->redecls_begin();
|
|
|
|
it != decl->redecls_end(); ++it) {
|
|
|
|
const clang::RecordDecl* redecl = cast<clang::RecordDecl>(*it);
|
|
|
|
// If this decl is a friend decl, don't count it: friend decls
|
|
|
|
// don't serve as forward-declarations. (This should never
|
|
|
|
// happen, I think, but it sometimes does due to a clang bug:
|
|
|
|
// http://llvm.org/bugs/show_bug.cgi?id=8669)
|
|
|
|
if (!IsFriendDecl(redecl))
|
|
|
|
redecls.insert(redecl);
|
|
|
|
}
|
|
|
|
return redecls;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unlike GetClassRedecls, this accepts both RecordDecls and
|
|
|
|
// ClassTemplateDecls -- the return Decl is guaranteed to be of the
|
|
|
|
// same type as the input Decl. It picks one redecl arbitrarily.
|
|
|
|
// This is used to recover from the clang bug that mixes friend decls
|
|
|
|
// with 'real' redecls (http://llvm.org/bugs/show_bug.cgi?id=8669);
|
|
|
|
// this function returns a 'real' redecl. If the input decl is not a
|
|
|
|
// friend decl, or not a class decl at all, it will always be returned.
|
|
|
|
// TODO(csilvers): remove once PR 8669 is fixed.
|
|
|
|
inline const clang::NamedDecl* GetNonfriendClassRedecl(
|
|
|
|
const clang::NamedDecl* decl) {
|
|
|
|
const clang::RecordDecl* record_decl = DynCastFrom(decl);
|
|
|
|
const clang::ClassTemplateDecl* tpl_decl = DynCastFrom(decl);
|
|
|
|
if (tpl_decl)
|
|
|
|
record_decl = tpl_decl->getTemplatedDecl();
|
|
|
|
if (!record_decl || !IsFriendDecl(record_decl))
|
|
|
|
return decl;
|
|
|
|
|
|
|
|
const set<const clang::RecordDecl*> redecls = GetClassRedecls(record_decl);
|
|
|
|
assert(!redecls.empty() && "Should be at least once 'real' decl");
|
|
|
|
const clang::RecordDecl* retval = *redecls.begin(); // arbitrary choice
|
|
|
|
|
|
|
|
if (tpl_decl) { // need to convert back to a ClassTemplateDecl
|
|
|
|
assert(isa<clang::CXXRecordDecl>(retval) &&
|
|
|
|
cast<clang::CXXRecordDecl>(retval)->getDescribedClassTemplate());
|
|
|
|
const clang::CXXRecordDecl* cxx_decl = cast<clang::CXXRecordDecl>(retval);
|
|
|
|
return cxx_decl->getDescribedClassTemplate();
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true if the innermost DeclContext for each decl is the
|
|
|
|
// same, and it's a class (or struct).
|
|
|
|
inline bool DeclsAreInSameClass(const clang::Decl* decl1,
|
|
|
|
const clang::Decl* decl2) {
|
|
|
|
if (!decl1 || !decl2)
|
|
|
|
return false;
|
|
|
|
if (decl1->getDeclContext() != decl2->getDeclContext())
|
|
|
|
return false;
|
|
|
|
return decl1->getDeclContext()->isRecord();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- Utilities for Type.
|
|
|
|
|
|
|
|
inline const clang::Type* GetTypeOf(const clang::Expr* expr) {
|
|
|
|
return expr->getType().getTypePtr();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the type of the given variable, function, or enum declaration.
|
|
|
|
inline const clang::Type* GetTypeOf(const clang::ValueDecl* decl) {
|
|
|
|
return decl->getType().getTypePtr();
|
|
|
|
}
|
|
|
|
// ...or class, struct, union, enum, typedef, or template type.
|
|
|
|
inline const clang::Type* GetTypeOf(const clang::TypeDecl* decl) {
|
|
|
|
return decl->getTypeForDecl();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Returns true if the type has any template arguments.
|
|
|
|
inline bool IsTemplatizedType(const clang::Type* type) {
|
|
|
|
return type && isa<clang::TemplateSpecializationType>(type);
|
|
|
|
}
|
|
|
|
|
|
|
|
// The ElaborationType -- which says whether a type is preceded by
|
|
|
|
// 'class' or 'struct' ('class Foo'), or whether the type-name has a
|
|
|
|
// namespace ('ns::Foo') -- often pops where it's not wanted. This
|
|
|
|
// removes the elaboration if it exists, else it's a noop. Note that
|
|
|
|
// if the type has both kinds of elaborations ('struct ns::Foo'), they
|
|
|
|
// will both be removed.
|
|
|
|
inline const clang::Type* RemoveElaboration(const clang::Type* type) {
|
|
|
|
if (const clang::ElaboratedType* elaborated_type = DynCastFrom(type))
|
|
|
|
return elaborated_type->getNamedType().getTypePtr();
|
|
|
|
else
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read past SubstTemplateTypeParmType to the underlying type, if type
|
|
|
|
// is itself a SubstTemplateTypeParmType. Thus: T is converted to int
|
|
|
|
// if we are parsing a template instantiated with T being int.
|
|
|
|
// However, vector<T> is *not* converted to vector<int>.
|
|
|
|
inline const clang::Type* RemoveSubstTemplateTypeParm(const clang::Type* type) {
|
|
|
|
if (const clang::SubstTemplateTypeParmType* subst_type = DynCastFrom(type))
|
|
|
|
return subst_type->getReplacementType().getTypePtr();
|
|
|
|
else
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true if type is a pointer type (pointer or reference,
|
|
|
|
// looking through elaborations like 'class Foo*' (vs 'Foo*'),
|
|
|
|
// but *not* following typedefs (which is why we can't just use
|
|
|
|
// type->isPointerType()).
|
|
|
|
// TODO(csilvers): what about array-type?
|
|
|
|
inline bool IsPointerOrReferenceAsWritten(const clang::Type* type) {
|
|
|
|
type = RemoveElaboration(type);
|
|
|
|
return isa<clang::PointerType>(type) || isa<clang::LValueReferenceType>(type);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Gets rid of all the pointers and references to get to the 'base'
|
|
|
|
// type. Also removes all elaborations (like 'class' keyword). We
|
|
|
|
// can't just use the default desugar() routine, because we *don't*
|
|
|
|
// want to look through typedefs.
|
|
|
|
inline const clang::Type* RemovePointersAndReferencesAsWritten(
|
|
|
|
const clang::Type* type) {
|
|
|
|
type = RemoveElaboration(type);
|
|
|
|
while (isa<clang::PointerType>(type) ||
|
|
|
|
isa<clang::LValueReferenceType>(type)) {
|
|
|
|
type = type->getPointeeType().getTypePtr();
|
|
|
|
}
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove one layer of pointers (or references) from type. We go
|
|
|
|
// through typedefs and the like, but only if we have to in order to
|
|
|
|
// figure out the dereferenced type, which is why we don't just use
|
|
|
|
// desugar(). Returns NULL if not a pointer.
|
|
|
|
inline const clang::Type* RemovePointerFromType(const clang::Type* type) {
|
|
|
|
if (!IsPointerOrReferenceAsWritten(type)) { // ah well, have to desugar
|
|
|
|
type = type->getUnqualifiedDesugaredType();
|
|
|
|
}
|
|
|
|
if (!IsPointerOrReferenceAsWritten(type)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
type = RemoveElaboration(type);
|
|
|
|
type = type->getPointeeType().getTypePtr();
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This follows typedefs/etc to remove pointers, if necessary.
|
|
|
|
inline const clang::Type* RemovePointersAndReferences(const clang::Type* type) {
|
|
|
|
while (1) {
|
|
|
|
const clang::Type* deref_type = RemovePointerFromType(type);
|
|
|
|
if (deref_type == NULL) // type wasn't a pointer (or reference) type
|
|
|
|
break; // removed all pointers
|
|
|
|
type = deref_type;
|
|
|
|
}
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
// To the best of our ability, maps a type to a declaration of that
|
|
|
|
// type *that is written in the source code*. For most types, of
|
|
|
|
// course, declarations are always written, but for implicit template
|
|
|
|
// specializations they typically aren't. For instance, if the type
|
|
|
|
// is vector<int>, there is a decl for 'class vector<int>', but it's
|
|
|
|
// not written anywhere; what is written is generic code, for
|
|
|
|
// 'class vector<T>'. 'class vector<int>' is an implicit declaration,
|
|
|
|
// constructed at need. This routine does not return that implicit
|
|
|
|
// declaration.
|
|
|
|
// If the type is a substituted template parameter, we get a
|
|
|
|
// decl for the substituted type. That is, for this code:
|
|
|
|
// template<class T> void MyFunc() { T foo; }
|
|
|
|
// MyFunc<MyClass>();
|
|
|
|
// If we're evaluating MyFunc<MyClass>() and see the type that's in
|
|
|
|
// the function body, this function returns a decl for MyClass.
|
|
|
|
// If the type is built-in, or otherwise doesn't have a decl,
|
|
|
|
// this function returns NULL.
|
|
|
|
inline const clang::NamedDecl* TypeToDeclAsWritten(const clang::Type* type) {
|
|
|
|
// Get past all the 'class' and 'struct' prefixes, and namespaces.
|
|
|
|
type = RemoveElaboration(type);
|
|
|
|
|
|
|
|
// Read past SubstTemplateTypeParmType (this can happen if a
|
|
|
|
// template function returns the tpl-arg type: e.g. for
|
|
|
|
// 'T MyFn<T>() {...}; MyFn<X>.a', the type of MyFn<X> will be a Subst.
|
|
|
|
type = RemoveSubstTemplateTypeParm(type);
|
|
|
|
|
|
|
|
assert(!isa<clang::ObjCObjectType>(type) &&
|
|
|
|
"IWYU doesn't support Objective-C");
|
|
|
|
|
|
|
|
// We have to be a bit careful about the order, because we want
|
|
|
|
// to keep typedefs as typedefs, so we do the record check last.
|
|
|
|
// We use getAs<> when we can -- unfortunately, it only exists
|
|
|
|
// for a few types so far.
|
|
|
|
if (const clang::TypedefType* typedef_type = DynCastFrom(type)) {
|
|
|
|
return typedef_type->getDecl();
|
|
|
|
} else if (const clang::InjectedClassNameType* icn_type
|
|
|
|
= type->getAs<clang::InjectedClassNameType>()) {
|
|
|
|
return icn_type->getDecl();
|
|
|
|
} else if (const clang::RecordType* record_type
|
|
|
|
= type->getAs<clang::RecordType>()) {
|
|
|
|
return record_type->getDecl();
|
|
|
|
} else if (const clang::TagType* tag_type = DynCastFrom(type)) {
|
|
|
|
return tag_type->getDecl(); // probably just enums
|
|
|
|
} else if (const clang::TemplateSpecializationType* template_spec_type
|
|
|
|
= DynCastFrom(type)) {
|
|
|
|
// A non-concrete template class, such as 'Myclass<T>'
|
|
|
|
return template_spec_type->getTemplateName().getAsTemplateDecl();
|
|
|
|
} else if (const clang::FunctionType* function_type = DynCastFrom(type)) {
|
|
|
|
// TODO(csilvers): is it possible to map from fn type to fn decl?
|
|
|
|
(void)function_type;
|
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const clang::Type* RemoveReferenceAsWritten(const clang::Type* type) {
|
|
|
|
if (const clang::LValueReferenceType* ref_type = DynCastFrom(type))
|
|
|
|
return ref_type->getPointeeType().getTypePtr();
|
|
|
|
else
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true if it's possible to implicitly convert a value of a
|
|
|
|
// different type to 'type' via an implicit constructor.
|
|
|
|
inline bool CanImplicitlyConvertTo(const clang::Type* type) {
|
|
|
|
type = RemoveElaboration(type); // get rid of the class keyword
|
|
|
|
if (isa<clang::PointerType>(type))
|
|
|
|
return false; // can't implicitly convert to a pointer
|
|
|
|
if (isa<clang::LValueReferenceType>(type) &&
|
|
|
|
!type->getPointeeType().isConstQualified())
|
|
|
|
return false; // can't implicitly convert to a non-const reference
|
|
|
|
|
|
|
|
type = RemoveReferenceAsWritten(type);
|
|
|
|
const clang::NamedDecl* decl = TypeToDeclAsWritten(type);
|
|
|
|
if (!decl) // not the kind of type that has a decl (e.g. built-in)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const clang::CXXRecordDecl* cxx_class = DynCastFrom(decl);
|
|
|
|
if (!cxx_class)
|
|
|
|
return false; // can't implicitly convert to a non-class type
|
|
|
|
|
|
|
|
return HasImplicitConversionCtor(cxx_class);
|
|
|
|
}
|
|
|
|
|
|
|
|
// For ease of calling, this accept any type, but will return an empty
|
|
|
|
// set for any input that's not a template specialization type.
|
|
|
|
inline set<const clang::Type*> GetExplicitTplTypeArgsOf(
|
|
|
|
const clang::Type* type) {
|
|
|
|
set<const clang::Type*> retval;
|
|
|
|
const clang::TemplateSpecializationType* tpl_spec_type = DynCastFrom(type);
|
|
|
|
if (!tpl_spec_type)
|
|
|
|
return retval;
|
|
|
|
// TemplateSpecializationType only includes explicitly specified
|
|
|
|
// types in its args list, which is just what we want.
|
|
|
|
for (unsigned i = 0; i < tpl_spec_type->getNumArgs(); ++i) {
|
|
|
|
AddTypelikeTemplateArgTo(tpl_spec_type->getArg(i), &retval);
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
// --- Utilities for Stmt.
|
|
|
|
|
|
|
|
// Returns true if the given expr is '&<something>'.
|
|
|
|
inline bool IsAddressOf(const clang::Expr* expr) {
|
|
|
|
if (const clang::UnaryOperator* unary = DynCastFrom(expr->IgnoreParens()))
|
|
|
|
return unary->getOpcode() == clang::UO_AddrOf;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this function call comes from a class method -- either a normal
|
|
|
|
// one or a static one -- returns the type of the class. Otherwise,
|
|
|
|
// returns NULL. Note that static class methods do *not* have a
|
|
|
|
// CXXMemberCallExpr type, which is why we take a CallExpr.
|
|
|
|
inline const clang::Type* TypeOfParentIfMethod(const clang::CallExpr* expr) {
|
|
|
|
// callee_expr is a MemberExpr if we're a normal class method, or
|
|
|
|
// DeclRefExpr if we're a static class method or an overloaded operator.
|
|
|
|
const clang::Expr* callee_expr = expr->getCallee()->IgnoreParenCasts();
|
|
|
|
if (const clang::MemberExpr* member_expr = DynCastFrom(callee_expr)) {
|
|
|
|
const clang::Type* class_type = GetTypeOf(member_expr->getBase());
|
|
|
|
// For class->member(), class_type is a pointer.
|
|
|
|
return RemovePointersAndReferencesAsWritten(class_type);
|
|
|
|
} else if (const clang::DeclRefExpr* ref_expr = DynCastFrom(callee_expr)) {
|
|
|
|
if (ref_expr->getQualifier()) { // static methods like C<T>::a()
|
|
|
|
return ref_expr->getQualifier()->getAsType();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Given a function call, return the first argument that's a class
|
|
|
|
// (possibly a template specialization). Note we ignore pointers to a
|
|
|
|
// class. This is used with 'free' overloaded operators ('ostream&
|
|
|
|
// operator<<(ostream& a, int x)' to figure out what class the
|
|
|
|
// operator 'logically' belongs to. This is a heuristic (the operator
|
|
|
|
// may "belong" to more than one argument, for instance), but covers
|
|
|
|
// all the common cases. Returns NULL if no class-type argument is
|
|
|
|
// found.
|
|
|
|
inline const clang::Expr* GetFirstClassArgument(clang::CallExpr* expr) {
|
|
|
|
for (clang::CallExpr::arg_iterator it = expr->arg_begin();
|
|
|
|
it != expr->arg_end(); ++it) {
|
|
|
|
const clang::Type* argtype = GetTypeOf(*it);
|
|
|
|
// Luckily, this code does the right thing given a function like
|
|
|
|
// template <typename T> void operator>>(const T& x, ostream& os);
|
|
|
|
// In this case ('myclass >> os'), we want to be returning the
|
|
|
|
// type of os, not of myclass, and we do, because myclass will be
|
|
|
|
// a SubstTemplateTypeParmType, not a RecordType.
|
|
|
|
if (isa<clang::RecordType>(argtype) ||
|
|
|
|
isa<clang::TemplateSpecializationType>(argtype)) {
|
|
|
|
return *it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns NULL if we're deleting an argument that has no destructor.
|
|
|
|
inline const clang::CXXDestructorDecl* GetDestructorForDeleteExpr(
|
|
|
|
const clang::CXXDeleteExpr* expr) {
|
|
|
|
const clang::Type* type = expr->getDestroyedType().getTypePtrOrNull();
|
|
|
|
// type is NULL when deleting a dependent type: 'T foo; delete foo'
|
|
|
|
if (type == NULL)
|
|
|
|
return NULL;
|
|
|
|
const clang::NamedDecl* decl = TypeToDeclAsWritten(type);
|
|
|
|
if (const clang::CXXRecordDecl* cxx_record = DynCastFrom(decl))
|
|
|
|
return cxx_record->getDestructor();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns NULL if the constructor has no corresponding destructor.
|
|
|
|
inline const clang::CXXDestructorDecl* GetSiblingDestructorFor(
|
|
|
|
const clang::CXXConstructorDecl* ctor) {
|
|
|
|
return ctor ? ctor->getParent()->getDestructor() : NULL;
|
|
|
|
}
|
|
|
|
inline const clang::CXXDestructorDecl* GetSiblingDestructorFor(
|
|
|
|
const clang::CXXConstructExpr* ctor_expr) {
|
|
|
|
return GetSiblingDestructorFor(ctor_expr->getConstructor());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Figuring out whether the to-type is a reference or not is different
|
|
|
|
// depending on whether the cast is explicit or implicit. (You'd
|
|
|
|
// think it would work to just look at expr->getSubExpr()->getType(),
|
|
|
|
// but that seems to strip off the reference.)
|
|
|
|
inline bool IsCastToReferenceType(const clang::CastExpr* expr) {
|
|
|
|
if (const clang::ExplicitCastExpr* explicit_cast = DynCastFrom(expr)) {
|
|
|
|
return explicit_cast->getTypeAsWritten()->isReferenceType();
|
|
|
|
} else if (const clang::ImplicitCastExpr* implicit_cast = DynCastFrom(expr)) {
|
|
|
|
return implicit_cast->getValueKind() == clang::VK_LValue;
|
|
|
|
} else {
|
|
|
|
assert(false && "Unexpected type of cast expression");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace include_what_you_use
|
|
|
|
#endif // DEVTOOLS_MAINTENANCE_INCLUDE_WHAT_YOU_USE_IWYU_AST_UTIL_H_
|