summaryrefslogtreecommitdiffstats
path: root/iwyu.cc
diff options
context:
space:
mode:
Diffstat (limited to 'iwyu.cc')
-rw-r--r--iwyu.cc258
1 files changed, 150 insertions, 108 deletions
diff --git a/iwyu.cc b/iwyu.cc
index 355e793..20fed76 100644
--- a/iwyu.cc
+++ b/iwyu.cc
@@ -167,6 +167,7 @@ using clang::ConstructorUsingShadowDecl;
using clang::Decl;
using clang::DeclContext;
using clang::DeclRefExpr;
+using clang::DeducedTemplateSpecializationType;
using clang::EnumType;
using clang::Expr;
using clang::FileEntry;
@@ -191,6 +192,7 @@ using clang::QualifiedTypeLoc;
using clang::RecordDecl;
using clang::RecursiveASTVisitor;
using clang::ReferenceType;
+using clang::Sema;
using clang::SourceLocation;
using clang::Stmt;
using clang::SubstTemplateTypeParmType;
@@ -532,17 +534,10 @@ class BaseAstVisitor : public RecursiveASTVisitor<Derived> {
//------------------------------------------------------------
// (4) Add implicit text.
-
- // When we see an object that has implicit text that iwyu
- // wants to look at, we make callbacks as if that text had
- // been explicitly written. Here's text we consider:
//
- // * CXXDestructorDecl: a destructor call for each non-POD field
- // in the dtor's class, and each base type of that class.
- // * CXXRecordDecl: a CXXConstructorDecl for each implicit
- // constructor (zero-arg and copy). A CXXDestructor decl
- // if the destructor is implicit. A CXXOperatorCallDecl if
- // operator= is explicit.
+ // This simulates a call to the destructor of every non-POD field and base
+ // class in all classes with destructors, to mark them as used by virtue of
+ // being class members.
bool TraverseCXXDestructorDecl(clang::CXXDestructorDecl* decl) {
if (!Base::TraverseCXXDestructorDecl(decl)) return false;
if (CanIgnoreCurrentASTNode()) return true;
@@ -575,69 +570,12 @@ class BaseAstVisitor : public RecursiveASTVisitor<Derived> {
return true;
}
- // clang lazily constructs the implicit methods of a C++ class (the
- // default constructor and destructor, etc) -- it only bothers to
- // create a CXXMethodDecl if someone actually calls these classes.
- // But we need to be non-lazy: iwyu depends on analyzing what future
- // code *may* call in a class, not what current code *does*. So we
- // force all the lazy evaluation to happen here. This will
- // (possibly) add a bunch of MethodDecls to the AST, as children of
- // decl. We're hoping it will always be safe to modify the AST
- // while it's being traversed!
- void InstantiateImplicitMethods(CXXRecordDecl* decl) {
- if (decl->isDependentType()) // only instantiate if class is instantiated
- return;
-
- clang::Sema& sema = compiler()->getSema();
- DeclContext::lookup_result ctors = sema.LookupConstructors(decl);
- for (NamedDecl* ctor_lookup : ctors) {
- // Ignore templated or inheriting constructors.
- if (isa<FunctionTemplateDecl>(ctor_lookup) ||
- isa<UsingDecl>(ctor_lookup) ||
- isa<ConstructorUsingShadowDecl>(ctor_lookup))
- continue;
- CXXConstructorDecl* ctor = cast<CXXConstructorDecl>(ctor_lookup);
- if (!ctor->hasBody() && !ctor->isDeleted() && ctor->isImplicit()) {
- if (sema.getSpecialMember(ctor) == clang::Sema::CXXDefaultConstructor) {
- sema.DefineImplicitDefaultConstructor(CurrentLoc(), ctor);
- } else {
- // TODO(nlewycky): enable this!
- //sema.DefineImplicitCopyConstructor(CurrentLoc(), ctor);
- }
- }
- // Unreferenced template constructors stay uninstantiated on purpose.
- }
-
- if (CXXDestructorDecl* dtor = sema.LookupDestructor(decl)) {
- if (!dtor->isDeleted()) {
- if (!dtor->hasBody() && dtor->isImplicit())
- sema.DefineImplicitDestructor(CurrentLoc(), dtor);
- if (!dtor->isDefined() && dtor->getTemplateInstantiationPattern())
- sema.PendingInstantiations.emplace_back(dtor, CurrentLoc());
- }
- }
-
- // TODO(nlewycky): copy assignment operator
-
- // clang queues up method instantiations. We need to process them now.
- sema.PerformPendingInstantiations();
- }
-
- // Handle implicit methods that otherwise wouldn't be seen by RAV.
- bool TraverseCXXRecordDecl(clang::CXXRecordDecl* decl) {
- if (CanIgnoreCurrentASTNode()) return true;
- // We only care about classes that are actually defined.
- if (decl && decl->isThisDeclarationADefinition()) {
- InstantiateImplicitMethods(decl);
- }
-
- return Base::TraverseCXXRecordDecl(decl);
- }
-
+ // Class template specialization are similar to regular C++ classes,
+ // particularly they need the same custom handling of implicit destructors.
bool TraverseClassTemplateSpecializationDecl(
clang::ClassTemplateSpecializationDecl* decl) {
if (!Base::TraverseClassTemplateSpecializationDecl(decl)) return false;
- return TraverseCXXRecordDecl(decl);
+ return Base::TraverseCXXRecordDecl(decl);
}
//------------------------------------------------------------
@@ -1322,7 +1260,26 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
for (const NamedDecl* redecl : GetClassRedecls(decl)) {
if (GetFileEntry(redecl) == macro_def_file && IsForwardDecl(redecl)) {
fwd_decl = redecl;
+ break;
+ }
+ }
+
+ if (!fwd_decl) {
+ if (const auto* func_decl = dyn_cast<FunctionDecl>(decl)) {
+ if (const FunctionTemplateDecl* ft_decl =
+ func_decl->getPrimaryTemplate()) {
+ VERRS(5) << "No fwd-decl found, looking for function template decl\n";
+ for (const NamedDecl* redecl : ft_decl->redecls()) {
+ if (GetFileEntry(redecl) == macro_def_file) {
+ fwd_decl = redecl;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (fwd_decl) {
// Make sure we keep that forward-declaration, even if it's probably
// unused in this file.
IwyuFileInfo* file_info =
@@ -1330,8 +1287,6 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
file_info->ReportForwardDeclareUse(
spelling_loc, fwd_decl,
ComputeUseFlags(current_ast_node()), nullptr);
- break;
- }
}
// Resolve the best use location based on our current knowledge.
@@ -1460,12 +1415,12 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
}
set<const Type*> GetCallerResponsibleTypesForTypedef(
- const TypedefDecl* decl) {
+ const TypedefNameDecl* decl) {
set<const Type*> retval;
const Type* underlying_type = decl->getUnderlyingType().getTypePtr();
// If the underlying type is itself a typedef, we recurse.
if (const TypedefType* underlying_typedef = DynCastFrom(underlying_type)) {
- if (const TypedefDecl* underlying_typedef_decl
+ if (const TypedefNameDecl* underlying_typedef_decl
= DynCastFrom(TypeToDeclAsWritten(underlying_typedef))) {
// TODO(csilvers): if one of the intermediate typedefs
// #includes the necessary definition of the 'final'
@@ -1610,12 +1565,12 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
// anywhere. ('autocast' is similar, but is handled in
// VisitCastExpr; 'fn-return-type' is also similar and is
// handled in HandleFunctionCall.)
- if (const TypedefDecl* typedef_decl = DynCastFrom(target_decl)) {
+ if (const TypedefNameDecl* typedef_decl = DynCastFrom(target_decl)) {
// One exception: if this TypedefType is being used in another
// typedef (that is, 'typedef MyTypedef OtherTypdef'), then the
// user -- the other typedef -- is never responsible for the
// underlying type. Instead, users of that typedef are.
- if (!current_ast_node()->template ParentIsA<TypedefDecl>()) {
+ if (!current_ast_node()->template ParentIsA<TypedefNameDecl>()) {
const set<const Type*>& underlying_types
= GetCallerResponsibleTypesForTypedef(typedef_decl);
if (!underlying_types.empty()) {
@@ -1757,7 +1712,7 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
// iwyu will demand the full type of pair, but not of its template
// arguments. This is handled not here, but below, in
// VisitSubstTemplateTypeParmType.
- bool VisitTypedefDecl(clang::TypedefDecl* decl) {
+ bool VisitTypedefNameDecl(clang::TypedefNameDecl* decl) {
if (CanIgnoreCurrentASTNode()) return true;
const Type* underlying_type = decl->getUnderlyingType().getTypePtr();
const Type* deref_type
@@ -1770,7 +1725,7 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
current_ast_node()->set_in_forward_declare_context(false);
}
- return Base::VisitTypedefDecl(decl);
+ return Base::VisitTypedefNameDecl(decl);
}
// If we're a declared (not defined) function, all our types --
@@ -1999,6 +1954,7 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
case clang::CK_IntegralToFixedPoint:
case clang::CK_IntegralToFloating:
case clang::CK_IntegralToPointer:
+ case clang::CK_MatrixCast:
case clang::CK_MemberPointerToBoolean:
case clang::CK_NullToMemberPointer:
case clang::CK_NullToPointer:
@@ -2591,7 +2547,7 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
// If we're in a typedef, we don't want to forward-declare even if
// we're a pointer. ('typedef Foo* Bar; Bar x; x->a' needs full
// type of Foo.)
- if (ast_node->ParentIsA<TypedefDecl>())
+ if (ast_node->ParentIsA<TypedefNameDecl>())
return false;
// If we ourselves are a forward-decl -- that is, we're the type
@@ -2645,8 +2601,11 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
void AddShadowDeclarations(const UsingDecl* using_decl) {
for (const UsingShadowDecl* shadow : using_decl->shadows()) {
- visitor_state_->using_declarations.insert(
- make_pair(shadow->getTargetDecl(), shadow->getUsingDecl()));
+ if (const auto* introducer =
+ dyn_cast<UsingDecl>(shadow->getIntroducer())) {
+ visitor_state_->using_declarations.insert(
+ make_pair(shadow->getTargetDecl(), introducer));
+ }
}
}
@@ -2665,8 +2624,9 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
const DeclContext* use_context) {
// First, if we have a UsingShadowDecl, then we don't need to do anything
// because we can just directly return the using decl from that.
- if (const UsingShadowDecl* shadow = DynCastFrom(decl))
- return shadow->getUsingDecl();
+ if (const auto* shadow = dyn_cast<UsingShadowDecl>(decl)) {
+ return dyn_cast<UsingDecl>(shadow->getIntroducer());
+ }
// But, if we don't have a UsingShadowDecl, then we need to look through
// all the using-decls of the given decl. We limit them to ones that are
@@ -3656,11 +3616,31 @@ class IwyuAstConsumer
const_cast<IwyuPreprocessorInfo*>(&preprocessor_info())->
HandlePreprocessingDone();
+ TranslationUnitDecl* tu_decl = context.getTranslationUnitDecl();
+
+ // Sema::TUScope is reset after parsing, but Sema::getCurScope still points
+ // to the translation unit decl scope. TUScope is required for lookup in
+ // some complex scenarios, so re-wire it before running IWYU AST passes.
+ // Assert their expected state so we notice if these assumptions change.
+ Sema& sema = compiler()->getSema();
+ CHECK_(sema.TUScope == nullptr);
+ CHECK_(sema.getCurScope() != nullptr);
+ sema.TUScope = sema.getCurScope();
+
// We run a separate pass to force parsing of late-parsed function
// templates.
- ParseFunctionTemplates(context.getTranslationUnitDecl());
+ ParseFunctionTemplates(sema, tu_decl);
+
+ // Clang lazily constructs the implicit methods of a C++ class (the
+ // default constructor and destructor, etc) -- it only bothers to
+ // create a CXXMethodDecl if someone actually calls these classes.
+ // But we need to be non-lazy: IWYU depends on analyzing what future
+ // code *may* call in a class, not what current code *does*. So we
+ // force all the lazy evaluation to happen here.
+ InstantiateImplicitMethods(sema, tu_decl);
- TraverseDecl(context.getTranslationUnitDecl());
+ // Run IWYU analysis.
+ TraverseDecl(tu_decl);
// Check if any unrecoverable errors have occurred.
// There is no point in continuing when the AST is in a bad state.
@@ -3705,9 +3685,8 @@ class IwyuAstConsumer
exit(EXIT_SUCCESS_OFFSET + num_edits);
}
- void ParseFunctionTemplates(TranslationUnitDecl* decl) {
- set<FunctionDecl*> late_parsed_decls = GetLateParsedFunctionDecls(decl);
- clang::Sema& sema = compiler()->getSema();
+ void ParseFunctionTemplates(Sema& sema, TranslationUnitDecl* tu_decl) {
+ set<FunctionDecl*> late_parsed_decls = GetLateParsedFunctionDecls(tu_decl);
// If we have any late-parsed functions, make sure the
// -fdelayed-template-parsing flag is on. Otherwise we don't know where
@@ -3730,6 +3709,55 @@ class IwyuAstConsumer
}
}
+ void InstantiateImplicitMethods(Sema& sema, TranslationUnitDecl* tu_decl) {
+ // Collect all implicit ctors/dtors that need to be instantiated.
+ struct Visitor : public RecursiveASTVisitor<Visitor> {
+ Visitor(Sema& sema) : sema(sema) {
+ }
+
+ bool VisitCXXRecordDecl(CXXRecordDecl* decl) {
+ if (CanIgnoreLocation(GetLocation(decl)))
+ return true;
+
+ if (!decl->getDefinition() || decl->isDependentContext() ||
+ decl->isBeingDefined()) {
+ return true;
+ }
+
+ if (CXXConstructorDecl* ctor = sema.LookupDefaultConstructor(decl)) {
+ may_need_definition.insert(ctor);
+ } else if (CXXDestructorDecl* dtor = sema.LookupDestructor(decl)) {
+ may_need_definition.insert(dtor);
+ }
+
+ return true;
+ }
+
+ Sema& sema;
+ std::set<CXXMethodDecl*> may_need_definition;
+ };
+
+ // Run visitor to collect implicit methods.
+ Visitor v(sema);
+ v.TraverseDecl(tu_decl);
+
+ // For each method collected, let Sema define them.
+ for (CXXMethodDecl* method : v.may_need_definition) {
+ if (!method->isDefaulted() || method->isDeleted() || method->hasBody())
+ continue;
+
+ SourceLocation loc = GetLocation(method->getParent());
+ if (auto* ctor = dyn_cast<CXXConstructorDecl>(method)) {
+ sema.DefineImplicitDefaultConstructor(loc, ctor);
+ } else if (auto* dtor = dyn_cast<CXXDestructorDecl>(method)) {
+ sema.DefineImplicitDestructor(loc, dtor);
+ }
+ }
+
+ // Clang queues up method instantiations. Process them now.
+ sema.PerformPendingInstantiations();
+ }
+
//------------------------------------------------------------
// AST visitors. We start by adding a visitor callback for
// most of the subclasses of Decl/Stmt/Type listed in:
@@ -3913,14 +3941,13 @@ class IwyuAstConsumer
// TODO(csilvers): we can probably relax this rule in .cc files.
// TODO(csilvers): this should really move into IwyuBaseASTVisitor
// (that way we'll correctly identify need for hash<> in hash_set).
- // This is a Traverse*() because Visit*() can't call HandleFunctionCall().
- bool TraverseTypedefDecl(clang::TypedefDecl* decl) {
- // Before we go up the tree, make sure the parents know we don't
- // forward-declare the underlying type of a typedef decl.
- current_ast_node()->set_in_forward_declare_context(false);
- if (!Base::TraverseTypedefDecl(decl))
- return false;
- if (CanIgnoreCurrentASTNode()) return true;
+ // This is called from Traverse*() because Visit*()
+ // can't call HandleFunctionCall().
+ bool HandleAliasedClassMethods(TypedefNameDecl* decl) {
+ if (CanIgnoreCurrentASTNode())
+ return true;
+ if (current_ast_node()->in_forward_declare_context())
+ return true;
const Type* underlying_type = decl->getUnderlyingType().getTypePtr();
const Decl* underlying_decl = TypeToDeclAsWritten(underlying_type);
@@ -3947,6 +3974,20 @@ class IwyuAstConsumer
return true;
}
+ bool TraverseTypedefDecl(clang::TypedefDecl* decl) {
+ if (!Base::TraverseTypedefDecl(decl))
+ return false;
+
+ return HandleAliasedClassMethods(decl);
+ }
+
+ bool TraverseTypeAliasDecl(clang::TypeAliasDecl* decl) {
+ if (!Base::TraverseTypeAliasDecl(decl))
+ return false;
+
+ return HandleAliasedClassMethods(decl);
+ }
+
// --- Visitors of types derived from clang::Stmt.
// Called whenever a variable, function, enum, etc is used.
@@ -4063,18 +4104,21 @@ class IwyuAstConsumer
bool VisitTemplateName(TemplateName template_name) {
if (CanIgnoreCurrentASTNode()) return true;
if (!Base::VisitTemplateName(template_name)) return false;
- // The only time we can see a TemplateName not in the
- // context of a TemplateSpecializationType is when it's
- // the default argument of a template template arg:
+ // We can see TemplateName not in the context of aTemplateSpecializationType
+ // when it's either the default argument of a template template arg:
// template<template<class T> class A = TplNameWithoutTST> class Foo ...
- // So that's the only case we need to handle here.
+ // or a deduced template specialization:
+ // std::pair x(10, 20); // type of x is really std::pair<int, int>
+ // So that's the only cases we need to handle here.
// TODO(csilvers): check if this is really forward-declarable or
// not. You *could* do something like: 'template<template<class
// T> class A = Foo> class C { A<int>* x; };' and never
// dereference x, but that's pretty unlikely. So for now, we just
// assume these default template template args always need full
// type info.
- if (IsDefaultTemplateTemplateArg(current_ast_node())) {
+ const ASTNode* ast_node = current_ast_node();
+ if (ast_node->ParentIsA<DeducedTemplateSpecializationType>() ||
+ IsDefaultTemplateTemplateArg(ast_node)) {
current_ast_node()->set_in_forward_declare_context(false);
ReportDeclUse(CurrentLoc(), template_name.getAsTemplateDecl());
}
@@ -4140,7 +4184,6 @@ class IwyuAction : public ASTFrontendAction {
#include "iwyu_driver.h"
#include "clang/Frontend/FrontendAction.h"
-#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/TargetSelect.h"
using include_what_you_use::OptionsParser;
@@ -4148,12 +4191,11 @@ using include_what_you_use::IwyuAction;
using include_what_you_use::CreateCompilerInstance;
int main(int argc, char **argv) {
- // Must initialize X86 target to be able to parse Microsoft inline
- // assembly. We do this unconditionally, because it allows an IWYU
- // built for non-X86 targets to parse MS inline asm without choking.
- LLVMInitializeX86TargetInfo();
- LLVMInitializeX86TargetMC();
- LLVMInitializeX86AsmParser();
+ // X86 target is required to parse Microsoft inline assembly, so we hope it's
+ // part of all targets. Clang parser will complain otherwise.
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmParsers();
// The command line should look like
// path/to/iwyu -Xiwyu --verbose=4 [-Xiwyu --other_iwyu_flag]... CLANG_FLAGS... foo.cc