From a94b33d012f8a41a99ee0362699070b5b20504b6 Mon Sep 17 00:00:00 2001 From: ykiko Date: Wed, 14 Aug 2024 21:44:05 +0800 Subject: [PATCH] update Directive. --- docs/clangd.md | 1 + docs/examples/Preprocessor.cpp | 141 +++++++++++++++++++----------- include/Clang/Clang.h | 6 ++ include/Clang/Directive.h | 147 ++++++++++++++++++++++++++++---- include/Feature/SemanticToken.h | 2 - src/Clang/Directive.cpp | 108 ++++++++++++++++------- src/Feature/SemanticToken.cpp | 2 - test.cpp | 18 ++-- 8 files changed, 318 insertions(+), 107 deletions(-) diff --git a/docs/clangd.md b/docs/clangd.md index f219b556..76b66c98 100644 --- a/docs/clangd.md +++ b/docs/clangd.md @@ -25,6 +25,7 @@ FIXME: - 提供更好的模板代码补全(需要在索引文件里面记录模板实例化),https://github.com/clangd/clangd/issues/443,然后补全的时候获取`.`号前面的表达式类型,之后再这里查找 - 支持模块:https://github.com/clangd/clangd/issues/1293 - https://github.com/clangd/clangd/issues/123 优化头文查找 +- 折叠预处理 https://github.com/clangd/clangd/issues/1661 ## 性能优化 TODO: 寻找核心优化点 diff --git a/docs/examples/Preprocessor.cpp b/docs/examples/Preprocessor.cpp index ab469ba9..e843564b 100644 --- a/docs/examples/Preprocessor.cpp +++ b/docs/examples/Preprocessor.cpp @@ -4,65 +4,105 @@ using namespace clang; -class PPCallback : public clang::PPCallbacks { +struct IfBlock { + SourceLocation If; + std::vector Elifs; + SourceLocation Else; + SourceLocation End; +}; + +struct IfdefBlock { + SourceLocation If; + std::vector Elifs; + SourceLocation Else; + SourceLocation End; +}; + +class DirectiveCollector : public clang::PPCallbacks { private: clang::Preprocessor& pp; clang::SourceManager& sm; public: - PPCallback(clang::Preprocessor& pp) : pp(pp), sm(pp.getSourceManager()) {} + DirectiveCollector(clang::Preprocessor& pp) : pp(pp), sm(pp.getSourceManager()) {} - void InclusionDirective(SourceLocation HashLoc, - const Token& IncludeTok, + virtual ~DirectiveCollector() = default; + + void InclusionDirective(clang::SourceLocation HashLoc, + const clang::Token& IncludeTok, StringRef FileName, bool IsAngled, - CharSourceRange FilenameRange, - OptionalFileEntryRef File, + clang::CharSourceRange FilenameRange, + clang::OptionalFileEntryRef File, StringRef SearchPath, StringRef RelativePath, - const Module* SuggestedModule, + const clang::Module* SuggestedModule, bool ModuleImported, - SrcMgr::CharacteristicKind FileType) override { - if(sm.isInMainFile(HashLoc)) { - HashLoc.dump(sm); - IncludeTok.getLocation().dump(sm); - IncludeTok.getEndLoc().dump(sm); + clang::SrcMgr::CharacteristicKind FileType) override {} + + void moduleImport(clang::SourceLocation ImportLoc, + clang::ModuleIdPath Path, + const clang::Module* Imported) override {} + + void PragmaDirective(clang::SourceLocation Loc, + clang::PragmaIntroducerKind Introducer) override {} + + void MacroExpands(const clang::Token& MacroNameTok, + const clang::MacroDefinition& MD, + clang::SourceRange Range, + const clang::MacroArgs* Args) override {} + + void MacroDefined(const clang::Token& MacroNameTok, const clang::MacroDirective* MD) override {} + + void MacroUndefined(const clang::Token& MacroNameTok, + const clang::MacroDefinition& MD, + const clang::MacroDirective* Undef) override {} + + void If(clang::SourceLocation Loc, + clang::SourceRange ConditionRange, + ConditionValueKind ConditionValue) override { + llvm::outs() << "If\n"; + Loc.dump(sm); + ConditionRange.dump(sm); + } + + void Elif(clang::SourceLocation Loc, + clang::SourceRange ConditionRange, + ConditionValueKind ConditionValue, + clang::SourceLocation IfLoc) override {} + + void Else(clang::SourceLocation Loc, clang::SourceLocation IfLoc) override {} + + void Ifdef(clang::SourceLocation Loc, + const clang::Token& MacroNameTok, + const clang::MacroDefinition& MD) override { + llvm::outs() << "Ifdef\n"; + Loc.dump(sm); + + llvm::outs() << "MacroName: " << pp.getSpelling(MacroNameTok) << "\n"; + auto info = MD.getMacroInfo(); + if(info) { + info->dump(); } } - // void MacroExpands(const clang::Token& token, - // const clang::MacroDefinition& macro, - // clang::SourceRange range, - // const clang::MacroArgs* args) override { - // std::string name = pp.getSpelling(token); - // if(name.starts_with("_")) - // return; - // - // clang::MacroInfo* info = macro.getMacroInfo(); - // // info->isBuiltinMacro(); - // // info->isFunctionLike(); - // // info->isObjectLike(); - // // info->isVariadic(); - // // info->getNumParams(); - // // info->params(); - // - // const int size = args->getNumMacroArguments(); // Expanding macro arguments - // for(auto i = 0; i < size; ++i) { - // // get first token of first argument of expanding macro - // const clang::Token* first = args->getUnexpArgument(i); - // // iterate over tokens of first argument of expanding macro - // for(auto j = 0; j < args->getArgLength(first); ++j) { - // const clang::Token& tok = *(first + j); - // // llvm::outs() << "Arg: " << pp.getSpelling(tok) << "\n"; - // } - // } - // - // auto expandingRange = sm.getExpansionRange(range); - // auto text = clang::Lexer::getSourceText(expandingRange, sm, pp.getLangOpts()); - // llvm::outs() << text << "\n"; - //} + void Elifdef(clang::SourceLocation Loc, + const clang::Token& MacroNameTok, + const clang::MacroDefinition& MD) override {} - void MacroDefined(const clang::Token& token, const clang::MacroDirective* directive) override {} + void Ifndef(clang::SourceLocation Loc, + const clang::Token& MacroNameTok, + const clang::MacroDefinition& MD) override {} + + void Elifndef(clang::SourceLocation Loc, + const clang::Token& MacroNameTok, + const clang::MacroDefinition& MD) override {} + + void Endif(clang::SourceLocation Loc, clang::SourceLocation IfLoc) override { + llvm::outs() << "Endif\n"; + Loc.dump(sm); + IfLoc.dump(sm); + } }; int main(int argc, const char** argv) { @@ -123,7 +163,7 @@ int main(int argc, const char** argv) { // // } // }); - pp.addPPCallbacks(std::make_unique(pp)); + pp.addPPCallbacks(std::make_unique(pp)); clang::syntax::TokenCollector collector{pp}; if(auto error = action.Execute()) { @@ -134,11 +174,12 @@ int main(int argc, const char** argv) { auto buffer = std::move(collector).consume(); buffer.dumpForTests(); auto tokens = buffer.spelledTokens(sm.getMainFileID()); - for(auto& token: tokens) { - - llvm::outs() << "Token: " << token.text(sm) << " " << clang::tok::getTokenName(token.kind()) - << "\n"; - } + // for(auto& token: tokens) { + // + // llvm::outs() << "Token: " << token.text(sm) << " " << + // clang::tok::getTokenName(token.kind()) + // << "\n"; + //} // auto tokens2 = buffer.expandedTokens(); // for(auto& token: tokens2) { diff --git a/include/Clang/Clang.h b/include/Clang/Clang.h index a806672c..53011e48 100644 --- a/include/Clang/Clang.h +++ b/include/Clang/Clang.h @@ -8,6 +8,7 @@ #include #include #include +#include namespace clice { @@ -16,4 +17,9 @@ using PathRef = StringRef; using clang::CompilerInstance; using clang::CompilerInvocation; +using clang::SourceLocation; +using clang::SourceRange; +using clang::PPCallbacks; +using clang::Token; + } // namespace clice diff --git a/include/Clang/Directive.h b/include/Clang/Directive.h index 331217eb..142cda41 100644 --- a/include/Clang/Directive.h +++ b/include/Clang/Directive.h @@ -2,26 +2,141 @@ namespace clice { -struct MacroDefinition { - std::string name; - std::string definition; - clang::SourceRange range; -}; - -struct MacroExpansion { - std::string name; - std::string expansion; -}; - +// note that `#` is not part of the directive token. it is a separate token. class Directive { + friend class DirectiveCollector; + private: - std::string name; - clang::SourceRange range; - std::vector definitions; - std::vector expansions; + /// represent a `#include` directive. + struct Header { + SourceLocation hashLoc; + Token includeTok; + StringRef fileName; + bool isAngled; + clang::CharSourceRange filenameRange; + clang::OptionalFileEntryRef file; + StringRef searchPath; + StringRef relativePath; + const clang::Module* suggestedModule; + bool moduleImported; + clang::SrcMgr::CharacteristicKind fileType; + }; + + /// represent a `#define` directive. + struct Define { + Token name; + const clang::MacroDirective* directive; + }; + + /// represent a `#undef` directive. + struct Undef { + Token name; + const clang::MacroDefinition* definition; + const clang::MacroDirective* directive; + }; + + /// represent a `#pragma` directive. + struct Pragma { + /// the location of `pragma` directive. + SourceLocation location; + /// the kind of the pragma directive. + clang::PragmaIntroducerKind kind; + }; + + /// represent a condition in `#if` or `#elif` directive. + struct Condition { + /// the source range of the condition. + SourceRange range; + /// the evaluated value of the condition. + PPCallbacks::ConditionValueKind value; + }; + + /// represent a `#if` directive + struct If { + /// the location of `if` directive. + SourceLocation location; + Condition condition; + }; + + /// represent a `#elif` directive + struct Elif { + /// the location of `elif` directive. + SourceLocation location; + Condition condition; + }; + + /// represent a macro condition in `#ifdef` or `#elifdef` directive. + struct MacroCondition { + /// the source range of the macro name. + Token token; + /// the corresponding macro definition(may be null). + clang::MacroDefinition definition; + }; + + /// represent a `#ifdef` directive + struct Ifdef { + /// the location of `ifdef` directive. + SourceLocation location; + MacroCondition condition; + }; + + /// represent a `#elifdef` directive + struct Elifdef { + /// the location of `elifdef` directive. + SourceLocation location; + MacroCondition condition; + }; + + struct Else { + /// the location of `else` directive. + SourceLocation location; + }; + + struct Endif { + /// the location of `endif` directive. + SourceLocation location; + }; + + struct IfBlock { + If if_; + std::vector elifs; + std::optional else_; + Endif endif; + }; + + struct IfdefBlock { + Ifdef ifdef; + std::vector elifdefs; + std::optional else_; + Endif endif; + }; + +private: + std::vector
headers; + std::vector defines; + std::vector undefs; + std::vector pragmas; + std::vector ifBlocks; + std::vector ifdefBlocks; public: - static std::unique_ptr create(clang::SourceManager& sourceManager, clang::SourceRange range); + Directive(clang::Preprocessor& pp); + + auto& Headers() { return headers; } + + auto& Defines() { return defines; } + + auto& Undefs() { return undefs; } + + auto& Pragmas() { return pragmas; } + + auto& IfBlocks() { return ifBlocks; } + + auto& IfdefBlocks() { return ifdefBlocks; } }; +#if 1111 + +#endif + } // namespace clice diff --git a/include/Feature/SemanticToken.h b/include/Feature/SemanticToken.h index 030862ee..4f091678 100644 --- a/include/Feature/SemanticToken.h +++ b/include/Feature/SemanticToken.h @@ -10,8 +10,6 @@ namespace feature { protocol::SemanticTokens semanticTokens(const ParsedAST& ast); - - } } // namespace clice diff --git a/src/Clang/Directive.cpp b/src/Clang/Directive.cpp index 1037da68..500f43ce 100644 --- a/src/Clang/Directive.cpp +++ b/src/Clang/Directive.cpp @@ -1,14 +1,18 @@ #include -#include namespace clice { -class DirectiveCollector : clang::PPCallbacks { +class DirectiveCollector : public PPCallbacks { +private: + Directive& directive; + public: + DirectiveCollector(Directive& directive) : directive(directive) {} + virtual ~DirectiveCollector() = default; - void InclusionDirective(clang::SourceLocation HashLoc, - const clang::Token& IncludeTok, + void InclusionDirective(SourceLocation HashLoc, + const Token& IncludeTok, StringRef FileName, bool IsAngled, clang::CharSourceRange FilenameRange, @@ -19,51 +23,95 @@ public: bool ModuleImported, clang::SrcMgr::CharacteristicKind FileType) override {} - void moduleImport(clang::SourceLocation ImportLoc, + void moduleImport(SourceLocation ImportLoc, clang::ModuleIdPath Path, const clang::Module* Imported) override {} - void PragmaDirective(clang::SourceLocation Loc, clang::PragmaIntroducerKind Introducer) override {} + void PragmaDirective(SourceLocation Loc, clang::PragmaIntroducerKind Introducer) override { + directive.pragmas.emplace_back(Loc, Introducer); + } - void MacroExpands(const clang::Token& MacroNameTok, + void MacroDefined(const Token& MacroNameTok, const clang::MacroDirective* MD) override { + directive.defines.emplace_back(MacroNameTok, MD); + } + + void MacroExpands(const Token& MacroNameTok, const clang::MacroDefinition& MD, - clang::SourceRange Range, + SourceRange Range, const clang::MacroArgs* Args) override {} - void MacroDefined(const clang::Token& MacroNameTok, const clang::MacroDirective* MD) override {} - - void MacroUndefined(const clang::Token& MacroNameTok, + void MacroUndefined(const Token& MacroNameTok, const clang::MacroDefinition& MD, - const clang::MacroDirective* Undef) override {} + const clang::MacroDirective* Undef) override { + directive.undefs.emplace_back(MacroNameTok, &MD, Undef); + } - void If(clang::SourceLocation Loc, - clang::SourceRange ConditionRange, - ConditionValueKind ConditionValue) override {} + void If(SourceLocation Loc, + SourceRange ConditionRange, + ConditionValueKind ConditionValue) override { + directive.ifBlocks.emplace_back(Directive::If{ + Loc, + {ConditionRange, ConditionValue} + }); + } - void Elif(clang::SourceLocation Loc, - clang::SourceRange ConditionRange, + void Elif(SourceLocation Loc, + SourceRange ConditionRange, ConditionValueKind ConditionValue, - clang::SourceLocation IfLoc) override {} + SourceLocation IfLoc) override { + assert(directive.ifBlocks.back().if_.location == IfLoc && + "The `#elif` directive must be preceded by an `#if` directive."); + directive.ifBlocks.back().elifs.emplace_back(Directive::Elif{ + Loc, + {ConditionRange, ConditionValue} + }); + } - void Ifdef(clang::SourceLocation Loc, - const clang::Token& MacroNameTok, - const clang::MacroDefinition& MD) override {} + void Ifdef(SourceLocation Loc, + const Token& MacroNameTok, + const clang::MacroDefinition& MD) override { + directive.ifdefBlocks.emplace_back(Directive::Ifdef{ + Loc, + {MacroNameTok, MD} + }); + } - void Elifdef(clang::SourceLocation Loc, - const clang::Token& MacroNameTok, - const clang::MacroDefinition& MD) override {} + // call when a `#elifdef` directive is skipped. + void Elifdef(SourceLocation Loc, SourceRange ConditionRange, SourceLocation IfLoc) override { + assert(directive.ifdefBlocks.back().ifdef.location == IfLoc && + "The `#elifdef` directive must be preceded by an `#ifdef` directive."); + // FIXME: + directive.ifdefBlocks.back().elifdefs.emplace_back(Directive::Elifdef{ + Loc, + //{ConditionRange, ConditionValueKind::Defined} + }); + } - void Ifndef(clang::SourceLocation Loc, - const clang::Token& MacroNameTok, + // call when a `#ifdef` directive is hit. + void Elifdef(SourceLocation Loc, + const Token& MacroNameTok, + const clang::MacroDefinition& MD) override { + directive.ifdefBlocks.back().elifdefs.emplace_back(Directive::Elifdef{ + Loc, + {MacroNameTok, MD} + }); + } + + void Ifndef(SourceLocation Loc, + const Token& MacroNameTok, const clang::MacroDefinition& MD) override {} - void Elifndef(clang::SourceLocation Loc, - const clang::Token& MacroNameTok, + void Elifndef(SourceLocation Loc, + const Token& MacroNameTok, const clang::MacroDefinition& MD) override {} - void Else(clang::SourceLocation Loc, clang::SourceLocation IfLoc) override {} + void Else(SourceLocation Loc, SourceLocation IfLoc) override {} - void Endif(clang::SourceLocation Loc, clang::SourceLocation IfLoc) override {} + void Endif(SourceLocation Loc, SourceLocation IfLoc) override {} }; +Directive::Directive(clang::Preprocessor& preprocessor) { + preprocessor.addPPCallbacks(std::make_unique(*this)); +} + } // namespace clice diff --git a/src/Feature/SemanticToken.cpp b/src/Feature/SemanticToken.cpp index ffd68a42..d9c8c855 100644 --- a/src/Feature/SemanticToken.cpp +++ b/src/Feature/SemanticToken.cpp @@ -17,8 +17,6 @@ private: SemanticTokenType type; uint32_t modifiers; -private: - public: SemanticToken(SemanticTokenType type, clang::SourceLocation begin, clang::SourceLocation end) : range(begin, end), type(type), modifiers(0) {} diff --git a/test.cpp b/test.cpp index 76babb12..226b8de7 100644 --- a/test.cpp +++ b/test.cpp @@ -1,11 +1,15 @@ -template -struct X{ - void foo(){}; -}; +#if 1 -template<> -void X::foo(){ +int x = 1; -} +#else +int y = 2; +#endif + +#ifdef X + +int y = 2; + +#endif \ No newline at end of file