Skip to content

Commit

Permalink
Merged main:c441f65f9183 into amd-gfx:9f2c08e8b1bc
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
SC llvm team authored and SC llvm team committed Jan 19, 2023
2 parents 9f2c08e + c441f65 commit 504bb99
Show file tree
Hide file tree
Showing 125 changed files with 1,238 additions and 436 deletions.
2 changes: 2 additions & 0 deletions clang-tools-extra/clangd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ if(MSVC AND NOT CLANG_CL)
endif()

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

add_clang_library(clangDaemon
AST.cpp
Expand Down Expand Up @@ -162,6 +163,7 @@ clang_target_link_libraries(clangDaemon
clangDriver
clangFormat
clangFrontend
clangIncludeCleaner
clangIndex
clangLex
clangSema
Expand Down
8 changes: 7 additions & 1 deletion clang-tools-extra/clangd/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,13 @@ struct Config {
bool StandardLibrary = true;
} Index;

enum UnusedIncludesPolicy { Strict, None };
enum UnusedIncludesPolicy {
/// Diagnose unused includes.
Strict,
None,
/// The same as Strict, but using the include-cleaner library.
Experiment,
};
/// Controls warnings and errors when parsing code.
struct {
bool SuppressAll = false;
Expand Down
12 changes: 7 additions & 5 deletions clang-tools-extra/clangd/ConfigCompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,11 +431,13 @@ struct FragmentCompiler {
});

if (F.UnusedIncludes)
if (auto Val = compileEnum<Config::UnusedIncludesPolicy>(
"UnusedIncludes", **F.UnusedIncludes)
.map("Strict", Config::UnusedIncludesPolicy::Strict)
.map("None", Config::UnusedIncludesPolicy::None)
.value())
if (auto Val =
compileEnum<Config::UnusedIncludesPolicy>("UnusedIncludes",
**F.UnusedIncludes)
.map("Strict", Config::UnusedIncludesPolicy::Strict)
.map("Experiment", Config::UnusedIncludesPolicy::Experiment)
.map("None", Config::UnusedIncludesPolicy::None)
.value())
Out.Apply.push_back([Val](const Params &, Config &C) {
C.Diagnostics.UnusedIncludes = *Val;
});
Expand Down
64 changes: 62 additions & 2 deletions clang-tools-extra/clangd/IncludeCleaner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "ParsedAST.h"
#include "Protocol.h"
#include "SourceCode.h"
#include "clang-include-cleaner/Analysis.h"
#include "clang-include-cleaner/Types.h"
#include "index/CanonicalIncludes.h"
#include "support/Logger.h"
#include "support/Trace.h"
Expand Down Expand Up @@ -458,6 +460,9 @@ translateToHeaderIDs(const ReferencedFiles &Files,
return TranslatedHeaderIDs;
}

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

Expand All @@ -469,11 +474,62 @@ std::vector<const Inclusion *> computeUnusedIncludes(ParsedAST &AST) {
translateToHeaderIDs(ReferencedFiles, AST.getIncludeStructure(), SM);
return getUnused(AST, ReferencedHeaders, ReferencedFiles.SpelledUmbrellas);
}
std::vector<const Inclusion *> computeUnusedIncludesExperimental(ParsedAST &AST) {
const auto &SM = AST.getSourceManager();
const auto &Includes = AST.getIncludeStructure();
// FIXME: this map should probably be in IncludeStructure.
llvm::StringMap<llvm::SmallVector<IncludeStructure::HeaderID>> BySpelling;
for (const auto &Inc : Includes.MainFileIncludes) {
if (Inc.HeaderID)
BySpelling.try_emplace(Inc.Written)
.first->second.push_back(
static_cast<IncludeStructure::HeaderID>(*Inc.HeaderID));
}
// FIXME: !!this is a hacky way to collect macro references.
std::vector<include_cleaner::SymbolReference> Macros;
auto& PP = AST.getPreprocessor();
for (const syntax::Token &Tok :
AST.getTokens().spelledTokens(SM.getMainFileID())) {
auto Macro = locateMacroAt(Tok, PP);
if (!Macro)
continue;
if (auto DefLoc = Macro->Info->getDefinitionLoc(); DefLoc.isValid())
Macros.push_back(
{Tok.location(),
include_cleaner::Macro{/*Name=*/PP.getIdentifierInfo(Tok.text(SM)),
DefLoc},
include_cleaner::RefType::Explicit});
}
llvm::DenseSet<IncludeStructure::HeaderID> Used;
include_cleaner::walkUsed(
AST.getLocalTopLevelDecls(), /*MacroRefs=*/Macros,
AST.getPragmaIncludes(), SM,
[&](const include_cleaner::SymbolReference &Ref,
llvm::ArrayRef<include_cleaner::Header> Providers) {
for (const auto &H : Providers) {
switch (H.kind()) {
case include_cleaner::Header::Physical:
if (auto HeaderID = Includes.getID(H.physical()))
Used.insert(*HeaderID);
break;
case include_cleaner::Header::Standard:
for (auto HeaderID : Includes.StdlibHeaders.lookup(H.standard()))
Used.insert(HeaderID);
break;
case include_cleaner::Header::Verbatim:
for (auto HeaderID : BySpelling.lookup(H.verbatim()))
Used.insert(HeaderID);
break;
}
}
});
return getUnused(AST, Used, /*ReferencedPublicHeaders*/{});
}

std::vector<Diag> issueUnusedIncludesDiagnostics(ParsedAST &AST,
llvm::StringRef Code) {
const Config &Cfg = Config::current();
if (Cfg.Diagnostics.UnusedIncludes != Config::UnusedIncludesPolicy::Strict ||
if (Cfg.Diagnostics.UnusedIncludes == Config::UnusedIncludesPolicy::None ||
Cfg.Diagnostics.SuppressAll ||
Cfg.Diagnostics.Suppress.contains("unused-includes"))
return {};
Expand All @@ -487,7 +543,11 @@ std::vector<Diag> issueUnusedIncludesDiagnostics(ParsedAST &AST,
.getFileEntryRefForID(AST.getSourceManager().getMainFileID())
->getName()
.str();
for (const auto *Inc : computeUnusedIncludes(AST)) {
const auto &UnusedIncludes =
Cfg.Diagnostics.UnusedIncludes == Config::UnusedIncludesPolicy::Experiment
? computeUnusedIncludesExperimental(AST)
: computeUnusedIncludes(AST);
for (const auto *Inc : UnusedIncludes) {
Diag D;
D.Message =
llvm::formatv("included header {0} is not used directly",
Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/clangd/IncludeCleaner.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ getUnused(ParsedAST &AST,
const llvm::StringSet<> &ReferencedPublicHeaders);

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

std::vector<Diag> issueUnusedIncludesDiagnostics(ParsedAST &AST,
llvm::StringRef Code);
Expand Down
7 changes: 7 additions & 0 deletions clang-tools-extra/clangd/ParsedAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "Preamble.h"
#include "SourceCode.h"
#include "TidyProvider.h"
#include "clang-include-cleaner/Record.h"
#include "index/CanonicalIncludes.h"
#include "index/Index.h"
#include "index/Symbol.h"
Expand Down Expand Up @@ -801,6 +802,12 @@ ParsedAST::ParsedAST(PathRef TUPath, llvm::StringRef Version,
assert(this->Action);
}

const include_cleaner::PragmaIncludes *ParsedAST::getPragmaIncludes() const {
if (!Preamble)
return nullptr;
return &Preamble->Pragmas;
}

std::optional<llvm::StringRef> ParsedAST::preambleVersion() const {
if (!Preamble)
return std::nullopt;
Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/clangd/ParsedAST.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "Diagnostics.h"
#include "Headers.h"
#include "Preamble.h"
#include "clang-include-cleaner/Record.h"
#include "index/CanonicalIncludes.h"
#include "support/Path.h"
#include "clang/Frontend/FrontendAction.h"
Expand Down Expand Up @@ -106,6 +107,9 @@ class ParsedAST {
/// Tokens recorded while parsing the main file.
/// (!) does not have tokens from the preamble.
const syntax::TokenBuffer &getTokens() const { return Tokens; }
/// Returns the PramaIncludes from the preamble.
/// Might be null if AST is built without a preamble.
const include_cleaner::PragmaIncludes *getPragmaIncludes() const;

/// Returns the version of the ParseInputs this AST was built from.
llvm::StringRef version() const { return Version; }
Expand Down
9 changes: 9 additions & 0 deletions clang-tools-extra/clangd/Preamble.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Config.h"
#include "Headers.h"
#include "SourceCode.h"
#include "clang-include-cleaner/Record.h"
#include "support/Logger.h"
#include "support/ThreadsafeFS.h"
#include "support/Trace.h"
Expand Down Expand Up @@ -77,6 +78,9 @@ class CppFilePreambleCallbacks : public PreambleCallbacks {

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

include_cleaner::PragmaIncludes takePragmaIncludes() {
return std::move(Pragmas);
}
CanonicalIncludes takeCanonicalIncludes() { return std::move(CanonIncludes); }

bool isMainFileIncludeGuarded() const { return IsMainFileIncludeGuarded; }
Expand Down Expand Up @@ -118,6 +122,9 @@ class CppFilePreambleCallbacks : public PreambleCallbacks {
LangOpts = &CI.getLangOpts();
SourceMgr = &CI.getSourceManager();
Includes.collect(CI);
if (Config::current().Diagnostics.UnusedIncludes ==
Config::UnusedIncludesPolicy::Experiment)
Pragmas.record(CI);
if (BeforeExecuteCallback)
BeforeExecuteCallback(CI);
}
Expand Down Expand Up @@ -187,6 +194,7 @@ class CppFilePreambleCallbacks : public PreambleCallbacks {
PreambleParsedCallback ParsedCallback;
IncludeStructure Includes;
CanonicalIncludes CanonIncludes;
include_cleaner::PragmaIncludes Pragmas;
MainFileMacros Macros;
std::vector<PragmaMark> Marks;
bool IsMainFileIncludeGuarded = false;
Expand Down Expand Up @@ -560,6 +568,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI,
Result->CompileCommand = Inputs.CompileCommand;
Result->Diags = std::move(Diags);
Result->Includes = CapturedInfo.takeIncludes();
Result->Pragmas = CapturedInfo.takePragmaIncludes();
Result->Macros = CapturedInfo.takeMacros();
Result->Marks = CapturedInfo.takeMarks();
Result->CanonIncludes = CapturedInfo.takeCanonicalIncludes();
Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/clangd/Preamble.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "Diagnostics.h"
#include "FS.h"
#include "Headers.h"
#include "clang-include-cleaner/Record.h"
#include "index/CanonicalIncludes.h"
#include "support/Path.h"
#include "clang/Frontend/CompilerInvocation.h"
Expand Down Expand Up @@ -57,6 +58,8 @@ struct PreambleData {
// Processes like code completions and go-to-definitions will need #include
// information, and their compile action skips preamble range.
IncludeStructure Includes;
// Captures #include-mapping information in #included headers.
include_cleaner::PragmaIncludes Pragmas;
// Macros defined in the preamble section of the main file.
// Users care about headers vs main-file, not preamble vs non-preamble.
// These should be treated as main-file entities e.g. for code completion.
Expand Down
12 changes: 12 additions & 0 deletions clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@ TEST(IncludeCleaner, StdlibUnused) {
auto AST = TU.build();
EXPECT_THAT(computeUnusedIncludes(AST),
ElementsAre(Pointee(writtenInclusion("<queue>"))));
EXPECT_THAT(computeUnusedIncludesExperimental(AST),
ElementsAre(Pointee(writtenInclusion("<queue>"))));
}

TEST(IncludeCleaner, GetUnusedHeaders) {
Expand Down Expand Up @@ -377,6 +379,10 @@ TEST(IncludeCleaner, GetUnusedHeaders) {
computeUnusedIncludes(AST),
UnorderedElementsAre(Pointee(writtenInclusion("\"unused.h\"")),
Pointee(writtenInclusion("\"dir/unused.h\""))));
EXPECT_THAT(
computeUnusedIncludesExperimental(AST),
UnorderedElementsAre(Pointee(writtenInclusion("\"unused.h\"")),
Pointee(writtenInclusion("\"dir/unused.h\""))));
}

TEST(IncludeCleaner, VirtualBuffers) {
Expand Down Expand Up @@ -531,6 +537,9 @@ TEST(IncludeCleaner, IWYUPragmas) {
// IWYU pragma: private, include "public.h"
void foo() {}
)cpp");
Config Cfg;
Cfg.Diagnostics.UnusedIncludes = Config::Experiment;
WithContextValue Ctx(Config::Key, std::move(Cfg));
ParsedAST AST = TU.build();

auto ReferencedFiles = findReferencedFiles(
Expand All @@ -545,6 +554,7 @@ TEST(IncludeCleaner, IWYUPragmas) {
ReferencedFiles.User.contains(AST.getSourceManager().getMainFileID()));
EXPECT_THAT(AST.getDiagnostics(), llvm::ValueIs(IsEmpty()));
EXPECT_THAT(computeUnusedIncludes(AST), IsEmpty());
EXPECT_THAT(computeUnusedIncludesExperimental(AST), IsEmpty());
}

TEST(IncludeCleaner, RecursiveInclusion) {
Expand Down Expand Up @@ -573,6 +583,7 @@ TEST(IncludeCleaner, RecursiveInclusion) {

EXPECT_THAT(AST.getDiagnostics(), llvm::ValueIs(IsEmpty()));
EXPECT_THAT(computeUnusedIncludes(AST), IsEmpty());
EXPECT_THAT(computeUnusedIncludesExperimental(AST), IsEmpty());
}

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

TEST(IncludeCleaner, NoDiagsForObjC) {
Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ TEST(WalkAST, Using) {
}
using ns::$explicit^Y;)cpp",
"^Y<int> x;");
testWalk(R"cpp(
namespace ns { class Foo {}; }
)cpp", "using ns::$explicit^Foo; class ^Foo foo;");
}

TEST(WalkAST, Namespaces) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ class Environment {
}

LLVM_DUMP_METHOD void dump() const;
LLVM_DUMP_METHOD void dump(raw_ostream &OS) const;

private:
/// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Analysis/FlowSensitive/Value.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <utility>

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

raw_ostream &operator<<(raw_ostream &OS, const Value &Val);

} // namespace dataflow
} // namespace clang

Expand Down
10 changes: 9 additions & 1 deletion clang/include/clang/Sema/DeclSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -506,8 +506,16 @@ class DeclSpec {
assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type");
return TypeRep;
}
// Returns the underlying decl, if any.
Decl *getRepAsDecl() const {
assert(isDeclRep((TST) TypeSpecType) && "DeclSpec does not store a decl");
auto *D = getRepAsFoundDecl();
if (const auto *Using = dyn_cast_or_null<UsingShadowDecl>(D))
return Using->getTargetDecl();
return D;
}
// Returns the originally found decl, if any.
Decl *getRepAsFoundDecl() const {
assert(isDeclRep((TST)TypeSpecType) && "DeclSpec does not store a decl");
return DeclRep;
}
Expr *getRepAsExpr() const {
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -3324,7 +3324,9 @@ class Sema final {
SourceLocation ScopedEnumKWLoc,
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
bool IsTypeSpecifier, bool IsTemplateParamOrArg,
OffsetOfKind OOK, SkipBodyInfo *SkipBody = nullptr);
OffsetOfKind OOK,
UsingShadowDecl*& FoundUsingShadow,
SkipBodyInfo *SkipBody = nullptr);

DeclResult ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
unsigned TagSpec, SourceLocation TagLoc,
Expand Down
Loading

0 comments on commit 504bb99

Please sign in to comment.