Add begin_keep and end_keep pragmas, test and docs
this was a proposed issue in #1095 where one could make a block of keeps as opposed to marking every keep with a pragma: keep instruction. added test to verify and updated documentation where appropriate.
This commit is contained in:
parent
109fdb4cdd
commit
cf1624a4e2
|
@ -15,6 +15,20 @@ This pragma applies to a single `#include` directive or forward declaration. It
|
|||
|
||||
In this case, `std::vector` isn't used, so `<vector>` would normally be discarded, but the pragma instructs IWYU to leave it. Similarly the class `ForwardDeclaration` isn't used but is kept because of the pragma on it.
|
||||
|
||||
## IWYU pragma: begin_keep/end_keep ##
|
||||
|
||||
This pragma applies to a set of `#include` directives and forward declarations. It declares that the headers and forward declarations in between are to be left alone by IWYU.
|
||||
|
||||
main.cc:
|
||||
// IWYU pragma: begin_keep
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
class MyClass;
|
||||
// IWYU pragma: end_keep
|
||||
|
||||
In the provided case nothing within the bounds of `begin_keep` and `end_keep` will be discarded.
|
||||
|
||||
## 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.
|
||||
|
|
|
@ -243,6 +243,11 @@ Used after
|
|||
.B #include
|
||||
directives or forward declarations it ensures that they won't be removed.
|
||||
.TP
|
||||
.BR "// IWYU pragma: begin_keep" , " // IWYU pragma: end_keep"
|
||||
Has the same effect as the previous pragma comment, but applies to a range of
|
||||
.BR #include s
|
||||
and forward declarations instead of a single line.
|
||||
.TP
|
||||
.B // IWYU pragma: export
|
||||
Used after an
|
||||
.B #include
|
||||
|
|
3
iwyu.cc
3
iwyu.cc
|
@ -3898,7 +3898,8 @@ class IwyuAstConsumer
|
|||
} else {
|
||||
SourceLocation decl_end_location = decl->getSourceRange().getEnd();
|
||||
if (LineHasText(decl_end_location, "// IWYU pragma: keep") ||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -177,6 +177,14 @@ bool IwyuPreprocessorInfo::HasOpenBeginExports(const FileEntry* file) const {
|
|||
GetFileEntry(begin_exports_location_stack_.top()) == file;
|
||||
}
|
||||
|
||||
// Only call this when the given files is the one being processed
|
||||
// Only return true if there is an open begin_keep pragma in the current
|
||||
// state of the parse of the given file.
|
||||
bool IwyuPreprocessorInfo::HasOpenBeginKeep(const FileEntry* file) const {
|
||||
return !begin_keep_location_stack_.empty() &&
|
||||
GetFileEntry(begin_keep_location_stack_.top()) == file;
|
||||
}
|
||||
|
||||
bool IwyuPreprocessorInfo::HandleComment(Preprocessor& pp,
|
||||
SourceRange comment_range) {
|
||||
HandlePragmaComment(comment_range);
|
||||
|
@ -209,6 +217,20 @@ void IwyuPreprocessorInfo::HandlePragmaComment(SourceRange comment_range) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (HasOpenBeginKeep(this_file_entry)) {
|
||||
if (MatchOneToken(tokens, "end_keep", 1, begin_loc)) {
|
||||
ERRSYM(this_file_entry) << "end_keep pragma seen\n";
|
||||
SourceLocation keep_loc_begin = begin_keep_location_stack_.top();
|
||||
begin_keep_location_stack_.pop();
|
||||
SourceRange keep_range(keep_loc_begin, begin_loc);
|
||||
keep_location_ranges_.insert(std::make_pair(this_file_entry, keep_range));
|
||||
} else {
|
||||
// No pragmas allowed within "begin_keep" - "end_keep"
|
||||
Warn(begin_loc, "Expected end_keep pragma");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (MatchOneToken(tokens, "begin_exports", 1, begin_loc)) {
|
||||
ERRSYM(this_file_entry) << "begin_exports pragma seen\n";
|
||||
begin_exports_location_stack_.push(begin_loc);
|
||||
|
@ -220,6 +242,17 @@ void IwyuPreprocessorInfo::HandlePragmaComment(SourceRange comment_range) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (MatchOneToken(tokens, "begin_keep", 1, begin_loc)) {
|
||||
ERRSYM(this_file_entry) << "begin_keep pragma seen\n";
|
||||
begin_keep_location_stack_.push(begin_loc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (MatchOneToken(tokens, "end_keep", 1, begin_loc)) {
|
||||
Warn(begin_loc, "end_keep without a begin_keep");
|
||||
return;
|
||||
}
|
||||
|
||||
if (MatchTwoTokens(tokens, "private,", "include", 3, begin_loc)) {
|
||||
// 3rd token should be a quoted header.
|
||||
const string& suggested = tokens[2];
|
||||
|
@ -397,7 +430,8 @@ void IwyuPreprocessorInfo::MaybeProtectInclude(
|
|||
// interpreted as a pragma. Maybe do "keep" and "export" pragma handling
|
||||
// in HandleComment?
|
||||
if (LineHasText(includer_loc, "// IWYU pragma: keep") ||
|
||||
LineHasText(includer_loc, "/* IWYU pragma: keep")) {
|
||||
LineHasText(includer_loc, "/* IWYU pragma: keep") ||
|
||||
HasOpenBeginKeep(includer)) {
|
||||
protect_reason = "pragma_keep";
|
||||
FileInfoFor(includer)->ReportKnownDesiredFile(includee);
|
||||
|
||||
|
@ -790,6 +824,12 @@ void IwyuPreprocessorInfo::FileChanged_ExitToFile(
|
|||
"begin_exports without an end_exports");
|
||||
begin_exports_location_stack_.pop();
|
||||
}
|
||||
|
||||
if (HasOpenBeginKeep(exiting_from)) {
|
||||
Warn(begin_keep_location_stack_.top(),
|
||||
"begin_keep without an end_keep");
|
||||
begin_keep_location_stack_.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void IwyuPreprocessorInfo::FileChanged_RenameFile(SourceLocation new_file) {
|
||||
|
@ -1087,4 +1127,15 @@ bool IwyuPreprocessorInfo::ForwardDeclareIsInhibited(
|
|||
ContainsKey(*inhibited_forward_declares, normalized_symbol_name);
|
||||
}
|
||||
|
||||
bool IwyuPreprocessorInfo::ForwardDeclareInKeepRange(SourceLocation loc) const {
|
||||
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) {
|
||||
if (it->second.fullyContains(loc)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace include_what_you_use
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
// f) // IWYU pragma: no_forward_declare foo::Bar
|
||||
// g) // IWYU pragma: friend <regexp>
|
||||
// // IWYU pragma: friend "<regexp>" -- needed if spaces in regexp.
|
||||
// h) // IWYU pragma: begin_keep
|
||||
// i) // IWYU pragma: end_keep
|
||||
// 'Annotation' constructs:
|
||||
// h) #include "foo/bar/baz.h" // IWYU pragma: export
|
||||
// i) #include "foo/bar/baz.h" // IWYU pragma: keep
|
||||
|
@ -86,6 +88,7 @@ using std::set;
|
|||
using std::stack;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::multimap;
|
||||
|
||||
class IwyuPreprocessorInfo : public clang::PPCallbacks,
|
||||
public clang::CommentHandler {
|
||||
|
@ -165,6 +168,10 @@ 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;
|
||||
|
||||
protected:
|
||||
// Preprocessor event handlers called by Clang.
|
||||
void MacroExpands(const clang::Token& macro_use_token,
|
||||
|
@ -281,6 +288,10 @@ class IwyuPreprocessorInfo : public clang::PPCallbacks,
|
|||
// there is a pending "begin_exports" pragma.
|
||||
bool HasOpenBeginExports(const clang::FileEntry* file) const;
|
||||
|
||||
// Return true if at the current point in the parse of the given files,
|
||||
// there is a pending "begin_keep" pragma.
|
||||
bool HasOpenBeginKeep(const clang::FileEntry* file) const;
|
||||
|
||||
// The C++ source file passed in as an argument to the compiler (as
|
||||
// opposed to other files seen via #includes).
|
||||
const clang::FileEntry* main_file_;
|
||||
|
@ -345,6 +356,15 @@ class IwyuPreprocessorInfo : public clang::PPCallbacks,
|
|||
// per file in the current inclusion chain..
|
||||
stack<clang::SourceLocation> begin_exports_location_stack_;
|
||||
|
||||
// For processing pragmas. It is the current stack of open "begin_keep"s.
|
||||
// There should be at most one item in this stack per file in the current
|
||||
// inclusion chain.
|
||||
stack<clang::SourceLocation> begin_keep_location_stack_;
|
||||
|
||||
// For processing forward decls. It is a multimap containing the bounds of
|
||||
// every keep range.
|
||||
multimap<const clang::FileEntry*, clang::SourceRange> keep_location_ranges_;
|
||||
|
||||
// For processing associated pragma. It is the current open
|
||||
// "associated" pragma.
|
||||
clang::SourceLocation associated_pragma_location_;
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
//===--- pragma_keep_multi.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 .
|
||||
|
||||
// This tests whether or not begin_keep/end_keep works
|
||||
|
||||
// Check empty block
|
||||
|
||||
// IWYU pragma: begin_keep
|
||||
// IWYU pragma: end_keep
|
||||
|
||||
// Check block with one include
|
||||
|
||||
// IWYU pragma: begin_keep
|
||||
#include "tests/cxx/comment_pragmas-d22.h"
|
||||
// IWYU pragma: end_keep
|
||||
|
||||
// Check block with several includes
|
||||
|
||||
// IWYU pragma: begin_keep
|
||||
#include "tests/cxx/comment_pragmas-d1.h"
|
||||
#include "tests/cxx/comment_pragmas-d10.h"
|
||||
#include "tests/cxx/comment_pragmas-d16.h"
|
||||
#include "tests/cxx/comment_pragmas-d21.h"
|
||||
// IWYU pragma: end_keep
|
||||
|
||||
// Block with one forward decl
|
||||
|
||||
// IWYU pragma: begin_keep
|
||||
class FakeClass;
|
||||
// IWYU pragma: end_keep
|
||||
|
||||
// Block with several forward decls
|
||||
|
||||
// IWYU pragma: begin_keep
|
||||
class FakeClass2;
|
||||
class FakeClass3;
|
||||
class FakeClass4;
|
||||
// IWYU pragma: end_keep
|
||||
|
||||
// Block with mix of includes and fwd decls
|
||||
|
||||
// IWYU pragma: begin_keep
|
||||
#include "tests/cxx/comment_pragmas-d17.h"
|
||||
#include "tests/cxx/comment_pragmas-d13.h"
|
||||
#include "tests/cxx/comment_pragmas-d14.h"
|
||||
|
||||
class FakeClass5;
|
||||
class FakeClass6;
|
||||
class FakeClass7;
|
||||
// IWYU pragma: end_keep
|
||||
|
||||
#include "tests/cxx/comment_pragmas-d9.h"
|
||||
|
||||
class AnotherFakeClass;
|
||||
|
||||
/**** IWYU_SUMMARY
|
||||
tests/cxx/pragma_keep_multi.cc should add these lines:
|
||||
|
||||
tests/cxx/pragma_keep_multi.cc should remove these lines:
|
||||
- #include "tests/cxx/comment_pragmas-d9.h" // lines XX-XX
|
||||
- class AnotherFakeClass; // lines XX-XX
|
||||
|
||||
The full include-list for tests/cxx/pragma_keep_multi.cc:
|
||||
#include "tests/cxx/comment_pragmas-d1.h"
|
||||
#include "tests/cxx/comment_pragmas-d10.h"
|
||||
#include "tests/cxx/comment_pragmas-d13.h"
|
||||
#include "tests/cxx/comment_pragmas-d14.h"
|
||||
#include "tests/cxx/comment_pragmas-d16.h"
|
||||
#include "tests/cxx/comment_pragmas-d17.h"
|
||||
#include "tests/cxx/comment_pragmas-d21.h"
|
||||
#include "tests/cxx/comment_pragmas-d22.h"
|
||||
class FakeClass2; // lines XX-XX
|
||||
class FakeClass3; // lines XX-XX
|
||||
class FakeClass4; // lines XX-XX
|
||||
class FakeClass5; // lines XX-XX
|
||||
class FakeClass6; // lines XX-XX
|
||||
class FakeClass7; // lines XX-XX
|
||||
class FakeClass; // lines XX-XX
|
||||
|
||||
***** IWYU_SUMMARY */
|
||||
|
Loading…
Reference in New Issue