ParserAutoComplete.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*
  2. * Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include "ParserAutoComplete.h"
  27. #include "AK/Assertions.h"
  28. #include "LibCpp/AST.h"
  29. #include "LibCpp/Lexer.h"
  30. #include <AK/HashTable.h>
  31. #include <LibCpp/Parser.h>
  32. // #define DEBUG_AUTOCOMPLETE
  33. #ifdef AUTOCOMPLETE_VERBOSE
  34. # define VERBOSE(fmt, ...) dbgln(fmt, ##__VA_ARGS__)
  35. #else
  36. # define VERBOSE(fmt, ...) \
  37. do { \
  38. } while (0)
  39. #endif
  40. namespace LanguageServers::Cpp {
  41. ParserAutoComplete::ParserAutoComplete(const String& code)
  42. : m_code(code)
  43. , m_parser(code.view())
  44. {
  45. auto root = m_parser.parse();
  46. #ifdef DEBUG_AUTOCOMPLETE
  47. root->dump(0);
  48. #endif
  49. }
  50. Vector<GUI::AutocompleteProvider::Entry> ParserAutoComplete::get_suggestions(const GUI::TextPosition& autocomplete_position) const
  51. {
  52. ASSERT(autocomplete_position.column() > 0);
  53. Cpp::Position position { autocomplete_position.line(), autocomplete_position.column() - 1 };
  54. VERBOSE("ParserAutoComplete position {}:{}", position.line, position.column);
  55. auto node = m_parser.node_at(position);
  56. if (!node) {
  57. VERBOSE("no node at position {}:{}", position.line, position.column);
  58. return {};
  59. }
  60. if (!node->is_identifier()) {
  61. if (is_empty_property(*node, position)) {
  62. ASSERT(node->is_member_expression());
  63. return autocomplete_property((MemberExpression&)(*node), "");
  64. }
  65. return {};
  66. }
  67. if (is_property(*node)) {
  68. return autocomplete_property((MemberExpression&)(*node->parent()), m_parser.text_of_node(*node));
  69. }
  70. return autocomplete_identifier(*node);
  71. }
  72. Vector<GUI::AutocompleteProvider::Entry> ParserAutoComplete::autocomplete_identifier(const ASTNode& node) const
  73. {
  74. const Cpp::ASTNode* current = &node;
  75. NonnullRefPtrVector<Cpp::Declaration> available_declarations;
  76. while (current) {
  77. available_declarations.append(current->declarations());
  78. current = current->parent();
  79. }
  80. Vector<StringView> available_names;
  81. auto add_name = [&available_names](auto& name) {
  82. if (name.is_null() || name.is_empty())
  83. return;
  84. if (!available_names.contains_slow(name))
  85. available_names.append(name);
  86. };
  87. for (auto& decl : available_declarations) {
  88. if (decl.start() > node.start())
  89. continue;
  90. if (decl.is_variable_or_parameter_declaration()) {
  91. add_name(((Cpp::VariableOrParameterDeclaration&)decl).m_name);
  92. }
  93. }
  94. auto partial_text = m_parser.text_of_node(node);
  95. Vector<GUI::AutocompleteProvider::Entry> suggestions;
  96. for (auto& name : available_names) {
  97. if (name.starts_with(partial_text)) {
  98. suggestions.append({ name.to_string(), partial_text.length(), GUI::AutocompleteProvider::CompletionKind::Identifier });
  99. }
  100. }
  101. return suggestions;
  102. }
  103. Vector<GUI::AutocompleteProvider::Entry> ParserAutoComplete::autocomplete_property(const MemberExpression& parent, const StringView partial_text) const
  104. {
  105. auto type = type_of(*parent.m_object);
  106. if (type.is_null()) {
  107. VERBOSE("Could not infer type of object");
  108. return {};
  109. }
  110. VERBOSE("type of object: {}", type);
  111. Vector<GUI::AutocompleteProvider::Entry> suggestions;
  112. for (auto& prop : properties_of_type(type)) {
  113. if (prop.name.starts_with(partial_text)) {
  114. suggestions.append({ prop.name, partial_text.length(), GUI::AutocompleteProvider::CompletionKind::Identifier });
  115. }
  116. }
  117. return suggestions;
  118. }
  119. bool ParserAutoComplete::is_property(const ASTNode& node) const
  120. {
  121. if (!node.parent()->is_member_expression())
  122. return false;
  123. auto& parent = (MemberExpression&)(*node.parent());
  124. return parent.m_property.ptr() == &node;
  125. }
  126. bool ParserAutoComplete::is_empty_property(const ASTNode& node, const Position& autocomplete_position) const
  127. {
  128. if (!node.is_member_expression())
  129. return false;
  130. auto previous_token = m_parser.token_at(autocomplete_position);
  131. if (!previous_token.has_value())
  132. return false;
  133. return previous_token.value().type() == Token::Type::Dot;
  134. }
  135. String ParserAutoComplete::type_of_property(const Identifier& identifier) const
  136. {
  137. auto& parent = (const MemberExpression&)(*identifier.parent());
  138. auto properties = properties_of_type(type_of(*parent.m_object));
  139. for (auto& prop : properties) {
  140. if (prop.name == identifier.m_name)
  141. return prop.type->m_name;
  142. }
  143. return {};
  144. }
  145. String ParserAutoComplete::type_of_variable(const Identifier& identifier) const
  146. {
  147. const ASTNode* current = &identifier;
  148. while (current) {
  149. for (auto& decl : current->declarations()) {
  150. if (decl.is_variable_or_parameter_declaration()) {
  151. auto& var_or_param = (VariableOrParameterDeclaration&)decl;
  152. if (var_or_param.m_name == identifier.m_name) {
  153. return var_or_param.m_type->m_name;
  154. }
  155. }
  156. }
  157. current = current->parent();
  158. }
  159. return {};
  160. }
  161. String ParserAutoComplete::type_of(const Expression& expression) const
  162. {
  163. if (expression.is_member_expression()) {
  164. auto& member_expression = (const MemberExpression&)expression;
  165. return type_of_property(*member_expression.m_property);
  166. }
  167. if (!expression.is_identifier()) {
  168. ASSERT_NOT_REACHED(); // TODO
  169. }
  170. auto& identifier = (const Identifier&)expression;
  171. if (is_property(identifier))
  172. return type_of_property(identifier);
  173. return type_of_variable(identifier);
  174. }
  175. Vector<ParserAutoComplete::PropertyInfo> ParserAutoComplete::properties_of_type(const String& type) const
  176. {
  177. Vector<PropertyInfo> properties;
  178. for (auto& decl : m_parser.root_node()->declarations()) {
  179. if (!decl.is_struct_or_class())
  180. continue;
  181. auto& struct_or_class = (StructOrClassDeclaration&)decl;
  182. if (struct_or_class.m_name != type)
  183. continue;
  184. for (auto& member : struct_or_class.m_members) {
  185. properties.append({ member.m_name, member.m_type });
  186. }
  187. }
  188. return properties;
  189. }
  190. }