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 = 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 
53 /// A source range that has been parsed on the command line.
54 struct ParsedSourceRange {
55   std::string FileName;
56   /// The starting location of the range. The first element is the line and
57   /// the second element is the column.
58   std::pair<unsigned, unsigned> Begin;
59   /// The ending location of the range. The first element is the line and the
60   /// second element is the column.
61   std::pair<unsigned, unsigned> End;
62 
63   /// Returns a parsed source range from a string or None if the string is
64   /// invalid.
65   ///
66   /// These source string has the following format:
67   ///
68   /// file:start_line:start_column[-end_line:end_column]
69   ///
70   /// If the end line and column are omitted, the starting line and columns
71   /// are used as the end values.
72   static Optional<ParsedSourceRange> fromString(StringRef Str) {
73     std::pair<StringRef, StringRef> RangeSplit = Str.rsplit('-');
74     unsigned EndLine, EndColumn;
75     bool HasEndLoc = false;
76     if (!RangeSplit.second.empty()) {
77       std::pair<StringRef, StringRef> Split = RangeSplit.second.rsplit(':');
78       if (Split.first.getAsInteger(10, EndLine) ||
79           Split.second.getAsInteger(10, EndColumn)) {
80         // The string does not end in end_line:end_column, so the '-'
81         // probably belongs to the filename which menas the whole
82         // string should be parsed.
83         RangeSplit.first = Str;
84       } else
85         HasEndLoc = true;
86     }
87     auto Begin = ParsedSourceLocation::FromString(RangeSplit.first);
88     if (Begin.FileName.empty())
89       return None;
90     if (!HasEndLoc) {
91       EndLine = Begin.Line;
92       EndColumn = Begin.Column;
93     }
94     return ParsedSourceRange{std::move(Begin.FileName),
95                              {Begin.Line, Begin.Column},
96                              {EndLine, EndColumn}};
97   }
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 
114     bool
115     parser<clang::ParsedSourceLocation>::
116     parse(Option &O, StringRef ArgName, StringRef ArgValue,
117           clang::ParsedSourceLocation &Val) {
118       using namespace clang;
119 
120       Val = ParsedSourceLocation::FromString(ArgValue);
121       if (Val.FileName.empty()) {
122         errs() << "error: "
123                << "source location must be of the form filename:line:column\n";
124         return true;
125       }
126 
127       return false;
128     }
129   }
130 }
131 
132 #endif
133