From 035de84264598cce1e5052df23a973c6a99aff2d Mon Sep 17 00:00:00 2001 From: ykiko Date: Thu, 17 Oct 2024 21:00:14 +0800 Subject: [PATCH] Some update. --- CMakeLists.txt | 2 +- docs/clice.toml | 6 ++ include/Compiler/Compiler.h | 4 +- include/Compiler/Resolver.h | 2 + include/Support/ADT.h | 3 + src/Compiler/Compiler.cpp | 16 ++-- src/Compiler/Diagnostic.cpp | 121 ++++++++++++++++++++++++++++++- src/Server/Server.cpp | 7 ++ tests/AST/ASTVisitor.cpp | 20 ++++- tests/AST/Compiler.cpp | 4 + tests/AST/Diagnostic.cpp | 23 ++++++ tests/Source/ASTVisitor/test.cpp | 17 +++-- tests/Source/Diagnostic/test.cpp | 6 ++ tests/Source/Diagnostic/test.h | 1 + 14 files changed, 215 insertions(+), 17 deletions(-) create mode 100644 tests/AST/Diagnostic.cpp create mode 100644 tests/Source/Diagnostic/test.cpp create mode 100644 tests/Source/Diagnostic/test.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3eef6981..0c10933f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ endif() function(target_clang target) target_precompile_headers(${target} PRIVATE - "${CMAKE_SOURCE_DIR}/include/Compiler/Diagnostic.h" + "${CMAKE_SOURCE_DIR}/include/Compiler/Clang.h" ) target_include_directories(${target} PRIVATE ${LLVM_INCLUDE_DIRS} diff --git a/docs/clice.toml b/docs/clice.toml index 174dfd10..57657ba3 100644 --- a/docs/clice.toml +++ b/docs/clice.toml @@ -40,3 +40,9 @@ parens = false [inlay-hint] # the maximum length of the inlay hint text. max-length = 20 + +# If array initializer elements are more than this, no inlay hints will be shown. +max-array-elements = 3 + +# Show implicit cast as hint like `1 as int` +implicit-cast = true \ No newline at end of file diff --git a/include/Compiler/Compiler.h b/include/Compiler/Compiler.h index fcf0b3be..f1642fe7 100644 --- a/include/Compiler/Compiler.h +++ b/include/Compiler/Compiler.h @@ -9,11 +9,13 @@ public: Compiler(llvm::StringRef filepath, llvm::StringRef content, llvm::ArrayRef args, + clang::DiagnosticConsumer* consumer = nullptr, llvm::IntrusiveRefCntPtr vfs = llvm::vfs::getRealFileSystem()); Compiler(llvm::ArrayRef args, + clang::DiagnosticConsumer* consumer = nullptr, llvm::IntrusiveRefCntPtr vfs = llvm::vfs::getRealFileSystem()) : - Compiler("", "", args, vfs) {} + Compiler("", "", args, consumer, vfs) {} ~Compiler(); diff --git a/include/Compiler/Resolver.h b/include/Compiler/Resolver.h index 9b026b30..3d123723 100644 --- a/include/Compiler/Resolver.h +++ b/include/Compiler/Resolver.h @@ -19,6 +19,8 @@ public: // TODO: // use a relative clear way to resolve `UnresolvedLookupExpr`. + + // TODO: desugar UsingType. private: clang::Sema& sema; }; diff --git a/include/Support/ADT.h b/include/Support/ADT.h index ec7ae074..b157cdfe 100644 --- a/include/Support/ADT.h +++ b/include/Support/ADT.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -11,5 +12,7 @@ #include + + namespace clice { } // namespace clice diff --git a/src/Compiler/Compiler.cpp b/src/Compiler/Compiler.cpp index 88a5636a..faeed2b9 100644 --- a/src/Compiler/Compiler.cpp +++ b/src/Compiler/Compiler.cpp @@ -17,6 +17,7 @@ static void setInvocation(clang::CompilerInvocation& invocation) { Compiler::Compiler(llvm::StringRef filepath, llvm::StringRef content, llvm::ArrayRef args, + clang::DiagnosticConsumer* consumer, llvm::IntrusiveRefCntPtr vfs) : filepath(filepath), content(content) { // FIXME: figure out should we use createInvocation? clang::CreateInvocationOptions options; @@ -27,7 +28,12 @@ Compiler::Compiler(llvm::StringRef filepath, instance->setInvocation(std::move(invocation)); // FIXME: customize DiagnosticConsumer - instance->createDiagnostics(new clang::TextDiagnosticPrinter(llvm::outs(), new clang::DiagnosticOptions()), true); + if(consumer) { + instance->createDiagnostics(consumer, true); + } else { + instance->createDiagnostics(new clang::TextDiagnosticPrinter(llvm::outs(), new clang::DiagnosticOptions()), + true); + } if(!instance->createTarget()) { llvm::errs() << "Failed to create target\n"; @@ -74,10 +80,10 @@ void Compiler::codeCompletion(llvm::StringRef filepath, std::uint32_t line, std::uint32_t column, clang::CodeCompleteConsumer* consumer) { - auto& codeComplete = instance->getFrontendOpts().CodeCompletionAt; - codeComplete.FileName = filepath; - codeComplete.Line = line; - codeComplete.Column = column; + auto& completion = instance->getFrontendOpts().CodeCompletionAt; + completion.FileName = filepath; + completion.Line = line; + completion.Column = column; instance->setCodeCompletionConsumer(consumer); buildAST(); } diff --git a/src/Compiler/Diagnostic.cpp b/src/Compiler/Diagnostic.cpp index bd5067a4..7a28b727 100644 --- a/src/Compiler/Diagnostic.cpp +++ b/src/Compiler/Diagnostic.cpp @@ -1,4 +1,10 @@ -#include "Compiler/Diagnostic.h" +#include +#include + +#include +#include + +#include namespace clice { @@ -6,11 +12,122 @@ void DiagnosticCollector::BeginSourceFile(const clang::LangOptions& Opts, const }; +const char* getDiagnosticCode(unsigned ID) { + switch(ID) { +#define DIAG(ENUM, \ + CLASS, \ + DEFAULT_MAPPING, \ + DESC, \ + GROPU, \ + SFINAE, \ + NOWERROR, \ + SHOWINSYSHEADER, \ + SHOWINSYSMACRO, \ + DEFERRABLE, \ + CATEGORY) \ + case clang::diag::ENUM: return #ENUM; +#include "clang/Basic/DiagnosticASTKinds.inc" +#include "clang/Basic/DiagnosticAnalysisKinds.inc" +#include "clang/Basic/DiagnosticCommentKinds.inc" +#include "clang/Basic/DiagnosticCommonKinds.inc" +#include "clang/Basic/DiagnosticDriverKinds.inc" +#include "clang/Basic/DiagnosticFrontendKinds.inc" +#include "clang/Basic/DiagnosticLexKinds.inc" +#include "clang/Basic/DiagnosticParseKinds.inc" +#include "clang/Basic/DiagnosticRefactoringKinds.inc" +#include "clang/Basic/DiagnosticSemaKinds.inc" +#include "clang/Basic/DiagnosticSerializationKinds.inc" +#undef DIAG + default: return nullptr; + } +} + +// see llvm/clang/include/clang/AST/ASTDiagnostic.h +void dumpArg(clang::DiagnosticsEngine::ArgumentKind kind, std::uint64_t value) { + switch(kind) { + case clang::DiagnosticsEngine::ak_identifierinfo: { + clang::IdentifierInfo* info = reinterpret_cast(value); + llvm::outs() << info->getName(); + break; + } + + case clang::DiagnosticsEngine::ak_qual: { + clang::Qualifiers qual = clang::Qualifiers::fromOpaqueValue(value); + llvm::outs() << qual.getAsString(); + break; + } + + case clang::DiagnosticsEngine::ak_qualtype: { + clang::QualType type = clang::QualType::getFromOpaquePtr(reinterpret_cast(value)); + llvm::outs() << type.getAsString(); + break; + } + + case clang::DiagnosticsEngine::ak_qualtype_pair: { + clang::TemplateDiffTypes& TDT = *reinterpret_cast(value); + clang::QualType type1 = clang::QualType::getFromOpaquePtr(reinterpret_cast(TDT.FromType)); + clang::QualType type2 = clang::QualType::getFromOpaquePtr(reinterpret_cast(TDT.ToType)); + llvm::outs() << type1.getAsString() << " -> " << type2.getAsString(); + break; + } + + case clang::DiagnosticsEngine::ak_declarationname: { + clang::DeclarationName name = clang::DeclarationName::getFromOpaqueInteger(value); + llvm::outs() << name.getAsString(); + break; + } + + case clang::DiagnosticsEngine::ak_nameddecl: { + clang::NamedDecl* decl = reinterpret_cast(value); + llvm::outs() << decl->getNameAsString(); + break; + } + + case clang::DiagnosticsEngine::ak_nestednamespec: { + clang::NestedNameSpecifier* spec = reinterpret_cast(value); + spec->dump(); + break; + } + + case clang::DiagnosticsEngine::ak_declcontext: { + clang::DeclContext* context = reinterpret_cast(value); + llvm::outs() << context->getDeclKindName(); + break; + } + + case clang::DiagnosticsEngine::ak_attr: { + clang::Attr* attr = reinterpret_cast(value); + break; + // attr->dump(); + } + + default: { + std::terminate(); + } + } + + llvm::outs() << "\n"; +} + void DiagnosticCollector::HandleDiagnostic(clang::DiagnosticsEngine::Level level, const clang::Diagnostic& diagnostic) { llvm::SmallString<128> message; diagnostic.FormatDiagnostic(message); // diagnostic.getLocation(); - llvm::outs() << "Diagnostic: " << message << "\n"; + fmt::print(fg(fmt::color::red), + "[Diagnostic, kind: {}, message: {}]\n", + refl::enum_name(level), + message.str().str()); + diagnostic.getLocation().dump(diagnostic.getDiags()->getSourceManager()); + // get diagnostic text. + auto id = diagnostic.getID(); + llvm::outs() << getDiagnosticCode(id) << "\n"; + // llvm::outs() << diagnostic.getDiags()->getDiagnosticIDs()->getDescription(id) << "\n"; + + // dumpArg(diagnostic.getArgKind(0), diagnostic.getRawArg(0)); + + // FIXME: + // use DiagnosticEngine::SetArgToStringFn to set a custom function to convert arguments to strings. + // Support markdown diagnostic in LSP 3.18. allow complex type to display in markdown code block. }; void DiagnosticCollector::EndSourceFile() { diff --git a/src/Server/Server.cpp b/src/Server/Server.cpp index 243a8177..6625cc62 100644 --- a/src/Server/Server.cpp +++ b/src/Server/Server.cpp @@ -147,6 +147,13 @@ void eventloop(uv_idle_t* handle) { auto Server::initialize(protocol::InitializeParams params) -> protocol::InitializeResult { config::init(URI::resolve(params.workspaceFolders[0].uri)); + + // TODO: sacn module: + + // TODO: load index result + + // TODO: initialize dependencies + return protocol::InitializeResult(); } diff --git a/tests/AST/ASTVisitor.cpp b/tests/AST/ASTVisitor.cpp index b294ca91..17602dad 100644 --- a/tests/AST/ASTVisitor.cpp +++ b/tests/AST/ASTVisitor.cpp @@ -1,6 +1,8 @@ #include "../Test.h" #include #include +#include +#include namespace { @@ -18,15 +20,31 @@ struct Visitor : public clang::RecursiveASTVisitor { clang::QualType result; clang::QualType expect; clice::Compiler compiler; + using Base = clang::RecursiveASTVisitor; Visitor(llvm::StringRef content) : compiler("main.cpp", content, compileArgs) { compiler.buildAST(); } + bool shouldVisitTemplateInstantiations() const { + return true; + } + + bool VisitNamedDecl(clang::NamedDecl* decl) { + llvm::outs() << "deck: " << decl->getName() << "\n"; + llvm::outs() << "linkage: " << refl::enum_name(decl->getLinkageInternal()) << "\n"; + decl->getFormalLinkage(); + llvm::SmallString<128> USR; + clang::index::generateUSRForDecl(decl, USR); + llvm::outs() << "USR: " << USR << "\n"; + return true; + } + void test() { auto decl = compiler.context().getTranslationUnitDecl(); TraverseDecl(decl); - EXPECT_EQ(result.getCanonicalType(), expect.getCanonicalType()); + // EXPECT_EQ(result.getCanonicalType(), expect.getCanonicalType()); + // compiler.context().getTranslationUnitDecl()->dump(); } }; diff --git a/tests/AST/Compiler.cpp b/tests/AST/Compiler.cpp index 4d8cd9d5..6b95a6b7 100644 --- a/tests/AST/Compiler.cpp +++ b/tests/AST/Compiler.cpp @@ -69,6 +69,8 @@ export module M; export constexpr int f() { return 42; } + +export void x; )"; const char* code = R"( @@ -99,6 +101,8 @@ int main() { compiler.generatePCM("/home/ykiko/C++/clice2/build/cache/M.pcm"); } + llvm::outs() << "=====================\n"; + static Compiler compiler("main.cpp", code, compileArgs); compiler.applyPCM("/home/ykiko/C++/clice2/build/cache/M.pcm", "M"); compiler.buildAST(); diff --git a/tests/AST/Diagnostic.cpp b/tests/AST/Diagnostic.cpp new file mode 100644 index 00000000..2fcf29db --- /dev/null +++ b/tests/AST/Diagnostic.cpp @@ -0,0 +1,23 @@ +#include "../Test.h" +#include +#include + +namespace { + +using namespace clice; + +TEST(clice, Diagnostic) { + foreachFile("Diagnostic", [](std::string file, llvm::StringRef content) { + std::vector compileArgs = { + "clang++", + "-std=c++20", + file.c_str(), + "-resource-dir", + "/home/ykiko/C++/clice2/build/lib/clang/20", + }; + Compiler compiler(file, content, compileArgs, new DiagnosticCollector()); + compiler.buildAST(); + }); +} + +} // namespace diff --git a/tests/Source/ASTVisitor/test.cpp b/tests/Source/ASTVisitor/test.cpp index 07276c61..909cbc0a 100644 --- a/tests/Source/ASTVisitor/test.cpp +++ b/tests/Source/ASTVisitor/test.cpp @@ -1,10 +1,13 @@ -template -void foo(U) {} - +namespace { template -int foo(T) {} +struct A {}; -template -void bar(T t) { - auto x = foo(t); +template <> +struct A {}; + +} // namespace + +int main() { + A a; + return 0; } diff --git a/tests/Source/Diagnostic/test.cpp b/tests/Source/Diagnostic/test.cpp new file mode 100644 index 00000000..b5780001 --- /dev/null +++ b/tests/Source/Diagnostic/test.cpp @@ -0,0 +1,6 @@ +// #include "test.h" +#include + +#if __has_include("test.h") + +#endif diff --git a/tests/Source/Diagnostic/test.h b/tests/Source/Diagnostic/test.h new file mode 100644 index 00000000..4c2f4555 --- /dev/null +++ b/tests/Source/Diagnostic/test.h @@ -0,0 +1 @@ +int x; \ No newline at end of file