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 
21 namespace clang {
22 
23 /// A source location that has been parsed on the command line.
24 struct ParsedSourceLocation {
25   std::string FileName;
26   unsigned Line;
27   unsigned Column;
28 
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 
38     // If both tail splits were valid integers, return success.
39     if (!ColSplit.second.getAsInteger(10, PSL.Column) &&
40         !LineSplit.second.getAsInteger(10, PSL.Line)) {
41       PSL.FileName = std::string(LineSplit.first);
42 
43       // On the command-line, stdin may be specified via "-". Inside the
44       // compiler, stdin is called "<stdin>".
45       if (PSL.FileName == "-")
46         PSL.FileName = "<stdin>";
47     }
48 
49     return PSL;
50   }
51 
52   /// Serialize ParsedSourceLocation back to a string.
53   std::string ToString() const {
54     return (llvm::Twine(FileName == "<stdin>" ? "-" : FileName) + ":" +
55             Twine(Line) + ":" + Twine(Column))
56         .str();
57   }
58 };
59 
60 /// A source range that has been parsed on the command line.
61 struct ParsedSourceRange {
62   std::string FileName;
63   /// The starting location of the range. The first element is the line and
64   /// the second element is the column.
65   std::pair<unsigned, unsigned> Begin;
66   /// The ending location of the range. The first element is the line and the
67   /// second element is the column.
68   std::pair<unsigned, unsigned> End;
69 
70   /// Returns a parsed source range from a string or None if the string is
71   /// invalid.
72   ///
73   /// These source string has the following format:
74   ///
75   /// file:start_line:start_column[-end_line:end_column]
76   ///
77   /// If the end line and column are omitted, the starting line and columns
78   /// are used as the end values.
79   static Optional<ParsedSourceRange> fromString(StringRef Str) {
80     std::pair<StringRef, StringRef> RangeSplit = Str.rsplit('-');
81     unsigned EndLine, EndColumn;
82     bool HasEndLoc = false;
83     if (!RangeSplit.second.empty()) {
84       std::pair<StringRef, StringRef> Split = RangeSplit.second.rsplit(':');
85       if (Split.first.getAsInteger(10, EndLine) ||
86           Split.second.getAsInteger(10, EndColumn)) {
87         // The string does not end in end_line:end_column, so the '-'
88         // probably belongs to the filename which menas the whole
89         // string should be parsed.
90         RangeSplit.first = Str;
91       } else
92         HasEndLoc = true;
93     }
94     auto Begin = ParsedSourceLocation::FromString(RangeSplit.first);
95     if (Begin.FileName.empty())
96       return None;
97     if (!HasEndLoc) {
98       EndLine = Begin.Line;
99       EndColumn = Begin.Column;
100     }
101     return ParsedSourceRange{std::move(Begin.FileName),
102                              {Begin.Line, Begin.Column},
103                              {EndLine, EndColumn}};
104   }
105 };
106 }
107 
108 namespace llvm {
109   namespace cl {
110     /// Command-line option parser that parses source locations.
111     ///
112     /// Source locations are of the form filename:line:column.
113     template<>
114     class parser<clang::ParsedSourceLocation> final
115       : public basic_parser<clang::ParsedSourceLocation> {
116     public:
117       inline bool parse(Option &O, StringRef ArgName, StringRef ArgValue,
118                  clang::ParsedSourceLocation &Val);
119     };
120 
121     bool
122     parser<clang::ParsedSourceLocation>::
123     parse(Option &O, StringRef ArgName, StringRef ArgValue,
124           clang::ParsedSourceLocation &Val) {
125       using namespace clang;
126 
127       Val = ParsedSourceLocation::FromString(ArgValue);
128       if (Val.FileName.empty()) {
129         errs() << "error: "
130                << "source location must be of the form filename:line:column\n";
131         return true;
132       }
133 
134       return false;
135     }
136   }
137 }
138 
139 #endif
140