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

source code of clang/include/clang/Frontend/CommandLineSourceLoc.h