1*0b57cec5SDimitry Andric 2*0b57cec5SDimitry Andric //===--- CommandLineSourceLoc.h - Parsing for source locations-*- C++ -*---===// 3*0b57cec5SDimitry Andric // 4*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 6*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7*0b57cec5SDimitry Andric // 8*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 9*0b57cec5SDimitry Andric // 10*0b57cec5SDimitry Andric // Command line parsing for source locations. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #ifndef LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H 15*0b57cec5SDimitry Andric #define LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H 16*0b57cec5SDimitry Andric 17*0b57cec5SDimitry Andric #include "clang/Basic/LLVM.h" 18*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 19*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 20*0b57cec5SDimitry Andric 21*0b57cec5SDimitry Andric namespace clang { 22*0b57cec5SDimitry Andric 23*0b57cec5SDimitry Andric /// A source location that has been parsed on the command line. 24*0b57cec5SDimitry Andric struct ParsedSourceLocation { 25*0b57cec5SDimitry Andric std::string FileName; 26*0b57cec5SDimitry Andric unsigned Line; 27*0b57cec5SDimitry Andric unsigned Column; 28*0b57cec5SDimitry Andric 29*0b57cec5SDimitry Andric public: 30*0b57cec5SDimitry Andric /// Construct a parsed source location from a string; the Filename is empty on 31*0b57cec5SDimitry Andric /// error. 32*0b57cec5SDimitry Andric static ParsedSourceLocation FromString(StringRef Str) { 33*0b57cec5SDimitry Andric ParsedSourceLocation PSL; 34*0b57cec5SDimitry Andric std::pair<StringRef, StringRef> ColSplit = Str.rsplit(':'); 35*0b57cec5SDimitry Andric std::pair<StringRef, StringRef> LineSplit = 36*0b57cec5SDimitry Andric ColSplit.first.rsplit(':'); 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric // If both tail splits were valid integers, return success. 39*0b57cec5SDimitry Andric if (!ColSplit.second.getAsInteger(10, PSL.Column) && 40*0b57cec5SDimitry Andric !LineSplit.second.getAsInteger(10, PSL.Line)) { 41*0b57cec5SDimitry Andric PSL.FileName = LineSplit.first; 42*0b57cec5SDimitry Andric 43*0b57cec5SDimitry Andric // On the command-line, stdin may be specified via "-". Inside the 44*0b57cec5SDimitry Andric // compiler, stdin is called "<stdin>". 45*0b57cec5SDimitry Andric if (PSL.FileName == "-") 46*0b57cec5SDimitry Andric PSL.FileName = "<stdin>"; 47*0b57cec5SDimitry Andric } 48*0b57cec5SDimitry Andric 49*0b57cec5SDimitry Andric return PSL; 50*0b57cec5SDimitry Andric } 51*0b57cec5SDimitry Andric }; 52*0b57cec5SDimitry Andric 53*0b57cec5SDimitry Andric /// A source range that has been parsed on the command line. 54*0b57cec5SDimitry Andric struct ParsedSourceRange { 55*0b57cec5SDimitry Andric std::string FileName; 56*0b57cec5SDimitry Andric /// The starting location of the range. The first element is the line and 57*0b57cec5SDimitry Andric /// the second element is the column. 58*0b57cec5SDimitry Andric std::pair<unsigned, unsigned> Begin; 59*0b57cec5SDimitry Andric /// The ending location of the range. The first element is the line and the 60*0b57cec5SDimitry Andric /// second element is the column. 61*0b57cec5SDimitry Andric std::pair<unsigned, unsigned> End; 62*0b57cec5SDimitry Andric 63*0b57cec5SDimitry Andric /// Returns a parsed source range from a string or None if the string is 64*0b57cec5SDimitry Andric /// invalid. 65*0b57cec5SDimitry Andric /// 66*0b57cec5SDimitry Andric /// These source string has the following format: 67*0b57cec5SDimitry Andric /// 68*0b57cec5SDimitry Andric /// file:start_line:start_column[-end_line:end_column] 69*0b57cec5SDimitry Andric /// 70*0b57cec5SDimitry Andric /// If the end line and column are omitted, the starting line and columns 71*0b57cec5SDimitry Andric /// are used as the end values. 72*0b57cec5SDimitry Andric static Optional<ParsedSourceRange> fromString(StringRef Str) { 73*0b57cec5SDimitry Andric std::pair<StringRef, StringRef> RangeSplit = Str.rsplit('-'); 74*0b57cec5SDimitry Andric unsigned EndLine, EndColumn; 75*0b57cec5SDimitry Andric bool HasEndLoc = false; 76*0b57cec5SDimitry Andric if (!RangeSplit.second.empty()) { 77*0b57cec5SDimitry Andric std::pair<StringRef, StringRef> Split = RangeSplit.second.rsplit(':'); 78*0b57cec5SDimitry Andric if (Split.first.getAsInteger(10, EndLine) || 79*0b57cec5SDimitry Andric Split.second.getAsInteger(10, EndColumn)) { 80*0b57cec5SDimitry Andric // The string does not end in end_line:end_column, so the '-' 81*0b57cec5SDimitry Andric // probably belongs to the filename which menas the whole 82*0b57cec5SDimitry Andric // string should be parsed. 83*0b57cec5SDimitry Andric RangeSplit.first = Str; 84*0b57cec5SDimitry Andric } else 85*0b57cec5SDimitry Andric HasEndLoc = true; 86*0b57cec5SDimitry Andric } 87*0b57cec5SDimitry Andric auto Begin = ParsedSourceLocation::FromString(RangeSplit.first); 88*0b57cec5SDimitry Andric if (Begin.FileName.empty()) 89*0b57cec5SDimitry Andric return None; 90*0b57cec5SDimitry Andric if (!HasEndLoc) { 91*0b57cec5SDimitry Andric EndLine = Begin.Line; 92*0b57cec5SDimitry Andric EndColumn = Begin.Column; 93*0b57cec5SDimitry Andric } 94*0b57cec5SDimitry Andric return ParsedSourceRange{std::move(Begin.FileName), 95*0b57cec5SDimitry Andric {Begin.Line, Begin.Column}, 96*0b57cec5SDimitry Andric {EndLine, EndColumn}}; 97*0b57cec5SDimitry Andric } 98*0b57cec5SDimitry Andric }; 99*0b57cec5SDimitry Andric } 100*0b57cec5SDimitry Andric 101*0b57cec5SDimitry Andric namespace llvm { 102*0b57cec5SDimitry Andric namespace cl { 103*0b57cec5SDimitry Andric /// Command-line option parser that parses source locations. 104*0b57cec5SDimitry Andric /// 105*0b57cec5SDimitry Andric /// Source locations are of the form filename:line:column. 106*0b57cec5SDimitry Andric template<> 107*0b57cec5SDimitry Andric class parser<clang::ParsedSourceLocation> final 108*0b57cec5SDimitry Andric : public basic_parser<clang::ParsedSourceLocation> { 109*0b57cec5SDimitry Andric public: 110*0b57cec5SDimitry Andric inline bool parse(Option &O, StringRef ArgName, StringRef ArgValue, 111*0b57cec5SDimitry Andric clang::ParsedSourceLocation &Val); 112*0b57cec5SDimitry Andric }; 113*0b57cec5SDimitry Andric 114*0b57cec5SDimitry Andric bool 115*0b57cec5SDimitry Andric parser<clang::ParsedSourceLocation>:: 116*0b57cec5SDimitry Andric parse(Option &O, StringRef ArgName, StringRef ArgValue, 117*0b57cec5SDimitry Andric clang::ParsedSourceLocation &Val) { 118*0b57cec5SDimitry Andric using namespace clang; 119*0b57cec5SDimitry Andric 120*0b57cec5SDimitry Andric Val = ParsedSourceLocation::FromString(ArgValue); 121*0b57cec5SDimitry Andric if (Val.FileName.empty()) { 122*0b57cec5SDimitry Andric errs() << "error: " 123*0b57cec5SDimitry Andric << "source location must be of the form filename:line:column\n"; 124*0b57cec5SDimitry Andric return true; 125*0b57cec5SDimitry Andric } 126*0b57cec5SDimitry Andric 127*0b57cec5SDimitry Andric return false; 128*0b57cec5SDimitry Andric } 129*0b57cec5SDimitry Andric } 130*0b57cec5SDimitry Andric } 131*0b57cec5SDimitry Andric 132*0b57cec5SDimitry Andric #endif 133