Skip to content

Commit ab88580

Browse files
committed
Refactor/migrate to DependencyDirectivesScanner.cpp for better code reuse
This moves the check for C++20 modules usage into DependencyDirectivesScanner.cpp to better reuuse existing code. This now also leverages the dependency directives scanner to lex the module text line.
1 parent a3bd364 commit ab88580

File tree

4 files changed

+61
-143
lines changed

4 files changed

+61
-143
lines changed

clang/include/clang/Driver/Driver.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,7 @@ class Driver {
819819
/// \returns True if module usage is detected, false otherwise, or an error on
820820
/// read failure.
821821
llvm::ErrorOr<bool>
822-
ScanInputsForCXXModuleUsage(const InputList &Inputs) const;
822+
ScanInputsForCXX20ModulesUsage(const InputList &Inputs) const;
823823

824824
/// Retrieves a ToolChain for a particular \p Target triple.
825825
///

clang/include/clang/Lex/DependencyDirectivesScanner.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,13 @@ void printDependencyDirectivesAsSource(
136136
ArrayRef<dependency_directives_scan::Directive> Directives,
137137
llvm::raw_ostream &OS);
138138

139+
/// Scan an input source buffer for C++20 named module usage.
140+
///
141+
/// \param Source The input source buffer.
142+
///
143+
/// \returns true if any C++20 named modules related directive was found.
144+
bool scanInputForCXX20ModulesUsage(StringRef Source);
145+
139146
/// Functor that returns the dependency directives for a given file.
140147
class DependencyDirectivesGetter {
141148
public:

clang/lib/Driver/Driver.cpp

Lines changed: 4 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
#include "clang/Driver/Tool.h"
6868
#include "clang/Driver/ToolChain.h"
6969
#include "clang/Driver/Types.h"
70+
#include "clang/Lex/DependencyDirectivesScanner.h"
7071
#include "llvm/ADT/ArrayRef.h"
7172
#include "llvm/ADT/STLExtras.h"
7273
#include "llvm/ADT/StringExtras.h"
@@ -4423,145 +4424,6 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args,
44234424
}
44244425
}
44254426

