Compare commits
10 Commits
8a6009f587
...
785ae7e7b1
Author | SHA1 | Date |
---|---|---|
Sameer Rahmani | 785ae7e7b1 | |
Petr Bred | 1a2cab9b71 | |
Bolshakov | f9f4fd2eef | |
Bolshakov | eb1697e002 | |
Kim Gräsman | 81ee985377 | |
Kim Gräsman | 80410de523 | |
Kim Gräsman | bd305afe7d | |
Kim Gräsman | 2dc0645882 | |
Bolshakov | f7c5a795ab | |
Bolshakov | 971a300bb9 |
|
@ -31,31 +31,37 @@ In the provided case nothing within the bounds of `begin_keep` and `end_keep` wi
|
|||
|
||||
## IWYU pragma: export ##
|
||||
|
||||
This pragma applies to a single `#include` directive. It says that the current file is to be considered the provider of any symbol from the included file.
|
||||
This pragma applies to a single `#include` directive or forward declaration. It says that the current file is to be considered the provider of any symbol from the included file or declaration.
|
||||
|
||||
facade.h:
|
||||
#include "detail/constants.h" // IWYU pragma: export
|
||||
#include "detail/types.h" // IWYU pragma: export
|
||||
#include <vector> // don't export stuff from <vector>
|
||||
|
||||
class Other; // IWYU pragma: export
|
||||
|
||||
main.cc:
|
||||
#include "facade.h"
|
||||
|
||||
// Assuming Thing comes from detail/types.h and MAX_THINGS from detail/constants.h
|
||||
std::vector<Thing> things(MAX_THINGS);
|
||||
|
||||
Here, since `detail/constants.h` and `detail/types.h` have both been exported, IWYU is happy with the `facade.h` include for `Thing` and `MAX_THINGS`.
|
||||
// Satisfied with forward-declaration from facade.h
|
||||
void foo(Other* thing);
|
||||
|
||||
Here, since `detail/constants.h`, `detail/types.h` and `Other` have all been exported, IWYU is happy with the `facade.h` include for `Thing` and `MAX_THINGS` and does not suggest a local forward declaration for `Other`.
|
||||
|
||||
In contrast, since `<vector>` has not been exported from `facade.h`, it will be suggested as an additional include.
|
||||
|
||||
## IWYU pragma: begin_exports/end_exports ##
|
||||
|
||||
This pragma applies to a set of `#include` directives. It declares that the including file is to be considered the provider of any symbol from these included files. This is the same as decorating every `#include` directive with `IWYU pragma: export`.
|
||||
This pragma applies to a set of `#include` directives or forward declarations. It declares that the including file is to be considered the provider any symbol from contained included files or declarations. This is the same as decorating every line with `IWYU pragma: export`.
|
||||
|
||||
facade.h:
|
||||
// IWYU pragma: begin_exports
|
||||
#include "detail/constants.h"
|
||||
#include "detail/types.h"
|
||||
class Other;
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include <vector> // don't export stuff from <vector>
|
||||
|
|
|
@ -251,13 +251,13 @@ and forward declarations instead of a single line.
|
|||
.B // IWYU pragma: export
|
||||
Used after an
|
||||
.B #include
|
||||
directive it indicates that the current file is considered to be a provider of
|
||||
the included file.
|
||||
directive or forward declaration it indicates that the current file is
|
||||
considered to be a provider of any symbol from the included file or declaration.
|
||||
.TP
|
||||
.BR "// IWYU pragma: begin_exports" , " // IWYU pragma: end_exports"
|
||||
Has the same effect as the previous pragma comment, but applies to a range of
|
||||
.BR #include s
|
||||
instead of a single line.
|
||||
or forward declarations instead of a single line.
|
||||
.TP
|
||||
.BR "// IWYU pragma: private" [ ", include \fIheader" ]
|
||||
Indicates that the current file is considered private,
|
||||
|
|
84
iwyu.cc
84
iwyu.cc
|
@ -1604,34 +1604,6 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
|
|||
preprocessor_info().FileInfoFor(used_in)->ReportUsingDeclUse(
|
||||
used_loc, using_decl, use_flags, "(for using decl)");
|
||||
}
|
||||
|
||||
// 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 TypedefNameDecl* typedef_decl = DynCastFrom(target_decl)) {
|
||||
// One exception: if this TypedefType is being used in another
|
||||
// typedef (that is, 'typedef MyTypedef OtherTypdef'), then the
|
||||
// user -- the other typedef -- is never responsible for the
|
||||
// underlying type. Instead, users of that typedef are.
|
||||
const ASTNode* ast_node = MostElaboratedAncestor(current_ast_node());
|
||||
if (!ast_node->ParentIsA<TypedefNameDecl>()) {
|
||||
const set<const Type*>& 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<Derived>::ReportTypeUse(used_loc, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The comment, if not nullptr, is extra text that is included along
|
||||
|
@ -1699,6 +1671,36 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
|
|||
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<TypedefType>()) {
|
||||
// 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<TypedefNameDecl>()) {
|
||||
const TypedefNameDecl* typedef_decl = typedef_type->getDecl();
|
||||
const set<const Type*>& 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<Derived>::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*
|
||||
|
@ -3985,13 +3987,10 @@ class IwyuAstConsumer
|
|||
definitely_keep_fwd_decl = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SourceLocation decl_end_location = decl->getSourceRange().getEnd();
|
||||
if (LineHasText(decl_end_location, "// IWYU pragma: keep") ||
|
||||
LineHasText(decl_end_location, "/* IWYU pragma: keep") ||
|
||||
preprocessor_info().ForwardDeclareInKeepRange(decl_end_location)) {
|
||||
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(
|
||||
|
@ -4123,11 +4122,9 @@ class IwyuAstConsumer
|
|||
if (CanIgnoreCurrentASTNode())
|
||||
return true;
|
||||
// TypedefType::getDecl() returns the place where the typedef is defined.
|
||||
if (CanForwardDeclareType(current_ast_node())) {
|
||||
ReportDeclForwardDeclareUse(CurrentLoc(), type->getDecl());
|
||||
} else {
|
||||
ReportDeclUse(CurrentLoc(), type->getDecl());
|
||||
}
|
||||
ReportDeclUse(CurrentLoc(), type->getDecl());
|
||||
if (!CanForwardDeclareType(current_ast_node()))
|
||||
ReportTypeUse(CurrentLoc(), type);
|
||||
return Base::VisitTypedefType(type);
|
||||
}
|
||||
|
||||
|
@ -4135,11 +4132,16 @@ class IwyuAstConsumer
|
|||
if (CanIgnoreCurrentASTNode())
|
||||
return true;
|
||||
|
||||
// UsingType is similar to TypedefType, so treat it the same.
|
||||
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<TypedefType>(underlying_type))
|
||||
ReportTypeUse(CurrentLoc(), underlying_type);
|
||||
}
|
||||
|
||||
return Base::VisitUsingType(type);
|
||||
|
|
|
@ -1144,7 +1144,6 @@ const Type* Desugar(const Type* type) {
|
|||
while (true) {
|
||||
// Don't desugar types that (potentially) add a name.
|
||||
if (cur->getTypeClass() == Type::Typedef ||
|
||||
cur->getTypeClass() == Type::Using ||
|
||||
cur->getTypeClass() == Type::TemplateSpecialization) {
|
||||
return cur;
|
||||
}
|
||||
|
@ -1508,4 +1507,9 @@ string GetKindName(const TypeLoc typeloc) {
|
|||
return string(typeloc.getTypePtr()->getTypeClassName()) + "TypeLoc";
|
||||
}
|
||||
|
||||
bool IsDeclaredInsideFunction(const Decl* decl) {
|
||||
const DeclContext* decl_ctx = decl->getDeclContext();
|
||||
return isa<FunctionDecl>(decl_ctx);
|
||||
}
|
||||
|
||||
} // namespace include_what_you_use
|
||||
|
|
|
@ -839,6 +839,10 @@ std::string GetKindName(const clang::Stmt* stmt);
|
|||
std::string GetKindName(const clang::Type* type);
|
||||
std::string GetKindName(const clang::TypeLoc typeloc);
|
||||
|
||||
// Returns true if decl is entirely inside a function, which implies it's only
|
||||
// visible from said function.
|
||||
bool IsDeclaredInsideFunction(const clang::Decl* decl);
|
||||
|
||||
} // namespace include_what_you_use
|
||||
|
||||
#endif // INCLUDE_WHAT_YOU_USE_IWYU_AST_UTIL_H_
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/TargetParser/Triple.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
|
|
|
@ -976,40 +976,46 @@ set<string> CalculateMinimalIncludes(
|
|||
// A4) If the file containing the use has a pragma inhibiting the forward
|
||||
// declaration of the symbol, change the use to a full info use in order
|
||||
// to make sure that the compiler can see some declaration of the symbol.
|
||||
// A5) If a nested class, discard this use (the parent class declaration
|
||||
// is sufficient).
|
||||
// A5) If declaration is nested inside a class or a function, discard this use.
|
||||
// The containing class/function is required to use the nested decl, and
|
||||
// so will force use of the containing header.
|
||||
// A6) If any of the redeclarations of this declaration is in the same
|
||||
// file as the use (and before it), and is actually a definition,
|
||||
// discard the forward-declare use.
|
||||
// A7) If --no_fwd_decls has been passed, recategorize as a full use.
|
||||
// A7) If any redeclaration is marked with IWYU pragma: export, mark as a
|
||||
// full use of this decl to keep its containing file included.
|
||||
// A8) If --no_fwd_decls has been passed, recategorize as a full use.
|
||||
|
||||
// Trimming symbol uses (1st pass):
|
||||
// B1) If the definition of a full use comes after the use, change the
|
||||
// B1) If declaration is nested inside a function, discard this use.
|
||||
// The function is required to use the nested decl, and so will force use of
|
||||
// the containing header.
|
||||
// B2) If the definition of a full use comes after the use, change the
|
||||
// full use to a forward-declare use that points to a fwd-decl
|
||||
// that comes before the use. (This is for cases like typedefs
|
||||
// where iwyu demands a full use but the language allows a
|
||||
// forward-declare.)
|
||||
// B2) Discard symbol uses of a symbol defined in the same file it's used.
|
||||
// B3) Discard symbol uses of a symbol defined in the same file it's used.
|
||||
// If the symbol is a typedef, function, or var -- every decl
|
||||
// that is re-declarable except for TagDecl -- discard if *any*
|
||||
// declaration is in the same file as the use.
|
||||
// B3) Discard symbol uses for builtin symbols ('__builtin_memcmp') and
|
||||
// B4) Discard symbol uses for builtin symbols ('__builtin_memcmp') and
|
||||
// for operator new and operator delete (excluding placement new),
|
||||
// which are effectively built-in even though they're in <new>.
|
||||
// B4) Discard symbol uses for member functions that live in the same
|
||||
// B5) Discard symbol uses for member functions that live in the same
|
||||
// file as the class they're part of (the parent check suffices).
|
||||
// B5) Sanity check: Discard 'backwards' #includes. These are
|
||||
// B6) Sanity check: Discard 'backwards' #includes. These are
|
||||
// #includes where we say a.h should #include b.h, but b.h is
|
||||
// already #including a.h. This happens when iwyu attributes a
|
||||
// use to the wrong file.
|
||||
// B6) In --transitive_includes_only mode, discard 'new' #includes.
|
||||
// B7) In --transitive_includes_only mode, discard 'new' #includes.
|
||||
// These are #includes where we say a.h should #include b.h, but
|
||||
// a.h does not see b.h in its transitive #includes. (Note: This
|
||||
// happens before include-picker mapping, so it's still possible to
|
||||
// see 'new' includes via a manual mapping.)
|
||||
// B1') Discard macro uses in the same file as the definition (B2 redux).
|
||||
// B2') Discard macro uses that form a 'backwards' #include (B5 redux).
|
||||
// B3') Discard macro uses from a 'new' #include (B6 redux).
|
||||
// B1') Discard macro uses in the same file as the definition (B3 redux).
|
||||
// B2') Discard macro uses that form a 'backwards' #include (B6 redux).
|
||||
// B3') Discard macro uses from a 'new' #include (B7 redux).
|
||||
|
||||
// Determining 'desired' #includes:
|
||||
// C1) Get a list of 'effective' direct includes. For most files, it's
|
||||
|
@ -1105,7 +1111,8 @@ void ProcessForwardDeclare(OneUse* use,
|
|||
}
|
||||
}
|
||||
|
||||
// (A5) If using a nested class, discard this use.
|
||||
// (A5) If using a nested class or a type declared inside a function, discard
|
||||
// this use.
|
||||
if (IsNestedClass(tag_decl)) {
|
||||
// iwyu will require the full type of the parent class when it
|
||||
// recurses on the qualifier (any use of Foo::Bar requires the
|
||||
|
@ -1124,6 +1131,12 @@ void ProcessForwardDeclare(OneUse* use,
|
|||
use->set_ignore_use();
|
||||
return;
|
||||
}
|
||||
} else if (IsDeclaredInsideFunction(tag_decl)) {
|
||||
VERRS(6) << "Ignoring fwd-decl use of " << use->symbol_name() << " ("
|
||||
<< use->PrintableUseLoc() << "): declared inside a "
|
||||
<< "function\n";
|
||||
use->set_ignore_use();
|
||||
return;
|
||||
}
|
||||
|
||||
// (A6) If a definition exists earlier in this file, discard this use.
|
||||
|
@ -1143,7 +1156,20 @@ void ProcessForwardDeclare(OneUse* use,
|
|||
}
|
||||
}
|
||||
|
||||
// (A7) If --no_fwd_decls has been passed, and a decl can be found in one of
|
||||
// (A7) If any arbitrary redeclaration is marked with IWYU pragma: export,
|
||||
// reset use as a full use of this decl to keep its containing file included.
|
||||
if (!use->is_full_use()) {
|
||||
for (const Decl* redecl : use->decl()->redecls()) {
|
||||
const auto* decl = cast<NamedDecl>(redecl);
|
||||
if (preprocessor_info->ForwardDeclareIsExported(decl)) {
|
||||
use->reset_decl(decl);
|
||||
use->set_full_use();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// (A8) If --no_fwd_decls has been passed, and a decl can be found in one of
|
||||
// the headers, suggest that header, and recategorize as a full use. If we can
|
||||
// only find a decl in this file, it must be a self-sufficent decl being used,
|
||||
// so we can just let IWYU do its work, and there is no need to recategorize.
|
||||
|
@ -1181,6 +1207,16 @@ void ProcessFullUse(OneUse* use,
|
|||
if (use->ignore_use()) // we're already ignoring it
|
||||
return;
|
||||
|
||||
// (B1) If declaration is inside a function, it can only be seen via said
|
||||
// function. Discard this use and assume the use of the function provides.
|
||||
if (IsDeclaredInsideFunction(use->decl())) {
|
||||
VERRS(6) << "Ignoring full use of " << use->symbol_name() << " ("
|
||||
<< use->PrintableUseLoc() << "): declared inside a "
|
||||
<< "function\n";
|
||||
use->set_ignore_use();
|
||||
return;
|
||||
}
|
||||
|
||||
// We normally ignore uses for builtins, but when there is a mapping defined
|
||||
// for the symbol, we should respect that. So, we need to determine whether
|
||||
// the symbol has any mappings.
|
||||
|
@ -1189,7 +1225,7 @@ void ProcessFullUse(OneUse* use,
|
|||
bool is_builtin_function_with_mappings =
|
||||
is_builtin_function && HasMapping(use->symbol_name());
|
||||
|
||||
// (B1) If the definition is after the use, re-point to a prior decl.
|
||||
// (B2) If the definition is after the use, re-point to a prior decl.
|
||||
// If iwyu followed the language precisely, this wouldn't be
|
||||
// necessary: code wouldn't compile if a full-use didn't have the
|
||||
// definition handy yet. But in fact, iwyu sometimes requires a full
|
||||
|
@ -1222,7 +1258,7 @@ void ProcessFullUse(OneUse* use,
|
|||
return;
|
||||
}
|
||||
|
||||
// (B2) Discard symbol uses of a symbol defined in the same file it's used.
|
||||
// (B3) Discard symbol uses of a symbol defined in the same file it's used.
|
||||
// If the symbol can be declared in multiple places, we count it if
|
||||
// *any* declaration is in the same file, unless the symbol is a
|
||||
// class or enum. (Every other kind of redeclarable symbol, such as
|
||||
|
@ -1250,7 +1286,7 @@ void ProcessFullUse(OneUse* use,
|
|||
}
|
||||
}
|
||||
|
||||
// (B3) Discard symbol uses for builtin symbols, including new/delete and
|
||||
// (B4) Discard symbol uses for builtin symbols, including new/delete and
|
||||
// template builtins.
|
||||
if (isa<clang::BuiltinTemplateDecl>(use->decl())) {
|
||||
VERRS(6) << "Ignoring use of " << use->symbol_name()
|
||||
|
@ -1281,7 +1317,7 @@ void ProcessFullUse(OneUse* use,
|
|||
}
|
||||
}
|
||||
|
||||
// (B4) Discard symbol uses for class members in the same file as parent.
|
||||
// (B5) Discard symbol uses for class members in the same file as parent.
|
||||
if (const CXXRecordDecl* parent_decl =
|
||||
DynCastFrom(use->decl()->getDeclContext())) {
|
||||
// See if we also recorded a use of the parent.
|
||||
|
@ -1319,7 +1355,7 @@ void ProcessFullUse(OneUse* use,
|
|||
}
|
||||
}
|
||||
|
||||
// (B5) Discard uses of symbols that form a 'backwards' #include.
|
||||
// (B6) Discard uses of symbols that form a 'backwards' #include.
|
||||
// This means that we say a.h is using a symbol in b.h, but b.h
|
||||
// already #includes a.h (either directly or indirectly). Since the
|
||||
// include graph should be acyclic, this means that iwyu messed up,
|
||||
|
@ -1338,7 +1374,7 @@ void ProcessFullUse(OneUse* use,
|
|||
return;
|
||||
}
|
||||
|
||||
// (B6) In --transitive_includes_only mode, discard 'new' #includes.
|
||||
// (B7) In --transitive_includes_only mode, discard 'new' #includes.
|
||||
// In practice, if we tell a.h to add an #include that is not in its
|
||||
// transitive includes, it's usually (but not always) an iwyu error
|
||||
// of some sort. So we allow a flag to discard such recommendations.
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "iwyu_string_util.h"
|
||||
#include "iwyu_verrs.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
|
||||
|
@ -37,12 +38,12 @@ using clang::FileID;
|
|||
using clang::MacroDefinition;
|
||||
using clang::MacroDirective;
|
||||
using clang::MacroInfo;
|
||||
using clang::NamedDecl;
|
||||
using clang::Preprocessor;
|
||||
using clang::SourceLocation;
|
||||
using clang::SourceRange;
|
||||
using clang::Token;
|
||||
using llvm::errs;
|
||||
using llvm::Optional;
|
||||
using llvm::StringRef;
|
||||
using std::make_pair;
|
||||
using std::string;
|
||||
|
@ -207,7 +208,11 @@ void IwyuPreprocessorInfo::HandlePragmaComment(SourceRange comment_range) {
|
|||
if (HasOpenBeginExports(this_file_entry)) {
|
||||
if (MatchOneToken(tokens, "end_exports", 1, begin_loc)) {
|
||||
ERRSYM(this_file_entry) << "end_exports pragma seen\n";
|
||||
SourceLocation export_loc_begin = begin_exports_location_stack_.top();
|
||||
begin_exports_location_stack_.pop();
|
||||
SourceRange export_range(export_loc_begin, begin_loc);
|
||||
export_location_ranges_.insert(
|
||||
std::make_pair(this_file_entry, export_range));
|
||||
} else {
|
||||
// No pragma allowed within "begin_exports" - "end_exports"
|
||||
Warn(begin_loc, "Expected end_exports pragma");
|
||||
|
@ -1123,7 +1128,12 @@ bool IwyuPreprocessorInfo::ForwardDeclareIsInhibited(
|
|||
ContainsKey(*inhibited_forward_declares, normalized_symbol_name);
|
||||
}
|
||||
|
||||
bool IwyuPreprocessorInfo::ForwardDeclareInKeepRange(SourceLocation loc) const {
|
||||
bool IwyuPreprocessorInfo::ForwardDeclareIsMarkedKeep(
|
||||
const NamedDecl* decl) const {
|
||||
// Use end-location so that any trailing comments match only on the last line.
|
||||
SourceLocation loc = decl->getEndLoc();
|
||||
|
||||
// Is the decl part of a begin_keep/end_keep block?
|
||||
const FileEntry* file = GetFileEntry(loc);
|
||||
auto keep_ranges = keep_location_ranges_.equal_range(file);
|
||||
for (auto it = keep_ranges.first; it != keep_ranges.second; ++it) {
|
||||
|
@ -1131,7 +1141,26 @@ bool IwyuPreprocessorInfo::ForwardDeclareInKeepRange(SourceLocation loc) const {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
// Is the declaration itself marked with trailing comment?
|
||||
return (LineHasText(loc, "// IWYU pragma: keep") ||
|
||||
LineHasText(loc, "/* IWYU pragma: keep"));
|
||||
}
|
||||
|
||||
bool IwyuPreprocessorInfo::ForwardDeclareIsExported(
|
||||
const NamedDecl* decl) const {
|
||||
// Use end-location so that any trailing comments match only on the last line.
|
||||
SourceLocation loc = decl->getEndLoc();
|
||||
|
||||
// Is the decl part of a begin_exports/end_exports block?
|
||||
const FileEntry* file = GetFileEntry(loc);
|
||||
auto export_ranges = export_location_ranges_.equal_range(file);
|
||||
for (auto it = export_ranges.first; it != export_ranges.second; ++it) {
|
||||
if (it->second.fullyContains(loc)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Is the declaration itself marked with trailing comment?
|
||||
return (LineHasText(loc, "// IWYU pragma: export") ||
|
||||
LineHasText(loc, "/* IWYU pragma: export"));
|
||||
}
|
||||
} // namespace include_what_you_use
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
namespace clang {
|
||||
class FileEntry;
|
||||
class MacroInfo;
|
||||
class NamedDecl;
|
||||
} // namespace clang
|
||||
|
||||
namespace include_what_you_use {
|
||||
|
@ -168,9 +169,11 @@ class IwyuPreprocessorInfo : public clang::PPCallbacks,
|
|||
bool ForwardDeclareIsInhibited(
|
||||
const clang::FileEntry* file, const string& qualified_symbol_name) const;
|
||||
|
||||
// Return true if the fwd decl is in the range of a begin_keep -> end_keep
|
||||
// block.
|
||||
bool ForwardDeclareInKeepRange(clang::SourceLocation loc) const;
|
||||
// Return true if the fwd decl is marked with "IWYU pragma: keep".
|
||||
bool ForwardDeclareIsMarkedKeep(const clang::NamedDecl* decl) const;
|
||||
|
||||
// Return true if the fwd decl is marked with "IWYU pragma: export".
|
||||
bool ForwardDeclareIsExported(const clang::NamedDecl* decl) const;
|
||||
|
||||
protected:
|
||||
// Preprocessor event handlers called by Clang.
|
||||
|
@ -365,6 +368,10 @@ class IwyuPreprocessorInfo : public clang::PPCallbacks,
|
|||
// every keep range.
|
||||
multimap<const clang::FileEntry*, clang::SourceRange> keep_location_ranges_;
|
||||
|
||||
// For processing forward decls. It is a multimap containing the bounds of
|
||||
// every export range.
|
||||
multimap<const clang::FileEntry*, clang::SourceRange> export_location_ranges_;
|
||||
|
||||
// For processing associated pragma. It is the current open
|
||||
// "associated" pragma.
|
||||
clang::SourceLocation associated_pragma_location_;
|
||||
|
|
|
@ -1111,7 +1111,8 @@ int main() {
|
|||
// a() returns a FOO, which in this case is I2_Enum.
|
||||
local_d1_template_class.a();
|
||||
(void)(local_i1_enum);
|
||||
// IWYU: I1_UnnamedStruct is...*badinc-i1.h
|
||||
// Typedef of unnamed type always provides that type, and it should be
|
||||
// included due to variable declaration.
|
||||
(void)(local_i1_unnamed_struct.a);
|
||||
local_d1_subclass.a();
|
||||
(void)(local_i2_class_ptr);
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
//===--- decl_inside_func-d1.h - test input file for iwyu -----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "tests/cxx/decl_inside_func-i1.h"
|
|
@ -0,0 +1,34 @@
|
|||
//===--- decl_inside_func-i1.h - test input file for iwyu -----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Reduced/derived/copied from Quill 1.6.3:
|
||||
// https://github.com/odygrd/quill/blob/v1.6.3/quill/include/quill/PatternFormatter.h#L35
|
||||
|
||||
// This macro defines a lambda containing a function-local declaration of a
|
||||
// union X, which is cleverly returned from the lambda.
|
||||
//
|
||||
// Declarations inside a function are only directly visible from the function
|
||||
// itself, so any uses of X should be ignored -- the only way to get in any
|
||||
// contact with X is to use MACRO, so this header will be desired already.
|
||||
|
||||
#define MACRO(str) \
|
||||
[] { \
|
||||
union X { \
|
||||
static constexpr auto value() { \
|
||||
return str; \
|
||||
} \
|
||||
}; \
|
||||
return X{}; \
|
||||
}()
|
||||
|
||||
/**** IWYU_SUMMARY
|
||||
|
||||
(tests/cxx/decl_inside_func-i1.h has correct #includes/fwd-decls)
|
||||
|
||||
***** IWYU_SUMMARY */
|
|
@ -0,0 +1,41 @@
|
|||
//===--- decl_inside_func.cc - test input file for iwyu -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// A declaration inside a function can sometimes escape (see implementation of
|
||||
// MACRO), and while such a declaration may look like it's independently used
|
||||
// here, the only way to make contact with it is through its containing
|
||||
// function.
|
||||
// Since we must have a declaration of _the function_ in order to call it, the
|
||||
// contained declaration will have followed along and we can ignore any direct
|
||||
// uses of the contained decl.
|
||||
// This used to lead to the contained declaration being fwd-decl used, and IWYU
|
||||
// crashing when trying to format a printable forward-decl. Ignoring it
|
||||
// completely avoids that malfunction.
|
||||
|
||||
// IWYU_ARGS: -I . -Xiwyu --check_also="tests/cxx/decl_inside_func-i1.h"
|
||||
|
||||
#include "tests/cxx/decl_inside_func-d1.h"
|
||||
|
||||
const char* f() {
|
||||
// IWYU: MACRO is ...*decl_inside_func-i1.h
|
||||
return MACRO("bleh").value();
|
||||
}
|
||||
|
||||
/**** IWYU_SUMMARY
|
||||
|
||||
tests/cxx/decl_inside_func.cc should add these lines:
|
||||
#include "tests/cxx/decl_inside_func-i1.h"
|
||||
|
||||
tests/cxx/decl_inside_func.cc should remove these lines:
|
||||
- #include "tests/cxx/decl_inside_func-d1.h" // lines XX-XX
|
||||
|
||||
The full include-list for tests/cxx/decl_inside_func.cc:
|
||||
#include "tests/cxx/decl_inside_func-i1.h" // for MACRO
|
||||
|
||||
***** IWYU_SUMMARY */
|
|
@ -120,6 +120,27 @@ void ViaMacro(const IndirectTemplate<IndirectClass>& ic) {
|
|||
IC_CALL_METHOD;
|
||||
}
|
||||
|
||||
// Test type use with member expression inside a template.
|
||||
|
||||
template <typename T>
|
||||
void MemberExprInside() {
|
||||
T* t = nullptr;
|
||||
(*t)->Method();
|
||||
}
|
||||
|
||||
class IndirectClass; // IndirectClassPtr doesn't provide IndirectClass.
|
||||
typedef IndirectClass* IndirectClassPtr;
|
||||
|
||||
namespace ns {
|
||||
using ::IndirectClassPtr;
|
||||
}
|
||||
|
||||
void Fn() {
|
||||
// IndirectClass is hidden by a pointer and (at least) two levels of sugar.
|
||||
// IWYU: IndirectClass is...*indirect.h
|
||||
MemberExprInside<ns::IndirectClassPtr>();
|
||||
}
|
||||
|
||||
/**** IWYU_SUMMARY
|
||||
|
||||
tests/cxx/member_expr.cc should add these lines:
|
||||
|
@ -127,6 +148,7 @@ tests/cxx/member_expr.cc should add these lines:
|
|||
|
||||
tests/cxx/member_expr.cc should remove these lines:
|
||||
- #include "tests/cxx/direct.h" // lines XX-XX
|
||||
- class IndirectClass; // lines XX-XX
|
||||
|
||||
The full include-list for tests/cxx/member_expr.cc:
|
||||
#include "tests/cxx/indirect.h" // for IndirectClass, IndirectTemplate
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
//===--- no_implicit_typedef_reporting-d1.h - test input file for iwyu ----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "tests/cxx/no_implicit_typedef_reporting-i1.h"
|
|
@ -0,0 +1,28 @@
|
|||
//===--- no_implicit_typedef_reporting-d2.h - test input file for iwyu ----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "tests/cxx/no_implicit_typedef_reporting-d1.h"
|
||||
|
||||
struct Struct {
|
||||
// IWYU: Int is...*no_implicit_typedef_reporting-i1.h
|
||||
Int typedefed;
|
||||
};
|
||||
|
||||
/**** IWYU_SUMMARY
|
||||
|
||||
tests/cxx/no_implicit_typedef_reporting-d2.h should add these lines:
|
||||
#include "tests/cxx/no_implicit_typedef_reporting-i1.h"
|
||||
|
||||
tests/cxx/no_implicit_typedef_reporting-d2.h should remove these lines:
|
||||
- #include "tests/cxx/no_implicit_typedef_reporting-d1.h" // lines XX-XX
|
||||
|
||||
The full include-list for tests/cxx/no_implicit_typedef_reporting-d2.h:
|
||||
#include "tests/cxx/no_implicit_typedef_reporting-i1.h" // for Int
|
||||
|
||||
***** IWYU_SUMMARY */
|
|
@ -0,0 +1,10 @@
|
|||
//===--- no_implicit_typedef_reporting-i1.h - test input file for iwyu ----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
typedef int Int;
|
|
@ -0,0 +1,48 @@
|
|||
//===--- no_implicit_typedef_reporting.cc - test input file for iwyu ------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// IWYU_ARGS: -I . \
|
||||
// -Xiwyu --check_also="tests/cxx/no_implicit_typedef_reporting-d2.h"
|
||||
|
||||
// Tests that IWYU doesn't suggest to include typedef-containing header due to
|
||||
// implicit-only use of the typedef, i.e. when it is not explicitly written
|
||||
// in a source.
|
||||
|
||||
#include "tests/cxx/no_implicit_typedef_reporting-d1.h"
|
||||
#include "tests/cxx/no_implicit_typedef_reporting-d2.h"
|
||||
|
||||
template <class T1, class T2>
|
||||
struct Template {
|
||||
T1 t1;
|
||||
decltype(T2::typedefed) t2;
|
||||
};
|
||||
|
||||
void Fn() {
|
||||
// Test use in unary expression.
|
||||
(void)sizeof(Struct::typedefed);
|
||||
|
||||
Struct s;
|
||||
// Test use for pointer arithmetic.
|
||||
void* p = &s.typedefed + 10;
|
||||
|
||||
// Test use in instantiated template.
|
||||
Template<decltype(Struct::typedefed), Struct> tpl;
|
||||
}
|
||||
|
||||
/**** IWYU_SUMMARY
|
||||
|
||||
tests/cxx/no_implicit_typedef_reporting.cc should add these lines:
|
||||
|
||||
tests/cxx/no_implicit_typedef_reporting.cc should remove these lines:
|
||||
- #include "tests/cxx/no_implicit_typedef_reporting-d1.h" // lines XX-XX
|
||||
|
||||
The full include-list for tests/cxx/no_implicit_typedef_reporting.cc:
|
||||
#include "tests/cxx/no_implicit_typedef_reporting-d2.h" // for Struct
|
||||
|
||||
***** IWYU_SUMMARY */
|
|
@ -43,6 +43,12 @@ void ExpressionsBuiltinTypes() {
|
|||
}
|
||||
|
||||
// New- and delete-expressions with user-defined types.
|
||||
|
||||
template <typename T>
|
||||
void TplFnWithDelete(T p) {
|
||||
delete p;
|
||||
}
|
||||
|
||||
void ExpressionsUserTypes() {
|
||||
// IWYU: IndirectClass needs a declaration
|
||||
// IWYU: IndirectClass is...*indirect.h
|
||||
|
@ -55,6 +61,11 @@ void ExpressionsUserTypes() {
|
|||
IndirectClass* arr = new IndirectClass[4];
|
||||
// IWYU: IndirectClass is...*indirect.h
|
||||
delete[] arr;
|
||||
|
||||
// Hide the pointer type behind "decltype" sugar.
|
||||
decltype(elem) elem2 = nullptr;
|
||||
// IWYU: IndirectClass is...*indirect.h
|
||||
TplFnWithDelete(elem2);
|
||||
}
|
||||
|
||||
// Aligned allocation uses operator new(size_t, std::align_val_t) under the
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
//===--- pragma_export_fwd-d1.h - test input file for iwyu ----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class FwdDecl3; // IWYU pragma: export
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
class FwdDecl4;
|
||||
// IWYU pragma: end_exports
|
|
@ -0,0 +1,31 @@
|
|||
//===--- pragma_export_fwd.cc - test input file for iwyu ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// IWYU_ARGS: -I .
|
||||
|
||||
#include "tests/cxx/pragma_export_fwd.h"
|
||||
|
||||
// Uses do not trigger warnings as they are already provided for.
|
||||
void a(const FwdDecl1&);
|
||||
void b(const FwdDecl2*);
|
||||
void c(const FwdDecl3&);
|
||||
void d(const FwdDecl4*);
|
||||
|
||||
/**** IWYU_SUMMARY
|
||||
|
||||
tests/cxx/pragma_export_fwd.cc should add these lines:
|
||||
#include "tests/cxx/pragma_export_fwd-d1.h"
|
||||
|
||||
tests/cxx/pragma_export_fwd.cc should remove these lines:
|
||||
|
||||
The full include-list for tests/cxx/pragma_export_fwd.cc:
|
||||
#include "tests/cxx/pragma_export_fwd.h"
|
||||
#include "tests/cxx/pragma_export_fwd-d1.h" // for FwdDecl3, FwdDecl4
|
||||
|
||||
***** IWYU_SUMMARY */
|
|
@ -0,0 +1,33 @@
|
|||
//===--- pragma_export_fwd.h - test input file for iwyu -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Forward declarations exported from this header are not used here, so it will
|
||||
// be suggested for removal.
|
||||
#include "tests/cxx/pragma_export_fwd-d1.h"
|
||||
|
||||
// Unused forward declarations in associated header would normally be moved to
|
||||
// main source file. Make sure they are left alone when exported.
|
||||
class FwdDecl1; // IWYU pragma: export
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
class FwdDecl2;
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
/**** IWYU_SUMMARY
|
||||
|
||||
tests/cxx/pragma_export_fwd.h should add these lines:
|
||||
|
||||
tests/cxx/pragma_export_fwd.h should remove these lines:
|
||||
- #include "tests/cxx/pragma_export_fwd-d1.h" // lines XX-XX
|
||||
|
||||
The full include-list for tests/cxx/pragma_export_fwd.h:
|
||||
class FwdDecl1; // lines XX-XX
|
||||
class FwdDecl2; // lines XX-XX
|
||||
|
||||
***** IWYU_SUMMARY */
|
|
@ -11,6 +11,10 @@
|
|||
|
||||
// Tests that sizeof(reference) is treated the same as
|
||||
// sizeof(underlying_object), like it's supposed to be.
|
||||
//
|
||||
// C++ [expr.sizeof]p2:
|
||||
// When applied to a reference or a reference type,
|
||||
// the result is the size of the referenced type.
|
||||
|
||||
#include <stddef.h>
|
||||
#include "tests/cxx/direct.h"
|
||||
|
@ -76,11 +80,17 @@ SizeofTakingStruct<IndirectClass&> sizeof_taking_struct1;
|
|||
// IWYU: IndirectClass needs a declaration
|
||||
SizeofTakingStructRef<IndirectClass> sizeof_taking_struct2;
|
||||
|
||||
// Not sure why, but C++ doesn't require full type of IndirectClass here.
|
||||
// sizeof(IndirectTemplateStruct<IndirectClass&>) doesn't require IndirectClass
|
||||
// full type because IndirectTemplateStruct<IndirectClass&> stores just
|
||||
// a pointer, in fact. Hence, its size doesn't depend on IndirectClass size.
|
||||
// C++ [expr.sizeof]p2:
|
||||
// When applied to a class, the result is the number of bytes in an object of
|
||||
// that class...
|
||||
// IWYU: IndirectClass needs a declaration
|
||||
SizeofTakingStructTpl<IndirectClass&> sizeof_taking_struct3;
|
||||
|
||||
// Not sure why, but C++ doesn't require full type of IndirectClass here.
|
||||
// sizeof(IndirectTemplateStruct<IndirectClass&>) doesn't require IndirectClass
|
||||
// full type.
|
||||
// IWYU: IndirectClass needs a declaration
|
||||
SizeofTakingStructTplRef<IndirectClass> sizeof_taking_struct4;
|
||||
|
||||
|
@ -88,10 +98,27 @@ SizeofTakingStructTplRef<IndirectClass> sizeof_taking_struct4;
|
|||
// IWYU: IndirectClass needs a declaration
|
||||
SizeofTakingStructTplRef2<IndirectClass> sizeof_taking_struct5;
|
||||
|
||||
// Not sure why, but C++ doesn't require full type of IndirectClass here.
|
||||
// sizeof(IndirectTemplateStruct<IndirectClass&>) doesn't require IndirectClass
|
||||
// full type.
|
||||
// IWYU: IndirectClass needs a declaration
|
||||
SizeofTakingStructTplRef2<IndirectClass&> sizeof_taking_struct6;
|
||||
|
||||
// The same with some sugar.
|
||||
|
||||
// IWYU: IndirectClass is...*indirect.h
|
||||
SizeofTakingStruct<decltype(ref)> sizeof_taking_struct7;
|
||||
|
||||
// IWYU: IndirectClass is...*indirect.h
|
||||
SizeofTakingStructRef<decltype(dummy)> sizeof_taking_struct8;
|
||||
|
||||
SizeofTakingStructTpl<decltype(ref)> sizeof_taking_struct9;
|
||||
|
||||
SizeofTakingStructTplRef<decltype(dummy)> sizeof_taking_struct10;
|
||||
|
||||
// IWYU: IndirectClass is...*indirect.h
|
||||
SizeofTakingStructTplRef2<decltype(dummy)> sizeof_taking_struct11;
|
||||
|
||||
SizeofTakingStructTplRef2<decltype(ref)> sizeof_taking_struct12;
|
||||
|
||||
/**** IWYU_SUMMARY
|
||||
|
||||
|
|
Loading…
Reference in New Issue