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