tree_node_location_translator.h 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_TOOLCHAIN_PARSE_TREE_NODE_LOCATION_TRANSLATOR_H_
  5. #define CARBON_TOOLCHAIN_PARSE_TREE_NODE_LOCATION_TRANSLATOR_H_
  6. #include "toolchain/diagnostics/diagnostic_emitter.h"
  7. #include "toolchain/lex/tokenized_buffer.h"
  8. #include "toolchain/parse/tree.h"
  9. namespace Carbon::Parse {
  10. class NodeLocation {
  11. public:
  12. NodeLocation(NodeId node_id) : NodeLocation(node_id, false) {}
  13. NodeLocation(NodeId node_id, bool token_only)
  14. : node_id_(node_id), token_only_(token_only) {}
  15. auto node_id() const -> NodeId { return node_id_; }
  16. auto token_only() const -> bool { return token_only_; }
  17. private:
  18. NodeId node_id_;
  19. bool token_only_;
  20. };
  21. inline auto TokenOnly(NodeId node_id) -> NodeLocation {
  22. return NodeLocation(node_id, true);
  23. }
  24. class NodeLocationTranslator
  25. : public DiagnosticLocationTranslator<NodeLocation> {
  26. public:
  27. explicit NodeLocationTranslator(const Lex::TokenizedBuffer* tokens,
  28. llvm::StringRef filename,
  29. const Tree* parse_tree)
  30. : token_translator_(tokens),
  31. filename_(filename),
  32. parse_tree_(parse_tree) {}
  33. // Map the given token into a diagnostic location.
  34. auto GetLocation(NodeLocation node_location) -> DiagnosticLocation override {
  35. // Support the invalid token as a way to emit only the filename, when there
  36. // is no line association.
  37. if (!node_location.node_id().is_valid()) {
  38. return {.file_name = filename_};
  39. }
  40. if (node_location.token_only()) {
  41. return token_translator_.GetLocation(
  42. parse_tree_->node_token(node_location.node_id()));
  43. }
  44. // Construct a location that encompasses all tokens that descend from this
  45. // node (including the root).
  46. Lex::TokenIndex start_token =
  47. parse_tree_->node_token(node_location.node_id());
  48. Lex::TokenIndex end_token = start_token;
  49. for (NodeId desc : parse_tree_->postorder(node_location.node_id())) {
  50. Lex::TokenIndex desc_token = parse_tree_->node_token(desc);
  51. if (!desc_token.is_valid()) {
  52. continue;
  53. }
  54. if (desc_token < start_token) {
  55. start_token = desc_token;
  56. } else if (desc_token > end_token) {
  57. end_token = desc_token;
  58. }
  59. }
  60. DiagnosticLocation start_loc = token_translator_.GetLocation(start_token);
  61. if (start_token == end_token) {
  62. return start_loc;
  63. }
  64. DiagnosticLocation end_loc = token_translator_.GetLocation(end_token);
  65. // For multiline locations we simply return the rest of the line for now
  66. // since true multiline locations are not yet supported.
  67. if (start_loc.line_number != end_loc.line_number) {
  68. start_loc.length = start_loc.line.size() - start_loc.column_number + 1;
  69. } else {
  70. if (start_loc.column_number != end_loc.column_number) {
  71. start_loc.length =
  72. end_loc.column_number + end_loc.length - start_loc.column_number;
  73. }
  74. }
  75. return start_loc;
  76. }
  77. private:
  78. Lex::TokenLocationTranslator token_translator_;
  79. llvm::StringRef filename_;
  80. const Tree* parse_tree_;
  81. };
  82. } // namespace Carbon::Parse
  83. #endif // CARBON_TOOLCHAIN_PARSE_TREE_NODE_LOCATION_TRANSLATOR_H_