diff options
Diffstat (limited to 'iwyu.cc')
-rw-r--r-- | iwyu.cc | 258 |
1 files changed, 150 insertions, 108 deletions
@@ -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 |