4426-
static void skipWhitespace(const char *&Ptr) {
4427-
while (isWhitespace(*Ptr))
4428-
++Ptr;
4429-
}
4430-
4431-
// Returns the length of EOL, either 0 (no end-of-line), 1 (\n) or 2 (\r\n).
4432-
static unsigned isEOL(const char *Ptr) {
4433-
if (*Ptr == '\0')
4434-
return 0;
4435-
if (*(Ptr + 1) != '\0' && isVerticalWhitespace(Ptr[0]) &&
4436-
isVerticalWhitespace(Ptr[1]) && Ptr[0] != Ptr[1])
4437-
return 2;
4438-
return !!isVerticalWhitespace(Ptr[0]);
4439-
}
4440-
4441-
static void skipLine(const char *&Ptr) {
4442-
for (;;) {
4443-
char LastNonWhitespace = ' ';
4444-
while (!isVerticalWhitespace(*Ptr) && *Ptr != '\0') {
4445-
if (!isHorizontalWhitespace(*Ptr))
4446-
LastNonWhitespace = *Ptr;
4447-
++Ptr;
4448-
}
4449-
4450-
const unsigned Len = isEOL(Ptr);
4451-
if (!Len)
4452-
return;
4453-
4454-
Ptr += Len;
4455-
if (LastNonWhitespace != '\\')
4456-
break;
4457-
}
4458-
}
4459-
4460-
// Returns the length of a line splice sequence (including trailing whitespace),
4461-
// or 0 if no line splice is found.
4462-
static unsigned isLineSplice(const char *Start) {
4463-
if (*Start != '\\')
4464-
return 0;
4465-
4466-
const char *Ptr = Start + 1;
4467-
while (isHorizontalWhitespace(*Ptr))
4468-
++Ptr;
4469-
4470-
if (unsigned Len = isEOL(Ptr))
4471-
return Ptr - Start + Len;
4472-
return 0;
4473-
}
4474-
4475-
static bool trySkipLineSplice(const char *&Ptr) {
4476-
if (unsigned Len = isLineSplice(Ptr); Len) {
4477-
Ptr += Len;
4478-
return true;
4479-
}
4480-
return false;
4481-
}
4482-
4483-
static bool trySkipDirective(const char *&Ptr) {
4484-
if (*Ptr != '#')
4485-
return false;
4486-
4487-
++Ptr;
4488-
skipLine(Ptr);
4489-
return true;
4490-
}
4491-
4492-
static bool trySkipLineComment(const char *&Ptr) {
4493-
if (Ptr[0] != '/' || Ptr[1] != '/')
4494-
return false;
4495-
4496-
Ptr += 2;
4497-
skipLine(Ptr);
4498-
return true;
4499-
}
4500-
4501-
static bool trySkipBlockComment(const char *&Ptr) {
4502-
if (Ptr[0] != '/' || Ptr[1] != '*')
4503-
return false;
4504-
4505-
Ptr += 2;
4506-
while (*Ptr != '\0') {
4507-
if (Ptr[0] == '*' && Ptr[1] == '/') {
4508-
Ptr += 2; // '*/'
4509-
return true;
4510-
}
4511-
++Ptr;
4512-
}
4513-
return true;
4514-
}
4515-
4516-
static bool trySkipComment(const char *&Ptr) {
4517-
return trySkipLineComment(Ptr) || trySkipBlockComment(Ptr);
4518-
}
4519-
4520-
// Skipps over comments and (non-module) directives
4521-
static void skipToRelevantCXXModuleText(const char *&Ptr) {
4522-
while (*Ptr != '\0') {
4523-
skipWhitespace(Ptr);
4524-
if (trySkipComment(Ptr) || trySkipDirective(Ptr) || trySkipLineSplice(Ptr))
4525-
continue;
4526-
break; // Found relevant text!
4527-
}
4528-
}
4529-
4530-
static bool scanBufferForCXXModuleUsage(const llvm::MemoryBuffer &Buffer) {
4531-
const char *Ptr = Buffer.getBufferStart();
4532-
skipToRelevantCXXModuleText(Ptr);
4533-
4534-
// Check if the buffer has enough remaining bytes left for any of the
4535-
// module-related declaration fragments we are checking for, without making
4536-
// the potentially memory-mapped buffer load unnecessary pages.
4537-
constexpr int MinKeywordLength = 6;
4538-
const char *Begin = Ptr;
4539-
for (int i = 0; i < MinKeywordLength; ++i) {
4540-
if (*Ptr == '\0')
4541-
return false;
4542-
++Ptr;
4543-
}
4544-
StringRef Text(Begin, MinKeywordLength);
4545-
4546-
const bool IsGlobalModule = Text.starts_with("module");
4547-
if (!IsGlobalModule && !Text.starts_with("import") &&
4548-
!Text.starts_with("export"))
4549-
return false;
4550-
4551-
// Ensure the keyword has a proper ending and isn't part of a identifier
4552-
// or namespace. For this we might have to skip comments and line
4553-
// continuations.
4554-
while (*Ptr != '\0') {
4555-
if (isWhitespace(*Ptr) || (IsGlobalModule && *Ptr == ';'))
4556-
return true;
4557-
if (trySkipBlockComment(Ptr) || trySkipLineSplice(Ptr))
4558-
continue;
4559-
return false;
4560-
}
4561-
4562-
return false;
4563-
}
4564-
45654427
static bool hasCXXModuleInputType(const Driver::InputList &Inputs) {
45664428
const auto IsTypeCXXModule = [](const auto &Input) -> bool {
45674429
const auto TypeID = Input.first;
@@ -4571,7 +4433,7 @@ static bool hasCXXModuleInputType(const Driver::InputList &Inputs) {
45714433
}
45724434

45734435
llvm::ErrorOr<bool>
4574-
Driver::ScanInputsForCXXModuleUsage(const InputList &Inputs) const {
4436+
Driver::ScanInputsForCXX20ModulesUsage(const InputList &Inputs) const {
45754437
const auto CXXInputs = llvm::make_filter_range(
45764438
Inputs, [](const auto &Input) { return types::isCXX(Input.first); });
45774439

@@ -4582,7 +4444,7 @@ Driver::ScanInputsForCXXModuleUsage(const InputList &Inputs) const {
45824444
return ErrOrBuffer.getError();
45834445
const auto Buffer = std::move(*ErrOrBuffer);
45844446

4585-
if (scanBufferForCXXModuleUsage(*Buffer)) {
4447+
if (scanInputForCXX20ModulesUsage(Buffer->getBuffer())) {
45864448
Diags.Report(diag::remark_found_cxx20_module_usage) << Filename;
45874449
return true;
45884450
}
@@ -4609,7 +4471,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
46094471
// Currently, this serves diagnostic purposes only.
46104472
bool UsesCXXModules = hasCXXModuleInputType(Inputs);
46114473
if (!UsesCXXModules) {
4612-
const auto ErrOrScanResult = ScanInputsForCXXModuleUsage(Inputs);
4474+
const auto ErrOrScanResult = ScanInputsForCXX20ModulesUsage(Inputs);
46134475
if (!ErrOrScanResult) {
46144476
Diags.Report(diag::err_cannot_open_file)
46154477
<< ErrOrScanResult.getError().message();

clang/lib/Lex/DependencyDirectivesScanner.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ struct Scanner {
8383
/// \returns True on error.
8484
bool scan(SmallVectorImpl<Directive> &Directives);
8585

86+
friend bool clang::scanInputForCXX20ModulesUsage(StringRef Source);
87+
8688
private:
8789
/// Lexes next token and advances \p First and the \p Lexer.
8890
[[nodiscard]] dependency_directives_scan::Token &
@@ -1075,3 +1077,50 @@ void clang::printDependencyDirectivesAsSource(
10751077
}
10761078
}
10771079
}
1080+
1081+
static void skipUntilMaybeCXX20ModuleDirective(const char *&First,
1082+
const char *const End) {
1083+
assert(First <= End);
1084+
while (First != End) {
1085+
if (*First == '#') {
1086+
++First;
1087+
skipToNewlineRaw(First, End);
1088+
}
1089+
skipWhitespace(First, End);
1090+
if (const auto Len = isEOL(First, End)) {
1091+
First += Len;
1092+
continue;
1093+
}
1094+
break;
1095+
}
1096+
}
1097+
1098+
bool clang::scanInputForCXX20ModulesUsage(StringRef Source) {
1099+
const char *First = Source.begin();
1100+
const char *const End = Source.end();
1101+
skipUntilMaybeCXX20ModuleDirective(First, End);
1102+
if (First == End)
1103+
return false;
1104+
1105+
// Check if the next token can even be a module directive before creating a
1106+
// full lexer.
1107+
if (!(*First == 'i' || *First == 'e' || *First == 'm'))
1108+
return false;
1109+
1110+
llvm::SmallVector<dependency_directives_scan::Token> Tokens;
1111+
Scanner S(StringRef(First, End - First), Tokens, nullptr, SourceLocation());
1112+
if (S.lexModule(First, End))
1113+
return false;
1114+
auto IsCXXNamedModuleDirective = [](const DirectiveWithTokens &D) {
1115+
switch (D.Kind) {
1116+
case dependency_directives_scan::cxx_module_decl:
1117+
case dependency_directives_scan::cxx_import_decl:
1118+
case dependency_directives_scan::cxx_export_module_decl:
1119+
case dependency_directives_scan::cxx_export_import_decl:
1120+
return true;
1121+
default:
1122+
return false;
1123+
}
1124+
};
1125+
return llvm::any_of(S.DirsWithToks, IsCXXNamedModuleDirective);
1126+
}

0 commit comments

Comments
 (0)