1 2 //===--- CommandLineSourceLoc.h - Parsing for source locations-*- C++ -*---===// 3 // 4 // The LLVM Compiler Infrastructure 5 // 6 // This file is distributed under the University of Illinois Open Source 7 // License. See LICENSE.TXT for details. 8 // 9 //===----------------------------------------------------------------------===// 10 // 11 // Command line parsing for source locations. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H 16 #define LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H 17 18 #include "clang/Basic/LLVM.h" 19 #include "llvm/Support/CommandLine.h" 20 #include "llvm/Support/raw_ostream.h" 21 22 namespace clang { 23 24 /// \brief 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 30 public: 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(':'); 36 std::pair<StringRef, StringRef> LineSplit = 37 ColSplit.first.rsplit(':'); 38 39 // If both tail splits were valid integers, return success. 40 if (!ColSplit.second.getAsInteger(10, PSL.Column) && 41 !LineSplit.second.getAsInteger(10, PSL.Line)) { 42 PSL.FileName = 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 54 /// A source range that has been parsed on the command line. 55 struct ParsedSourceRange { 56 std::string FileName; 57 /// The starting location of the range. The first element is the line and 58 /// the second element is the column. 59 std::pair<unsigned, unsigned> Begin; 60 /// The ending location of the range. The first element is the line and the 61 /// second element is the column. 62 std::pair<unsigned, unsigned> End; 63 64 /// Returns a parsed source range from a string or None if the string is 65 /// 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 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 None; 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 102 namespace llvm { 103 namespace cl { 104 /// \brief Command-line option parser that parses source locations. 105 /// 106 /// Source locations are of the form filename:line:column. 107 template<> 108 class parser<clang::ParsedSourceLocation> final 109 : public basic_parser<clang::ParsedSourceLocation> { 110 public: 111 inline bool parse(Option &O, StringRef ArgName, StringRef ArgValue, 112 clang::ParsedSourceLocation &Val); 113 }; 114 115 bool 116 parser<clang::ParsedSourceLocation>:: 117 parse(Option &O, StringRef ArgName, StringRef ArgValue, 118 clang::ParsedSourceLocation &Val) { 119 using namespace clang; 120 121 Val = ParsedSourceLocation::FromString(ArgValue); 122 if (Val.FileName.empty()) { 123 errs() << "error: " 124 << "source location must be of the form filename:line:column\n"; 125 return true; 126 } 127 128 return false; 129 } 130 } 131 } 132 133 #endif 134