[clang] 99b5ec1 - [include-cleaner] Merge 2 parseIWYUPragma impls in libToolingInclusions
Sam McCall via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 28 04:21:36 PST 2022
Author: Sam McCall
Date: 2022-11-28T13:20:09+01:00
New Revision: 99b5ec1fd1a70680a8483e5efb86807254e44e0e
URL: https://github.com/llvm/llvm-project/commit/99b5ec1fd1a70680a8483e5efb86807254e44e0e
DIFF: https://github.com/llvm/llvm-project/commit/99b5ec1fd1a70680a8483e5efb86807254e44e0e.diff
LOG: [include-cleaner] Merge 2 parseIWYUPragma impls in libToolingInclusions
Based on include-cleaner's version, but:
- remove assert that can fail for input `/\<newline>* */`
- assert was also checking the wrong condition: that the prefix *differed* from
either `//` or from `/*`. Avoid use of strncmp where we can.
- add a comment that the brittleness of the text matching is intentional
Differential Revision: https://reviews.llvm.org/D138780
Added:
Modified:
clang-tools-extra/clangd/Headers.cpp
clang-tools-extra/clangd/Headers.h
clang-tools-extra/clangd/unittests/HeadersTests.cpp
clang-tools-extra/include-cleaner/lib/Record.cpp
clang/include/clang/Tooling/Inclusions/HeaderAnalysis.h
clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp
clang/unittests/Tooling/HeaderAnalysisTest.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/Headers.cpp b/clang-tools-extra/clangd/Headers.cpp
index f276f5bd8c6c1..c808c6f2bcc51 100644
--- a/clang-tools-extra/clangd/Headers.cpp
+++ b/clang-tools-extra/clangd/Headers.cpp
@@ -23,18 +23,6 @@
namespace clang {
namespace clangd {
-llvm::Optional<StringRef> parseIWYUPragma(const char *Text) {
- // This gets called for every comment seen in the preamble, so it's quite hot.
- constexpr llvm::StringLiteral IWYUPragma = "// IWYU pragma: ";
- if (strncmp(Text, IWYUPragma.data(), IWYUPragma.size()))
- return llvm::None;
- Text += IWYUPragma.size();
- const char *End = Text;
- while (*End != 0 && *End != '\n')
- ++End;
- return StringRef(Text, End - Text);
-}
-
class IncludeStructure::RecordHeaders : public PPCallbacks,
public CommentHandler {
public:
@@ -136,7 +124,8 @@ class IncludeStructure::RecordHeaders : public PPCallbacks,
}
bool HandleComment(Preprocessor &PP, SourceRange Range) override {
- auto Pragma = parseIWYUPragma(SM.getCharacterData(Range.getBegin()));
+ auto Pragma =
+ tooling::parseIWYUPragma(SM.getCharacterData(Range.getBegin()));
if (!Pragma)
return false;
diff --git a/clang-tools-extra/clangd/Headers.h b/clang-tools-extra/clangd/Headers.h
index ba72ad397bf8f..ff3f063168325 100644
--- a/clang-tools-extra/clangd/Headers.h
+++ b/clang-tools-extra/clangd/Headers.h
@@ -35,12 +35,6 @@ namespace clangd {
/// Returns true if \p Include is literal include like "path" or <path>.
bool isLiteralInclude(llvm::StringRef Include);
-/// If Text begins an Include-What-You-Use directive, returns it.
-/// Given "// IWYU pragma: keep", returns "keep".
-/// Input is a null-terminated char* as provided by SM.getCharacterData().
-/// (This should not be StringRef as we do *not* want to scan for its length).
-llvm::Optional<StringRef> parseIWYUPragma(const char *Text);
-
/// Represents a header file to be #include'd.
struct HeaderFile {
std::string File;
diff --git a/clang-tools-extra/clangd/unittests/HeadersTests.cpp b/clang-tools-extra/clangd/unittests/HeadersTests.cpp
index 324d4b58a1ef1..cad81d40ffc81 100644
--- a/clang-tools-extra/clangd/unittests/HeadersTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HeadersTests.cpp
@@ -447,18 +447,6 @@ TEST_F(HeadersTest, HasIWYUPragmas) {
EXPECT_FALSE(Includes.hasIWYUExport(getID("none.h", Includes)));
}
-TEST(Headers, ParseIWYUPragma) {
- EXPECT_THAT(parseIWYUPragma("// IWYU pragma: keep"), HasValue(Eq("keep")));
- EXPECT_THAT(parseIWYUPragma("// IWYU pragma: keep\netc"),
- HasValue(Eq("keep")));
- EXPECT_EQ(parseIWYUPragma("/* IWYU pragma: keep"), llvm::None)
- << "Only // comments supported!";
- EXPECT_EQ(parseIWYUPragma("// IWYU pragma: keep"), llvm::None)
- << "Sensitive to whitespace";
- EXPECT_EQ(parseIWYUPragma("// IWYU pragma:keep"), llvm::None)
- << "Sensitive to whitespace";
-}
-
} // namespace
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/include-cleaner/lib/Record.cpp b/clang-tools-extra/include-cleaner/lib/Record.cpp
index e93bc14d4b46a..a0aa1ad6845d2 100644
--- a/clang-tools-extra/include-cleaner/lib/Record.cpp
+++ b/clang-tools-extra/include-cleaner/lib/Record.cpp
@@ -141,21 +141,6 @@ class PPRecorder : public PPCallbacks {
} // namespace
-// FIXME: this is a mirror of clang::clangd::parseIWYUPragma, move to libTooling
-// to share the code?
-static llvm::Optional<StringRef> parseIWYUPragma(const char *Text) {
- assert(strncmp(Text, "//", 2) || strncmp(Text, "/*", 2));
- constexpr llvm::StringLiteral IWYUPragma = " IWYU pragma: ";
- Text += 2; // Skip the comment start, // or /*.
- if (strncmp(Text, IWYUPragma.data(), IWYUPragma.size()))
- return llvm::None;
- Text += IWYUPragma.size();
- const char *End = Text;
- while (*End != 0 && *End != '\n')
- ++End;
- return StringRef(Text, End - Text);
-}
-
class PragmaIncludes::RecordPragma : public PPCallbacks, public CommentHandler {
public:
RecordPragma(const CompilerInstance &CI, PragmaIncludes *Out)
@@ -229,7 +214,8 @@ class PragmaIncludes::RecordPragma : public PPCallbacks, public CommentHandler {
bool HandleComment(Preprocessor &PP, SourceRange Range) override {
auto &SM = PP.getSourceManager();
- auto Pragma = parseIWYUPragma(SM.getCharacterData(Range.getBegin()));
+ auto Pragma =
+ tooling::parseIWYUPragma(SM.getCharacterData(Range.getBegin()));
if (!Pragma)
return false;
diff --git a/clang/include/clang/Tooling/Inclusions/HeaderAnalysis.h b/clang/include/clang/Tooling/Inclusions/HeaderAnalysis.h
index b0b4b1455c5df..3d47829296e91 100644
--- a/clang/include/clang/Tooling/Inclusions/HeaderAnalysis.h
+++ b/clang/include/clang/Tooling/Inclusions/HeaderAnalysis.h
@@ -9,6 +9,8 @@
#ifndef LLVM_CLANG_TOOLING_INCLUSIONS_HEADER_ANALYSIS_H
#define LLVM_CLANG_TOOLING_INCLUSIONS_HEADER_ANALYSIS_H
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
namespace clang {
class FileEntry;
class SourceManager;
@@ -27,6 +29,13 @@ namespace tooling {
bool isSelfContainedHeader(const FileEntry *FE, const SourceManager &SM,
HeaderSearch &HeaderInfo);
+/// If Text begins an Include-What-You-Use directive, returns it.
+/// Given "// IWYU pragma: keep", returns "keep".
+/// Input is a null-terminated char* as provided by SM.getCharacterData().
+/// (This should not be StringRef as we do *not* want to scan for its length).
+/// For multi-line comments, we return only the first line.
+llvm::Optional<llvm::StringRef> parseIWYUPragma(const char *Text);
+
} // namespace tooling
} // namespace clang
diff --git a/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp b/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp
index 78b866eae0967..c0ed78134f1a1 100644
--- a/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp
+++ b/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp
@@ -64,4 +64,28 @@ bool isSelfContainedHeader(const FileEntry *FE, const SourceManager &SM,
const_cast<SourceManager &>(SM).getMemoryBufferForFileOrNone(FE).value_or(
llvm::MemoryBufferRef()));
}
+
+llvm::Optional<StringRef> parseIWYUPragma(const char *Text) {
+ // Skip the comment start, // or /*.
+ if (Text[0] != '/' || (Text[1] != '/' && Text[1] != '*'))
+ return llvm::None;
+ bool BlockComment = Text[1] == '*';
+ Text += 2;
+
+ // Per spec, direcitves are whitespace- and case-sensitive.
+ constexpr llvm::StringLiteral IWYUPragma = " IWYU pragma: ";
+ if (strncmp(Text, IWYUPragma.data(), IWYUPragma.size()))
+ return llvm::None;
+ Text += IWYUPragma.size();
+ const char *End = Text;
+ while (*End != 0 && *End != '\n')
+ ++End;
+ StringRef Rest(Text, End - Text);
+ // Strip off whitespace and comment markers to avoid confusion. This isn't
+ // fully-compatible with IWYU, which splits into whitespace-delimited tokens.
+ if (BlockComment)
+ Rest.consume_back("*/");
+ return Rest.trim();
+}
+
} // namespace clang::tooling
diff --git a/clang/unittests/Tooling/HeaderAnalysisTest.cpp b/clang/unittests/Tooling/HeaderAnalysisTest.cpp
index 37a4c3ffb483e..c6ba625c0c062 100644
--- a/clang/unittests/Tooling/HeaderAnalysisTest.cpp
+++ b/clang/unittests/Tooling/HeaderAnalysisTest.cpp
@@ -9,11 +9,14 @@
#include "clang/Tooling/Inclusions/HeaderAnalysis.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Testing/TestAST.h"
+#include "llvm/Testing/Support/SupportHelpers.h"
#include "gtest/gtest.h"
namespace clang {
namespace tooling {
namespace {
+using llvm::ValueIs;
+using testing::Eq;
TEST(HeaderAnalysisTest, IsSelfContained) {
TestInputs Inputs;
@@ -58,6 +61,19 @@ TEST(HeaderAnalysisTest, IsSelfContained) {
EXPECT_FALSE(isSelfContainedHeader(FM.getFile("bad.h").get(), SM, HI));
}
+TEST(HeaderAnalysisTest, ParseIWYUPragma) {
+ EXPECT_THAT(parseIWYUPragma("// IWYU pragma: keep"), ValueIs(Eq("keep")));
+ EXPECT_THAT(parseIWYUPragma("// IWYU pragma: keep me\netc"),
+ ValueIs(Eq("keep me")));
+ EXPECT_THAT(parseIWYUPragma("/* IWYU pragma: keep */"), ValueIs(Eq("keep")));
+ EXPECT_EQ(parseIWYUPragma("// IWYU pragma: keep"), llvm::None)
+ << "Prefix is sensitive to whitespace";
+ EXPECT_EQ(parseIWYUPragma("// IWYU pragma:keep"), llvm::None)
+ << "Prefix is sensitive to whitespace";
+ EXPECT_EQ(parseIWYUPragma("/\n* IWYU pragma: keep */"), llvm::None)
+ << "Must start with /* or //";
+}
+
} // namespace
} // namespace tooling
} // namespace clang
More information about the cfe-commits
mailing list