CommandLineSourceLoc.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===--- CommandLineSourceLoc.h - Parsing for source locations-*- C++ -*---===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // Command line parsing for source locations.
  15. //
  16. //===----------------------------------------------------------------------===//
  17. #ifndef LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H
  18. #define LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H
  19. #include "clang/Basic/LLVM.h"
  20. #include "llvm/Support/CommandLine.h"
  21. #include "llvm/Support/raw_ostream.h"
  22. #include <optional>
  23. namespace clang {
  24. /// A source location that has been parsed on the command line.
  25. struct ParsedSourceLocation {
  26. std::string FileName;
  27. unsigned Line;
  28. unsigned Column;
  29. public:
  30. /// Construct a parsed source location from a string; the Filename is empty on
  31. /// error.
  32. static ParsedSourceLocation FromString(StringRef Str) {
  33. ParsedSourceLocation PSL;
  34. std::pair<StringRef, StringRef> ColSplit = Str.rsplit(':');
  35. std::pair<StringRef, StringRef> LineSplit =
  36. ColSplit.first.rsplit(':');
  37. // If both tail splits were valid integers, return success.
  38. if (!ColSplit.second.getAsInteger(10, PSL.Column) &&
  39. !LineSplit.second.getAsInteger(10, PSL.Line)) {
  40. PSL.FileName = std::string(LineSplit.first);
  41. // On the command-line, stdin may be specified via "-". Inside the
  42. // compiler, stdin is called "<stdin>".
  43. if (PSL.FileName == "-")
  44. PSL.FileName = "<stdin>";
  45. }
  46. return PSL;
  47. }
  48. /// Serialize ParsedSourceLocation back to a string.
  49. std::string ToString() const {
  50. return (llvm::Twine(FileName == "<stdin>" ? "-" : FileName) + ":" +
  51. Twine(Line) + ":" + Twine(Column))
  52. .str();
  53. }
  54. };
  55. /// A source range that has been parsed on the command line.
  56. struct ParsedSourceRange {
  57. std::string FileName;
  58. /// The starting location of the range. The first element is the line and
  59. /// the second element is the column.
  60. std::pair<unsigned, unsigned> Begin;
  61. /// The ending location of the range. The first element is the line and the
  62. /// second element is the column.
  63. std::pair<unsigned, unsigned> End;
  64. /// Returns a parsed source range from a string or std::nullopt if the string
  65. /// is invalid.
  66. ///
  67. /// These source string has the following format:
  68. ///
  69. /// file:start_line:start_column[-end_line:end_column]
  70. ///
  71. /// If the end line and column are omitted, the starting line and columns
  72. /// are used as the end values.
  73. static std::optional<ParsedSourceRange> fromString(StringRef Str) {
  74. std::pair<StringRef, StringRef> RangeSplit = Str.rsplit('-');
  75. unsigned EndLine, EndColumn;
  76. bool HasEndLoc = false;
  77. if (!RangeSplit.second.empty()) {
  78. std::pair<StringRef, StringRef> Split = RangeSplit.second.rsplit(':');
  79. if (Split.first.getAsInteger(10, EndLine) ||
  80. Split.second.getAsInteger(10, EndColumn)) {
  81. // The string does not end in end_line:end_column, so the '-'
  82. // probably belongs to the filename which menas the whole
  83. // string should be parsed.
  84. RangeSplit.first = Str;
  85. } else
  86. HasEndLoc = true;
  87. }
  88. auto Begin = ParsedSourceLocation::FromString(RangeSplit.first);
  89. if (Begin.FileName.empty())
  90. return std::nullopt;
  91. if (!HasEndLoc) {
  92. EndLine = Begin.Line;
  93. EndColumn = Begin.Column;
  94. }
  95. return ParsedSourceRange{std::move(Begin.FileName),
  96. {Begin.Line, Begin.Column},
  97. {EndLine, EndColumn}};
  98. }
  99. };
  100. }
  101. namespace llvm {
  102. namespace cl {
  103. /// Command-line option parser that parses source locations.
  104. ///
  105. /// Source locations are of the form filename:line:column.
  106. template<>
  107. class parser<clang::ParsedSourceLocation> final
  108. : public basic_parser<clang::ParsedSourceLocation> {
  109. public:
  110. inline bool parse(Option &O, StringRef ArgName, StringRef ArgValue,
  111. clang::ParsedSourceLocation &Val);
  112. };
  113. bool
  114. parser<clang::ParsedSourceLocation>::
  115. parse(Option &O, StringRef ArgName, StringRef ArgValue,
  116. clang::ParsedSourceLocation &Val) {
  117. using namespace clang;
  118. Val = ParsedSourceLocation::FromString(ArgValue);
  119. if (Val.FileName.empty()) {
  120. errs() << "error: "
  121. << "source location must be of the form filename:line:column\n";
  122. return true;
  123. }
  124. return false;
  125. }
  126. }
  127. }
  128. #endif
  129. #ifdef __GNUC__
  130. #pragma GCC diagnostic pop
  131. #endif