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