Skip to content

Commit 504bb99

Browse files
SC llvm teamSC llvm team
SC llvm team
authored and
SC llvm team
committed
Merged main:c441f65f9183 into amd-gfx:9f2c08e8b1bc
Local branch amd-gfx 9f2c08e Merged main:8df7e818de45 into amd-gfx:9e95c53a9656 Remote branch main c441f65 [clang][dataflow] Add (initial) debug printing for `Value` and `Environment`.
2 parents 9f2c08e + c441f65 commit 504bb99

File tree

125 files changed

+1238
-436
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

125 files changed

+1238
-436
lines changed

clang-tools-extra/clangd/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ if(MSVC AND NOT CLANG_CL)
5959
endif()
6060

6161
include_directories(BEFORE "${CMAKE_CURRENT_BINARY_DIR}/../clang-tidy")
62+
include_directories(BEFORE "${CMAKE_CURRENT_SOURCE_DIR}/../include-cleaner/include")
6263

6364
add_clang_library(clangDaemon
6465
AST.cpp
@@ -162,6 +163,7 @@ clang_target_link_libraries(clangDaemon
162163
clangDriver
163164
clangFormat
164165
clangFrontend
166+
clangIncludeCleaner
165167
clangIndex
166168
clangLex
167169
clangSema

clang-tools-extra/clangd/Config.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,13 @@ struct Config {
8888
bool StandardLibrary = true;
8989
} Index;
9090

91-
enum UnusedIncludesPolicy { Strict, None };
91+
enum UnusedIncludesPolicy {
92+
/// Diagnose unused includes.
93+
Strict,
94+
None,
95+
/// The same as Strict, but using the include-cleaner library.
96+
Experiment,
97+
};
9298
/// Controls warnings and errors when parsing code.
9399
struct {
94100
bool SuppressAll = false;

clang-tools-extra/clangd/ConfigCompile.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -431,11 +431,13 @@ struct FragmentCompiler {
431431
});
432432

433433
if (F.UnusedIncludes)
434-
if (auto Val = compileEnum<Config::UnusedIncludesPolicy>(
435-
"UnusedIncludes", **F.UnusedIncludes)
436-
.map("Strict", Config::UnusedIncludesPolicy::Strict)
437-
.map("None", Config::UnusedIncludesPolicy::None)
438-
.value())
434+
if (auto Val =
435+
compileEnum<Config::UnusedIncludesPolicy>("UnusedIncludes",
436+
**F.UnusedIncludes)
437+
.map("Strict", Config::UnusedIncludesPolicy::Strict)
438+
.map("Experiment", Config::UnusedIncludesPolicy::Experiment)
439+
.map("None", Config::UnusedIncludesPolicy::None)
440+
.value())
439441
Out.Apply.push_back([Val](const Params &, Config &C) {
440442
C.Diagnostics.UnusedIncludes = *Val;
441443
});

clang-tools-extra/clangd/IncludeCleaner.cpp

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include "ParsedAST.h"
1313
#include "Protocol.h"
1414
#include "SourceCode.h"
15+
#include "clang-include-cleaner/Analysis.h"
16+
#include "clang-include-cleaner/Types.h"
1517
#include "index/CanonicalIncludes.h"
1618
#include "support/Logger.h"
1719
#include "support/Trace.h"
@@ -458,6 +460,9 @@ translateToHeaderIDs(const ReferencedFiles &Files,
458460
return TranslatedHeaderIDs;
459461
}
460462

463+
// This is the original clangd-own implementation for computing unused
464+
// #includes. Eventually it will be deprecated and replaced by the
465+
// include-cleaner-lib-based implementation.
461466
std::vector<const Inclusion *> computeUnusedIncludes(ParsedAST &AST) {
462467
const auto &SM = AST.getSourceManager();
463468

@@ -469,11 +474,62 @@ std::vector<const Inclusion *> computeUnusedIncludes(ParsedAST &AST) {
469474
translateToHeaderIDs(ReferencedFiles, AST.getIncludeStructure(), SM);
470475
return getUnused(AST, ReferencedHeaders, ReferencedFiles.SpelledUmbrellas);
471476
}
477+
std::vector<const Inclusion *> computeUnusedIncludesExperimental(ParsedAST &AST) {
478+
const auto &SM = AST.getSourceManager();
479+
const auto &Includes = AST.getIncludeStructure();
480+
// FIXME: this map should probably be in IncludeStructure.
481+
llvm::StringMap<llvm::SmallVector<IncludeStructure::HeaderID>> BySpelling;
482+
for (const auto &Inc : Includes.MainFileIncludes) {
483+
if (Inc.HeaderID)
484+
BySpelling.try_emplace(Inc.Written)
485+
.first->second.push_back(
486+
static_cast<IncludeStructure::HeaderID>(*Inc.HeaderID));
487+
}
488+
// FIXME: !!this is a hacky way to collect macro references.
489+
std::vector<include_cleaner::SymbolReference> Macros;
490+
auto& PP = AST.getPreprocessor();
491+
for (const syntax::Token &Tok :
492+
AST.getTokens().spelledTokens(SM.getMainFileID())) {
493+
auto Macro = locateMacroAt(Tok, PP);
494+
if (!Macro)
495+
continue;
496+
if (auto DefLoc = Macro->Info->getDefinitionLoc(); DefLoc.isValid())
497+
Macros.push_back(
498+
{Tok.location(),
499+
include_cleaner::Macro{/*Name=*/PP.getIdentifierInfo(Tok.text(SM)),
500+
DefLoc},
501+
include_cleaner::RefType::Explicit});
502+
}
503+
llvm::DenseSet<IncludeStructure::HeaderID> Used;
504+
include_cleaner::walkUsed(
505+
AST.getLocalTopLevelDecls(), /*MacroRefs=*/Macros,
506+
AST.getPragmaIncludes(), SM,
507+
[&](const include_cleaner::SymbolReference &Ref,
508+
llvm::ArrayRef<include_cleaner::Header> Providers) {
509+
for (const auto &H : Providers) {
510+
switch (H.kind()) {
511+
case include_cleaner::Header::Physical:
512+
if (auto HeaderID = Includes.getID(H.physical()))
513+
Used.insert(*HeaderID);
514+
break;
515+
case include_cleaner::Header::Standard:
516+
for (auto HeaderID : Includes.StdlibHeaders.lookup(H.standard()))
517+
Used.insert(HeaderID);
518+
break;
519+
case include_cleaner::Header::Verbatim:
520+
for (auto HeaderID : BySpelling.lookup(H.verbatim()))
521+
Used.insert(HeaderID);
522+
break;
523+
}
524+
}
525+
});
526+
return getUnused(AST, Used, /*ReferencedPublicHeaders*/{});
527+
}
472528

473529
std::vector<Diag> issueUnusedIncludesDiagnostics(ParsedAST &AST,
474530
llvm::StringRef Code) {
475531
const Config &Cfg = Config::current();
476-
if (Cfg.Diagnostics.UnusedIncludes != Config::UnusedIncludesPolicy::Strict ||
532+
if (Cfg.Diagnostics.UnusedIncludes == Config::UnusedIncludesPolicy::None ||
477533
Cfg.Diagnostics.SuppressAll ||
478534
Cfg.Diagnostics.Suppress.contains("unused-includes"))
479535
return {};
@@ -487,7 +543,11 @@ std::vector<Diag> issueUnusedIncludesDiagnostics(ParsedAST &AST,
487543
.getFileEntryRefForID(AST.getSourceManager().getMainFileID())
488544
->getName()
489545
.str();
490-
for (const auto *Inc : computeUnusedIncludes(AST)) {
546+
const auto &UnusedIncludes =
547+
Cfg.Diagnostics.UnusedIncludes == Config::UnusedIncludesPolicy::Experiment
548+
? computeUnusedIncludesExperimental(AST)
549+
: computeUnusedIncludes(AST);
550+
for (const auto *Inc : UnusedIncludes) {
491551
Diag D;
492552
D.Message =
493553
llvm::formatv("included header {0} is not used directly",

clang-tools-extra/clangd/IncludeCleaner.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ getUnused(ParsedAST &AST,
9797
const llvm::StringSet<> &ReferencedPublicHeaders);
9898

9999
std::vector<const Inclusion *> computeUnusedIncludes(ParsedAST &AST);
100+
// The same as computeUnusedIncludes, but it is an experimental and
101+
// include-cleaner-lib-based implementation.
102+
std::vector<const Inclusion *>
103+
computeUnusedIncludesExperimental(ParsedAST &AST);
100104

101105
std::vector<Diag> issueUnusedIncludesDiagnostics(ParsedAST &AST,
102106
llvm::StringRef Code);

clang-tools-extra/clangd/ParsedAST.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "Preamble.h"
2424
#include "SourceCode.h"
2525
#include "TidyProvider.h"
26+
#include "clang-include-cleaner/Record.h"
2627
#include "index/CanonicalIncludes.h"
2728
#include "index/Index.h"
2829
#include "index/Symbol.h"
@@ -801,6 +802,12 @@ ParsedAST::ParsedAST(PathRef TUPath, llvm::StringRef Version,
801802
assert(this->Action);
802803
}
803804

805+
const include_cleaner::PragmaIncludes *ParsedAST::getPragmaIncludes() const {
806+
if (!Preamble)
807+
return nullptr;
808+
return &Preamble->Pragmas;
809+
}
810+
804811
std::optional<llvm::StringRef> ParsedAST::preambleVersion() const {
805812
if (!Preamble)
806813
return std::nullopt;

clang-tools-extra/clangd/ParsedAST.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "Diagnostics.h"
2626
#include "Headers.h"
2727
#include "Preamble.h"
28+
#include "clang-include-cleaner/Record.h"
2829
#include "index/CanonicalIncludes.h"
2930
#include "support/Path.h"
3031
#include "clang/Frontend/FrontendAction.h"
@@ -106,6 +107,9 @@ class ParsedAST {
106107
/// Tokens recorded while parsing the main file.
107108
/// (!) does not have tokens from the preamble.
108109
const syntax::TokenBuffer &getTokens() const { return Tokens; }
110+
/// Returns the PramaIncludes from the preamble.
111+
/// Might be null if AST is built without a preamble.
112+
const include_cleaner::PragmaIncludes *getPragmaIncludes() const;
109113

110114
/// Returns the version of the ParseInputs this AST was built from.
111115
llvm::StringRef version() const { return Version; }

clang-tools-extra/clangd/Preamble.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "Config.h"
1212
#include "Headers.h"
1313
#include "SourceCode.h"
14+
#include "clang-include-cleaner/Record.h"
1415
#include "support/Logger.h"
1516
#include "support/ThreadsafeFS.h"
1617
#include "support/Trace.h"
@@ -77,6 +78,9 @@ class CppFilePreambleCallbacks : public PreambleCallbacks {
7778

7879
std::vector<PragmaMark> takeMarks() { return std::move(Marks); }
7980

81+
include_cleaner::PragmaIncludes takePragmaIncludes() {
82+
return std::move(Pragmas);
83+
}
8084
CanonicalIncludes takeCanonicalIncludes() { return std::move(CanonIncludes); }
8185

8286
bool isMainFileIncludeGuarded() const { return IsMainFileIncludeGuarded; }
@@ -118,6 +122,9 @@ class CppFilePreambleCallbacks : public PreambleCallbacks {
118122
LangOpts = &CI.getLangOpts();
119123
SourceMgr = &CI.getSourceManager();
120124
Includes.collect(CI);
125+
if (Config::current().Diagnostics.UnusedIncludes ==
126+
Config::UnusedIncludesPolicy::Experiment)
127+
Pragmas.record(CI);
121128
if (BeforeExecuteCallback)
122129
BeforeExecuteCallback(CI);
123130
}
@@ -187,6 +194,7 @@ class CppFilePreambleCallbacks : public PreambleCallbacks {
187194
PreambleParsedCallback ParsedCallback;
188195
IncludeStructure Includes;
189196
CanonicalIncludes CanonIncludes;
197+
include_cleaner::PragmaIncludes Pragmas;
190198
MainFileMacros Macros;
191199
std::vector<PragmaMark> Marks;
192200
bool IsMainFileIncludeGuarded = false;
@@ -560,6 +568,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI,
560568
Result->CompileCommand = Inputs.CompileCommand;
561569
Result->Diags = std::move(Diags);
562570
Result->Includes = CapturedInfo.takeIncludes();
571+
Result->Pragmas = CapturedInfo.takePragmaIncludes();
563572
Result->Macros = CapturedInfo.takeMacros();
564573
Result->Marks = CapturedInfo.takeMarks();
565574
Result->CanonIncludes = CapturedInfo.takeCanonicalIncludes();

clang-tools-extra/clangd/Preamble.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "Diagnostics.h"
2828
#include "FS.h"
2929
#include "Headers.h"
30+
#include "clang-include-cleaner/Record.h"
3031
#include "index/CanonicalIncludes.h"
3132
#include "support/Path.h"
3233
#include "clang/Frontend/CompilerInvocation.h"
@@ -57,6 +58,8 @@ struct PreambleData {
5758
// Processes like code completions and go-to-definitions will need #include
5859
// information, and their compile action skips preamble range.
5960
IncludeStructure Includes;
61+
// Captures #include-mapping information in #included headers.
62+
include_cleaner::PragmaIncludes Pragmas;
6063
// Macros defined in the preamble section of the main file.
6164
// Users care about headers vs main-file, not preamble vs non-preamble.
6265
// These should be treated as main-file entities e.g. for code completion.

clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ TEST(IncludeCleaner, StdlibUnused) {
342342
auto AST = TU.build();
343343
EXPECT_THAT(computeUnusedIncludes(AST),
344344
ElementsAre(Pointee(writtenInclusion("<queue>"))));
345+
EXPECT_THAT(computeUnusedIncludesExperimental(AST),
346+
ElementsAre(Pointee(writtenInclusion("<queue>"))));
345347
}
346348

347349
TEST(IncludeCleaner, GetUnusedHeaders) {
@@ -377,6 +379,10 @@ TEST(IncludeCleaner, GetUnusedHeaders) {
377379
computeUnusedIncludes(AST),
378380
UnorderedElementsAre(Pointee(writtenInclusion("\"unused.h\"")),
379381
Pointee(writtenInclusion("\"dir/unused.h\""))));
382+
EXPECT_THAT(
383+
computeUnusedIncludesExperimental(AST),
384+
UnorderedElementsAre(Pointee(writtenInclusion("\"unused.h\"")),
385+
Pointee(writtenInclusion("\"dir/unused.h\""))));
380386
}
381387

382388
TEST(IncludeCleaner, VirtualBuffers) {
@@ -531,6 +537,9 @@ TEST(IncludeCleaner, IWYUPragmas) {
531537
// IWYU pragma: private, include "public.h"
532538
void foo() {}
533539
)cpp");
540+
Config Cfg;
541+
Cfg.Diagnostics.UnusedIncludes = Config::Experiment;
542+
WithContextValue Ctx(Config::Key, std::move(Cfg));
534543
ParsedAST AST = TU.build();
535544

536545
auto ReferencedFiles = findReferencedFiles(
@@ -545,6 +554,7 @@ TEST(IncludeCleaner, IWYUPragmas) {
545554
ReferencedFiles.User.contains(AST.getSourceManager().getMainFileID()));
546555
EXPECT_THAT(AST.getDiagnostics(), llvm::ValueIs(IsEmpty()));
547556
EXPECT_THAT(computeUnusedIncludes(AST), IsEmpty());
557+
EXPECT_THAT(computeUnusedIncludesExperimental(AST), IsEmpty());
548558
}
549559

550560
TEST(IncludeCleaner, RecursiveInclusion) {
@@ -573,6 +583,7 @@ TEST(IncludeCleaner, RecursiveInclusion) {
573583

574584
EXPECT_THAT(AST.getDiagnostics(), llvm::ValueIs(IsEmpty()));
575585
EXPECT_THAT(computeUnusedIncludes(AST), IsEmpty());
586+
EXPECT_THAT(computeUnusedIncludesExperimental(AST), IsEmpty());
576587
}
577588

578589
TEST(IncludeCleaner, IWYUPragmaExport) {
@@ -597,6 +608,7 @@ TEST(IncludeCleaner, IWYUPragmaExport) {
597608
// FIXME: This is not correct: foo.h is unused but is not diagnosed as such
598609
// because we ignore headers with IWYU export pragmas for now.
599610
EXPECT_THAT(computeUnusedIncludes(AST), IsEmpty());
611+
EXPECT_THAT(computeUnusedIncludesExperimental(AST), IsEmpty());
600612
}
601613

602614
TEST(IncludeCleaner, NoDiagsForObjC) {

clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ TEST(WalkAST, Using) {
150150
}
151151
using ns::$explicit^Y;)cpp",
152152
"^Y<int> x;");
153+
testWalk(R"cpp(
154+
namespace ns { class Foo {}; }
155+
)cpp", "using ns::$explicit^Foo; class ^Foo foo;");
153156
}
154157

155158
TEST(WalkAST, Namespaces) {

clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ class Environment {
430430
}
431431

432432
LLVM_DUMP_METHOD void dump() const;
433+
LLVM_DUMP_METHOD void dump(raw_ostream &OS) const;
433434

434435
private:
435436
/// Creates a value appropriate for `Type`, if `Type` is supported, otherwise

clang/include/clang/Analysis/FlowSensitive/Value.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/ADT/DenseMap.h"
2020
#include "llvm/ADT/StringMap.h"
2121
#include "llvm/ADT/StringRef.h"
22+
#include "llvm/Support/raw_ostream.h"
2223
#include <cassert>
2324
#include <utility>
2425

@@ -310,6 +311,8 @@ class StructValue final : public Value {
310311
llvm::DenseMap<const ValueDecl *, Value *> Children;
311312
};
312313

314+
raw_ostream &operator<<(raw_ostream &OS, const Value &Val);
315+
313316
} // namespace dataflow
314317
} // namespace clang
315318

clang/include/clang/Sema/DeclSpec.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,8 +506,16 @@ class DeclSpec {
506506
assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type");
507507
return TypeRep;
508508
}
509+
// Returns the underlying decl, if any.
509510
Decl *getRepAsDecl() const {
510-
assert(isDeclRep((TST) TypeSpecType) && "DeclSpec does not store a decl");
511+
auto *D = getRepAsFoundDecl();
512+
if (const auto *Using = dyn_cast_or_null<UsingShadowDecl>(D))
513+
return Using->getTargetDecl();
514+
return D;
515+
}
516+
// Returns the originally found decl, if any.
517+
Decl *getRepAsFoundDecl() const {
518+
assert(isDeclRep((TST)TypeSpecType) && "DeclSpec does not store a decl");
511519
return DeclRep;
512520
}
513521
Expr *getRepAsExpr() const {

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3324,7 +3324,9 @@ class Sema final {
33243324
SourceLocation ScopedEnumKWLoc,
33253325
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
33263326
bool IsTypeSpecifier, bool IsTemplateParamOrArg,
3327-
OffsetOfKind OOK, SkipBodyInfo *SkipBody = nullptr);
3327+
OffsetOfKind OOK,
3328+
UsingShadowDecl*& FoundUsingShadow,
3329+
SkipBodyInfo *SkipBody = nullptr);
33283330

33293331
DeclResult ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
33303332
unsigned TagSpec, SourceLocation TagLoc,

0 commit comments

Comments
 (0)