OptionValueFileColonLine.cpp
5.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//===-- OptionValueFileColonLine.cpp---------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lldb/Interpreter/OptionValueFileColonLine.h"
#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/State.h"
using namespace lldb;
using namespace lldb_private;
// This is an OptionValue for parsing file:line:column specifications.
// I set the completer to "source file" which isn't quite right, but we can
// only usefully complete in the file name part of it so it should be good
// enough.
OptionValueFileColonLine::OptionValueFileColonLine()
: OptionValue(), m_file_spec(), m_line_number(LLDB_INVALID_LINE_NUMBER),
m_column_number(LLDB_INVALID_COLUMN_NUMBER),
m_completion_mask(CommandCompletions::eSourceFileCompletion) {}
OptionValueFileColonLine::OptionValueFileColonLine(llvm::StringRef input)
: OptionValue(), m_file_spec(), m_line_number(LLDB_INVALID_LINE_NUMBER),
m_column_number(LLDB_INVALID_COLUMN_NUMBER),
m_completion_mask(CommandCompletions::eSourceFileCompletion) {
SetValueFromString(input, eVarSetOperationAssign);
}
void OptionValueFileColonLine::DumpValue(const ExecutionContext *exe_ctx,
Stream &strm, uint32_t dump_mask) {
if (dump_mask & eDumpOptionType)
strm.Printf("(%s)", GetTypeAsCString());
if (dump_mask & eDumpOptionValue) {
if (dump_mask & eDumpOptionType)
strm.PutCString(" = ");
if (m_file_spec)
strm << '"' << m_file_spec.GetPath().c_str() << '"';
if (m_line_number != LLDB_INVALID_LINE_NUMBER)
strm.Printf(":%d", m_line_number);
if (m_column_number != LLDB_INVALID_COLUMN_NUMBER)
strm.Printf(":%d", m_column_number);
}
}
Status OptionValueFileColonLine::SetValueFromString(llvm::StringRef value,
VarSetOperationType op) {
Status error;
switch (op) {
case eVarSetOperationClear:
Clear();
NotifyValueChanged();
break;
case eVarSetOperationReplace:
case eVarSetOperationAssign:
if (value.size() > 0) {
// This is in the form filename:linenumber:column.
// I wish we could use filename:linenumber.column, that would make the
// parsing unambiguous and so much easier...
// But clang & gcc both print the output with two : so we're stuck with
// the two colons. Practically, the only actual ambiguity this introduces
// is with files like "foo:10", which doesn't seem terribly likely.
// Providing the column is optional, so the input value might have one or
// two colons. First pick off the last colon separated piece.
// It has to be there, since the line number is required:
llvm::StringRef last_piece;
llvm::StringRef left_of_last_piece;
std::tie(left_of_last_piece, last_piece) = value.rsplit(':');
if (last_piece.empty()) {
error.SetErrorStringWithFormat("Line specifier must include file and "
"line: '%s'",
value.str().c_str());
return error;
}
// Now see if there's another colon and if so pull out the middle piece:
// Then check whether the middle piece is an integer. If it is, then it
// was the line number, and if it isn't we're going to assume that there
// was a colon in the filename (see note at the beginning of the function)
// and ignore it.
llvm::StringRef file_name;
llvm::StringRef middle_piece;
std::tie(file_name, middle_piece) = left_of_last_piece.rsplit(':');
if (middle_piece.empty() || !llvm::to_integer(middle_piece,
m_line_number)) {
// The middle piece was empty or not an integer, so there were only two
// legit pieces; our original division was right. Reassign the file
// name and pull out the line number:
file_name = left_of_last_piece;
if (!llvm::to_integer(last_piece, m_line_number)) {
error.SetErrorStringWithFormat("Bad line number value '%s' in: '%s'",
last_piece.str().c_str(),
value.str().c_str());
return error;
}
} else {
// There were three pieces, and we've got the line number. So now
// we just need to check the column number which was the last peice.
if (!llvm::to_integer(last_piece, m_column_number)) {
error.SetErrorStringWithFormat("Bad column value '%s' in: '%s'",
last_piece.str().c_str(),
value.str().c_str());
return error;
}
}
m_value_was_set = true;
m_file_spec.SetFile(file_name, FileSpec::Style::native);
NotifyValueChanged();
} else {
error.SetErrorString("invalid value string");
}
break;
case eVarSetOperationInsertBefore:
case eVarSetOperationInsertAfter:
case eVarSetOperationRemove:
case eVarSetOperationAppend:
case eVarSetOperationInvalid:
error = OptionValue::SetValueFromString(value, op);
break;
}
return error;
}
lldb::OptionValueSP OptionValueFileColonLine::DeepCopy() const {
return OptionValueSP(new OptionValueFileColonLine(*this));
}
void OptionValueFileColonLine::AutoComplete(CommandInterpreter &interpreter,
CompletionRequest &request) {
CommandCompletions::InvokeCommonCompletionCallbacks(
interpreter, m_completion_mask, request, nullptr);
}