Skip to content

Commit 9862080

Browse files
Pass LangOpts from CompilerInstance to DependencyScanningWorker (#93753)
This commit fixes #88896 by passing LangOpts from the CompilerInstance to DependencyScanningWorker so that the original LangOpts are preserved/respected. This makes for more accurate parsing/lexing when certain language versions or features specific to versions are to be used.
1 parent d1aa9ba commit 9862080

File tree

8 files changed

+95
-31
lines changed

8 files changed

+95
-31
lines changed

clang/include/clang/Lex/DependencyDirectivesScanner.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#ifndef LLVM_CLANG_LEX_DEPENDENCYDIRECTIVESSCANNER_H
1818
#define LLVM_CLANG_LEX_DEPENDENCYDIRECTIVESSCANNER_H
1919

20+
#include "clang/Basic/LangOptions.h"
2021
#include "clang/Basic/SourceLocation.h"
2122
#include "llvm/ADT/ArrayRef.h"
2223

@@ -117,7 +118,7 @@ struct Directive {
117118
bool scanSourceForDependencyDirectives(
118119
StringRef Input, SmallVectorImpl<dependency_directives_scan::Token> &Tokens,
119120
SmallVectorImpl<dependency_directives_scan::Directive> &Directives,
120-
DiagnosticsEngine *Diags = nullptr,
121+
const LangOptions &LangOpts, DiagnosticsEngine *Diags = nullptr,
121122
SourceLocation InputSourceLoc = SourceLocation());
122123

123124
/// Print the previously scanned dependency directives as minimized source text.

clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,8 @@ class DependencyScanningWorkerFilesystem
363363
///
364364
/// Returns true if the directive tokens are populated for this file entry,
365365
/// false if not (i.e. this entry is not a file or its scan fails).
366-
bool ensureDirectiveTokensArePopulated(EntryRef Entry);
366+
bool ensureDirectiveTokensArePopulated(EntryRef Entry,
367+
const LangOptions &LangOpts);
367368

368369
/// Check whether \p Path exists. By default checks cached result of \c
369370
/// status(), and falls back on FS if unable to do so.

clang/lib/Frontend/FrontendActions.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,8 +1169,8 @@ void PrintDependencyDirectivesSourceMinimizerAction::ExecuteAction() {
11691169
llvm::SmallVector<dependency_directives_scan::Token, 16> Tokens;
11701170
llvm::SmallVector<dependency_directives_scan::Directive, 32> Directives;
11711171
if (scanSourceForDependencyDirectives(
1172-
FromFile.getBuffer(), Tokens, Directives, &CI.getDiagnostics(),
1173-
SM.getLocForStartOfFile(SM.getMainFileID()))) {
1172+
FromFile.getBuffer(), Tokens, Directives, CI.getLangOpts(),
1173+
&CI.getDiagnostics(), SM.getLocForStartOfFile(SM.getMainFileID()))) {
11741174
assert(CI.getDiagnostics().hasErrorOccurred() &&
11751175
"no errors reported for failure");
11761176

clang/lib/Lex/DependencyDirectivesScanner.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,17 @@ struct DirectiveWithTokens {
6262
struct Scanner {
6363
Scanner(StringRef Input,
6464
SmallVectorImpl<dependency_directives_scan::Token> &Tokens,
65-
DiagnosticsEngine *Diags, SourceLocation InputSourceLoc)
65+
DiagnosticsEngine *Diags, SourceLocation InputSourceLoc,
66+
const LangOptions &LangOpts)
6667
: Input(Input), Tokens(Tokens), Diags(Diags),
67-
InputSourceLoc(InputSourceLoc), LangOpts(getLangOptsForDepScanning()),
68-
TheLexer(InputSourceLoc, LangOpts, Input.begin(), Input.begin(),
68+
InputSourceLoc(InputSourceLoc),
69+
LangOpts(getLangOptsForDepScanning(LangOpts)),
70+
TheLexer(InputSourceLoc, this->LangOpts, Input.begin(), Input.begin(),
6971
Input.end()) {}
7072

71-
static LangOptions getLangOptsForDepScanning() {
72-
LangOptions LangOpts;
73+
static LangOptions
74+
getLangOptsForDepScanning(const LangOptions &invocationLangOpts) {
75+
LangOptions LangOpts(invocationLangOpts);
7376
// Set the lexer to use 'tok::at' for '@', instead of 'tok::unknown'.
7477
LangOpts.ObjC = true;
7578
LangOpts.LineComment = true;
@@ -700,7 +703,7 @@ bool Scanner::lex_Pragma(const char *&First, const char *const End) {
700703
SmallVector<dependency_directives_scan::Token> DiscardTokens;
701704
const char *Begin = Buffer.c_str();
702705
Scanner PragmaScanner{StringRef(Begin, Buffer.size()), DiscardTokens, Diags,
703-
InputSourceLoc};
706+
InputSourceLoc, LangOptions()};
704707

705708
PragmaScanner.TheLexer.setParsingPreprocessorDirective(true);
706709
if (PragmaScanner.lexPragma(Begin, Buffer.end()))
@@ -950,9 +953,10 @@ bool Scanner::scan(SmallVectorImpl<Directive> &Directives) {
950953

951954
bool clang::scanSourceForDependencyDirectives(
952955
StringRef Input, SmallVectorImpl<dependency_directives_scan::Token> &Tokens,
953-
SmallVectorImpl<Directive> &Directives, DiagnosticsEngine *Diags,
954-
SourceLocation InputSourceLoc) {
955-
return Scanner(Input, Tokens, Diags, InputSourceLoc).scan(Directives);
956+
SmallVectorImpl<Directive> &Directives, const LangOptions &LangOpts,
957+
DiagnosticsEngine *Diags, SourceLocation InputSourceLoc) {
958+
return Scanner(Input, Tokens, Diags, InputSourceLoc, LangOpts)
959+
.scan(Directives);
956960
}
957961

958962
void clang::printDependencyDirectivesAsSource(

clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ DependencyScanningWorkerFilesystem::readFile(StringRef Filename) {
4242
}
4343

4444
bool DependencyScanningWorkerFilesystem::ensureDirectiveTokensArePopulated(
45-
EntryRef Ref) {
45+
EntryRef Ref, const LangOptions &LangOpts) {
4646
auto &Entry = Ref.Entry;
4747

4848
if (Entry.isError() || Entry.isDirectory())
@@ -66,7 +66,7 @@ bool DependencyScanningWorkerFilesystem::ensureDirectiveTokensArePopulated(
6666
// dependencies.
6767
if (scanSourceForDependencyDirectives(Contents->Original->getBuffer(),
6868
Contents->DepDirectiveTokens,
69-
Directives)) {
69+
Directives, LangOpts)) {
7070
Contents->DepDirectiveTokens.clear();
7171
// FIXME: Propagate the diagnostic if desired by the client.
7272
Contents->DepDirectives.store(new std::optional<DependencyDirectivesTy>());

clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,11 +364,12 @@ class DependencyScanningAction : public tooling::ToolAction {
364364
// Use the dependency scanning optimized file system if requested to do so.
365365
if (DepFS)
366366
ScanInstance.getPreprocessorOpts().DependencyDirectivesForFile =
367-
[LocalDepFS = DepFS](FileEntryRef File)
367+
[LocalDepFS = DepFS,
368+
&LangOpts = ScanInstance.getLangOpts()](FileEntryRef File)
368369
-> std::optional<ArrayRef<dependency_directives_scan::Directive>> {
369370
if (llvm::ErrorOr<EntryRef> Entry =
370371
LocalDepFS->getOrCreateFileSystemEntry(File.getName()))
371-
if (LocalDepFS->ensureDirectiveTokensArePopulated(*Entry))
372+
if (LocalDepFS->ensureDirectiveTokensArePopulated(*Entry, LangOpts))
372373
return Entry->getDirectiveTokens();
373374
return std::nullopt;
374375
};

clang/unittests/Lex/DependencyDirectivesScannerTest.cpp

Lines changed: 69 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "clang/Lex/DependencyDirectivesScanner.h"
10+
#include "clang/Basic/TokenKinds.h"
1011
#include "llvm/ADT/SmallString.h"
1112
#include "gtest/gtest.h"
1213

@@ -17,11 +18,11 @@ using namespace clang::dependency_directives_scan;
1718
static bool minimizeSourceToDependencyDirectives(
1819
StringRef Input, SmallVectorImpl<char> &Out,
1920
SmallVectorImpl<dependency_directives_scan::Token> &Tokens,
20-
SmallVectorImpl<Directive> &Directives) {
21+
SmallVectorImpl<Directive> &Directives, const LangOptions &LangOpts) {
2122
Out.clear();
2223
Tokens.clear();
2324
Directives.clear();
24-
if (scanSourceForDependencyDirectives(Input, Tokens, Directives))
25+
if (scanSourceForDependencyDirectives(Input, Tokens, Directives, LangOpts))
2526
return true;
2627

2728
raw_svector_ostream OS(Out);
@@ -38,7 +39,9 @@ static bool minimizeSourceToDependencyDirectives(StringRef Input,
3839
SmallVectorImpl<char> &Out) {
3940
SmallVector<dependency_directives_scan::Token, 16> Tokens;
4041
SmallVector<Directive, 32> Directives;
41-
return minimizeSourceToDependencyDirectives(Input, Out, Tokens, Directives);
42+
LangOptions LangOpts;
43+
return minimizeSourceToDependencyDirectives(Input, Out, Tokens, Directives,
44+
LangOpts);
4245
}
4346

4447
namespace {
@@ -47,16 +50,17 @@ TEST(MinimizeSourceToDependencyDirectivesTest, Empty) {
4750
SmallVector<char, 128> Out;
4851
SmallVector<dependency_directives_scan::Token, 4> Tokens;
4952
SmallVector<Directive, 4> Directives;
53+
LangOptions LangOpts;
5054

51-
ASSERT_FALSE(
52-
minimizeSourceToDependencyDirectives("", Out, Tokens, Directives));
55+
ASSERT_FALSE(minimizeSourceToDependencyDirectives("", Out, Tokens, Directives,
56+
LangOpts));
5357
EXPECT_TRUE(Out.empty());
5458
EXPECT_TRUE(Tokens.empty());
5559
ASSERT_EQ(1u, Directives.size());
5660
ASSERT_EQ(pp_eof, Directives.back().Kind);
5761

5862
ASSERT_FALSE(minimizeSourceToDependencyDirectives("abc def\nxyz", Out, Tokens,
59-
Directives));
63+
Directives, LangOpts));
6064
EXPECT_STREQ("<TokBeforeEOF>\n", Out.data());
6165
EXPECT_TRUE(Tokens.empty());
6266
ASSERT_EQ(2u, Directives.size());
@@ -68,6 +72,7 @@ TEST(MinimizeSourceToDependencyDirectivesTest, AllTokens) {
6872
SmallVector<char, 128> Out;
6973
SmallVector<dependency_directives_scan::Token, 4> Tokens;
7074
SmallVector<Directive, 4> Directives;
75+
LangOptions LangOpts;
7176

7277
ASSERT_FALSE(
7378
minimizeSourceToDependencyDirectives("#define A\n"
@@ -92,7 +97,7 @@ TEST(MinimizeSourceToDependencyDirectivesTest, AllTokens) {
9297
"export module m;\n"
9398
"import m;\n"
9499
"#pragma clang system_header\n",
95-
Out, Tokens, Directives));
100+
Out, Tokens, Directives, LangOpts));
96101
EXPECT_EQ(pp_define, Directives[0].Kind);
97102
EXPECT_EQ(pp_undef, Directives[1].Kind);
98103
EXPECT_EQ(pp_endif, Directives[2].Kind);
@@ -145,9 +150,10 @@ TEST(MinimizeSourceToDependencyDirectivesTest, Define) {
145150
SmallVector<char, 128> Out;
146151
SmallVector<dependency_directives_scan::Token, 4> Tokens;
147152
SmallVector<Directive, 4> Directives;
153+
LangOptions LangOpts;
148154

149-
ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define MACRO", Out,
150-
Tokens, Directives));
155+
ASSERT_FALSE(minimizeSourceToDependencyDirectives(
156+
"#define MACRO", Out, Tokens, Directives, LangOpts));
151157
EXPECT_STREQ("#define MACRO\n", Out.data());
152158
ASSERT_EQ(4u, Tokens.size());
153159
ASSERT_EQ(2u, Directives.size());
@@ -838,15 +844,16 @@ TEST(MinimizeSourceToDependencyDirectivesTest, PragmaOnce) {
838844
SmallVector<char, 128> Out;
839845
SmallVector<dependency_directives_scan::Token, 4> Tokens;
840846
SmallVector<Directive, 4> Directives;
847+
LangOptions LangOpts;
841848

842849
StringRef Source = R"(// comment
843850
#pragma once
844851
// another comment
845852
#include <test.h>
846853
_Pragma("once")
847854
)";
848-
ASSERT_FALSE(
849-
minimizeSourceToDependencyDirectives(Source, Out, Tokens, Directives));
855+
ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out, Tokens,
856+
Directives, LangOpts));
850857
EXPECT_STREQ("#pragma once\n#include <test.h>\n_Pragma(\"once\")\n",
851858
Out.data());
852859
ASSERT_EQ(Directives.size(), 4u);
@@ -926,6 +933,7 @@ TEST(MinimizeSourceToDependencyDirectivesTest, CxxModules) {
926933
SmallVector<char, 128> Out;
927934
SmallVector<dependency_directives_scan::Token, 4> Tokens;
928935
SmallVector<Directive, 4> Directives;
936+
LangOptions LangOpts;
929937

930938
StringRef Source = R"(
931939
module;
@@ -954,8 +962,8 @@ ort \
954962
import f(->a = 3);
955963
}
956964
)";
957-
ASSERT_FALSE(
958-
minimizeSourceToDependencyDirectives(Source, Out, Tokens, Directives));
965+
ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out, Tokens,
966+
Directives, LangOpts));
959967
EXPECT_STREQ("#include \"textual-header.h\"\nexport module m;"
960968
"exp\\\nort import:l[[rename]];"
961969
"import<<=3;import a b d e d e f e;"
@@ -1012,4 +1020,52 @@ TEST(MinimizeSourceToDependencyDirectivesTest, TokensBeforeEOF) {
10121020
EXPECT_STREQ("#ifndef A\n#define A\n#endif\n<TokBeforeEOF>\n", Out.data());
10131021
}
10141022

1023+
TEST(MinimizeSourceToDependencyDirectivesTest, CPlusPlus14PPNumber) {
1024+
SmallVector<char, 128> Out;
1025+
SmallVector<dependency_directives_scan::Token, 4> Tokens;
1026+
SmallVector<Directive, 4> Directives;
1027+
LangOptions LangOpts;
1028+
1029+
StringRef Source = R"(
1030+
#if 123'124
1031+
#endif
1032+
)";
1033+
1034+
LangOpts.CPlusPlus14 = true;
1035+
ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out, Tokens,
1036+
Directives, LangOpts));
1037+
EXPECT_STREQ("#if 123'124\n#endif\n", Out.data());
1038+
ASSERT_EQ(Directives.size(), 3u);
1039+
EXPECT_EQ(Directives[0].Kind, dependency_directives_scan::pp_if);
1040+
EXPECT_EQ(Directives[1].Kind, dependency_directives_scan::pp_endif);
1041+
EXPECT_EQ(Directives[2].Kind, dependency_directives_scan::pp_eof);
1042+
ASSERT_EQ(Tokens.size(), 7u);
1043+
1044+
ASSERT_TRUE(Tokens[0].is(tok::hash));
1045+
ASSERT_TRUE(Tokens[1].is(tok::raw_identifier)); // "if"
1046+
ASSERT_TRUE(Tokens[2].is(tok::numeric_constant)); // 123'124
1047+
ASSERT_TRUE(Tokens[3].is(tok::eod));
1048+
ASSERT_TRUE(Tokens[4].is(tok::hash));
1049+
ASSERT_TRUE(Tokens[5].is(tok::raw_identifier)); // #endif
1050+
ASSERT_TRUE(Tokens[6].is(tok::eod));
1051+
1052+
LangOpts.CPlusPlus14 = false;
1053+
ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out, Tokens,
1054+
Directives, LangOpts));
1055+
EXPECT_STREQ("#if 123'124\n#endif\n", Out.data());
1056+
ASSERT_EQ(Directives.size(), 3u);
1057+
EXPECT_EQ(Directives[0].Kind, dependency_directives_scan::pp_if);
1058+
EXPECT_EQ(Directives[1].Kind, dependency_directives_scan::pp_endif);
1059+
EXPECT_EQ(Directives[2].Kind, dependency_directives_scan::pp_eof);
1060+
ASSERT_EQ(Tokens.size(), 8u);
1061+
ASSERT_TRUE(Tokens[0].is(tok::hash));
1062+
ASSERT_TRUE(Tokens[1].is(tok::raw_identifier)); // "if"
1063+
ASSERT_TRUE(Tokens[2].is(tok::numeric_constant)); // 123
1064+
ASSERT_TRUE(Tokens[3].is(tok::unknown)); // '124
1065+
ASSERT_TRUE(Tokens[4].is(tok::eod));
1066+
ASSERT_TRUE(Tokens[5].is(tok::hash));
1067+
ASSERT_TRUE(Tokens[6].is(tok::raw_identifier)); // #endif
1068+
ASSERT_TRUE(Tokens[7].is(tok::eod));
1069+
}
1070+
10151071
} // end anonymous namespace

clang/unittests/Lex/PPDependencyDirectivesTest.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,15 @@ TEST_F(PPDependencyDirectivesTest, MacroGuard) {
104104
SmallVector<dependency_directives_scan::Directive> Directives;
105105
};
106106
SmallVector<std::unique_ptr<DepDirectives>> DepDirectivesObjects;
107+
LangOptions LangOpts;
107108

108109
auto getDependencyDirectives = [&](FileEntryRef File)
109110
-> std::optional<ArrayRef<dependency_directives_scan::Directive>> {
110111
DepDirectivesObjects.push_back(std::make_unique<DepDirectives>());
111112
StringRef Input = (*FileMgr.getBufferForFile(File))->getBuffer();
112113
bool Err = scanSourceForDependencyDirectives(
113114
Input, DepDirectivesObjects.back()->Tokens,
114-
DepDirectivesObjects.back()->Directives);
115+
DepDirectivesObjects.back()->Directives, LangOpts);
115116
EXPECT_FALSE(Err);
116117
return llvm::ArrayRef(DepDirectivesObjects.back()->Directives);
117118
};

0 commit comments

Comments
 (0)