//===--- iwyu.cc - main logic and driver 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. // //===----------------------------------------------------------------------===// // A Clang-based tool that catches Include-What-You-Use violations: // // The analysis enforces the following rule: // // - For every symbol (variable, function, constant, type, and macro) // X in C++ file CU.cc, X must be declared in CU.cc or in a header // file directly included by itself, CU.h, or CU-inl.h. Likewise // for CU.h and CU-inl.h. // // The rule has a few slight wrinkles: // 1) CU_test.cc can also 'inherit' #includes from CU.h and CU-inl.h. // Likewise for CU_unittest.cc, CU_regtest.cc, etc. // 2) CU.cc can inherit #includes from ../public/CU.h in addition to // ./CU.h (likewise for -inl.h). // 3) For system #includes, and a few google #includes, we hard-code // in knowledge of which #include files are public and which are not. // (For instance, is public, is not.) // We force CU.cc, CU.h, and CU-inl.h to #include the public version. // // iwyu.cc checks if a symbol can be forward-declared instead of fully // declared. If so, it will enforce the rule that the symbol is // forward-declared in the file that references it. We only forward- // declare classes and structs (possibly templatized). We will not // try to forward-declare variables or functions. // // Checking iwyu violations for variables, functions, constants, and // macros is easy. Types can be trickier. Obviously, if you declare // a variable of type Foo in cu.cc, it's straightforward to check // whether it's an iwyu violation. But what if you call a function // that returns a type, e.g. 'if (FnReturningSomeSTLType()->empty())'? // Is it an iwyu violation if you don't #include the header for that // STL type? We say no: whatever file provided the function // FnReturningSomeSTLType is also responsible for providing whatever // the STL type is, so we don't have to. Otherwise, we get into an // un-fun propagation problem if we change the signature of // FnReturningSomeSTLType to return a different type of STL type. So // in general, types are only iwyu-checked if they appear explicitly // in the source code. // // It can likewise be difficult to say whether a template arg is // forward-declable: set x does not require the full type info // for Foo, but remove_pointer::type does. And f() doesn't // require full type info for Foo if f doesn't actually use Foo in it. // For now we do the simple heuristic that if the template arg is a // pointer, it's ok if it's forward-declared, and if not, it's not. // // We use the following terminology: // // - A *symbol* is the name of a function, variable, constant, type, // macro, etc. // // - A *quoted include path* is an include path with the surrounding <> // or "", e.g. or "ads/util.h". // // - Any #include falls into exactly one of three (non-overlapping) // categories: // // * it's said to be *necessary* if it's a compiler or IWYU error to // omit the #include; // // * it's said to be *optional* if the #include is unnecessary but // having it is not an IWYU error either (e.g. if bar.h is a // necessary #include of foo.h, and foo.cc uses symbols from // bar.h, it's optional for foo.cc to #include bar.h.); // // * it's said to be *undesired* if it's an IWYU error to have the // #include. // // Therefore, when we say a #include is *desired*, we mean that it's // either necessary or optional. // // - We also say that a #include is *recommended* if the IWYU tool // recommends to have it in the C++ source file. Obviously, any // necessary #include must be recommended, and no undesired // #include can be recommended. An optional #include can be // either recommended or not -- the IWYU tool can decide which // case it is. For example, if foo.cc desires bar.h, but can // already get it via foo.h, IWYU won't recommend foo.cc to // #include bar.h, unless it already does so. #include // for swap, find, make_pair #include // for size_t #include // for atoi, exit #include #include // for swap #include // for find #include // for swap #include // for map, swap, etc #include // for unique_ptr #include // for set, set<>::iterator, swap #include // for string, operator+, etc #include // for pair, make_pair #include // for vector, swap #include "iwyu_ast_util.h" #include "iwyu_cache.h" #include "iwyu_globals.h" #include "iwyu_lexer_utils.h" #include "iwyu_location_util.h" #include "iwyu_output.h" #include "iwyu_path_util.h" #include "iwyu_port.h" // for CHECK_ #include "iwyu_preprocessor.h" #include "iwyu_stl_util.h" #include "iwyu_string_util.h" #include "iwyu_use_flags.h" #include "iwyu_verrs.h" #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprConcepts.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/OperationKinds.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Stmt.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/SourceLocation.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Sema/Sema.h" namespace clang { class FileEntry; class PPCallbacks; } // namespace clang namespace include_what_you_use { // I occasionally clean up this list by running: // $ grep "using clang":: iwyu.cc | cut -b14- | tr -d ";" | while read t; do grep -q "[^:]$t" iwyu.cc || echo $t; done using clang::ASTConsumer; using clang::ASTContext; using clang::ASTFrontendAction; using clang::Attr; using clang::CXXConstructExpr; using clang::CXXConstructorDecl; using clang::CXXDeleteExpr; using clang::CXXDestructorDecl; using clang::CXXMethodDecl; using clang::CXXNewExpr; using clang::CXXOperatorCallExpr; using clang::CXXRecordDecl; using clang::CallExpr; using clang::ClassTemplateDecl; using clang::ClassTemplateSpecializationDecl; using clang::CompilerInstance; using clang::ConceptSpecializationExpr; using clang::ConstructorUsingShadowDecl; using clang::Decl; using clang::DeclContext; using clang::DeclRefExpr; using clang::DeducedTemplateSpecializationType; using clang::EnumConstantDecl; using clang::EnumDecl; using clang::EnumType; using clang::Expr; using clang::FileEntry; using clang::FriendDecl; using clang::FriendTemplateDecl; using clang::FunctionDecl; using clang::FunctionProtoType; using clang::FunctionTemplateDecl; using clang::FunctionType; using clang::LValueReferenceType; using clang::LinkageSpecDecl; using clang::MemberExpr; using clang::NamedDecl; using clang::NestedNameSpecifier; using clang::NestedNameSpecifierLoc; using clang::OverloadExpr; using clang::ParmVarDecl; using clang::PPCallbacks; using clang::PointerType; using clang::QualType; using clang::QualifiedTypeLoc; using clang::RecordDecl; using clang::RecursiveASTVisitor; using clang::ReferenceType; using clang::Sema; using clang::SourceLocation; using clang::Stmt; using clang::SubstTemplateTypeParmType; using clang::TagDecl; using clang::TagType; using clang::TemplateArgument; using clang::TemplateArgumentList; using clang::TemplateArgumentLoc; using clang::TemplateDecl; using clang::TemplateName; using clang::TemplateSpecializationType; using clang::TemplateSpecializationTypeLoc; using clang::TranslationUnitDecl; using clang::Type; using clang::TypeDecl; using clang::TypeLoc; using clang::TypedefDecl; using clang::TypedefNameDecl; using clang::TypedefType; using clang::UnaryExprOrTypeTraitExpr; using clang::UsingDecl; using clang::UsingDirectiveDecl; using clang::UsingShadowDecl; using clang::ValueDecl; using clang::VarDecl; using llvm::cast; using llvm::dyn_cast; using llvm::dyn_cast_or_null; using llvm::errs; using llvm::isa; using std::make_pair; using std::map; using std::set; using std::string; using std::swap; using std::vector; namespace { bool CanIgnoreLocation(SourceLocation loc) { // If we're in a macro expansion, we always want to treat this as // being in the expansion location, never the as-written location, // since that's what the compiler does. CanIgnoreCurrentASTNode() // is an optimization, so we want to be conservative about what we // ignore. const FileEntry* file_entry = GetFileEntry(loc); const FileEntry* file_entry_after_macro_expansion = GetFileEntry(GetInstantiationLoc(loc)); // ignore symbols used outside foo.{h,cc} + check_also return (!ShouldReportIWYUViolationsFor(file_entry) && !ShouldReportIWYUViolationsFor(file_entry_after_macro_expansion)); } } // anonymous namespace // ---------------------------------------------------------------------- // --- BaseAstVisitor // ---------------------------------------------------------------------- // // We have a hierarchy of AST visitor classes, to keep the logic // as clear as possible. The top level, BaseAstVisitor, has some // basic, not particularly iwyu-related, functionality: // // 1) Maintain current_ast_node_, the current chain in the AST tree. // 2) Provide functions related to the current location. // 3) Print each node we're visiting, depending on --verbose settings. // 4) Add appropriate implicit text. iwyu acts as if all constructor // initializers were explicitly written, all default constructors // were explicitly written, etc, even if they're not. We traverse // the implicit stuff as if it were explicit. // 5) Add two callbacks that subclasses can override (just like any // other AST callback): TraverseImplicitDestructorCall and // HandleFunctionCall. TraverseImplicitDestructorCall is a // callback for a "pseudo-AST" node that covers destruction not // specified in source, such as a destructor destroying one of the // fields in its class. HandleFunctionCall is a convenience // callback that bundles callbacks from many different kinds of // function-calling callbacks (CallExpr, CXXConstructExpr, etc) // into one place. // // To maintain current_ast_node_ properly, this class also implements // VisitNestedNameSpecifier, VisitTemplateName, VisitTemplateArg, and // VisitTemplateArgLoc, which are parallel to the Visit*Decl()/etc // visitors. Subclasses should override these Visit routines, and not // the Traverse routine directly. template class BaseAstVisitor : public RecursiveASTVisitor { public: typedef RecursiveASTVisitor Base; // We need to create implicit ctor/dtor nodes, which requires // non-const methods on CompilerInstance, so the var can't be const. explicit BaseAstVisitor(CompilerInstance* compiler) : compiler_(compiler), current_ast_node_(nullptr) {} virtual ~BaseAstVisitor() = default; //------------------------------------------------------------ // Pure virtual methods that a subclass must implement. // Returns true if we are not interested in the current ast node for // any reason (for instance, it lives in a file we're not // analyzing). virtual bool CanIgnoreCurrentASTNode() const = 0; // Returns true if we should print the information for the // current AST node, given what file it's in. For instance, // except at very high verbosity levels, we don't print AST // nodes from system header files. virtual bool ShouldPrintSymbolFromCurrentFile() const = 0; // A string to add to the information we print for each symbol. // Each subclass can thus annotate if it's handling a node. // The return value, if not empty, should start with a space! virtual string GetSymbolAnnotation() const = 0; //------------------------------------------------------------ // (1) Maintain current_ast_node_ // How subclasses can access current_ast_node_; const ASTNode* current_ast_node() const { return current_ast_node_; } ASTNode* current_ast_node() { return current_ast_node_; } void set_current_ast_node(ASTNode* an) { current_ast_node_ = an; } bool TraverseDecl(Decl* decl) { if (current_ast_node_ && current_ast_node_->StackContainsContent(decl)) return true; // avoid recursion ASTNode node(decl); CurrentASTNodeUpdater canu(¤t_ast_node_, &node); return Base::TraverseDecl(decl); } bool TraverseStmt(Stmt* stmt) { if (current_ast_node_ && current_ast_node_->StackContainsContent(stmt)) return true; // avoid recursion ASTNode node(stmt); CurrentASTNodeUpdater canu(¤t_ast_node_, &node); return Base::TraverseStmt(stmt); } bool TraverseType(QualType qualtype) { if (qualtype.isNull()) return Base::TraverseType(qualtype); const Type* type = qualtype.getTypePtr(); if (current_ast_node_ && current_ast_node_->StackContainsContent(type)) return true; // avoid recursion ASTNode node(type); CurrentASTNodeUpdater canu(¤t_ast_node_, &node); return Base::TraverseType(qualtype); } // RecursiveASTVisitor has a hybrid type-visiting system: it will // call TraverseTypeLoc when it can, but will call TraverseType // otherwise. For instance, if we see a FunctionDecl, and it // exposes the return type via a TypeLoc, it will recurse via // TraverseTypeLoc. If it exposes the return type only via a // QualType, though, it will recurse via TraverseType. The upshot // is we need two versions of all the Traverse*Type routines. (We // don't need two versions the Visit*Type routines, since the // default behavior of Visit*TypeLoc is to just call Visit*Type.) bool TraverseTypeLoc(TypeLoc typeloc) { // QualifiedTypeLoc is a bit of a special case in the typeloc // system, off to the side. We don't care about qualifier // positions, so avoid the need for special-casing by just // traversing the unqualified version instead. if (typeloc.getAs()) { typeloc = typeloc.getUnqualifiedLoc(); } if (current_ast_node_ && current_ast_node_->StackContainsContent(&typeloc)) return true; // avoid recursion ASTNode node(&typeloc); CurrentASTNodeUpdater canu(¤t_ast_node_, &node); return Base::TraverseTypeLoc(typeloc); } bool TraverseNestedNameSpecifier(NestedNameSpecifier* nns) { if (nns == nullptr) return true; ASTNode node(nns); CurrentASTNodeUpdater canu(¤t_ast_node_, &node); if (!this->getDerived().VisitNestedNameSpecifier(nns)) return false; return Base::TraverseNestedNameSpecifier(nns); } bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc nns_loc) { if (!nns_loc) // using NNSLoc::operator bool() return true; ASTNode node(&nns_loc); CurrentASTNodeUpdater canu(¤t_ast_node_, &node); // TODO(csilvers): have VisitNestedNameSpecifierLoc instead. if (!this->getDerived().VisitNestedNameSpecifier( nns_loc.getNestedNameSpecifier())) return false; return Base::TraverseNestedNameSpecifierLoc(nns_loc); } bool TraverseTemplateName(TemplateName template_name) { ASTNode node(&template_name); CurrentASTNodeUpdater canu(¤t_ast_node_, &node); if (!this->getDerived().VisitTemplateName(template_name)) return false; return Base::TraverseTemplateName(template_name); } bool TraverseTemplateArgument(const TemplateArgument& arg) { ASTNode node(&arg); CurrentASTNodeUpdater canu(¤t_ast_node_, &node); if (!this->getDerived().VisitTemplateArgument(arg)) return false; return Base::TraverseTemplateArgument(arg); } bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc& argloc) { ASTNode node(&argloc); CurrentASTNodeUpdater canu(¤t_ast_node_, &node); if (!this->getDerived().VisitTemplateArgumentLoc(argloc)) return false; return Base::TraverseTemplateArgumentLoc(argloc); } //------------------------------------------------------------ // (2) Provide functions related to the current location. SourceLocation CurrentLoc() const { CHECK_(current_ast_node_ && "Call CurrentLoc within Visit* or Traverse*"); return current_ast_node_->GetLocation(); } string CurrentFilePath() const { return GetFilePath(CurrentLoc()); } const FileEntry* CurrentFileEntry() const { return GetFileEntry(CurrentLoc()); } string PrintableCurrentLoc() const { return PrintableLoc(CurrentLoc()); } //------------------------------------------------------------ // (3) Print each node we're visiting. // The current file location, the class or decl or type name in // brackets, along with annotations such as the indentation depth, // etc. string AnnotatedName(const string& name) const { return (PrintableCurrentLoc() + ": (" + std::to_string(current_ast_node_->depth()) + GetSymbolAnnotation() + (current_ast_node_->in_forward_declare_context() ? ", fwd decl" : "") + ") [ " + name + " ] "); } // At verbose level 7 and above, returns a printable version of // the pointer, suitable for being emitted after AnnotatedName. // At lower verbose levels, returns the empty string. string PrintablePtr(const void* ptr) const { if (ShouldPrint(7)) { char buffer[32]; snprintf(buffer, sizeof(buffer), "%p ", ptr); return buffer; } return ""; } // The top-level Decl class. All Decls call this visitor (in // addition to any more-specific visitors that apply for a // particular decl). bool VisitDecl(clang::Decl* decl) { if (ShouldPrintSymbolFromCurrentFile()) { errs() << AnnotatedName(GetKindName(decl)) << PrintablePtr(decl) << PrintableDecl(decl) << "\n"; } return true; } bool VisitStmt(clang::Stmt* stmt) { if (ShouldPrintSymbolFromCurrentFile()) { errs() << AnnotatedName(GetKindName(stmt)) << PrintablePtr(stmt) << PrintableStmt(stmt) << "\n"; } return true; } bool VisitType(clang::Type* type) { if (ShouldPrintSymbolFromCurrentFile()) { errs() << AnnotatedName(GetKindName(type)) << PrintablePtr(type) << PrintableType(type) << "\n"; } return true; } // Make sure our logging message shows we're in the TypeLoc hierarchy. bool VisitTypeLoc(clang::TypeLoc typeloc) { if (ShouldPrintSymbolFromCurrentFile()) { errs() << AnnotatedName(GetKindName(typeloc)) << PrintableTypeLoc(typeloc) << "\n"; } return true; } bool VisitNestedNameSpecifier(NestedNameSpecifier* nns) { if (ShouldPrintSymbolFromCurrentFile()) { errs() << AnnotatedName("NestedNameSpecifier") << PrintablePtr(nns) << PrintableNestedNameSpecifier(nns) << "\n"; } return true; } bool VisitTemplateName(TemplateName template_name) { if (ShouldPrintSymbolFromCurrentFile()) { errs() << AnnotatedName("TemplateName") << PrintableTemplateName(template_name) << "\n"; } return true; } bool VisitTemplateArgument(const TemplateArgument& arg) { if (ShouldPrintSymbolFromCurrentFile()) { errs() << AnnotatedName("TemplateArgument") << PrintablePtr(&arg) << PrintableTemplateArgument(arg) << "\n"; } return true; } bool VisitTemplateArgumentLoc(const TemplateArgumentLoc& argloc) { if (ShouldPrintSymbolFromCurrentFile()) { errs() << AnnotatedName("TemplateArgumentLoc") << PrintablePtr(&argloc) << PrintableTemplateArgumentLoc(argloc) << "\n"; } return true; } //------------------------------------------------------------ // (4) Add implicit text. // // 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; // We only care about calls that are actually defined. if (!decl || !decl->isThisDeclarationADefinition()) return true; // Collect all the fields (and bases) we destroy, and call the dtor. set member_types; const CXXRecordDecl* record = decl->getParent(); for (RecordDecl::field_iterator it = record->field_begin(); it != record->field_end(); ++it) { member_types.insert(it->getType().getTypePtr()); } for (CXXRecordDecl::base_class_const_iterator it = record->bases_begin(); it != record->bases_end(); ++it) { member_types.insert(it->getType().getTypePtr()); } for (const Type* type : member_types) { const NamedDecl* member_decl = TypeToDeclAsWritten(type); // We only want those fields that are c++ classes. if (const CXXRecordDecl* cxx_field_decl = DynCastFrom(member_decl)) { if (const CXXDestructorDecl* field_dtor = cxx_field_decl->getDestructor()) { if (!this->getDerived().TraverseImplicitDestructorCall( const_cast(field_dtor), type)) return false; } } } return true; } // 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 Base::TraverseCXXRecordDecl(decl); } //------------------------------------------------------------ // (5) Add TraverseImplicitDestructorCall and HandleFunctionCall. // TraverseImplicitDestructorCall: This is a callback this class // introduces that is a first-class callback just like any AST-node // callback. It is used to cover two places where the compiler // destroys objects, but there's no written indication of that in // the text: (1) when a local variable or a temporary goes out of // scope (NOTE: in this case, we attribute the destruction to the // same line as the corresponding construction, not to where the // scope ends). (2) When a destructor destroys one of the fields of // a class. For instance: 'class Foo { MyClass b; }': In addition // to executing its body, Foo::~Foo calls MyClass::~Myclass on b. // Note we only call this if an actual destructor is being executed: // we don't call it when an int goes out of scope! // // HandleFunctionCall: A convenience callback that 'bundles' // the following Expr's, each of which causes one or more // function calls when evaluated (though most of them are // not a child of CallExpr): // * CallExpr (obviously) // * CXXMemberCallExpr // * CXXOperatorCallExpr -- a call to operatorXX() // * CXXConstructExpr -- calls a constructor to create an object, // and maybe a destructor when the object goes out of scope. // * CXXTemporaryObjectExpr -- subclass of CXXConstructExpr // * CXXNewExpr -- calls operator new and a constructor // * CXXDeleteExpr -- calls operator delete and a destructor // * DeclRefExpr -- if the declref is a function pointer, we // treat it as a function call, since it can act like one // in the future // * ImplicitDestructorCall -- calls a destructor // Each of these calls HandleFunctionCall for the function calls // it does. A subclass interested only in function calls, and // not exactly what expression caused them, can override // HandleFunctionCall. Note: subclasses should expect that // the first argument to HandleFunctionCall may be nullptr (e.g. when // constructing a built-in type), in which case the handler should // immediately return. // If the function being called is a member of a class, parent_type // is the type of the method's owner (parent), as it is written in // the source. (We need the type-as-written so we can distinguish // explicitly-written template args from default template args.) We // also pass in the CallExpr (or CXXConstructExpr, etc). This may // be nullptr if the function call is implicit. bool HandleFunctionCall(clang::FunctionDecl* callee, const clang::Type* parent_type, const clang::Expr* calling_expr) { if (!callee) return true; if (ShouldPrintSymbolFromCurrentFile()) { errs() << AnnotatedName("FunctionCall") << PrintablePtr(callee) << PrintableDecl(callee) << "\n"; } return true; } bool TraverseImplicitDestructorCall(clang::CXXDestructorDecl* decl, const Type* type_being_destroyed) { if (CanIgnoreCurrentASTNode()) return true; if (!decl) return true; if (ShouldPrintSymbolFromCurrentFile()) { errs() << AnnotatedName("Destruction") << PrintableType(type_being_destroyed) << "\n"; } return this->getDerived().HandleFunctionCall(decl, type_being_destroyed, static_cast(nullptr)); } bool TraverseCallExpr(clang::CallExpr* expr) { if (!Base::TraverseCallExpr(expr)) return false; if (CanIgnoreCurrentASTNode()) return true; return this->getDerived().HandleFunctionCall(expr->getDirectCallee(), TypeOfParentIfMethod(expr), expr); } bool TraverseCXXMemberCallExpr(clang::CXXMemberCallExpr* expr) { if (!Base::TraverseCXXMemberCallExpr(expr)) return false; if (CanIgnoreCurrentASTNode()) return true; return this->getDerived().HandleFunctionCall(expr->getDirectCallee(), TypeOfParentIfMethod(expr), expr); } bool TraverseCXXOperatorCallExpr(clang::CXXOperatorCallExpr* expr) { if (!Base::TraverseCXXOperatorCallExpr(expr)) return false; if (CanIgnoreCurrentASTNode()) return true; const Type* parent_type = TypeOfParentIfMethod(expr); // If we're a free function -- bool operator==(MyClass a, MyClass b) -- // we still want to have a parent_type, as if we were defined as // MyClass::operator==. So we go through the arguments and take the // first one that's a class, and associate the function with that. if (!parent_type) { if (const Expr* first_argument = GetFirstClassArgument(expr)) parent_type = GetTypeOf(first_argument); } return this->getDerived().HandleFunctionCall(expr->getDirectCallee(), parent_type, expr); } bool TraverseCXXConstructExpr(clang::CXXConstructExpr* expr) { if (!Base::TraverseCXXConstructExpr(expr)) return false; if (CanIgnoreCurrentASTNode()) return true; if (!this->getDerived().HandleFunctionCall(expr->getConstructor(), GetTypeOf(expr), expr)) return false; // When creating a local variable or a temporary, but not a pointer, the // constructor is also responsible for destruction (which happens // implicitly when the variable goes out of scope). Only when initializing // a field of a class does the constructor not have to worry // about destruction. It turns out it's easier to check for that. bool will_call_implicit_destructor_on_leaving_scope = !IsCXXConstructExprInInitializer(current_ast_node()) && !IsCXXConstructExprInNewExpr(current_ast_node()); if (will_call_implicit_destructor_on_leaving_scope) { if (const CXXDestructorDecl* dtor_decl = GetSiblingDestructorFor(expr)) { if (!this->getDerived().TraverseImplicitDestructorCall( const_cast(dtor_decl), GetTypeOf(expr))) return false; } } return true; } bool TraverseCXXTemporaryObjectExpr(clang::CXXTemporaryObjectExpr* expr) { if (!Base::TraverseCXXTemporaryObjectExpr(expr)) return false; if (CanIgnoreCurrentASTNode()) return true; // In this case, we *know* we're responsible for destruction as well. CXXConstructorDecl* ctor_decl = expr->getConstructor(); CXXDestructorDecl* dtor_decl = const_cast(GetSiblingDestructorFor(expr)); const Type* type = GetTypeOf(expr); return (this->getDerived().HandleFunctionCall(ctor_decl, type, expr) && this->getDerived().HandleFunctionCall(dtor_decl, type, expr)); } bool TraverseCXXNewExpr(clang::CXXNewExpr* expr) { if (!Base::TraverseCXXNewExpr(expr)) return false; if (CanIgnoreCurrentASTNode()) return true; const Type* parent_type = expr->getAllocatedType().getTypePtrOrNull(); // 'new' calls operator new in addition to the ctor of the new-ed type. if (FunctionDecl* operator_new = expr->getOperatorNew()) { // If operator new is a method, it must (by the semantics of // per-class operator new) be a method on the class we're newing. const Type* op_parent = nullptr; if (isa(operator_new)) op_parent = parent_type; if (!this->getDerived().HandleFunctionCall(operator_new, op_parent, expr)) return false; } return true; } bool TraverseCXXDeleteExpr(clang::CXXDeleteExpr* expr) { if (!Base::TraverseCXXDeleteExpr(expr)) return false; if (CanIgnoreCurrentASTNode()) return true; const Type* parent_type = expr->getDestroyedType().getTypePtrOrNull(); // We call operator delete in addition to the dtor of the deleted type. if (FunctionDecl* operator_delete = expr->getOperatorDelete()) { // If operator delete is a method, it must (by the semantics of per- // class operator delete) be a method on the class we're deleting. const Type* op_parent = nullptr; if (isa(operator_delete)) op_parent = parent_type; if (!this->getDerived().HandleFunctionCall(operator_delete, op_parent, expr)) return false; } const CXXDestructorDecl* dtor = GetDestructorForDeleteExpr(expr); return this->getDerived().HandleFunctionCall( const_cast(dtor), parent_type, expr); } // This is to catch function pointers to templates. // For instance, 'MyFunctionPtr p = &TplFn;': we need to // expand TplFn to see if it needs full type info for MyClass. bool TraverseDeclRefExpr(clang::DeclRefExpr* expr) { if (!Base::TraverseDeclRefExpr(expr)) return false; if (CanIgnoreCurrentASTNode()) return true; if (FunctionDecl* fn_decl = DynCastFrom(expr->getDecl())) { // If fn_decl has a class-name before it -- 'MyClass::method' -- // it's a method pointer. const Type* parent_type = nullptr; if (expr->getQualifier() && expr->getQualifier()->getAsType()) parent_type = expr->getQualifier()->getAsType(); if (!this->getDerived().HandleFunctionCall(fn_decl, parent_type, expr)) return false; } return true; } /// Return whether this visitor should recurse into implicit /// code, e.g., implicit constructors and destructors. bool shouldVisitImplicitCode() const { return true; } protected: CompilerInstance* compiler() { return compiler_; } private: template friend class BaseAstVisitor; CompilerInstance* const compiler_; // The currently active decl/stmt/type/etc -- that is, the node // being currently visited in a Visit*() or Traverse*() method. The // advantage of ASTNode over the object passed in to Visit*() and // Traverse*() is ASTNode knows its parent. ASTNode* current_ast_node_; }; // ---------------------------------------------------------------------- // --- AstTreeFlattenerVisitor // ---------------------------------------------------------------------- // // This simple visitor just creates a set of all AST nodes (stored as // void*'s) seen while traversing via BaseAstVisitor. class AstFlattenerVisitor : public BaseAstVisitor { public: typedef BaseAstVisitor Base; // We divide our set of nodes into category by type. For most AST // nodes, we can store just a pointer to the node. However, for // some AST nodes we don't get a pointer into the AST, we get a // temporary (stack-allocated) object, and have to store the full // object ourselves and use its operator== to test for equality. // These types each get their own set (or, usually, vector, since // the objects tend not to support operator< or hash<>()). class NodeSet { public: // We could add more versions, but these are the only useful ones so far. bool Contains(const Type* type) const { return ContainsKey(others, type); } bool Contains(const Decl* decl) const { return ContainsKey(others, decl); } bool Contains(const ASTNode& node) const { if (const TypeLoc* tl = node.GetAs()) { return ContainsValue(typelocs, *tl); } else if (const NestedNameSpecifierLoc* nl = node.GetAs()) { return ContainsValue(nnslocs, *nl); } else if (const TemplateName* tn = node.GetAs()) { // The best we can do is to compare the associated decl if (tn->getAsTemplateDecl() == nullptr) return false; // be conservative if we can't compare decls for (const TemplateName& tpl_name : tpl_names) { if (tpl_name.getAsTemplateDecl() == tn->getAsTemplateDecl()) return true; } return false; } else if (const TemplateArgument* ta = node.GetAs()) { // TODO(csilvers): figure out how to compare template arguments (void)ta; return false; } else if (const TemplateArgumentLoc* tal = node.GetAs()) { // TODO(csilvers): figure out how to compare template argument-locs (void)tal; return false; } else { return ContainsKey(others, node.GetAs()); } } void AddAll(const NodeSet& that) { Extend(&typelocs, that.typelocs); Extend(&nnslocs, that.nnslocs); Extend(&tpl_names, that.tpl_names); Extend(&tpl_args, that.tpl_args); Extend(&tpl_arglocs, that.tpl_arglocs); InsertAllInto(that.others, &others); } // Needed since we're treated like an stl-like object. bool empty() const { return (typelocs.empty() && nnslocs.empty() && tpl_names.empty() && tpl_args.empty() && tpl_arglocs.empty() && others.empty()); } void clear() { typelocs.clear(); nnslocs.clear(); tpl_names.clear(); tpl_args.clear(); tpl_arglocs.clear(); others.clear(); } private: friend class AstFlattenerVisitor; // It's ok not to check for duplicates; we're just traversing the tree. void Add(TypeLoc tl) { typelocs.push_back(tl); } void Add(NestedNameSpecifierLoc nl) { nnslocs.push_back(nl); } void Add(TemplateName tn) { tpl_names.push_back(tn); } void Add(TemplateArgument ta) { tpl_args.push_back(ta); } void Add(TemplateArgumentLoc tal) { tpl_arglocs.push_back(tal); } void Add(const void* o) { others.insert(o); } vector typelocs; vector nnslocs; vector tpl_names; vector tpl_args; vector tpl_arglocs; set others; }; //------------------------------------------------------------ // Public interface: explicit AstFlattenerVisitor(CompilerInstance* compiler) : Base(compiler) { } const NodeSet& GetNodesBelow(Decl* decl) { CHECK_(seen_nodes_.empty() && "Nodes should be clear before GetNodesBelow"); NodeSet* node_set = &nodeset_decl_cache_[decl]; if (node_set->empty()) { TraverseDecl(decl); swap(*node_set, seen_nodes_); // move the seen_nodes_ into the cache } return *node_set; // returns the cache entry } //------------------------------------------------------------ // Pure virtual methods that the base class requires. bool CanIgnoreCurrentASTNode() const override { return false; } bool ShouldPrintSymbolFromCurrentFile() const override { return false; } string GetSymbolAnnotation() const override { return "[Uninstantiated template AST-node] "; } //------------------------------------------------------------ // Top-level handlers that construct the tree. bool VisitDecl(Decl*) { AddCurrentAstNodeAsPointer(); return true; } bool VisitStmt(Stmt*) { AddCurrentAstNodeAsPointer(); return true; } bool VisitType(Type*) { AddCurrentAstNodeAsPointer(); return true; } bool VisitTypeLoc(TypeLoc typeloc) { VERRS(7) << GetSymbolAnnotation() << PrintableTypeLoc(typeloc) << "\n"; seen_nodes_.Add(typeloc); return true; } bool VisitNestedNameSpecifier(NestedNameSpecifier*) { AddCurrentAstNodeAsPointer(); return true; } bool VisitTemplateName(TemplateName tpl_name) { VERRS(7) << GetSymbolAnnotation() << PrintableTemplateName(tpl_name) << "\n"; seen_nodes_.Add(tpl_name); return true; } bool VisitTemplateArgument(const TemplateArgument& tpl_arg) { VERRS(7) << GetSymbolAnnotation() << PrintableTemplateArgument(tpl_arg) << "\n"; seen_nodes_.Add(tpl_arg); return true; } bool VisitTemplateArgumentLoc(const TemplateArgumentLoc& tpl_argloc) { VERRS(7) << GetSymbolAnnotation() << PrintableTemplateArgumentLoc(tpl_argloc) << "\n"; seen_nodes_.Add(tpl_argloc); return true; } bool TraverseImplicitDestructorCall(clang::CXXDestructorDecl* decl, const Type* type) { VERRS(7) << GetSymbolAnnotation() << "[implicit dtor] " << static_cast(decl) << " " << PrintableDecl(decl) << "\n"; AddAstNodeAsPointer(decl); return Base::TraverseImplicitDestructorCall(decl, type); } bool HandleFunctionCall(clang::FunctionDecl* callee, const clang::Type* parent_type, const clang::Expr* calling_expr) { VERRS(7) << GetSymbolAnnotation() << "[function call] " << static_cast(callee) << " " << PrintableDecl(callee) << "\n"; AddAstNodeAsPointer(callee); return Base::HandleFunctionCall(callee, parent_type, calling_expr); } //------------------------------------------------------------ // Class logic. void AddAstNodeAsPointer(const void* node) { seen_nodes_.Add(node); } void AddCurrentAstNodeAsPointer() { if (ShouldPrint(7)) { errs() << GetSymbolAnnotation() << current_ast_node()->GetAs() << " " << PrintableASTNode(current_ast_node()) << "\n"; } AddAstNodeAsPointer(current_ast_node()->GetAs()); } private: NodeSet seen_nodes_; // Because we make a new AstFlattenerVisitor each time we flatten, we // need to make this map static. // TODO(csilvers): just have one flattener, so this needn't be static. static map nodeset_decl_cache_; }; map AstFlattenerVisitor::nodeset_decl_cache_; // ---------------------------------------------------------------------- // --- VisitorState // ---------------------------------------------------------------------- // // This is a simple struct holding data that IwyuBaseASTVisitor will // need to access and manipulate. It's held separately from // IwyuBaseASTVisitor because we want this information to be shared // between the IwyuASTConsumer and the InstantiatedTemplateVisitor, // each of which gets its own copy of IwyuBaseASTVisitor data. So to // share data, we need to hold it somewhere else. struct VisitorState { VisitorState(CompilerInstance* c, const IwyuPreprocessorInfo& ipi) : compiler(c), preprocessor_info(ipi) {} CompilerInstance* const compiler; // Information gathered at preprocessor time, including #include info. const IwyuPreprocessorInfo& preprocessor_info; // When we see an overloaded function that depends on a template // parameter, we can't resolve the overload until the template // is instantiated (e.g., MyFunc in the following example): // template MyFunc() { OverloadedFunction(T()); } // However, sometimes we can do iwyu even before resolving the // overload, if *all* potential overloads live in the same file. We // mark the location of such 'early-processed' functions here, so // when we see the function again at template-instantiation time, we // know not to do iwyu-checking on it again. (Since the actual // function-call exprs are different between the uninstantiated and // instantiated calls, we can't store the exprs themselves, but have // to store their location.) set processed_overload_locs; }; // ---------------------------------------------------------------------- // --- IwyuBaseAstVisitor // ---------------------------------------------------------------------- // // We use two AST visitor classes to implement IWYU: IwyuAstConsumer // is the main visitor that traverses the AST corresponding to what's // actually written in the source code, and // InstantiatedTemplateVisitor is for traversing template // instantiations. This class template holds iwyu work that is be // shared by both. template class IwyuBaseAstVisitor : public BaseAstVisitor { public: typedef BaseAstVisitor Base; explicit IwyuBaseAstVisitor(VisitorState* visitor_state) : Base(visitor_state->compiler), visitor_state_(visitor_state) {} ~IwyuBaseAstVisitor() override = default; // To avoid having this-> pointers everywhere, we re-export Base's // functions that we use in this class. This is a language nit(?) // when a templated class subclasses from another templated class. using Base::CanIgnoreCurrentASTNode; using Base::CurrentLoc; using Base::CurrentFileEntry; using Base::PrintableCurrentLoc; using Base::current_ast_node; using Base::compiler; enum class IgnoreKind { ForUse, ForExpansion, }; //------------------------------------------------------------ // Pure virtual methods that a subclass must implement. // Returns true if we are not interested in iwyu information for the // given type, where the type is *not* the current AST node. // TODO(csilvers): check we're calling this consistent with its API. virtual bool CanIgnoreType(const Type* type, IgnoreKind = IgnoreKind::ForUse) const = 0; // Returns true if we are not interested in doing an iwyu check on // the given decl, where the decl is *not* the current AST node. // TODO(csilvers): check we're calling this consistent with its API. virtual bool CanIgnoreDecl(const Decl* decl) const = 0; //------------------------------------------------------------ // IWYU logic. // Helper for MapPrivateDeclToPublicDecl. Returns true if the decl // is a template specialization whose (written qualified) name matches // the given name, has the given number of template arguments, and // whose specified tpl argument is a type. bool DeclIsTemplateWithNameAndNumArgsAndTypeArg( const Decl* decl, const string& name, size_t num_args, size_t type_arg_idx) const { const ClassTemplateSpecializationDecl* tpl_decl = DynCastFrom(decl); if (!tpl_decl) return false; const string actual_name = GetWrittenQualifiedNameAsString(tpl_decl); if (name != actual_name) return false; const TemplateArgumentList& tpl_args = tpl_decl->getTemplateArgs(); if (tpl_args.size() != num_args) return false; if (tpl_args.get(type_arg_idx).getKind() != TemplateArgument::Type) return false; return true; } // This requires the above function to have been called on decl, first. const Type* GetTplTypeArg(const Decl* decl, size_t type_arg_idx) const { const ClassTemplateSpecializationDecl* tpl_decl = DynCastFrom(decl); CHECK_(tpl_decl && "Must call DeclIsTemplateWithNameAndNumArgsAndTypeArg"); const TemplateArgumentList& tpl_args = tpl_decl->getTemplateArgs(); CHECK_(tpl_args.size() > type_arg_idx && "Invalid type_arg_idx"); CHECK_(tpl_args.get(type_arg_idx).getKind() == TemplateArgument::Type); return tpl_args.get(type_arg_idx).getAsType().getTypePtr(); } // Some types, such as __gnu_cxx::__normal_iterator or std::__wrap_iter, are // private types that should not be exposed to the user. Instead, they're // exposed to the user via typedefs, like vector::iterator. // Sometimes, the typedef gets lost (such as for find(myvec.begin(), // myvec.end(), foo)), so we need to manually map back. We map // __normal_iterator to vector<> and __wrap_iter to foo, // assuming that the vector<> class includes the typedef. Likewise, we map // any free function taking a private iterator (such as operator==) the // same way, assuming that that (templatized) function is instantiated // as part of the vector class. // We do something similar for _List_iterator and _List_const_iterator // from GNU libstdc++, and for __list_iterator and __list_const_iterator // from libc++. These private names are defined in stl_list.h and list // respectively, so we don't need to re-map them, but we do want to re-map // reverse_iterator<_List_iterator> to something in list header. // If the input decl does not correspond to one of these private // decls, we return nullptr. This method is actually a helper for // MapPrivateDeclToPublicDecl() and MapPrivateTypeToPublicType(). const Type* MapPrivateDeclToPublicType(const NamedDecl* decl) const { const NamedDecl* class_decl = decl; // If we're a member method, then the __normal_iterator or __wrap_iter will // be the parent: __normal_iterator::operator=. If we're a free // overloaded operator, then the __normal_iterator will be the // first argument: operator==(__normal_iterator<...>& lhs, ...); if (const CXXMethodDecl* method_decl = DynCastFrom(class_decl)) { class_decl = method_decl->getParent(); } else if (const FunctionDecl* fn = DynCastFrom(decl)) { if (fn->isOverloadedOperator() && fn->getNumParams() >= 1) { const Type* firstarg_type = fn->getParamDecl(0)->getType().getTypePtr(); firstarg_type = RemovePointersAndReferencesAsWritten(firstarg_type); class_decl = TypeToDeclAsWritten(firstarg_type); } } // In addition to __normal_iterator and __wrap_iter, we want // to handle reverse_iterator<__normal_iterator>, and in the same way. if (DeclIsTemplateWithNameAndNumArgsAndTypeArg( class_decl, "std::reverse_iterator", 1, 0)) { const Type* reversed_iterator_type = GetTplTypeArg(class_decl, 0); // Gets class_decl to be reversed iterator. class_decl = TypeToDeclAsWritten(reversed_iterator_type); // If it's reverse_iterator<_List_iterator>, map to // _List_iterator, which is defined in stl_list like we want. Also map // reverse_iterator<__list_iterator> to __list_iterator which is defined // in list. if (DeclIsTemplateWithNameAndNumArgsAndTypeArg( class_decl, "std::_List_iterator", 1, 0) || DeclIsTemplateWithNameAndNumArgsAndTypeArg( class_decl, "std::_List_const_iterator", 1, 0) || DeclIsTemplateWithNameAndNumArgsAndTypeArg( class_decl, "std::__list_iterator", 2, 0) || DeclIsTemplateWithNameAndNumArgsAndTypeArg( class_decl, "std::__list_const_iterator", 2, 0)) { return reversed_iterator_type; } } if (DeclIsTemplateWithNameAndNumArgsAndTypeArg( class_decl, "__gnu_cxx::__normal_iterator", 2, 1)) { return GetTplTypeArg(class_decl, 1); } if (DeclIsTemplateWithNameAndNumArgsAndTypeArg( class_decl, "std::__wrap_iter", 1, 0)) { return GetTplTypeArg(class_decl, 0); } return nullptr; } const NamedDecl* MapPrivateDeclToPublicDecl(const NamedDecl* decl) const { const Type* public_type = MapPrivateDeclToPublicType(decl); if (public_type) return TypeToDeclAsWritten(public_type); return decl; } const Type* MapPrivateTypeToPublicType(const Type* type) const { const NamedDecl* private_decl = TypeToDeclAsWritten(type); const Type* public_type = MapPrivateDeclToPublicType(private_decl); if (public_type) return public_type; return type; } // Get the canonical use location for a (location, decl) pair. // Decide whether the file expanding the macro or the file defining the macro // should be held responsible for a use. SourceLocation GetCanonicalUseLocation(SourceLocation use_loc, const NamedDecl* decl) { CHECK_(decl != nullptr) << ": Need a decl to compute use location"; // If we're not in a macro, just echo the use location. if (!use_loc.isMacroID()) return use_loc; VERRS(5) << "Trying to determine use location for '" << PrintableDecl(decl) << "'\n"; clang::SourceManager* sm = GlobalSourceManager(); SourceLocation spelling_loc = sm->getSpellingLoc(use_loc); SourceLocation expansion_loc = sm->getExpansionLoc(use_loc); // If the file defining the macro contains a forward decl, keep it around // and treat it as a hint that the expansion loc is responsible for the // symbol. const FileEntry* macro_def_file = GetLocFileEntry(spelling_loc); VERRS(5) << "Macro is defined in '" << GetFilePath(macro_def_file) << "'\n"; const NamedDecl* fwd_decl = nullptr; for (const NamedDecl* redecl : GetTagRedecls(decl)) { if (GetFileEntry(redecl) == macro_def_file && IsForwardDecl(redecl)) { VERRS(5) << "Found fwd-decl hint at " << PrintableLoc(GetLocation(redecl)) << "\n"; fwd_decl = redecl; break; } } if (!fwd_decl) { if (const auto* func_decl = dyn_cast(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) { VERRS(5) << "Found function template at " << PrintableLoc(GetLocation(redecl)) << "\n"; 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 = preprocessor_info().FileInfoFor(macro_def_file); file_info->ReportForwardDeclareUse( spelling_loc, fwd_decl, ComputeUseFlags(current_ast_node()), nullptr); } // Resolve the best use location based on our current knowledge. // // 1) If the use_loc is in , we assume it's formed by macro // argument concatenation, and attribute responsibility to the expansion // location. // 2) If the macro definition file forward-declares the used decl, that's a // hint that it wants the expansion location to take responsibility. // // Otherwise, the spelling loc is responsible. const char* side; if (IsInScratchSpace(spelling_loc)) { VERRS(5) << "Spelling location is in , presumably as a " << "result of macro arg concatenation\n"; use_loc = expansion_loc; side = "expansion"; } else if (fwd_decl != nullptr) { VERRS(5) << "Found a hint decl in macro definition file\n"; use_loc = expansion_loc; side = "expansion"; } else { use_loc = spelling_loc; side = "spelling"; } VERRS(4) << "Attributing use of '" << PrintableDecl(decl) << "' to " << side << " location at " << PrintableLoc(use_loc) << "\n"; return use_loc; } // There are a few situations where iwyu is more restrictive than // C++: where C++ allows a forward-declare but iwyu wants the full // type. One is in a typedef: if you write 'typedef Foo MyTypedef', // iwyu says that you are responsible for #including "foo.h", but // the language allows a forward-declare. Another is for // 'autocast': if your function has a parameter with a conversion // (one-arg, not-explicit) constructor, iwyu requires that the // function-author provides the full type of that parameter, but // the language doesn't. (It's ok with all callers providing the // full type instead.) // // In each of these situations, we allow the user to say that iwyu // should not require #includes for these underlying types, but // allow forward-declares instead. The author can do this by // explicitly forward-declaring in the same file: for instance, they // would do // class Foo; typedef Foo MyTypedef; // can be on different lines :-) // class AutocastType; void MyFunc(AutocastType); // but in same file // If a definition- or declaration-site does this forward-declaring // *and* does not directly #include the necessary file for Foo or // AutocastType, we take that as a signal from the code-author that // iwyu should relax its policies. These functions calculate the // types (which may have many component-types if it's a templated // type) for which the code-author has made this decision. bool CodeAuthorWantsJustAForwardDeclare(const Type* type, SourceLocation use_loc) { const NamedDecl* decl = TypeToDeclAsWritten(type); if (decl == nullptr) // only class-types are candidates for returning true return false; // Sometimes a type points back to an implicit decl (e.g. a bultin type), // and we can't do author-intent analysis without location information. // Assume that it's not forward-declarable. if (decl->isImplicit()) { VERRS(5) << "Skipping forward-declare analysis for implicit decl: '" << PrintableDecl(decl) << "'\n"; return false; } // If we're a template specialization, we also accept // forward-declarations of the underlying template (vector, not // vector). set redecls = GetTagRedecls(decl); if (const ClassTemplateSpecializationDecl* spec_decl = DynCastFrom(decl)) { InsertAllInto(GetTagRedecls(spec_decl->getSpecializedTemplate()), &redecls); } // Check if the author forward-declared the class in the same file. bool found_earlier_forward_declare_in_same_file = false; for (const NamedDecl* redecl : redecls) { if (IsBeforeInSameFile(redecl, use_loc)) { found_earlier_forward_declare_in_same_file = true; break; } } if (!found_earlier_forward_declare_in_same_file) return false; // Check if the the author is not #including the file with the // definition. PublicHeaderIntendsToProvide has exactly the // semantics we want. Note if there's no definition anywhere, we // say the author does not want the full type (which is a good // thing, since there isn't one!) if (const NamedDecl* dfn = GetTagDefinition(decl)) { if (IsBeforeInSameFile(dfn, use_loc)) return false; if (preprocessor_info().PublicHeaderIntendsToProvide( GetFileEntry(use_loc), GetFileEntry(dfn))) { return false; } } // OK, looks like the author has stated they don't want the fulll type. return true; } // Returns the first type that is not a typedef in a template. For example, // for template // // template class Foo { // typedef T value_type; // typedef value_type& reference; // }; // // for type 'reference' it will return type T with which Foo was instantiated. const Type* DesugarDependentTypedef(const TypedefType* typedef_type) { const DeclContext* parent = typedef_type->getDecl()->getLexicalDeclContext(); if (const ClassTemplateSpecializationDecl* template_parent = DynCastFrom(parent)) { return DesugarDependentTypedef(typedef_type, template_parent); } return typedef_type; } const Type* DesugarDependentTypedef( const TypedefType* typedef_type, const RecordDecl* parent) { const Type* underlying_type = typedef_type->getDecl()->getUnderlyingType().getTypePtr(); if (const TypedefType* underlying_typedef = DynCastFrom(underlying_type)) { if (underlying_typedef->getDecl()->getLexicalDeclContext() == parent) { return DesugarDependentTypedef(underlying_typedef, parent); } } return underlying_type; } set GetCallerResponsibleTypesForTypedef( const TypedefNameDecl* decl) { set retval; const Type* underlying_type = decl->getUnderlyingType().getTypePtr(); // If the underlying type is itself a typedef, we recurse. if (const auto* underlying_typedef = underlying_type->getAs()) { if (const auto* underlying_typedef_decl = dyn_cast(TypeToDeclAsWritten(underlying_typedef))) { // TODO(csilvers): if one of the intermediate typedefs // #includes the necessary definition of the 'final' // underlying type, do we want to return the empty set here? return GetCallerResponsibleTypesForTypedef(underlying_typedef_decl); } } const Type* deref_type = RemovePointersAndReferencesAsWritten(underlying_type); if (isa(underlying_type) || CodeAuthorWantsJustAForwardDeclare(deref_type, GetLocation(decl))) { retval.insert(deref_type); // TODO(csilvers): include template type-args if appropriate. // This requires doing an iwyu visit of the instantiated // underlying type and seeing which type-args we require full // use for. Also have to handle the case where the type-args // are themselves templates. It will require pretty substantial // iwyu surgery. } return retval; } // ast_node is the node for the autocast CastExpr. We use it to get // the parent CallExpr to figure out what function is being called. set GetCallerResponsibleTypesForAutocast( const ASTNode* ast_node) { while (ast_node && !ast_node->IsA()) ast_node = ast_node->parent(); CHECK_(ast_node && "Should only check Autocast if under a CallExpr"); const CallExpr* call_expr = ast_node->GetAs(); const FunctionDecl* fn_decl = call_expr->getDirectCallee(); if (!fn_decl) // TODO(csilvers): what to do for fn ptrs and the like? return set(); // Collect the non-explicit, one-arg constructor ('autocast') types. set autocast_types; for (FunctionDecl::param_const_iterator param = fn_decl->param_begin(); param != fn_decl->param_end(); ++param) { const Type* param_type = GetTypeOf(*param); if (HasImplicitConversionConstructor(param_type)) { const Type* deref_param_type = RemovePointersAndReferencesAsWritten(param_type); autocast_types.insert(Desugar(deref_param_type)); } } // Now look at all the function decls that are visible from the // call-location. We keep only the autocast params that *all* // the function decl authors want the caller to be responsible // for. We do this by elimination: start with all types, and // remove them as we see authors providing the full type. set retval = autocast_types; for (FunctionDecl::redecl_iterator fn_redecl = fn_decl->redecls_begin(); fn_redecl != fn_decl->redecls_end(); ++fn_redecl) { // Ignore function-decls that we can't see from the use-location. if (!preprocessor_info().FileTransitivelyIncludes( GetFileEntry(call_expr), GetFileEntry(*fn_redecl))) { continue; } if (fn_redecl->isThisDeclarationADefinition() && !IsInHeader(*fn_redecl)) continue; for (set::iterator it = retval.begin(); it != retval.end(); ) { if (!CodeAuthorWantsJustAForwardDeclare(*it, GetLocation(*fn_redecl))) { // set<> has nice property that erasing doesn't invalidate iterators. retval.erase(it++); } else { ++it; } } } // TODO(csilvers): include template type-args of each entry of retval. return retval; } set GetCallerResponsibleTypesForFnReturn( const FunctionDecl* decl) { set retval; const Type* return_type = Desugar(decl->getReturnType().getTypePtr()); if (CodeAuthorWantsJustAForwardDeclare(return_type, GetLocation(decl))) { retval.insert(return_type); // TODO(csilvers): include template type-args if appropriate. } return retval; } //------------------------------------------------------------ // Checkers, that tell iwyu_output about uses of symbols. // We let, but don't require, subclasses to override these. // The comment, if not nullptr, is extra text that is included along with // the warning message that iwyu emits. The extra use flags is optional // info that can be assigned to the use (see the UF_* constants) virtual void ReportDeclUse(SourceLocation used_loc, const NamedDecl* used_decl, const char* comment = nullptr, UseFlags extra_use_flags = 0) { const NamedDecl* target_decl = used_decl; // Sometimes a shadow decl comes between us and the 'real' decl. const UsingDecl* using_decl = nullptr; if (const auto* shadow_decl = dyn_cast(used_decl)) { target_decl = shadow_decl->getTargetDecl(); using_decl = dyn_cast(shadow_decl->getIntroducer()); } // Map private decls like __normal_iterator to their public counterpart. target_decl = MapPrivateDeclToPublicDecl(target_decl); if (CanIgnoreDecl(target_decl)) return; UseFlags use_flags = ComputeUseFlags(current_ast_node()) | extra_use_flags; // Canonicalize the use location and report the use. used_loc = GetCanonicalUseLocation(used_loc, target_decl); const FileEntry* used_in = GetFileEntry(used_loc); preprocessor_info().FileInfoFor(used_in)->ReportFullSymbolUse( used_loc, target_decl, use_flags, comment); // Sometimes using a decl drags in a few other uses as well: // If we're a use that depends on a using declaration, make sure // we #include the file with the using declaration. Need to check // the original reported decl so we don't lose the shadow information. // TODO(csilvers): check that our getQualifier() does not match // the namespace of the decl. If we have 'using std::vector;' + // 'std::vector foo;' we don't actually care about the // using-decl. // TODO(csilvers): maybe just insert our own using declaration // instead? We can call it "Use what you use". :-) // TODO(csilvers): check for using statements and namespace aliases too. if (using_decl) { preprocessor_info().FileInfoFor(used_in)->ReportUsingDeclUse( used_loc, using_decl, use_flags, "(for using decl)"); } } // The comment, if not nullptr, is extra text that is included along // with the warning message that iwyu emits. virtual void ReportDeclForwardDeclareUse(SourceLocation used_loc, const NamedDecl* used_decl, const char* comment = nullptr) { const NamedDecl* target_decl = used_decl; // Sometimes a shadow decl comes between us and the 'real' decl. const UsingDecl* using_decl = nullptr; if (const auto* shadow_decl = dyn_cast(used_decl)) { target_decl = shadow_decl->getTargetDecl(); using_decl = dyn_cast(shadow_decl->getIntroducer()); } target_decl = MapPrivateDeclToPublicDecl(target_decl); if (CanIgnoreDecl(target_decl)) return; UseFlags use_flags = ComputeUseFlags(current_ast_node()); // Canonicalize the use location and report the use. used_loc = GetCanonicalUseLocation(used_loc, target_decl); const FileEntry* used_in = GetFileEntry(used_loc); preprocessor_info().FileInfoFor(used_in)->ReportForwardDeclareUse( used_loc, target_decl, use_flags, comment); // If we're a use that depends on a using declaration, make sure // we #include the file with the using declaration. if (using_decl) { preprocessor_info().FileInfoFor(used_in)->ReportUsingDeclUse( used_loc, using_decl, use_flags, "(for using decl)"); } } void ReportDeclsUse(SourceLocation used_loc, const set& decls) { for (const NamedDecl* decl : decls) ReportDeclUse(used_loc, decl); } // Called when the given type is fully used at used_loc, regardless // of the type being explicitly written in the source code or not. // The comment, if not nullptr, is extra text that is included along // with the warning message that iwyu emits. virtual void ReportTypeUse(SourceLocation used_loc, const Type* type, const char* comment = nullptr) { // TODO(csilvers): figure out if/when calling CanIgnoreType() is correct. if (!type) return; // Enum type uses can be ignored. Their size is known (either implicitly // 'int' or from a mandatory transitive inclusion of a non-fixed enum full // declaration, or explicitly using a C++ 11 enum base). Only if an enum // type or its enumerators are explicitly mentioned will they be reported // by IWYU from VisitTagType or VisitDeclRefExpr correspondingly. if (type->getAs()) return; // Types in fwd-decl-context should be ignored here and reported from more // specialized places, i.e. when they are explicitly written. But in fact, // this check is redundant because TypeToDeclAsWritten returns nullptr for // pointers and references. if (IsPointerOrReferenceAsWritten(type)) return; // For typedefs, the user of the type is sometimes the one // responsible for the underlying type. We check if that is the // case here, since we might be using a typedef type from // anywhere. ('autocast' is similar, but is handled in // VisitCastExpr; 'fn-return-type' is also similar and is // handled in HandleFunctionCall.) if (const auto* typedef_type = type->getAs()) { // 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. const ASTNode* ast_node = MostElaboratedAncestor(current_ast_node()); if (!ast_node->ParentIsA()) { const TypedefNameDecl* typedef_decl = typedef_type->getDecl(); const set& underlying_types = GetCallerResponsibleTypesForTypedef(typedef_decl); if (!underlying_types.empty()) { VERRS(6) << "User, not author, of typedef " << typedef_decl->getQualifiedNameAsString() << " owns the underlying type:\n"; // If any of the used types are themselves typedefs, this will // result in a recursive expansion. Note we are careful to // recurse inside this class, and not go back to subclasses. for (const Type* type : underlying_types) IwyuBaseAstVisitor::ReportTypeUse(used_loc, type); } } return; } // Map private types like __normal_iterator to their public counterpart. type = MapPrivateTypeToPublicType(type); // For the below, we want to be careful to call *our* // ReportDeclUse(), not any of the ones in subclasses. if (const auto* template_spec_type = dyn_cast(Desugar(type))) { this->getDerived().ReportTplSpecComponentTypes(template_spec_type); } if (const NamedDecl* decl = TypeToDeclAsWritten(type)) { decl = GetDefinitionAsWritten(decl); VERRS(6) << "(For type " << PrintableType(type) << "):\n"; IwyuBaseAstVisitor::ReportDeclUse(used_loc, decl, comment); } } void ReportTypesUse(SourceLocation used_loc, const set& types) { for (const Type* type : types) ReportTypeUse(used_loc, type); } //------------------------------------------------------------ // Visitors of types derived from clang::Decl. // Friend declarations only need their types forward-declared. bool VisitFriendDecl(clang::FriendDecl* decl) { if (CanIgnoreCurrentASTNode()) return true; current_ast_node()->set_in_forward_declare_context(true); return true; } bool VisitFriendTemplateDecl(clang::FriendTemplateDecl* decl) { if (CanIgnoreCurrentASTNode()) return true; current_ast_node()->set_in_forward_declare_context(true); return true; } bool VisitEnumDecl(EnumDecl* decl) { if (CanIgnoreCurrentASTNode()) return true; clang::QualType integer_type = decl->getIntegerType(); if (const clang::Type* type = integer_type.getTypePtrOrNull()) { ReportTypeUse(CurrentLoc(), type); } return true; } // If you say 'typedef Foo Bar', C++ says you just need to // forward-declare Foo. But iwyu would rather you fully define Foo, // so all users of Bar don't have to. We make two exceptions: // 1) The author of the typedef doesn't *want* to provide Foo, and // is happy making all the callers do so. The author indicates // this by explicitly forward-declaring Foo and not #including // foo.h. // 2) The typedef is a member of a templated class, and the // underlying type is a template parameter: // template struct C { typedef T value_type; }; // This is not a re-export because you need the type to // access the typedef (via 'C::value_type'), so // there's no need for the typedef-file to provide the type // too. TODO(csilvers): this is patently wrong; figure out // something better. We need something that doesn't require // the full type info for creating a scoped_ptr. // As an extension of (2), if the typedef is a template type that // contains T as a template parameter, the typedef still re-exports // the template type (it's not (2)), but the template parameter // itself can be forward-declared, just as in (2). That is: // template struct C { typedef pair value_type; }; // iwyu will demand the full type of pair, but not of its template // arguments. This is handled not here, but below, in // VisitSubstTemplateTypeParmType. bool VisitTypedefNameDecl(clang::TypedefNameDecl* decl) { if (CanIgnoreCurrentASTNode()) return true; const Type* underlying_type = decl->getUnderlyingType().getTypePtr(); const Type* deref_type = RemovePointersAndReferencesAsWritten(underlying_type); if (CodeAuthorWantsJustAForwardDeclare(deref_type, GetLocation(decl)) || isa(underlying_type)) { current_ast_node()->set_in_forward_declare_context(true); } else { current_ast_node()->set_in_forward_declare_context(false); } return true; } // If we're a declared (not defined) function, all our types -- // return type and argument types -- are forward-declarable. The // one exception required by the language is the throw types, which // we clean up in VisitType(). // There are two more exceptions that iwyu imposes: // (1) iwyu asks the function author to provide the full type // information for the return type. That way the user doesn't // have to. // (2) If any of our function parameters have a type with a // non-explicit, one-arg constructor, or is a const reference to // such a type, mark that type as not forward declarable. The // worry is that people might need the full type for the // implicit conversion (the 'autocast'), for instance, passing // in a char* to Fn(const StringPiece& foo) { ... } // Both of these iwyu requirements can be overridden by the function // author; for details, see CodeAuthorWantsJustAForwardDeclare. bool VisitFunctionDecl(clang::FunctionDecl* decl) { if (CanIgnoreCurrentASTNode()) return true; if (decl->isThisDeclarationADefinition()) { // For free functions, report use of all previously seen decls. if (decl->getKind() == Decl::Function) { FunctionDecl* redecl = decl; while ((redecl = redecl->getPreviousDecl())) ReportDeclUse(CurrentLoc(), redecl); } if (!IsInHeader(decl)) { // No point in author-intent analysis of function definitions // in source files or for builtins. return true; } } else { // Make all our types forward-declarable... current_ast_node()->set_in_forward_declare_context(true); } // (The exceptions below don't apply to friend declarations; we // never need full types for them.) if (IsFriendDecl(decl)) return true; // ...except the return value. const Type* return_type = Desugar(decl->getReturnType().getTypePtr()); const bool is_responsible_for_return_type = (!CanIgnoreType(return_type) && !IsPointerOrReferenceAsWritten(return_type) && !CodeAuthorWantsJustAForwardDeclare(return_type, GetLocation(decl))); // Don't bother to report here, when the language agrees with us // we need the full type; that will be reported elsewhere, so // reporting here would be double-counting. const bool type_use_reported_in_visit_function_type = (!current_ast_node()->in_forward_declare_context() || !IsClassType(return_type)); if (is_responsible_for_return_type && !type_use_reported_in_visit_function_type) { ReportTypeUse(GetLocation(decl), return_type, "(for fn return type)"); } // ...and non-explicit, one-arg ('autocast') constructor types. for (FunctionDecl::param_iterator param = decl->param_begin(); param != decl->param_end(); ++param) { const Type* param_type = GetTypeOf(*param); if (!HasImplicitConversionConstructor(param_type)) continue; const Type* deref_param_type = RemovePointersAndReferencesAsWritten(param_type); if (CanIgnoreType(param_type) && CanIgnoreType(deref_param_type)) continue; // TODO(csilvers): remove this 'if' check when we've resolved the // clang bug where getTypeSourceInfo() can return nullptr. if ((*param)->getTypeSourceInfo()) { const TypeLoc param_tl = (*param)->getTypeSourceInfo()->getTypeLoc(); // While iwyu requires the full type of autocast parameters, // c++ does not. Function-writers can force iwyu to follow // the language by explicitly forward-declaring the type. // Check for that now, and don't require the full type. if (CodeAuthorWantsJustAForwardDeclare(deref_param_type, GetLocation(¶m_tl))) continue; // This is a 'full type required' check, to 'turn off' fwd decl. // But don't bother to report in situations where we need the // full type for other reasons; that's just double-reporting. if (current_ast_node()->in_forward_declare_context() || IsPointerOrReferenceAsWritten(param_type)) { ReportTypeUse(GetLocation(¶m_tl), deref_param_type, "(for autocast)"); } } else { VERRS(6) << "WARNING: nullptr TypeSourceInfo for " << PrintableDecl(*param) << " (type " << PrintableType(param_type) << ")\n"; } } return true; } // Special handling for C++ methods to detect covariant return types. // These are defined as a derived class overriding a method with a different // return type from the base. bool VisitCXXMethodDecl(CXXMethodDecl* method_decl) { if (CanIgnoreCurrentASTNode()) return true; if (HasCovariantReturnType(method_decl)) { const Type* return_type = RemovePointersAndReferencesAsWritten( method_decl->getReturnType().getTypePtr()); VERRS(6) << "Found covariant return type in " << method_decl->getQualifiedNameAsString() << ", needs complete type of " << PrintableType(return_type) << "\n"; ReportTypeUse(CurrentLoc(), return_type); } return true; } //------------------------------------------------------------ // Visitors of types derived from clang::Stmt. // Catch statements always require the full type to be visible, // no matter if we're catching by value, reference or pointer. bool VisitCXXCatchStmt(clang::CXXCatchStmt* stmt) { if (CanIgnoreCurrentASTNode()) return true; if (const VarDecl* exception_decl = stmt->getExceptionDecl()) { // Get the caught type from the decl via associated type source info to // get more precise location info for the type use. TypeLoc typeloc = exception_decl->getTypeSourceInfo()->getTypeLoc(); const Type* caught_type = typeloc.getType().getTypePtr(); // Strip off pointers/references to get to the pointee type. caught_type = RemovePointersAndReferencesAsWritten(caught_type); ReportTypeUse(GetLocation(&typeloc), caught_type); } else { // catch(...): no type to act on here. } return true; } // The type of the for-range-init expression is fully required, because the // compiler generates method calls to it, e.g. 'for (auto t : ts)' translates // roughly into 'for (auto i = std::begin(ts); i != std::end(ts); ++i)'. // Both the iterator type and the begin/end calls depend on the complete type // of ts, so make sure we include it. bool VisitCXXForRangeStmt(clang::CXXForRangeStmt* stmt) { if (CanIgnoreCurrentASTNode()) return true; if (const Type* type = stmt->getRangeInit()->getType().getTypePtrOrNull()) { ReportTypeUse(CurrentLoc(), RemovePointersAndReferencesAsWritten(type)); // TODO: We should probably find a way to require inclusion of any // argument-dependent begin/end declarations. } return true; } // When casting non-pointers, iwyu will do the right thing // automatically, but sometimes when casting from one pointer to // another, you still need the full type information of both types: // for instance, when static-casting from a sub-class to a // super-class. Testing shows this is true for static, dynamic // casts, and implicit casts, but not for reinterpret casts, const // casts, or C-style casts. (Functional casts like int(3.5) are // treated the same as C-style casts.) clang helpfully provides a // 'cast kind', which we use to determine when full types are // needed. When we notice that the cast is a cast up or down a // class hierarchy, we require full type info for both types even // for C-style casts (though the language doesn't), to give the // compiler a fighting chance of generating correct code. bool VisitCastExpr(clang::CastExpr* expr) { if (CanIgnoreCurrentASTNode()) return true; const Type* from_type = GetTypeOf(expr->getSubExprAsWritten()); const Type* to_type = GetTypeOf(expr); // If this cast requires a user-defined conversion of the from-type, look up // its return type so we can see through up/down-casts via such conversions. const Type* converted_from_type = nullptr; if (const NamedDecl* conv_decl = expr->getConversionFunction()) { converted_from_type = cast(conv_decl)->getReturnType().getTypePtr(); } std::vector required_full_types; // The list of kinds: http://clang.llvm.org/doxygen/namespaceclang.html switch (expr->getCastKind()) { // This cast still isn't handled directly. case clang::CK_Dependent: break; // These casts don't require any iwyu action. case clang::CK_LValueToRValue: case clang::CK_AtomicToNonAtomic: case clang::CK_NonAtomicToAtomic: case clang::CK_ReinterpretMemberPointer: case clang::CK_BuiltinFnToFnPtr: case clang::CK_ZeroToOCLOpaqueType: // OpenCL opaque types are built-in. case clang::CK_IntToOCLSampler: // OpenCL sampler_t is a built-in type. case clang::CK_AddressSpaceConversion: // Address spaces are associated // with pointers, so no need for // the full type. break; // Ignore non-ptr-to-ptr casts. case clang::CK_ArrayToPointerDecay: case clang::CK_BooleanToSignedIntegral: case clang::CK_FixedPointCast: case clang::CK_FixedPointToBoolean: case clang::CK_FixedPointToFloating: case clang::CK_FixedPointToIntegral: case clang::CK_FloatingCast: case clang::CK_FloatingComplexCast: case clang::CK_FloatingComplexToBoolean: case clang::CK_FloatingComplexToIntegralComplex: case clang::CK_FloatingComplexToReal: case clang::CK_FloatingRealToComplex: case clang::CK_FloatingToBoolean: case clang::CK_FloatingToFixedPoint: case clang::CK_FloatingToIntegral: case clang::CK_FunctionToPointerDecay: case clang::CK_IntegralCast: case clang::CK_IntegralComplexCast: case clang::CK_IntegralComplexToBoolean: case clang::CK_IntegralComplexToFloatingComplex: case clang::CK_IntegralComplexToReal: case clang::CK_IntegralRealToComplex: case clang::CK_IntegralToBoolean: 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: case clang::CK_PointerToBoolean: case clang::CK_PointerToIntegral: case clang::CK_ToUnion: case clang::CK_ToVoid: break; case clang::CK_AnyPointerToBlockPointerCast: case clang::CK_ARCConsumeObject: case clang::CK_ARCExtendBlockObject: case clang::CK_ARCProduceObject: case clang::CK_ARCReclaimReturnedObject: case clang::CK_BlockPointerToObjCPointerCast: case clang::CK_CopyAndAutoreleaseBlockObject: case clang::CK_CPointerToObjCPointerCast: case clang::CK_ObjCObjectLValueCast: case clang::CK_VectorSplat: CHECK_UNREACHABLE_( "TODO(csilvers): for objc and clang lang extensions"); break; // Kinds for reinterpret_cast and const_cast, which need no full types. case clang::CK_BitCast: // used for reinterpret_cast case clang::CK_LValueBitCast: // used for reinterpret_cast case clang::CK_LValueToRValueBitCast: // used for reinterpret_cast case clang::CK_NoOp: // used for const_cast, etc break; // Need the full to-type so we can call its constructor. case clang::CK_ConstructorConversion: // 'Autocast' in function calls is handled in VisitCXXConstructExpr. if (!current_ast_node()->template HasAncestorOfType()) required_full_types.push_back(to_type); break; // Need the full from-type so we can call its 'operator ()'. case clang::CK_UserDefinedConversion: required_full_types.push_back(from_type); break; // Kinds that cast up or down an inheritance hierarchy. case clang::CK_BaseToDerived: case clang::CK_BaseToDerivedMemberPointer: // Just 'to' type is enough: full type for derived gets base type too. required_full_types.push_back(to_type); break; case clang::CK_DerivedToBase: case clang::CK_UncheckedDerivedToBase: case clang::CK_DerivedToBaseMemberPointer: // Just 'from' type is enough: full type for derived gets base type too. required_full_types.push_back(from_type); // If this derived-to-base cast had an associated conversion function, // it's a user-defined conversion operator. The from-type in this cast // is not necessarily related to the base type, but the converted // from-type must be, so make sure we require both. if (converted_from_type) { required_full_types.push_back(converted_from_type); } break; case clang::CK_Dynamic: // Usually dynamic casting is a base-to-derived cast, but it is // possible to dynamic-cast between siblings, in which case we // need both types. required_full_types.push_back(from_type); required_full_types.push_back(to_type); break; } // TODO(csilvers): test if we correctly say we use FooPtr for // typedef Foo* FooPtr; ... static_cast(...) ... for (const Type* type : required_full_types) { const Type* deref_type = RemovePointersAndReferences(type); if (CanIgnoreType(deref_type)) continue; ReportTypeUse(CurrentLoc(), deref_type); } return true; } // Mark that we need the full type info for our base type -- the // thing we're a member of -- and it's not just forward-declarable. // For instance, for code 'Mytype* myvar; myvar->a;', we'll get a // MemberExpr callback whose base has the type of myvar. bool VisitMemberExpr(clang::MemberExpr* expr) { if (CanIgnoreCurrentASTNode()) return true; const Expr* base_expr = expr->getBase()->IgnoreParenImpCasts(); const Type* base_type = GetTypeOf(base_expr); CHECK_(base_type && "Member's base does not have a type?"); const Type* deref_base_type // For myvar->a, base-type will have a * = expr->isArrow() ? RemovePointerFromType(base_type) : base_type; if (CanIgnoreType(base_type) && CanIgnoreType(deref_base_type)) return true; if (const TypedefType* typedef_type = DynCastFrom(deref_base_type)) { deref_base_type = DesugarDependentTypedef(typedef_type); } // Technically, we should say the type is being used at the // location of base_expr. That may be a different file than us in // cases like MACRO.b(). However, while one can imagine // situations where the base-type is the responsibility of the // macro-author ('SOME_GLOBAL_OBJECT.a()'), the more common case // is it's our responsibility ('CHECK_NOTNULL(x).a()'). Until we // can better distinguish whether a macro body is an expression // that's responsible for its type or not, we just assume it is. // TODO(csilvers): fix when we can determine what the macro-text // is responsible for and what we're responsible for. // TODO(csilvers): we should be reporting a fwd-decl use for // GetTypeOf(expr), not on deref_base_type. ReportTypeUse(CurrentLoc(), deref_base_type); return true; } // For a[4], report that we need the full type of *a (to get its // size; otherwise the compiler can't tell the address of a[4]). bool VisitArraySubscriptExpr(clang::ArraySubscriptExpr* expr) { if (CanIgnoreCurrentASTNode()) return true; const Type* element_type = GetTypeOf(expr); if (CanIgnoreType(element_type)) return true; ReportTypeUse(CurrentLoc(), element_type); return true; } // If a binary operator expression results in pointer arithmetic, we need the // full types of all pointers involved. bool VisitBinaryOperator(clang::BinaryOperator* expr) { if (CanIgnoreCurrentASTNode()) return true; // If it's not +, +=, - or -=, this can't be pointer arithmetic clang::BinaryOperator::Opcode op = expr->getOpcode(); if (op != clang::BO_Add && op != clang::BO_Sub && op != clang::BO_AddAssign && op != clang::BO_SubAssign) return true; for (const Stmt* child : expr->children()) { if (const PointerType* pointer_type = dyn_cast(GetTypeOf(cast(child)))) { // It's a pointer-typed expression. Get the pointed-to type (which may // itself be a pointer) and report it. const Type* deref_type = pointer_type->getPointeeType().getTypePtr(); if (!CanIgnoreType(deref_type)) ReportTypeUse(CurrentLoc(), deref_type); } } return true; } bool VisitTypeTraitExpr(clang::TypeTraitExpr* expr) { if (CanIgnoreCurrentASTNode()) return true; // We assume that all type traits with >= 2 arguments require // full type information even for pointer types. For example, // this is the case for `__is_convertible_to` trait. if (expr == nullptr || expr->getNumArgs() < 2) return true; for (const clang::TypeSourceInfo* arg : expr->getArgs()) { clang::QualType qual_type = arg->getType(); const Type* type = qual_type.getTypePtr(); const Type* deref_type = RemovePointersAndReferencesAsWritten(type); if (!CanIgnoreType(deref_type)) { ReportTypeUse(CurrentLoc(), deref_type); } } return true; } // Mark that we need the full type info for the thing we're taking // sizeof of. Sometimes this is double-counting: for // sizeof(some_type), RecursiveASTVisitor will visit some_type and // say it needs the full type information there, and for // sizeof(some_var), we'll report we need full type information when // some_var is defined. But if the arg is a reference, nobody else // will say we need full type info but us. bool VisitUnaryExprOrTypeTraitExpr(clang::UnaryExprOrTypeTraitExpr* expr) { if (CanIgnoreCurrentASTNode()) return true; current_ast_node()->set_in_forward_declare_context(false); // Calling sizeof on a reference-to-X is the same as calling it on X. // If sizeof() takes a type, this is easy to check. If sizeof() // takes an expr, it's hard to tell -- GetTypeOf(expr) 'sees through' // references. Luckily, we want to see through references, so we // just use the GetTypeOf(). if (expr->isArgumentType()) { const TypeLoc& arg_tl = expr->getArgumentTypeInfo()->getTypeLoc(); if (const auto* reftype = arg_tl.getTypePtr()->getAs()) { const Type* dereftype = reftype->getPointeeTypeAsWritten().getTypePtr(); if (!CanIgnoreType(reftype) || !CanIgnoreType(dereftype)) ReportTypeUse(GetLocation(&arg_tl), dereftype); } else { // No need to report on non-ref types, RecursiveASTVisitor will get 'em. } } else { const Expr* arg_expr = expr->getArgumentExpr(); const Type* dereftype = arg_expr->getType().getTypePtr(); if (!CanIgnoreType(dereftype)) // This reports even if the expr ends up not being a reference, but // that's ok (if potentially redundant). ReportTypeUse(GetLocation(arg_expr->IgnoreParenImpCasts()), dereftype); } return true; } // We want to mark use of the base type For 'free function' operator // overloads ('ostream& operator<<(ostream& o, int x)') just like we // do for member functions ('ostream& ostream::operator<<(int x)') // -- for iwyu purposes, 'x << 4' is just semantic sugar around // x.operator<<(4). bool VisitCXXOperatorCallExpr(clang::CXXOperatorCallExpr* expr) { if (CanIgnoreCurrentASTNode()) return true; if (const Expr* owner_expr = GetFirstClassArgument(expr)) { const Type* owner_type = GetTypeOf(owner_expr); // Note we report the type use is the location of owner_expr // (the 'a' in 'a << b' or the 'MACRO' in 'MACRO << b'), rather // than our location (which is the '<<'). That way, we properly // situate the owner when it's a macro. if (!CanIgnoreType(owner_type)) ReportTypeUse(GetLocation(owner_expr), owner_type); } return true; } // We have to check the type being deleted is fully defined (the // language doesn't require it, but bad things happen if it's not: // the destructor isn't run). bool VisitCXXDeleteExpr(clang::CXXDeleteExpr* expr) { if (CanIgnoreCurrentASTNode()) return true; const Expr* delete_arg = expr->getArgument()->IgnoreParenImpCasts(); // We always delete a pointer, so do one dereference to get the // actual type being deleted. const Type* delete_ptr_type = GetTypeOf(delete_arg); const Type* delete_type = RemovePointerFromType(delete_ptr_type); if (CanIgnoreType(delete_ptr_type) && CanIgnoreType(delete_type)) return true; if (delete_type && !IsPointerOrReferenceAsWritten(delete_type)) ReportTypeUse(CurrentLoc(), delete_type); return true; } // Handle the case of passing references to variadic functions // (those with '...'). We need the full type information for the // reference in that case, since compilers seem to just deref the // var before passing it in. Note we subclass all the // function-calling methods rather than HandleFunctionCall, because // a) we need type-specific caller information anyway, and b) // HandleFunctionCall isn't called for calls via function-pointers, // which we want. void ReportIfReferenceVararg(const Expr* const* args, unsigned num_args, const FunctionProtoType* callee_type) { if (callee_type && callee_type->isVariadic()) { const unsigned first_vararg_index = callee_type->getNumParams(); for (unsigned i = first_vararg_index; i < num_args; i++) { // We only care about reporting for references, but it's ok if // we catch a few non-ref types too (it's just redundant). // All expressions that are references will have their // valuekind be an LValue, so we use that as the test. if (args[i]->getValueKind() == clang::VK_LValue) { // The types of expressions 'see through' the reference to // the underlying type, which is exactly what we want here. ReportTypeUse(CurrentLoc(), GetTypeOf(args[i])); } } } } void ReportIfReferenceVararg(const Expr* const* args, unsigned num_args, const FunctionDecl* callee) { if (callee) { const FunctionProtoType* callee_type = DynCastFrom(callee->getType().getTypePtr()); CHECK_(callee_type && "The type of a FunctionDecl must be a FunctionProtoType."); ReportIfReferenceVararg(args, num_args, callee_type); } } // We only need visitors for CallExpr, ConstructExpr, and NewExpr // (which also captures their subclasses). We can ignore DeleteExpr // since destructors never have arguments. NewExpr we treat below, // since it requires other checks as well. bool VisitCallExpr(clang::CallExpr* expr) { if (CanIgnoreCurrentASTNode()) return true; // Nothing to do if the called function is an old K&R-style function. const FunctionType* fn_type = GetCalleeFunctionType(expr); if (const FunctionProtoType* fn_proto = DynCastFrom(fn_type)) ReportIfReferenceVararg(expr->getArgs(), expr->getNumArgs(), fn_proto); return true; } bool VisitCXXConstructExpr(clang::CXXConstructExpr* expr) { if (CanIgnoreCurrentASTNode()) return true; ReportIfReferenceVararg(expr->getArgs(), expr->getNumArgs(), expr->getConstructor()); // 'Autocast' -- calling a one-arg, non-explicit constructor // -- is a special case when it's done for a function call. // iwyu requires the function-writer to provide the #include // for the casted-to type, just so we don't have to require it // here. *However*, the function-author can override this // iwyu requirement, in which case we're responsible for the // casted-to type. See IwyuBaseASTVisitor::VisitFunctionDecl. // Explicitly written CXXTemporaryObjectExpr are ignored here. if (expr->getStmtClass() == Stmt::StmtClass::CXXConstructExprClass) { const Type* type = Desugar(expr->getType().getTypePtr()); if (current_ast_node()->template HasAncestorOfType() && ContainsKey(GetCallerResponsibleTypesForAutocast(current_ast_node()), RemoveReferenceAsWritten(type))) { if (!CanIgnoreType(type)) ReportTypeUse(CurrentLoc(), type); } } return true; } // An OverloadExpr is an overloaded function (or method) in an // uninstantiated template, that can't be resolved until the // template is instantiated. The simplest case is something like: // void Foo(int) { ... } // void Foo(float) { ... } // template Fn(T t) { Foo(t); } // But by far the most common case is when the function-to-be-called // is also a templated function: // template Fn1(T t) { ... } // template Fn2(T t) { Fn1(t); } // In either case, we look at all the potential overloads. If they // all exist in the same file -- which is pretty much always the // case, especially with a template calling a template -- we can do // an iwyu warning now, even without knowing the exact overload. // In that case, we store the fact we warned, so we won't warn again // when the template is instantiated. // TODO(csilvers): to be really correct, we should report *every* // overload that callers couldn't match via ADL. bool VisitOverloadExpr(clang::OverloadExpr* expr) { // No CanIgnoreCurrentASTNode() check here! It's later in the function. // Make sure all overloads are in the same file. if (expr->decls_begin() == expr->decls_end()) // not sure this is possible return true; const NamedDecl* first_decl = *expr->decls_begin(); const FileEntry* first_decl_file_entry = GetFileEntry(first_decl); for (OverloadExpr::decls_iterator it = expr->decls_begin(); it != expr->decls_end(); ++it) { if (GetFileEntry(*it) != first_decl_file_entry) return true; } // For now, we're only worried about function calls. // TODO(csilvers): are there other kinds of overloads we need to check? const FunctionDecl* arbitrary_fn_decl = nullptr; for (OverloadExpr::decls_iterator it = expr->decls_begin(); it != expr->decls_end(); ++it) { const NamedDecl* decl = *it; // Sometimes a UsingShadowDecl comes between us and the 'real' decl. if (const UsingShadowDecl* using_shadow_decl = DynCastFrom(decl)) decl = using_shadow_decl->getTargetDecl(); if (const FunctionDecl* fn_decl = DynCastFrom(decl)) { arbitrary_fn_decl = fn_decl; break; } else if (const FunctionTemplateDecl* tpl_decl = DynCastFrom(decl)) { arbitrary_fn_decl = tpl_decl->getTemplatedDecl(); break; } } // If we're an overloaded operator, we can never do the iwyu check // before instantiation-time, because we don't know if we might // end up being the built-in form of the operator. (Even if the // only operator==() we see is in foo.h, we don't need to #include // foo.h if the only call to operator== we see is on two integers.) if (arbitrary_fn_decl && !arbitrary_fn_decl->isOverloadedOperator()) { AddProcessedOverloadLoc(CurrentLoc()); VERRS(7) << "Adding to processed_overload_locs: " << PrintableCurrentLoc() << "\n"; // Because processed_overload_locs might be set in one visitor // but used in another, each with a different definition of // CanIgnoreCurrentASTNode(), we have to be conservative and set // the has-considered flag always. But of course we only // actually report the function use if CanIgnoreCurrentASTNode() // is *currently* false. if (!CanIgnoreCurrentASTNode()) ReportDeclUse(CurrentLoc(), arbitrary_fn_decl); } return true; } // TODO(csilvers): handle some special cases when we're a // CXXDependentScopeMemberExpr (e.g. vector::resize().). If the // base class is a TemplateSpecializationType, get its TemplateDecl // and if all explicit specializations and patterns are defined in // the same file, treat it as an expr with only one decl. May have // trouble with methods defined in a different file than they're // declared. // If getOperatorNew() returns nullptr, it means the operator-new is // overloaded, and technically we can't know which operator-new is // being called until the template is instantiated. But if it looks // like a placement-new, we handle it at template-writing time // anyway. bool VisitCXXNewExpr(clang::CXXNewExpr* expr) { // Like in VisitOverloadExpr(), we update processed_overload_locs // regardless of the value of CanIgnoreCurrentASTNode(). // We say it's placement-new if the (lone) placment-arg is a // pointer. Unfortunately, often clang will just say it's a // dependent type. In that case, we can still say it's a pointer // in the (common) case the placement arg looks like '&something'. // (This is possibly wrong for classes that override operator&, but // those classes deserve what they get.) if (!expr->getOperatorNew() && expr->getNumPlacementArgs() == 1 && (GetTypeOf(expr->getPlacementArg(0))->isPointerType() || GetTypeOf(expr->getPlacementArg(0))->isArrayType() || IsAddressOf(expr->getPlacementArg(0)))) { // Treat this like an OverloadExpr. AddProcessedOverloadLoc(CurrentLoc()); VERRS(7) << "Adding to processed_overload_locs (placement-new): " << PrintableCurrentLoc() << "\n"; if (!CanIgnoreCurrentASTNode()) { // We have to 'make up' a full file path for 'new'. We'll // parse it to '' before using, so any path that does // that, and is clearly a c++ path, is fine; its exact // contents don't matter that much. using clang::OptionalFileEntryRef; const FileEntry* use_file = CurrentFileEntry(); OptionalFileEntryRef file = compiler()->getPreprocessor().LookupFile( CurrentLoc(), "new", true, nullptr, use_file, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, false); if (file) { preprocessor_info().FileInfoFor(use_file)->ReportFullSymbolUse( CurrentLoc(), *file, "operator new"); } } } // We also need to do a varargs check, like for other function calls. if (CanIgnoreCurrentASTNode()) return true; // ... only if this NewExpr involves a constructor call. const Expr* initializer = expr->getInitializer(); if (const CXXConstructExpr* cce = DynCastFrom(initializer)) { ReportIfReferenceVararg(cce->getArgs(), cce->getNumArgs(), cce->getConstructor()); } return true; } bool VisitDeclRefExpr(clang::DeclRefExpr* expr) { if (CanIgnoreCurrentASTNode()) return true; // Report EnumName instead of EnumName::Item. // It supports for removing EnumName forward- (opaque-) declarations // from output. if (const auto* enum_constant_decl = dyn_cast(expr->getDecl())) { const auto* enum_decl = cast(enum_constant_decl->getDeclContext()); // For unnamed enums, enumerator name is still preferred. if (enum_decl->getIdentifier()) ReportDeclUse(CurrentLoc(), enum_decl); else ReportDeclUse(CurrentLoc(), enum_constant_decl); } return true; } // When we call (or potentially call) a function, do an IWYU check // via ReportDeclUse() to make sure the definition of the function // is properly #included. bool HandleFunctionCall(FunctionDecl* callee, const Type* parent_type, const clang::Expr* calling_expr) { if (!Base::HandleFunctionCall(callee, parent_type, calling_expr)) return false; if (!callee || CanIgnoreCurrentASTNode() || CanIgnoreDecl(callee)) return true; // We may have already been checked in a previous // VisitOverloadExpr() call. Don't check again in that case. if (IsProcessedOverloadLoc(CurrentLoc())) return true; ReportDeclUse(CurrentLoc(), callee); // Usually the function-author is responsible for providing the // full type information for the return type of the function, but // in cases where it's not, we have to take responsibility. // TODO(csilvers): check the fn argument types as well. const Type* return_type = Desugar(callee->getReturnType().getTypePtr()); if (ContainsKey(GetCallerResponsibleTypesForFnReturn(callee), return_type)) { ReportTypeUse(CurrentLoc(), return_type); } return true; } //------------------------------------------------------------ // Visitors of types derived from clang::Type. bool VisitType(clang::Type* type) { // In VisitFunctionDecl(), we say all children of function // declarations are forward-declarable. This is true, *except* // for the exception (throw) types. We clean that up here. // TODO(csilvers): figure out how to do these two steps in one place. const FunctionProtoType* fn_type = nullptr; if (!fn_type) { fn_type = current_ast_node()->template GetParentAs(); } if (!fn_type) { if (const FunctionDecl* fn_decl = current_ast_node()->template GetParentAs()) fn_type = dyn_cast(GetTypeOf(fn_decl)); } if (fn_type) { for (FunctionProtoType::exception_iterator it = fn_type->exception_begin(); it != fn_type->exception_end(); ++it) if (it->getTypePtr() == type) { // *we're* an exception decl current_ast_node()->set_in_forward_declare_context(false); break; } } return true; } bool VisitTemplateSpecializationType(TemplateSpecializationType* type) { if (CanIgnoreCurrentASTNode() || CanIgnoreType(type)) return true; const NamedDecl* decl = TypeToDeclAsWritten(type); // If we are forward-declarable, so are our template arguments. if (CanForwardDeclareType(current_ast_node())) { ReportDeclForwardDeclareUse(CurrentLoc(), decl); current_ast_node()->set_in_forward_declare_context(true); } else { ReportDeclUse(CurrentLoc(), decl); } return true; } //------------------------------------------------------------ // Visitors defined by BaseAstVisitor. bool VisitNestedNameSpecifier(NestedNameSpecifier* nns) { if (!Base::VisitNestedNameSpecifier(nns)) return false; // If we're in an nns (e.g. the Foo in Foo::bar), we're never // forward-declarable, even if we're part of a pointer type, or in // a template argument, or whatever. current_ast_node()->set_in_forward_declare_context(false); return true; } // Template arguments are forward-declarable by default. However, // default template template args shouldn't be: we're responsible for // the full type info for default args. So no forward-declaring // MyClass in 'template class T = MyClass> C ...' // We detect because MyClass's parent is TemplateTemplateParmDecl. // TODO(csilvers): And not when they're a type that's in // known_fully_used_tpl_type_args_. See if that solves the problem with // I1_TemplateClass> i1_nested_templateclass(...) void DetermineForwardDeclareStatusForTemplateArg(ASTNode* ast_node) { CHECK_(ast_node->IsA() && "Should only pass in a template arg to DFDSFTA"); if (!IsDefaultTemplateTemplateArg(ast_node)) { ast_node->set_in_forward_declare_context(true); } } bool VisitTemplateArgument(const TemplateArgument& arg) { if (!Base::VisitTemplateArgument(arg)) return false; // Template arguments are forward-declarable...usually. DetermineForwardDeclareStatusForTemplateArg(current_ast_node()); return true; } bool VisitTemplateArgumentLoc(const TemplateArgumentLoc& argloc) { if (!Base::VisitTemplateArgumentLoc(argloc)) return false; // Template arguments are forward-declarable...usually. DetermineForwardDeclareStatusForTemplateArg(current_ast_node()); return true; } //------------------------------------------------------------ // Helper routines for visiting and traversing. These helpers // encode the logic of whether a particular type of object // can be forward-declared or not. // TODO(csilvers): get rid of in_forward_declare_context() and make // this the canonical place to figure out if we can forward-declare. bool CanForwardDeclareType(const ASTNode* ast_node) const { CHECK_(ast_node->IsA()); if (const auto* type = ast_node->GetAs()) { if (const auto* enum_type = type->getAs()) { return CanBeOpaqueDeclared(enum_type); } } // If we're in a forward-declare context, well then, there you have it. if (ast_node->in_forward_declare_context()) return true; // Another place we disregard what the language allows: if we're // a dependent type, in theory we can be forward-declared. But // we require the full definition anyway, so all the template // callers don't have to provide it instead. Thus we don't // run the following commented-out code (left here for reference): //if (ast_node->GetAs()->isDependentType()) // return false; // Read past elaborations like 'class' keyword or namespaces. ast_node = MostElaboratedAncestor(ast_node); // Now there are two options: either we are part of a type or we are part of // a declaration involving a type. const Type* parent_type = ast_node->GetParentAs(); if (parent_type == nullptr) { // It's not a type; analyze different kinds of declarations. if (const auto *decl = ast_node->GetParentAs()) { // We can shortcircuit static data member declarations immediately, // they can always be forward-declared. if (const auto *var_decl = dyn_cast(decl)) { if (!var_decl->isThisDeclarationADefinition() && var_decl->isStaticDataMember()) { return true; } } parent_type = GetTypeOf(decl); } else if (const auto *decl = ast_node->GetParentAs()) { // Elaborated types in type decls are always forward-declarable // (and usually count as forward declarations themselves). if (IsElaboratedTypeSpecifier(ast_node)) { return true; } // If we ourselves are a forward-decl -- that is, we're the type // component of a forward-declaration (which would be our parent // AST node) -- then we're forward-declarable by definition. if (const auto* parent_decl = ast_node->GetParentAs()) { if (IsForwardDecl(parent_decl)) return true; } // If we're part of a typedef declaration, 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()) { return false; } } } // TODO(csilvers): should probably just be IsPointerOrReference return parent_type && IsPointerOrReferenceAsWritten(parent_type); } protected: const IwyuPreprocessorInfo& preprocessor_info() const { return visitor_state_->preprocessor_info; } private: template friend class IwyuBaseAstVisitor; bool IsProcessedOverloadLoc(SourceLocation loc) const { return ContainsKey(visitor_state_->processed_overload_locs, loc); } void AddProcessedOverloadLoc(SourceLocation loc) { visitor_state_->processed_overload_locs.insert(loc); } // Report types needed for template instantiation in cases when template // specialization type isn't explicitly written in a source code // in a non-fwd-declarable context (otherwise, they should be reported from // VisitTemplateSpecializationType), e.g.: // template struct S { T t; }; // void fn(const S& s) { // Forward declarations are sufficient here. // (void)s.t; // Full 'Class' type is needed due to template instantiation. // } void ReportTplSpecComponentTypes(const TemplateSpecializationType*) = delete; // Do not add any variables here! If you do, they will not be shared // between the normal iwyu ast visitor and the // template-instantiation visitor, which is almost always a mistake. // Instead, add them to the VisitorState struct, above. VisitorState* const visitor_state_; }; // ---------------------------------------------------------------------- // --- InstantiatedTemplateVisitor // ---------------------------------------------------------------------- // // This class is used to find all template-specified types used in an // instantiated template class, function, or method -- or rather, all // such types that are used in a way that can't be forward-declared. // That is, for // template int Myfunc() { T* t; U u; Thirdclass z; } // if we saw an instantiation such as myfunc, we would pass // that instantiation to this traversal class, and it would report // that Bar is used in a non-forward-declarable way. (It would not // report Foo, which is used only in a forward-declarable way, and // would not report Thirdclass, which is not a type specified in a // template.) // // This class has two main entry points: one for instantiated // template functions and methods (including static methods, // constructor calls, and operator overloads), and one for // instantiated template classes. // // In each case, it is given the appropriate node from the AST that // captures the instantiation (a TemplateSpecializationType or // CallExpr), and returns a set of Type* nodes of types that are used // in a non-forward-declarable way. Note it's safe to call this even // on non-templatized functions and classes; we'll just always return // the empty set in that case. // // The traversal of the AST is done via RecursiveASTVisitor, which uses // CRTP (http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) // TODO(csilvers): move this to its own file? class InstantiatedTemplateVisitor : public IwyuBaseAstVisitor { public: typedef IwyuBaseAstVisitor Base; InstantiatedTemplateVisitor(VisitorState* visitor_state) : Base(visitor_state) { Clear(); } //------------------------------------------------------------ // Public entry points // ScanInstantiatedFunction() looks through the template definition of // the given function as well as the definitions of all functions // called from it (directly or indirectly) and records all template // type arguments fully used by them and all methods used by them. // The "fully used type arguments" are a subset of // tpl_type_args_of_interest, which are the types we care about, and // usually explicitly written at the call site. // // ScanInstantiatedType() is similar, except that it looks through // the definition of a class template instead of a statement. // resugar_map is a map from an unsugared (canonicalized) template // type to the template type as written (or as close as we can find // to it). If a type is not in resugar-map, it might be due to a // recursive template call and encode a template type we don't care // about ourselves. If it's in the resugar_map but with a nullptr // value, it's a default template parameter, that the // template-caller may or may not be responsible for. void ScanInstantiatedFunction( const FunctionDecl* fn_decl, const Type* parent_type, const ASTNode* caller_ast_node, const map& resugar_map) { Clear(); caller_ast_node_ = caller_ast_node; resugar_map_ = resugar_map; // Make sure that the caller didn't already put the decl on the ast-stack. CHECK_(caller_ast_node->GetAs() != fn_decl && "AST node already set"); // caller_ast_node requires a non-const ASTNode, but our node is // const. This cast is safe because we don't do anything with this // node (instead, we immediately push a new node on top of it). set_current_ast_node(const_cast(caller_ast_node)); TraverseExpandedTemplateFunctionHelper(fn_decl, parent_type); } // This isn't a Stmt, but sometimes we need to fully instantiate // a template class to get at a field of it, for instance: // MyClass::size_type s; void ScanInstantiatedType(ASTNode* caller_ast_node, const map& resugar_map) { Clear(); caller_ast_node_ = caller_ast_node; resugar_map_ = resugar_map; // The caller node *is* the current node, unlike ScanInstantiatedFunction // which instead starts in the context of the parent expression and relies // on a TraverseDecl call to push the decl to the top of the AST stack. set_current_ast_node(caller_ast_node); const TemplateSpecializationType* type = caller_ast_node->GetAs(); CHECK_(type != nullptr && "Not a template specialization"); // As in TraverseExpandedTemplateFunctionHelper, we ignore all AST nodes // that will be reported when we traverse the uninstantiated type. if (const NamedDecl* type_decl_as_written = GetDefinitionAsWritten(TypeToDeclAsWritten(type))) { AstFlattenerVisitor nodeset_getter(compiler()); nodes_to_ignore_ = nodeset_getter.GetNodesBelow( const_cast(type_decl_as_written)); } TraverseTemplateSpecializationType( const_cast(type)); } //------------------------------------------------------------ // Implements virtual methods from Base. // When checking a template instantiation, we don't care where the // template definition is, so we never have any reason to ignore a // node. bool CanIgnoreCurrentASTNode() const override { // TODO(csilvers): call CanIgnoreType() if we're a type. return nodes_to_ignore_.Contains(*current_ast_node()); } // For template instantiations, we want to print the symbol even if // it's not from the main compilation unit. bool ShouldPrintSymbolFromCurrentFile() const override { return GlobalFlags().verbose >= 5; } string GetSymbolAnnotation() const override { return " in tpl"; } bool CanIgnoreType(const Type* type, IgnoreKind ignore_kind = IgnoreKind::ForUse) const override { if (!IsTypeInteresting(type)) return true; switch (ignore_kind) { case IgnoreKind::ForUse: if (!IsKnownTemplateParam(type)) return true; break; case IgnoreKind::ForExpansion: if (!InvolvesKnownTemplateParam(type)) return true; break; } // If we're a default template argument, we should ignore the type // if the template author intend-to-provide it, but otherwise we // should not ignore it -- the caller is responsible for the type. // This captures cases like hash_set, where the caller is // responsible for defining hash. // IsProvidedByTemplate handles the case we // have a templated class that #includes "foo.h" and has a // scoped_ptr: we say the templated class provides Foo, even // though it's scoped_ptr.h that's actually trying to call // Foo::Foo and ::~Foo. // TODO(csilvers): this isn't ideal: ideally we'd want // 'TheInstantiatedTemplateForWhichTypeWasADefaultTemplateArgumentIntendsToProvide', // but clang doesn't store that information. return IsDefaultTemplateParameter(type) && IsProvidedByTemplate(type); } bool IsTypeInteresting(const Type* type) const { // We only care about types that would have been dependent in the // uninstantiated template: that is, SubstTemplateTypeParmType types // or types derived from them. We use nodes_to_ignore_ to select down // to those. return !nodes_to_ignore_.Contains(type); } bool IsKnownTemplateParam(const Type* type) const { // Among all subst-type params, we only want those in the resugar-map. If // we're not in the resugar-map at all, we're not a type corresponding to // the template being instantiated, so we can be ignored. type = Desugar(type); return ContainsKey(resugar_map_, type); } bool InvolvesKnownTemplateParam(const Type* type) const { return InvolvesTypeForWhich( type, [&](const Type* type) { return IsKnownTemplateParam(type); }); } // We ignore function calls in nodes_to_ignore_, which were already // handled by the template-as-written, and function names that we // are not responsible for because the template code is (for // instance, we're not responsible for a vector's call to // allocator::allocator(), because provides it for us). bool CanIgnoreDecl(const Decl* decl) const override { if (!decl) return true; return nodes_to_ignore_.Contains(decl); } // We always attribute type uses to the template instantiator. For // decls, we do unless it looks like the template "intends to // provide" the decl, by #including the file that defines the decl // (if templates call other templates, we have to find the right // template). void ReportDeclUse(SourceLocation used_loc, const NamedDecl* decl, const char* comment = nullptr, UseFlags extra_use_flags = 0) override { const SourceLocation actual_used_loc = GetLocOfTemplateThatProvides(decl); if (actual_used_loc.isValid()) { // If a template is responsible for this decl, then we don't add // it to the cache; the cache is only for decls that the // original caller is responsible for. Base::ReportDeclUse(actual_used_loc, decl, comment, extra_use_flags); } else { // Let all the currently active types and decls know about this // report, so they can update their cache entries. for (CacheStoringScope* storer : cache_storers_) storer->NoteReportedDecl(decl); Base::ReportDeclUse(caller_loc(), decl, comment, extra_use_flags); } } void ReportTypeUse(SourceLocation used_loc, const Type* type, const char* comment = nullptr) override { // clang desugars template types, so Foo() gets turned // into Foo(). Try to convert back. type = ResugarType(type); for (CacheStoringScope* storer : cache_storers_) storer->NoteReportedType(type); Base::ReportTypeUse(caller_loc(), type, comment); } //------------------------------------------------------------ // Overridden traverse-style methods from Base. // The 'convenience' HandleFunctionCall is perfect for us! bool HandleFunctionCall(FunctionDecl* callee, const Type* parent_type, const clang::Expr* calling_expr) { if (const Type* resugared_type = ResugarType(parent_type)) parent_type = resugared_type; if (!Base::HandleFunctionCall(callee, parent_type, calling_expr)) return false; if (!callee || CanIgnoreCurrentASTNode() || CanIgnoreDecl(callee)) return true; return TraverseExpandedTemplateFunctionHelper(callee, parent_type); } bool TraverseUnaryExprOrTypeTraitExpr(clang::UnaryExprOrTypeTraitExpr* expr) { if (!Base::TraverseUnaryExprOrTypeTraitExpr(expr)) return false; if (CanIgnoreCurrentASTNode()) return true; const Type* arg_type = expr->getTypeOfArgument().getTypePtr(); // Calling sizeof on a reference-to-X is the same as calling it on X. if (const auto* reftype = arg_type->getAs()) { arg_type = reftype->getPointeeTypeAsWritten().getTypePtr(); } if (const auto* type = arg_type->getAs()) { // Even though sizeof(MyClass) only requires knowing how much // storage MyClass takes, the language seems to require that // MyClass be fully instantiated, even typedefs. (Try // compiling 'template struct C { typedef typename T::a t; }; // class S; int main() { return sizeof(C); }'.) return TraverseDataAndTypeMembersOfClassHelper(type); } return true; } bool TraverseTemplateSpecializationTypeHelper( const TemplateSpecializationType* type) { if (CanIgnoreCurrentASTNode()) return true; // Skip the template traversal if this occurrence of the template name is // just a class qualifier for an out of line method, as opposed to an object // instantiation, where the templated code would need to be inspected. // // Class::method() { // |-Type---^ // |-NNS------^ // |-CXXMethodDecl--^ ASTNode* ast_node = current_ast_node(); if (const auto* nns = ast_node->GetParentAs()) { if (nns->getAsType() == type) { if (const auto* method = ast_node->GetAncestorAs(2)) { CHECK_(nns == method->getQualifier()); return true; } } } if (CanForwardDeclareType(ast_node)) ast_node->set_in_forward_declare_context(true); return TraverseDataAndTypeMembersOfClassHelper(type); } bool TraverseTemplateSpecializationType(TemplateSpecializationType* type) { if (!Base::TraverseTemplateSpecializationType(type)) return false; return TraverseTemplateSpecializationTypeHelper(type); } bool TraverseTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc typeloc) { if (!Base::TraverseTemplateSpecializationTypeLoc(typeloc)) return false; return TraverseTemplateSpecializationTypeHelper(typeloc.getTypePtr()); } bool TraverseSubstTemplateTypeParmTypeHelper( const clang::SubstTemplateTypeParmType* type) { if (CanIgnoreCurrentASTNode() || CanIgnoreType(type, IgnoreKind::ForExpansion)) return true; const Type* actual_type = ResugarType(type); CHECK_(actual_type && "If !CanIgnoreType(), we should be resugar-able"); return TraverseType(QualType(actual_type, 0)); } // When we see a template argument used inside an instantiated // template, we want to explore the type recursively. For instance // if we see Inner>(), we want to recurse onto Foo. bool TraverseSubstTemplateTypeParmType( clang::SubstTemplateTypeParmType* type) { if (!Base::TraverseSubstTemplateTypeParmType(type)) return false; return TraverseSubstTemplateTypeParmTypeHelper(type); } bool TraverseSubstTemplateTypeParmTypeLoc( clang::SubstTemplateTypeParmTypeLoc typeloc) { if (!Base::TraverseSubstTemplateTypeParmTypeLoc(typeloc)) return false; return TraverseSubstTemplateTypeParmTypeHelper(typeloc.getTypePtr()); } // Check whether a use of a template parameter is a full use. bool IsTemplateTypeParmUseFullUse(const Type* type) { const ASTNode* node = MostElaboratedAncestor(current_ast_node()); // If we're a nested-name-specifier class (the Foo in Foo::bar), // we need our full type info no matter what the context (even if // we're a pointer, or a template arg, or whatever). // TODO(csilvers): consider encoding this logic via // in_forward_declare_context. I think this will require changing // in_forward_declare_context to yes/no/maybe. if (node->ParentIsA()) { return true; } // If we're inside a typedef, we don't need our full type info -- // in this case we follow what the C++ language allows and let // the underlying type of a typedef be forward-declared. This has // the effect that code like: // class MyClass; // template struct Foo { typedef T value_type; ... } // Foo f; // does not make us require the full type of MyClass. The idea // is that using Foo::value_type already requires the // type for MyClass, so it doesn't make sense for the typedef // to require it as well. TODO(csilvers): this doesn't really // make any sense. Who figures out we need the full type if // you do 'Foo::value_type m;'? for (const ASTNode* ast_node = node; ast_node != caller_ast_node_; ast_node = ast_node->parent()) { if (ast_node->IsA()) { return false; } if (ast_node->IsA()) { // If we hit a template specialization node before the typedef then we // probably still need a full-use, so stop looking. break; } } // sizeof(a reference type) is the same as sizeof(underlying type). // We have to handle that specially here, or else we'll say the // reference is forward-declarable, below. if (node->ParentIsA() && isa(type)) { return true; } // If we're used in a forward-declare context (MyFunc() { T* t; }), // or are ourselves a pointer type (MyFunc()), // we don't need to do anything: we're fine being forward-declared. if (node->in_forward_declare_context()) return false; if (node->ParentIsA() || node->ParentIsA() || IsPointerOrReferenceAsWritten(type)) return false; return true; } // This helper is called on every use of a template argument type in an // instantiated template. Its goal is to determine whether that use should // constitute a full-use by the template caller, and perform other necessary // bookkeeping. void AnalyzeTemplateTypeParmUse(const Type* type) { const ASTNode* node = MostElaboratedAncestor(current_ast_node()); // If the immediate parent node is a typedef, then register the new type as // a new name for the template argument. if (const TypedefNameDecl* typedef_decl = node->GetParentAs()) { const Type* typedef_type = typedef_decl->getTypeForDecl(); VERRS(6) << "Registering " << PrintableType(typedef_type) << " as an alias for " << PrintableType(type) << " in the context of this instantiation\n"; template_argument_aliases_.emplace(typedef_type, type); } // Figure out how this type was actually written. clang always // canonicalizes SubstTemplateTypeParmType, losing typedef info, etc. const Type* actual_type = ResugarType(type); CHECK_(actual_type && "Type passed to AnalyzeTemplateTypeParmUse should be resugar-able"); VERRS(6) << "AnalyzeTemplateTypeParmUse: type = " << PrintableType(type) << ", actual_type = " << PrintableType(actual_type) << '\n'; if (!IsTemplateTypeParmUseFullUse(actual_type)) { // Non-full uses will already have been reported when they were used as // template arguments, so nothing to do here. return; } if (isa(actual_type)) { // If the argument type is a reference type, then we actually care about // the referred-to type. const ReferenceType* actual_reftype = cast(actual_type); type = actual_reftype->getPointeeTypeAsWritten().getTypePtr(); } // At this point we know we are looking at a full-use of type. However, // there are still two cases. If this is a template param that was written // by the user, then we report a use of it. However, it might also be a // parameter of some implementation detail template which just happens top // involve the user's template parameter somehow. In this case, we need to // recursively explore the instantiation of *that* template to see if the // user's type is full-used therein. if (IsKnownTemplateParam(type)) { // We attribute all uses in an instantiated template to the // template's caller. ReportTypeUse(caller_loc(), type); // Also report all previous explicit instantiations (declarations and // definitions) as uses of the caller's location. ReportExplicitInstantiations(type); } else { const Decl* decl = TypeToDeclAsWritten(type); if (const auto* cts_decl = dyn_cast(decl)) { if (ContainsKey(traversed_decls_, decl)) return; // avoid recursion & repetition traversed_decls_.insert(decl); VERRS(6) << "Recursively traversing " << PrintableDecl(cts_decl) << " which was full-used and involves a known template param\n"; TraverseDecl(const_cast(cts_decl)); } } } // Our task is made easier since (at least in theory), every time we // instantiate a template type, the instantiation has type // SubstTemplateTypeParmTypeLoc in the AST tree. bool VisitSubstTemplateTypeParmType(clang::SubstTemplateTypeParmType* type) { if (CanIgnoreCurrentASTNode() || CanIgnoreType(type, IgnoreKind::ForExpansion)) return true; AnalyzeTemplateTypeParmUse(type); return Base::VisitSubstTemplateTypeParmType(type); } bool VisitTypedefType(clang::TypedefType* type) { if (CanIgnoreCurrentASTNode()) return true; // Typedefs of template arguments require special handling to ensure that // we record full-uses of those arguments where appropriate. Those // typedefs are stored in the template_argument_aliases_ map. if (const Type* template_arg_type = GetOrDefault(template_argument_aliases_, type, nullptr)) { AnalyzeTemplateTypeParmUse(template_arg_type); } return Base::VisitTypedefType(type); } bool VisitTemplateSpecializationType(TemplateSpecializationType* type) { if (CanIgnoreCurrentASTNode()) return true; CHECK_(current_ast_node()->GetAs() == type) << "The current node must be equal to the template spec. type"; // Report previous explicit instantiations here, only if the type is needed // fully. if (!CanForwardDeclareType(current_ast_node())) ReportExplicitInstantiations(type); return Base::VisitTemplateSpecializationType(type); } void ReportExplicitInstantiations(const Type* type) { const auto* decl = dyn_cast_or_null( TypeToDeclAsWritten(type)); if (decl == nullptr) return; // Go through all previous redecls and filter out those that are not // explicit template instantiations or already provided by the template. for (const NamedDecl* redecl : decl->redecls()) { if (!IsExplicitInstantiation(redecl) || !GlobalSourceManager()->isBeforeInTranslationUnit( redecl->getLocation(), caller_loc()) || IsProvidedByTemplate(decl)) continue; // Report the specific decl that points to the explicit instantiation Base::ReportDeclUse(caller_loc(), redecl, "(for explicit instantiation)", UF_ExplicitInstantiation); } } // If constructing an object, check the type we're constructing. // Normally we'd see that type later, when traversing the return // type of the constructor-decl, but if we wait for that, we'll lose // any SubstTemplateTypeParmType's we have (we lose all // SubstTemplateTypeParmType's going from Expr to Decl). // TODO(csilvers): This should maybe move to HandleFunctionCall. bool VisitCXXConstructExpr(clang::CXXConstructExpr* expr) { if (CanIgnoreCurrentASTNode()) return true; const Type* class_type = GetTypeOf(expr); if (CanIgnoreType(class_type)) return true; // If the ctor type is a SubstTemplateTypeParmType, get the type-as-written. const Type* actual_type = ResugarType(class_type); CHECK_(actual_type && "If !CanIgnoreType(), we should be resugar-able"); ReportTypeUse(caller_loc(), actual_type); return Base::VisitCXXConstructExpr(expr); } // --- Handler declared in IwyuBaseASTVisitor. void ReportTplSpecComponentTypes(const TemplateSpecializationType* type) { TraverseDataAndTypeMembersOfClassHelper(type); } private: // Clears the state of the visitor. void Clear() { caller_ast_node_ = nullptr; resugar_map_.clear(); template_argument_aliases_.clear(); traversed_decls_.clear(); nodes_to_ignore_.clear(); cache_storers_.clear(); } // If we see the instantiated template using a type or decl (such as // std::allocator), we want to know if the author of the template is // providing the type or decl, so the code using the instantiated // template doesn't have to. For instance: // vector*/> v; // in foo.cc // Does provide the definition of allocator? If not, // foo.cc will have to #include . // We say the template-as-written does provide the decl if it, or // any other header seen since we started instantiating the // template, sees it. The latter requirement is to deal with a // situation like this: we have a templated class that #includes // "foo.h" and has a scoped_ptr; we say the templated class // provides Foo, even though it's scoped_ptr.h that's actually // trying to call Foo::Foo and Foo::~Foo. SourceLocation GetLocOfTemplateThatProvides(const NamedDecl* decl) const { if (!decl) return SourceLocation(); // an invalid source-loc for (const ASTNode* ast_node = current_ast_node(); ast_node != caller_ast_node_; ast_node = ast_node->parent()) { if (preprocessor_info().PublicHeaderIntendsToProvide( GetFileEntry(ast_node->GetLocation()), GetFileEntry(decl->getLocation()))) return ast_node->GetLocation(); } return SourceLocation(); // an invalid source-loc } bool IsProvidedByTemplate(const NamedDecl* decl) const { return GetLocOfTemplateThatProvides(decl).isValid(); } bool IsProvidedByTemplate(const Type* type) const { type = Desugar(type); type = RemovePointersAndReferences(type); // get down to the decl if (const NamedDecl* decl = TypeToDeclAsWritten(type)) { decl = GetDefinitionAsWritten(decl); return GetLocOfTemplateThatProvides(decl).isValid(); } return true; // we always provide non-decl types like int, etc. } // For a SubstTemplateTypeParmType, says whether it corresponds to a // default template parameter (one not explicitly specified when the // class was instantiated) or not. We store this in resugar_map by // having the value be nullptr. bool IsDefaultTemplateParameter(const Type* type) const { type = Desugar(type); return ContainsKeyValue(resugar_map_, type, static_cast(nullptr)); } // clang desugars template types, so Foo() gets turned // into Foo(). We can 'resugar' using resugar_map_. // If we're not in the resugar-map, then we weren't canonicalized, // so we can just use the input type unchanged. const Type* ResugarType(const Type* type) const { type = Desugar(type); // If we're the resugar-map but with a value of nullptr, it means // we're a default template arg, which means we don't have anything // to resugar to. So just return the input type. if (ContainsKeyValue(resugar_map_, type, static_cast(nullptr))) return type; return GetOrDefault(resugar_map_, type, type); } bool TraverseExpandedTemplateFunctionHelper(const FunctionDecl* fn_decl, const Type* parent_type) { if (!fn_decl || ContainsKey(traversed_decls_, fn_decl)) return true; // avoid recursion and repetition traversed_decls_.insert(fn_decl); // If we have cached the reporting done for this decl before, // report again (but with the new caller_loc this time). // Otherwise, for all reporting done in the rest of this scope, // store in the cache for this function. if (ReplayUsesFromCache(*FunctionCallsFullUseCache(), fn_decl, caller_loc())) return true; // Make sure all the types we report in the recursive TraverseDecl // calls, below, end up in the cache for fn_decl. CacheStoringScope css(&cache_storers_, FunctionCallsFullUseCache(), fn_decl, resugar_map_); // We want to ignore all nodes that are the same in this // instantiated function as they are in the uninstantiated version // of the function. The latter will be reported when we traverse // the uninstantiated function, so we don't need to re-traverse // them here. AstFlattenerVisitor nodeset_getter(compiler()); // This gets to the decl for the (uninstantiated) template-as-written: const FunctionDecl* decl_as_written = fn_decl->getTemplateInstantiationPattern(); if (!decl_as_written) { if (fn_decl->isImplicit()) { // TIP not set up for implicit methods // TODO(csilvers): handle implicit template methods } else { // not a templated decl decl_as_written = fn_decl; } } if (decl_as_written) { FunctionDecl* const daw = const_cast(decl_as_written); nodes_to_ignore_.AddAll(nodeset_getter.GetNodesBelow(daw)); } // We need to iterate over the function. if (!TraverseDecl(const_cast(fn_decl))) return false; // If we're a constructor, we also need to construct the entire class, // even typedefs that aren't used at construct time. Try compiling // template struct C { typedef typename T::a t; }; // class S; int main() { C c; } if (isa(fn_decl)) { CHECK_(parent_type && "How can a constructor have no parent?"); parent_type = Desugar(parent_type); if (!TraverseDataAndTypeMembersOfClassHelper( dyn_cast(parent_type))) return false; } return true; } // Does the actual recursing over data members and type members of // the instantiated class. Unlike // TraverseClassTemplateSpecializationDecl() in the base class, it // does *not* traverse the methods. bool TraverseDataAndTypeMembersOfClassHelper( const TemplateSpecializationType* type) { if (!type) return true; // No point in doing traversal if we're forward-declared if (current_ast_node()->in_forward_declare_context()) return true; while (type->isTypeAlias()) { type = type->getAliasedType()->getAs(); if (!type) return true; } // If we're a dependent type, we only try to be analyzed if we're // in the precomputed list -- in general, the only thing clang // tells us about dependent types is their name (which is all we // need for the precomputed list!). This means iwyu will properly // analyze the use of SomeClass in code like 'map', // but not in 'MyMap', since we have precomputed // information about the STL map<>, but not the user type MyMap. // TODO(csilvers): do better here. if (type->isDependentType()) { // TODO(csilvers): This is currently always a noop; need to fix // GetTplTypeResugarMapForClassNoComponentTypes to do something // useful for dependent types. ReplayClassMemberUsesFromPrecomputedList(type); // best-effort return true; } const NamedDecl* named_decl = TypeToDeclAsWritten(type); const ClassTemplateSpecializationDecl* class_decl = DynCastFrom(named_decl); // Bail out if we are not a proper class if (class_decl == nullptr) { // If the template specialization decl is not sugar for a class, we // expect it to be another kind of template decl, like a built-in. // Also in some rare cases named_decl can be a record decl (e.g. when // using the built-in __type_pack_element). CHECK_(llvm::isa(named_decl) || llvm::isa(named_decl)) << "TemplateSpecializationType has no decl of type TemplateDecl or " "RecordDecl?"; return true; } if (ContainsKey(traversed_decls_, class_decl)) return true; // avoid recursion & repetition traversed_decls_.insert(class_decl); // If we have cached the reporting done for this decl before, // report again (but with the new caller_loc this time). // Otherwise, for all reporting done in the rest of this scope, // store in the cache for this function. if (ReplayUsesFromCache(*ClassMembersFullUseCache(), class_decl, caller_loc())) return true; if (ReplayClassMemberUsesFromPrecomputedList(type)) return true; // Make sure all the types we report in the recursive TraverseDecl // calls, below, end up in the cache for class_decl. CacheStoringScope css(&cache_storers_, ClassMembersFullUseCache(), class_decl, resugar_map_); for (DeclContext::decl_iterator it = class_decl->decls_begin(); it != class_decl->decls_end(); ++it) { if (isa(*it) || isa(*it)) continue; if (!TraverseDecl(*it)) return false; } // Most methods on template classes are instantiated when they're // called, and we don't need to deal with them here. But virtual // methods are instantiated when the class's key method is // instantiated, and since template classes rarely have a key // method, it means they're instantiated whenever the class is // instantiated. So we need to instantiate virtual methods here. for (DeclContext::decl_iterator it = class_decl->decls_begin(); it != class_decl->decls_end(); ++it) { if (const CXXMethodDecl* method_decl = DynCastFrom(*it)) { if (method_decl->isVirtual()) { if (!TraverseExpandedTemplateFunctionHelper(method_decl, type)) return false; } } } return true; } //------------------------------------------------------------ // Cache methods. Caches hold the list of full uses found when we // last instantiated a given decl, saving a lot of tree-walking if // we have to do it again. // Returns true if we replayed uses, false if key isn't in the cache. bool ReplayUsesFromCache(const FullUseCache& cache, const NamedDecl* key, SourceLocation use_loc) { if (!cache.Contains(key, resugar_map_)) return false; VERRS(6) << "(Replaying full-use information from the cache for " << key->getQualifiedNameAsString() << ")\n"; ReportTypesUse(use_loc, cache.GetFullUseTypes(key, resugar_map_)); ReportDeclsUse(use_loc, cache.GetFullUseDecls(key, resugar_map_)); return true; } // We precompute (hard-code) results of calling // TraverseDataAndTypeMembersOfClassHelper for some types (mostly // STL types). This way we don't even need to traverse them once. // Returns true iff we did appropriate reporting for this type. bool ReplayClassMemberUsesFromPrecomputedList( const TemplateSpecializationType* tpl_type) { if (current_ast_node() && current_ast_node()->in_forward_declare_context()) return true; // never depend on any types if a fwd-decl const NamedDecl* tpl_decl = TypeToDeclAsWritten(tpl_type); // This says how the template-args are used by this hard-coded type // (a set<>, or map<>, or ...), to avoid having to recurse into them. const map& resugar_map_for_precomputed_type = FullUseCache::GetPrecomputedResugarMap(tpl_type); // But we need to reconcile that with the types-of-interest, as // stored in resugar_map_. To do this, we take only those entries // from resugar_map_for_precomputed_type that are also present in // resugar_map_. We consider type components, so if // resugar_map_for_precomputed_type has less_than or hash, // we'll add those in even if resugar_map_ only includes 'Foo'. map resugar_map; for (const auto& item : resugar_map_for_precomputed_type) { // TODO(csilvers): for default template args, item.first is sometimes // a RecordType even when it's a template specialization. Figure out // how to get the proper type components in that situation. const set type_components = GetComponentsOfType(item.first); if (ContainsAnyKey(resugar_map_, type_components)) { resugar_map.insert(item); } } if (resugar_map.empty()) return false; VERRS(6) << "(Using pre-computed list of full-use information for " << tpl_decl->getQualifiedNameAsString() << ")\n"; // For entries with a non-nullptr value, we report the value, which // is the unsugared type, as being fully used. Entries with a // nullptr value are default template args, and we only report them // if the template class doesn't intend-to-provide them. for (const auto& item : resugar_map) { const Type* resugared_type = nullptr; if (item.second) { resugared_type = item.second; } else { const NamedDecl* resugared_decl = TypeToDeclAsWritten(item.first); if (!preprocessor_info().PublicHeaderIntendsToProvide( GetFileEntry(tpl_decl), GetFileEntry(resugared_decl))) resugared_type = item.first; } if (resugared_type && !resugared_type->isPointerType()) { ReportTypeUse(caller_loc(), resugared_type); // For a templated type, check the template args as well. if (const TemplateSpecializationType* spec_type = DynCastFrom(resugared_type)) { TraverseDataAndTypeMembersOfClassHelper(spec_type); } } } return true; } //------------------------------------------------------------ // Member accessors. SourceLocation caller_loc() const { return caller_ast_node_->GetLocation(); } //------------------------------------------------------------ // Member variables. // The AST-chain when this template was instantiated. const ASTNode* caller_ast_node_; // resugar_map is a map from an unsugared (canonicalized) template // type to the template type as written (or as close as we can find // to it). If a type is not in resugar-map, it might be due to a // recursive template call and encode a template type we don't care // about ourselves. If it's in the resugar_map but with a nullptr // value, it's a default template parameter, that the // template-caller may or may not be responsible for. map resugar_map_; // When we see a full-use of a template argument we need to assign that full // use to the template-caller. Sometimes those uses are hidden behind // type aliases (typedefs). This maps those aliases to the underlying // template arguments. map template_argument_aliases_; // Used to avoid recursion in the *Helper() methods. set traversed_decls_; AstFlattenerVisitor::NodeSet nodes_to_ignore_; // The current set of nodes we're updating cache entries for. set cache_storers_; }; // class InstantiatedTemplateVisitor // ---------------------------------------------------------------------- // --- IwyuAstConsumer // ---------------------------------------------------------------------- // // This class listens to Clang's events as the AST is generated. // // The traversal of the AST is done via RecursiveASTVisitor, which uses // CRTP (http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) class IwyuAstConsumer : public ASTConsumer, public IwyuBaseAstVisitor { public: typedef IwyuBaseAstVisitor Base; IwyuAstConsumer(VisitorState* visitor_state) : Base(visitor_state), instantiated_template_visitor_(visitor_state) {} //------------------------------------------------------------ // Implements pure virtual methods from Base. // Returns true if we are not interested in symbols used in used_in // for whatever reason. For instance, we can ignore nodes that are // neither in the file we're compiling nor in its associated .h file. bool CanIgnoreCurrentASTNode() const override { // If we're outside of foo.{h,cc} and the set of check_also files, // just ignore. if (CanIgnoreLocation(current_ast_node()->GetLocation())) return true; // TODO(csilvers): if we're a type, call CanIgnoreType(). return false; } // We print symbols from files in the main compilation unit (foo.cc, // foo.h, foo-inl.h) if the debug level is 5 or 6, for non-system // files if the debug level is 7, and all files if the debug level // is 8 or more. bool ShouldPrintSymbolFromCurrentFile() const override { return ShouldPrintSymbolFromFile(CurrentFileEntry()); } string GetSymbolAnnotation() const override { return ""; } // We are interested in all types for iwyu checking. bool CanIgnoreType(const Type* type, IgnoreKind) const override { return type == nullptr; } bool CanIgnoreDecl(const Decl* decl) const override { return decl == nullptr; } //------------------------------------------------------------ // Parser event handlers. Clang will call them to notify this // ASTConsumer as it parses the source code. See class ASTConsumer in // clang/AST/ASTConsumer.h // for all the handlers we can override. // Called once at the beginning of the compilation. void Initialize(ASTContext& context) override {} // NOLINT // Called once at the end of the compilation. void HandleTranslationUnit(ASTContext& context) override { // NOLINT // TODO(csilvers): automatically detect preprocessing is done, somehow. const_cast(&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(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); // 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. if (compiler()->getDiagnostics().hasUnrecoverableErrorOccurred()) exit(EXIT_FAILURE); const set* const files_to_report_iwyu_violations_for = preprocessor_info().files_to_report_iwyu_violations_for(); // Some analysis, such as UsingDecl resolution, is deferred until the // entire AST is visited because it's only at that point that we know if // the symbol was actually used or not. // We perform that analysis here before CalculateAndReportIwyuViolations. for (const FileEntry* file : *files_to_report_iwyu_violations_for) { CHECK_(preprocessor_info().FileInfoFor(file)); preprocessor_info().FileInfoFor(file)->ResolvePendingAnalysis(); } // We have to calculate the .h files before the .cc file, since // the .cc file inherits #includes from the .h files, and we // need to figure out what those #includes are going to be. size_t num_edits = 0; const FileEntry* const main_file = preprocessor_info().main_file(); for (const FileEntry* file : *files_to_report_iwyu_violations_for) { if (file == main_file) continue; CHECK_(preprocessor_info().FileInfoFor(file)); num_edits += preprocessor_info().FileInfoFor(file) ->CalculateAndReportIwyuViolations(); } CHECK_(preprocessor_info().FileInfoFor(main_file)); num_edits += preprocessor_info().FileInfoFor(main_file) ->CalculateAndReportIwyuViolations(); int exit_code = EXIT_SUCCESS; if (GlobalFlags().exit_code_always) { // If we should always fail, use --error_always value. exit_code = GlobalFlags().exit_code_always; } else if (num_edits > 0) { // If there were IWYU violations, use --error value. exit_code = GlobalFlags().exit_code_error; } exit(exit_code); } void ParseFunctionTemplates(Sema& sema, TranslationUnitDecl* tu_decl) { set 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 // they came from. CHECK_((compiler()->getLangOpts().DelayedTemplateParsing || late_parsed_decls.empty()) && "Should not have late-parsed decls without " "-fdelayed-template-parsing."); for (const FunctionDecl* fd : late_parsed_decls) { CHECK_(fd->isLateTemplateParsed()); if (CanIgnoreLocation(GetLocation(fd))) continue; // Force parsing and AST building of the yet-uninstantiated function // template body. clang::LateParsedTemplate* lpt = sema.LateParsedTemplateMap[fd].get(); sema.LateTemplateParser(sema.OpaqueParser, *lpt); } } void InstantiateImplicitMethods(Sema& sema, TranslationUnitDecl* tu_decl) { // Collect all implicit ctors/dtors that need to be instantiated. struct Visitor : public RecursiveASTVisitor { 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 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(method)) { sema.DefineImplicitDefaultConstructor(loc, ctor); } else if (auto* dtor = dyn_cast(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: // clang/AST/DeclNodes.def // clang/AST/StmtNodes.td // clang/AST/TypeNodes.def // We exclude only: // 1) abstract declarations and types with no logic (e.g. NamedDecl) // 2) ObjC declarations, statements, and types (e.g. ObjcIvarDecl) // RecursiveASTVisitor defines specialized visitors for each specific // math operation (MulAssign, OffsetOf, etc). We don't override // those callbacks, but use their default behavior, which is to call // back to VisitUnaryOperator, VisitBinaryOperator, etc. // // Over time, as we understand when a callback is called and // which can be ignored by iwyu, we will pare down the list. // Each of these returns a bool: false if we want to abort the // traversal (we never do). For Visit*(), we can abort early if // we're not in the main compilation-unit, since we only ever give // iwyu warnings on symbols in those files. // --- Visitors of types derived from clang::Decl. bool VisitNamespaceAliasDecl(clang::NamespaceAliasDecl* decl) { if (CanIgnoreCurrentASTNode()) return true; ReportDeclUse(CurrentLoc(), decl->getNamespace()); return Base::VisitNamespaceAliasDecl(decl); } bool VisitUsingDecl(clang::UsingDecl* decl) { // The shadow decls hold the declarations for the var/fn/etc we're // using. (There may be more than one if, say, we're using an // overloaded function.) We don't want to add all of them at once // though, because that will drag in every overload even if we're // only using one. Instead, we keep track of the using decl and // mark it as touched when something actually uses it. IwyuFileInfo* file_info = preprocessor_info().FileInfoFor(CurrentFileEntry()); if (file_info) { file_info->AddUsingDecl(decl); } else { // For using declarations in a PCH, the preprocessor won't have any // location information. As far as we know, that's the only time the // file-info will be null, so assert that we have a PCH on the // command-line. const string& pch_include = compiler()->getInvocation().getPreprocessorOpts().ImplicitPCHInclude; CHECK_(!pch_include.empty()); } if (CanIgnoreCurrentASTNode()) return true; return Base::VisitUsingDecl(decl); } bool VisitTagDecl(clang::TagDecl* decl) { if (CanIgnoreCurrentASTNode()) return true; // Skip the injected class name. if (decl->isImplicit()) return Base::VisitTagDecl(decl); if (IsForwardDecl(decl)) { // If we're a templated class, make sure we add the whole template. const NamedDecl* decl_to_fwd_declare = decl; if (const CXXRecordDecl* cxx_decl = DynCastFrom(decl)) if (cxx_decl->getDescribedClassTemplate()) decl_to_fwd_declare = cxx_decl->getDescribedClassTemplate(); // We've found a forward-declaration. We'll report we've found // it, but we also want to report if we know already that we // should keep this forward-declaration around (and not consider // it for deletion if it's never used). There are a few // situations we can do this, described below. bool definitely_keep_fwd_decl = false; // (1) If the forward-decl has a linkage spec ('extern "C"') // then it can't be removed, since that information probably // isn't encoded anywhere else. // (Surprisingly classes can have linkage specs! -- they are // applied to all static methods of the class. See // http://msdn.microsoft.com/en-us/library/ms882260.aspx.) if (current_ast_node()->ParentIsA()) { definitely_keep_fwd_decl = true; // (2) GCC-style __attributes__ work the same way: we can't assume // that attributes are consistent between declarations, so we can't // remove a decl with attributes unless they're inherited, i.e. propagated // from another redeclaration as opposed to explicitly written. } else if (decl->hasAttrs()) { for (const Attr* attr : decl->getAttrs()) { if (!attr->isInherited()) { definitely_keep_fwd_decl = true; break; } } // (3) If we're a nested class ("class A { class SubA; };"), // then we can't necessary be removed either, since we're part // of the public API of the enclosing class -- it's illegal to // have a nested class and not at least declare it in the // enclosing class. If the nested class is actually defined in // the enclosing class, then we're fine; if not, we need to keep // the first forward-declaration. } else if (IsNestedTagAsWritten(current_ast_node())) { if (!decl->getDefinition() || decl->getDefinition()->isOutOfLine()) { // TODO(kimgr): Member class redeclarations are illegal, per C++ // standard DR85, so this check for first redecl can be removed. // Nested classes should always be definitely kept. More details here: // http://comments.gmane.org/gmane.comp.compilers.clang.scm/74782 // GCC and MSVC both still allow redeclarations of nested classes, // though, so it seems hygienic to remove all but one. if (const NamedDecl* first_decl = GetFirstRedecl(decl)) { // Check if we're the decl with the smallest line number. if (decl == first_decl) definitely_keep_fwd_decl = true; } } } else if (preprocessor_info().ForwardDeclareIsMarkedKeep(decl)) { definitely_keep_fwd_decl = true; } else if (preprocessor_info().ForwardDeclareIsExported(decl)) { definitely_keep_fwd_decl = true; } preprocessor_info().FileInfoFor(CurrentFileEntry())->AddForwardDeclare( decl_to_fwd_declare, definitely_keep_fwd_decl); } return Base::VisitTagDecl(decl); } // If you specialize a template, you need a declaration of the // template you're specializing. That is, for code like this: // template struct Foo; // template<> struct Foo { ... }; // we don't want iwyu to recommend removing the 'forward declare' of Foo. // // Additionally, this type of decl is also used to represent explicit template // instantiations, in which case we want the full type, not only a forward // declaration. bool VisitClassTemplateSpecializationDecl( clang::ClassTemplateSpecializationDecl* decl) { if (CanIgnoreCurrentASTNode()) return true; ClassTemplateDecl* specialized_decl = decl->getSpecializedTemplate(); if (IsExplicitInstantiation(decl)) ReportDeclUse(CurrentLoc(), specialized_decl); else ReportDeclForwardDeclareUse(CurrentLoc(), specialized_decl); return Base::VisitClassTemplateSpecializationDecl(decl); } // Track use of namespace in using directive decl // a.h: // namespace a { ... }; // // b.cpp: // include "a.h" // using namespace a; // ... bool VisitUsingDirectiveDecl(clang::UsingDirectiveDecl *decl) { if (CanIgnoreCurrentASTNode()) return true; ReportDeclUse(CurrentLoc(), decl->getNominatedNamespaceAsWritten()); return Base::VisitUsingDirectiveDecl(decl); } // If you say 'typedef Foo Bar', then clients can use Bar however // they want without having to worry about #including anything // except you. That puts you on the hook for all the #includes that // Bar might need, for *anything* one might want to do to a Bar. // 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 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); // We simulate a user calling all the methods in a class. if (const CXXRecordDecl* record_decl = DynCastFrom(underlying_decl)) { for (DeclContext::decl_iterator it = record_decl->decls_begin(); it != record_decl->decls_end(); ++it) { FunctionDecl* fn_decl = nullptr; if (CXXMethodDecl* method_decl = DynCastFrom(*it)) { fn_decl = method_decl; } else if (FunctionTemplateDecl* tpl_decl = DynCastFrom(*it)) { fn_decl = tpl_decl->getTemplatedDecl(); // templated method decl } else { continue; // not a method or static method } if (!this->getDerived().HandleFunctionCall( fn_decl, underlying_type, static_cast(nullptr))) return false; } } // We don't have to simulate a user instantiating the type, because // RecursiveASTVisitor.h will recurse on the typedef'ed type for us. 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. bool VisitDeclRefExpr(clang::DeclRefExpr* expr) { if (CanIgnoreCurrentASTNode()) return true; // Special case for UsingShadowDecl to track UsingDecls correctly. The // actual decl will be reported by obtaining it from the UsingShadowDecl // once we've tracked the UsingDecl use. if (const UsingShadowDecl* found_decl = DynCastFrom(expr->getFoundDecl())) { ReportDeclUse(CurrentLoc(), found_decl); } else if (!isa(expr->getDecl())) { ReportDeclUse(CurrentLoc(), expr->getDecl()); } return Base::VisitDeclRefExpr(expr); } bool VisitConceptSpecializationExpr(ConceptSpecializationExpr* expr) { if (CanIgnoreCurrentASTNode()) return true; ReportDeclUse(CurrentLoc(), expr->getNamedConcept()); // TODO(bolshakov): analyze type parameter usage. return Base::VisitConceptSpecializationExpr(expr); } // --- Visitors of types derived from clang::Type. bool VisitTypedefType(clang::TypedefType* type) { if (CanIgnoreCurrentASTNode()) return true; // TypedefType::getDecl() returns the place where the typedef is defined. ReportDeclUse(CurrentLoc(), type->getDecl()); if (!CanForwardDeclareType(current_ast_node())) ReportTypeUse(CurrentLoc(), type); return Base::VisitTypedefType(type); } bool VisitUsingType(clang::UsingType* type) { if (CanIgnoreCurrentASTNode()) return true; if (CanForwardDeclareType(current_ast_node())) { ReportDeclForwardDeclareUse(CurrentLoc(), type->getFoundDecl()); } else { ReportDeclUse(CurrentLoc(), type->getFoundDecl()); // If UsingType refers to a typedef, report the underlying type of that // typedef if needed (which is determined in ReportTypeUse). const Type* underlying_type = type->getUnderlyingType().getTypePtr(); if (isa(underlying_type)) ReportTypeUse(CurrentLoc(), underlying_type); } return Base::VisitUsingType(type); } // This is a superclass of RecordType and CXXRecordType. bool VisitTagType(clang::TagType* type) { if (CanIgnoreCurrentASTNode()) return true; // If we're forward-declarable, then no complicated checking is // needed: just forward-declare. if (CanForwardDeclareType(current_ast_node())) { current_ast_node()->set_in_forward_declare_context(true); if (compiler()->getLangOpts().CPlusPlus) { // In C++, if we're already elaborated ('class Foo x') but not // a qualified name ('class ns::Foo x', 'class Class::Nested x') there's // no need even to forward-declare. // Note that enums are never forward-declarable, so elaborated enums are // already short-circuited in CanForwardDeclareType. const ASTNode* parent = current_ast_node()->parent(); if (!IsElaboratedTypeSpecifier(parent) || IsQualifiedNameNode(parent)) ReportDeclForwardDeclareUse(CurrentLoc(), type->getDecl()); } else { // In C, all struct references are elaborated, so we really never need // to forward-declare. But there's one case where an elaborated struct // decl in a parameter list causes Clang to warn about constrained // visibility, so we recommend forward declaration to avoid the warning. // E.g. // void init(struct mystruct* s); // warning: declaration of 'struct mystruct' will not be visible // outside of this function [-Wvisibility] if (current_ast_node()->HasAncestorOfType()) ReportDeclForwardDeclareUse(CurrentLoc(), type->getDecl()); } return Base::VisitTagType(type); } // OK, seems to be a use that requires the full type. ReportDeclUse(CurrentLoc(), type->getDecl()); return Base::VisitTagType(type); } // Like for CXXConstructExpr, etc., we sometimes need to instantiate // a class when looking at TemplateSpecializationType -- for instance, // when we need to access a class typedef: MyClass::value_type. bool VisitTemplateSpecializationType(TemplateSpecializationType* type) { if (CanIgnoreCurrentASTNode()) return true; // If we're not in a forward-declare context, use of a template // specialization requires having the full type information. if (!CanForwardDeclareType(current_ast_node())) { const map resugar_map = GetTplTypeResugarMapForClass(type); instantiated_template_visitor_.ScanInstantiatedType(current_ast_node(), resugar_map); } return Base::VisitTemplateSpecializationType(type); } // --- Visitors defined by BaseASTVisitor (not RecursiveASTVisitor). bool VisitTemplateName(TemplateName template_name) { if (CanIgnoreCurrentASTNode()) return true; if (!Base::VisitTemplateName(template_name)) return false; // We can see TemplateName outside the context of a // TemplateSpecializationType when it's either the default argument of a // template template arg: // template class A = TplNameWithoutTST> class Foo ... // or a deduced template specialization: // std::pair x(10, 20); // type of x is really std::pair // 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 class A = Foo> class C { A* 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. const ASTNode* ast_node = current_ast_node(); if (ast_node->ParentIsA() || IsDefaultTemplateTemplateArg(ast_node)) { current_ast_node()->set_in_forward_declare_context(false); // Not all template name kinds have an associated template decl; notably // dependent names, overloaded template names and ADL-resolved names. Only // report the use if we can find a decl. if (TemplateDecl* template_decl = template_name.getAsTemplateDecl()) { ReportDeclUse(CurrentLoc(), template_decl); } else { // TODO: There should probably be handling of these delayed-resolution // template decls as well, but probably not here. } } return true; } // For expressions that require us to instantiate a template // (CallExpr of a template function, or CXXConstructExpr of a // template class, etc), we need to instantiate the template and // check IWYU status of the template parameters *in the template // code* (so for 'MyFunc() { T t; ... }', the contents of // MyFunc add an iwyu requirement on MyClass). bool HandleFunctionCall(FunctionDecl* callee, const Type* parent_type, const clang::Expr* calling_expr) { if (!Base::HandleFunctionCall(callee, parent_type, calling_expr)) return false; if (!callee || CanIgnoreCurrentASTNode() || CanIgnoreDecl(callee)) return true; if (!IsTemplatizedFunctionDecl(callee) && !IsTemplatizedType(parent_type)) return true; map resugar_map = GetTplTypeResugarMapForFunction(callee, calling_expr); if (parent_type) { // means we're a method of a class InsertAllInto(GetTplTypeResugarMapForClass(parent_type), &resugar_map); } instantiated_template_visitor_.ScanInstantiatedFunction( callee, parent_type, current_ast_node(), resugar_map); return true; } // --- Handler declared in IwyuBaseASTVisitor. void ReportTplSpecComponentTypes(const TemplateSpecializationType* type) { const map resugar_map = GetTplTypeResugarMapForClass(type); ASTNode node(type); node.SetParent(current_ast_node()); instantiated_template_visitor_.ScanInstantiatedType(&node, resugar_map); } private: // Class we call to handle instantiated template functions and classes. InstantiatedTemplateVisitor instantiated_template_visitor_; }; // class IwyuAstConsumer // We use an ASTFrontendAction to hook up IWYU with Clang. class IwyuAction : public ASTFrontendAction { protected: std::unique_ptr CreateASTConsumer( CompilerInstance& compiler, // NOLINT llvm::StringRef /* dummy */) override { // Do this first thing after getting our hands on a CompilerInstance. InitGlobals(&compiler.getSourceManager(), &compiler.getPreprocessor().getHeaderSearchInfo()); auto* const preprocessor_consumer = new IwyuPreprocessorInfo(); compiler.getPreprocessor().addPPCallbacks( std::unique_ptr(preprocessor_consumer)); compiler.getPreprocessor().addCommentHandler(preprocessor_consumer); auto* const visitor_state = new VisitorState(&compiler, *preprocessor_consumer); return std::unique_ptr(new IwyuAstConsumer(visitor_state)); } }; } // namespace include_what_you_use #include "iwyu_driver.h" #include "clang/Frontend/FrontendAction.h" #include "llvm/Support/TargetSelect.h" using include_what_you_use::OptionsParser; using include_what_you_use::IwyuAction; using include_what_you_use::CreateCompilerInstance; int main(int argc, char **argv) { llvm::llvm_shutdown_obj scoped_shutdown; // 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 OptionsParser options_parser(argc, argv); std::unique_ptr compiler(CreateCompilerInstance( options_parser.clang_argc(), options_parser.clang_argv())); if (!compiler) { return EXIT_FAILURE; } // Create and execute the frontend to generate an LLVM bitcode module. std::unique_ptr action(new IwyuAction); compiler->ExecuteAction(*action); return EXIT_SUCCESS; }