forked from OSchip/llvm-project
[clang-scan-deps] Add minimizer support for C++20 modules.
This only adds support to the minimizer, it doesn't actually capture the dependencies yet. llvm-svn: 368381
This commit is contained in:
parent
179dc276eb
commit
1861f4ea25
|
@ -47,6 +47,9 @@ enum TokenKind {
|
||||||
pp_else,
|
pp_else,
|
||||||
pp_endif,
|
pp_endif,
|
||||||
decl_at_import,
|
decl_at_import,
|
||||||
|
cxx_export_decl,
|
||||||
|
cxx_module_decl,
|
||||||
|
cxx_import_decl,
|
||||||
pp_eof,
|
pp_eof,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ private:
|
||||||
LLVM_NODISCARD bool minimizeImpl(const char *First, const char *const End);
|
LLVM_NODISCARD bool minimizeImpl(const char *First, const char *const End);
|
||||||
LLVM_NODISCARD bool lexPPLine(const char *&First, const char *const End);
|
LLVM_NODISCARD bool lexPPLine(const char *&First, const char *const End);
|
||||||
LLVM_NODISCARD bool lexAt(const char *&First, const char *const End);
|
LLVM_NODISCARD bool lexAt(const char *&First, const char *const End);
|
||||||
|
LLVM_NODISCARD bool lexModule(const char *&First, const char *const End);
|
||||||
LLVM_NODISCARD bool lexDefine(const char *&First, const char *const End);
|
LLVM_NODISCARD bool lexDefine(const char *&First, const char *const End);
|
||||||
LLVM_NODISCARD bool lexPragma(const char *&First, const char *const End);
|
LLVM_NODISCARD bool lexPragma(const char *&First, const char *const End);
|
||||||
LLVM_NODISCARD bool lexEndif(const char *&First, const char *const End);
|
LLVM_NODISCARD bool lexEndif(const char *&First, const char *const End);
|
||||||
|
@ -576,6 +577,59 @@ bool Minimizer::lexAt(const char *&First, const char *const End) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Minimizer::lexModule(const char *&First, const char *const End) {
|
||||||
|
IdInfo Id = lexIdentifier(First, End);
|
||||||
|
First = Id.Last;
|
||||||
|
bool Export = false;
|
||||||
|
if (Id.Name == "export") {
|
||||||
|
Export = true;
|
||||||
|
skipWhitespace(First, End);
|
||||||
|
if (!isIdentifierBody(*First)) {
|
||||||
|
skipLine(First, End);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Id = lexIdentifier(First, End);
|
||||||
|
First = Id.Last;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Id.Name != "module" && Id.Name != "import") {
|
||||||
|
skipLine(First, End);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
skipWhitespace(First, End);
|
||||||
|
|
||||||
|
// Ignore this as a module directive if the next character can't be part of
|
||||||
|
// an import.
|
||||||
|
|
||||||
|
switch (*First) {
|
||||||
|
case ':':
|
||||||
|
case '<':
|
||||||
|
case '"':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!isIdentifierBody(*First)) {
|
||||||
|
skipLine(First, End);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Export) {
|
||||||
|
makeToken(cxx_export_decl);
|
||||||
|
append("export ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Id.Name == "module")
|
||||||
|
makeToken(cxx_module_decl);
|
||||||
|
else
|
||||||
|
makeToken(cxx_import_decl);
|
||||||
|
append(Id.Name);
|
||||||
|
append(" ");
|
||||||
|
printToNewline(First, End);
|
||||||
|
append("\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Minimizer::lexDefine(const char *&First, const char *const End) {
|
bool Minimizer::lexDefine(const char *&First, const char *const End) {
|
||||||
makeToken(pp_define);
|
makeToken(pp_define);
|
||||||
append("#define ");
|
append("#define ");
|
||||||
|
@ -677,6 +731,18 @@ bool Minimizer::lexDefault(TokenKind Kind, StringRef Directive,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isStartOfRelevantLine(char First) {
|
||||||
|
switch (First) {
|
||||||
|
case '#':
|
||||||
|
case '@':
|
||||||
|
case 'i':
|
||||||
|
case 'e':
|
||||||
|
case 'm':
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Minimizer::lexPPLine(const char *&First, const char *const End) {
|
bool Minimizer::lexPPLine(const char *&First, const char *const End) {
|
||||||
assert(First != End);
|
assert(First != End);
|
||||||
|
|
||||||
|
@ -685,7 +751,7 @@ bool Minimizer::lexPPLine(const char *&First, const char *const End) {
|
||||||
if (First == End)
|
if (First == End)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (*First != '#' && *First != '@') {
|
if (!isStartOfRelevantLine(*First)) {
|
||||||
skipLine(First, End);
|
skipLine(First, End);
|
||||||
assert(First <= End);
|
assert(First <= End);
|
||||||
return false;
|
return false;
|
||||||
|
@ -695,6 +761,9 @@ bool Minimizer::lexPPLine(const char *&First, const char *const End) {
|
||||||
if (*First == '@')
|
if (*First == '@')
|
||||||
return lexAt(First, End);
|
return lexAt(First, End);
|
||||||
|
|
||||||
|
if (*First == 'i' || *First == 'e' || *First == 'm')
|
||||||
|
return lexModule(First, End);
|
||||||
|
|
||||||
// Handle preprocessing directives.
|
// Handle preprocessing directives.
|
||||||
++First; // Skip over '#'.
|
++First; // Skip over '#'.
|
||||||
skipWhitespace(First, End);
|
skipWhitespace(First, End);
|
||||||
|
|
|
@ -60,7 +60,9 @@ TEST(MinimizeSourceToDependencyDirectivesTest, AllTokens) {
|
||||||
"#__include_macros <A>\n"
|
"#__include_macros <A>\n"
|
||||||
"#import <A>\n"
|
"#import <A>\n"
|
||||||
"@import A;\n"
|
"@import A;\n"
|
||||||
"#pragma clang module import A\n",
|
"#pragma clang module import A\n"
|
||||||
|
"export module m;\n"
|
||||||
|
"import m;\n",
|
||||||
Out, Tokens));
|
Out, Tokens));
|
||||||
EXPECT_EQ(pp_define, Tokens[0].K);
|
EXPECT_EQ(pp_define, Tokens[0].K);
|
||||||
EXPECT_EQ(pp_undef, Tokens[1].K);
|
EXPECT_EQ(pp_undef, Tokens[1].K);
|
||||||
|
@ -76,7 +78,10 @@ TEST(MinimizeSourceToDependencyDirectivesTest, AllTokens) {
|
||||||
EXPECT_EQ(pp_import, Tokens[11].K);
|
EXPECT_EQ(pp_import, Tokens[11].K);
|
||||||
EXPECT_EQ(decl_at_import, Tokens[12].K);
|
EXPECT_EQ(decl_at_import, Tokens[12].K);
|
||||||
EXPECT_EQ(pp_pragma_import, Tokens[13].K);
|
EXPECT_EQ(pp_pragma_import, Tokens[13].K);
|
||||||
EXPECT_EQ(pp_eof, Tokens[14].K);
|
EXPECT_EQ(cxx_export_decl, Tokens[14].K);
|
||||||
|
EXPECT_EQ(cxx_module_decl, Tokens[15].K);
|
||||||
|
EXPECT_EQ(cxx_import_decl, Tokens[16].K);
|
||||||
|
EXPECT_EQ(pp_eof, Tokens[17].K);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MinimizeSourceToDependencyDirectivesTest, Define) {
|
TEST(MinimizeSourceToDependencyDirectivesTest, Define) {
|
||||||
|
@ -568,4 +573,48 @@ TEST(MinimizeSourceToDependencyDirectivesTest, PragmaOnce) {
|
||||||
EXPECT_STREQ("#pragma once\n#include <test.h>\n", Out.data());
|
EXPECT_STREQ("#pragma once\n#include <test.h>\n", Out.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(MinimizeSourceToDependencyDirectivesTest, CxxModules) {
|
||||||
|
SmallVector<char, 128> Out;
|
||||||
|
SmallVector<Token, 4> Tokens;
|
||||||
|
|
||||||
|
StringRef Source = R"(
|
||||||
|
module;
|
||||||
|
#include "textual-header.h"
|
||||||
|
|
||||||
|
export module m;
|
||||||
|
exp\
|
||||||
|
ort \
|
||||||
|
import \
|
||||||
|
:l [[rename]];
|
||||||
|
|
||||||
|
export void f();
|
||||||
|
|
||||||
|
void h() {
|
||||||
|
import.a = 3;
|
||||||
|
import = 3;
|
||||||
|
import <<= 3;
|
||||||
|
import->a = 3;
|
||||||
|
import();
|
||||||
|
import . a();
|
||||||
|
|
||||||
|
import a b d e d e f e;
|
||||||
|
import foo [[no_unique_address]];
|
||||||
|
import foo();
|
||||||
|
import f(:sefse);
|
||||||
|
import f(->a = 3);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out, Tokens));
|
||||||
|
EXPECT_STREQ("#include \"textual-header.h\"\nexport module m;\n"
|
||||||
|
"export import :l [[rename]];\n"
|
||||||
|
"import <<= 3;\nimport a b d e d e f e;\n"
|
||||||
|
"import foo [[no_unique_address]];\nimport foo();\n"
|
||||||
|
"import f(:sefse);\nimport f(->a = 3);\n", Out.data());
|
||||||
|
ASSERT_EQ(Tokens.size(), 12u);
|
||||||
|
EXPECT_EQ(Tokens[0].K,
|
||||||
|
minimize_source_to_dependency_directives::pp_include);
|
||||||
|
EXPECT_EQ(Tokens[2].K,
|
||||||
|
minimize_source_to_dependency_directives::cxx_module_decl);
|
||||||
|
}
|
||||||
|
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
Loading…
Reference in New Issue