Serenity Operating System
at master 204 lines 9.0 kB view raw
1/* 2 * Copyright (c) 2021-2022, Itamar S. <itamar8910@gmail.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#pragma once 8 9#include <AK/DeprecatedString.h> 10#include <AK/Function.h> 11#include <AK/Vector.h> 12#include <DevTools/HackStudio/AutoCompleteResponse.h> 13#include <DevTools/HackStudio/LanguageServers/FileDB.h> 14#include <LibCpp/AST.h> 15#include <LibCpp/Parser.h> 16#include <LibCpp/Preprocessor.h> 17#include <LibGUI/TextPosition.h> 18#include <Libraries/LibCodeComprehension/CodeComprehensionEngine.h> 19 20namespace CodeComprehension::Cpp { 21 22using namespace ::Cpp; 23 24class CppComprehensionEngine : public CodeComprehensionEngine { 25public: 26 CppComprehensionEngine(FileDB const& filedb); 27 28 virtual Vector<CodeComprehension::AutocompleteResultEntry> get_suggestions(DeprecatedString const& file, GUI::TextPosition const& autocomplete_position) override; 29 virtual void on_edit(DeprecatedString const& file) override; 30 virtual void file_opened([[maybe_unused]] DeprecatedString const& file) override; 31 virtual Optional<CodeComprehension::ProjectLocation> find_declaration_of(DeprecatedString const& filename, GUI::TextPosition const& identifier_position) override; 32 virtual Optional<FunctionParamsHint> get_function_params_hint(DeprecatedString const&, GUI::TextPosition const&) override; 33 virtual Vector<CodeComprehension::TokenInfo> get_tokens_info(DeprecatedString const& filename) override; 34 35private: 36 struct SymbolName { 37 StringView name; 38 Vector<StringView> scope; 39 40 static SymbolName create(StringView, Vector<StringView>&&); 41 static SymbolName create(StringView); 42 DeprecatedString scope_as_string() const; 43 DeprecatedString to_deprecated_string() const; 44 45 bool operator==(SymbolName const&) const = default; 46 }; 47 48 struct Symbol { 49 SymbolName name; 50 NonnullRefPtr<Cpp::Declaration const> declaration; 51 52 // Local symbols are symbols that should not appear in a global symbol search. 53 // For example, a variable that is declared inside a function will have is_local = true. 54 bool is_local { false }; 55 56 enum class IsLocal { 57 No, 58 Yes 59 }; 60 static Symbol create(StringView name, Vector<StringView> const& scope, NonnullRefPtr<Cpp::Declaration const>, IsLocal is_local); 61 }; 62 63 friend Traits<SymbolName>; 64 65 struct DocumentData { 66 DeprecatedString const& filename() const { return m_filename; } 67 DeprecatedString const& text() const { return m_text; } 68 Preprocessor const& preprocessor() const 69 { 70 VERIFY(m_preprocessor); 71 return *m_preprocessor; 72 } 73 Preprocessor& preprocessor() 74 { 75 VERIFY(m_preprocessor); 76 return *m_preprocessor; 77 } 78 Parser const& parser() const 79 { 80 VERIFY(m_parser); 81 return *m_parser; 82 } 83 Parser& parser() 84 { 85 VERIFY(m_parser); 86 return *m_parser; 87 } 88 89 DeprecatedString m_filename; 90 DeprecatedString m_text; 91 OwnPtr<Preprocessor> m_preprocessor; 92 OwnPtr<Parser> m_parser; 93 94 HashMap<SymbolName, Symbol> m_symbols; 95 HashTable<DeprecatedString> m_available_headers; 96 }; 97 98 Vector<CodeComprehension::AutocompleteResultEntry> autocomplete_property(DocumentData const&, MemberExpression const&, const DeprecatedString partial_text) const; 99 Vector<AutocompleteResultEntry> autocomplete_name(DocumentData const&, ASTNode const&, DeprecatedString const& partial_text) const; 100 DeprecatedString type_of(DocumentData const&, Expression const&) const; 101 DeprecatedString type_of_property(DocumentData const&, Identifier const&) const; 102 DeprecatedString type_of_variable(Identifier const&) const; 103 bool is_property(ASTNode const&) const; 104 RefPtr<Cpp::Declaration const> find_declaration_of(DocumentData const&, ASTNode const&) const; 105 RefPtr<Cpp::Declaration const> find_declaration_of(DocumentData const&, SymbolName const&) const; 106 RefPtr<Cpp::Declaration const> find_declaration_of(DocumentData const&, const GUI::TextPosition& identifier_position); 107 108 enum class RecurseIntoScopes { 109 No, 110 Yes 111 }; 112 113 Vector<Symbol> properties_of_type(DocumentData const& document, DeprecatedString const& type) const; 114 Vector<Symbol> get_child_symbols(ASTNode const&) const; 115 Vector<Symbol> get_child_symbols(ASTNode const&, Vector<StringView> const& scope, Symbol::IsLocal) const; 116 117 DocumentData const* get_document_data(DeprecatedString const& file) const; 118 DocumentData const* get_or_create_document_data(DeprecatedString const& file); 119 void set_document_data(DeprecatedString const& file, OwnPtr<DocumentData>&& data); 120 121 OwnPtr<DocumentData> create_document_data_for(DeprecatedString const& file); 122 DeprecatedString document_path_from_include_path(StringView include_path) const; 123 void update_declared_symbols(DocumentData&); 124 void update_todo_entries(DocumentData&); 125 CodeComprehension::DeclarationType type_of_declaration(Cpp::Declaration const&); 126 Vector<StringView> scope_of_node(ASTNode const&) const; 127 Vector<StringView> scope_of_reference_to_symbol(ASTNode const&) const; 128 129 Optional<CodeComprehension::ProjectLocation> find_preprocessor_definition(DocumentData const&, const GUI::TextPosition&); 130 Optional<Cpp::Preprocessor::Substitution> find_preprocessor_substitution(DocumentData const&, Cpp::Position const&); 131 132 OwnPtr<DocumentData> create_document_data(DeprecatedString text, DeprecatedString const& filename); 133 Optional<Vector<CodeComprehension::AutocompleteResultEntry>> try_autocomplete_property(DocumentData const&, ASTNode const&, Optional<Token> containing_token) const; 134 Optional<Vector<CodeComprehension::AutocompleteResultEntry>> try_autocomplete_name(DocumentData const&, ASTNode const&, Optional<Token> containing_token) const; 135 Optional<Vector<CodeComprehension::AutocompleteResultEntry>> try_autocomplete_include(DocumentData const&, Token include_path_token, Cpp::Position const& cursor_position) const; 136 static bool is_symbol_available(Symbol const&, Vector<StringView> const& current_scope, Vector<StringView> const& reference_scope); 137 Optional<FunctionParamsHint> get_function_params_hint(DocumentData const&, FunctionCall const&, size_t argument_index); 138 139 template<typename Func> 140 void for_each_available_symbol(DocumentData const&, Func) const; 141 142 template<typename Func> 143 void for_each_included_document_recursive(DocumentData const&, Func) const; 144 145 CodeComprehension::TokenInfo::SemanticType get_token_semantic_type(DocumentData const&, Token const&); 146 CodeComprehension::TokenInfo::SemanticType get_semantic_type_for_identifier(DocumentData const&, Position); 147 148 HashMap<DeprecatedString, OwnPtr<DocumentData>> m_documents; 149 150 // A document's path will be in this set if we're currently processing it. 151 // A document is added to this set when we start processing it (e.g because it was #included) and removed when we're done. 152 // We use this to prevent circular #includes from looping indefinitely. 153 HashTable<DeprecatedString> m_unfinished_documents; 154}; 155 156template<typename Func> 157void CppComprehensionEngine::for_each_available_symbol(DocumentData const& document, Func func) const 158{ 159 for (auto& item : document.m_symbols) { 160 auto decision = func(item.value); 161 if (decision == IterationDecision::Break) 162 return; 163 } 164 165 for_each_included_document_recursive(document, [&](DocumentData const& document) { 166 for (auto& item : document.m_symbols) { 167 auto decision = func(item.value); 168 if (decision == IterationDecision::Break) 169 return IterationDecision::Break; 170 } 171 return IterationDecision::Continue; 172 }); 173} 174 175template<typename Func> 176void CppComprehensionEngine::for_each_included_document_recursive(DocumentData const& document, Func func) const 177{ 178 for (auto& included_path : document.m_available_headers) { 179 auto* included_document = get_document_data(included_path); 180 if (!included_document) 181 continue; 182 auto decision = func(*included_document); 183 if (decision == IterationDecision::Break) 184 continue; 185 } 186} 187} 188 189namespace AK { 190 191template<> 192struct Traits<CodeComprehension::Cpp::CppComprehensionEngine::SymbolName> : public GenericTraits<CodeComprehension::Cpp::CppComprehensionEngine::SymbolName> { 193 static unsigned hash(CodeComprehension::Cpp::CppComprehensionEngine::SymbolName const& key) 194 { 195 unsigned hash = 0; 196 hash = pair_int_hash(hash, string_hash(key.name.characters_without_null_termination(), key.name.length())); 197 for (auto& scope_part : key.scope) { 198 hash = pair_int_hash(hash, string_hash(scope_part.characters_without_null_termination(), scope_part.length())); 199 } 200 return hash; 201 } 202}; 203 204}