summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Help/manual/cmake.1.rst8
-rw-r--r--Help/release/dev/trace-line-end.rst7
-rw-r--r--Source/cmCMakeLanguageCommand.cxx3
-rw-r--r--Source/cmCPluginAPI.cxx2
-rw-r--r--Source/cmListFileCache.cxx4
-rw-r--r--Source/cmListFileCache.h9
-rw-r--r--Source/cmMacroCommand.cxx2
-rw-r--r--Source/cmMakefile.cxx4
-rw-r--r--Source/cmVariableWatchCommand.cxx2
-rwxr-xr-xTests/RunCMake/CommandLine/trace-json-v1-check.py37
-rw-r--r--Tests/RunCMake/CommandLine/trace-json-v1.cmake6
11 files changed, 64 insertions, 20 deletions
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index 54eb244dde..37cf7d85cd 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -309,7 +309,13 @@ Options
was called.
``line``
- The line in ``file`` of the function call.
+ The line in ``file`` where the function call begins.
+
+ ``line_end``
+ If the function call spans multiple lines, this field will
+ be set to the line where the function call ends. If the function
+ calls spans a single line, this field will be unset. This field
+ was added in minor version 2 of the ``json-v1`` format.
``defer``
Optional member that is present when the function call was deferred
diff --git a/Help/release/dev/trace-line-end.rst b/Help/release/dev/trace-line-end.rst
new file mode 100644
index 0000000000..beade4b4b2
--- /dev/null
+++ b/Help/release/dev/trace-line-end.rst
@@ -0,0 +1,7 @@
+trace-line-end
+--------------
+
+* Add the field ``line_end`` to the json-v1 trace format. This
+ field tells you the line in file ``file`` at which the function
+ call ends. Tools can use this new field, together with ``line``
+ and ``file``, to map traces to lines of CMake source code.
diff --git a/Source/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx
index 789c78d4bc..27d8cb836f 100644
--- a/Source/cmCMakeLanguageCommand.cxx
+++ b/Source/cmCMakeLanguageCommand.cxx
@@ -84,7 +84,8 @@ bool cmCMakeLanguageCommandCALL(std::vector<cmListFileArgument> const& args,
for (size_t i = startArg; i < args.size(); ++i) {
funcArgs.emplace_back(args[i].Value, args[i].Delim, context.Line);
}
- cmListFileFunction func{ callCommand, context.Line, std::move(funcArgs) };
+ cmListFileFunction func{ callCommand, context.Line, context.Line,
+ std::move(funcArgs) };
if (defer) {
if (defer->Id.empty()) {
diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx
index 1b11f209c4..abec9684ed 100644
--- a/Source/cmCPluginAPI.cxx
+++ b/Source/cmCPluginAPI.cxx
@@ -432,7 +432,7 @@ static int CCONV cmExecuteCommand(void* arg, const char* name, int numArgs,
lffArgs.emplace_back(args[i], cmListFileArgument::Quoted, 0);
}
- cmListFileFunction lff{ name, 0, std::move(lffArgs) };
+ cmListFileFunction lff{ name, 0, 0, std::move(lffArgs) };
cmExecutionStatus status(*mf);
return mf->ExecuteCommand(lff, status);
}
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
index b28b282201..b90af0859e 100644
--- a/Source/cmListFileCache.cxx
+++ b/Source/cmListFileCache.cxx
@@ -40,6 +40,7 @@ struct cmListFileParser
cmListFileLexer* Lexer;
std::string FunctionName;
long FunctionLine;
+ long FunctionLineEnd;
std::vector<cmListFileArgument> FunctionArguments;
enum
{
@@ -146,7 +147,7 @@ bool cmListFileParser::Parse()
if (this->ParseFunction(token->text, token->line)) {
this->ListFile->Functions.emplace_back(
std::move(this->FunctionName), this->FunctionLine,
- std::move(this->FunctionArguments));
+ this->FunctionLineEnd, std::move(this->FunctionArguments));
} else {
return false;
}
@@ -259,6 +260,7 @@ bool cmListFileParser::ParseFunction(const char* name, long line)
}
} else if (token->type == cmListFileLexer_Token_ParenRight) {
if (parenDepth == 0) {
+ this->FunctionLineEnd = token->line;
return true;
}
parenDepth--;
diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h
index 58bc57ef50..c3da81bc6b 100644
--- a/Source/cmListFileCache.h
+++ b/Source/cmListFileCache.h
@@ -51,9 +51,9 @@ struct cmListFileArgument
class cmListFileFunction
{
public:
- cmListFileFunction(std::string name, long line,
+ cmListFileFunction(std::string name, long line, long lineEnd,
std::vector<cmListFileArgument> args)
- : Impl{ std::make_shared<Implementation>(std::move(name), line,
+ : Impl{ std::make_shared<Implementation>(std::move(name), line, lineEnd,
std::move(args)) }
{
}
@@ -69,6 +69,7 @@ public:
}
long Line() const noexcept { return this->Impl->Line; }
+ long LineEnd() const noexcept { return this->Impl->LineEnd; }
std::vector<cmListFileArgument> const& Arguments() const noexcept
{
@@ -78,11 +79,12 @@ public:
private:
struct Implementation
{
- Implementation(std::string name, long line,
+ Implementation(std::string name, long line, long lineEnd,
std::vector<cmListFileArgument> args)
: OriginalName{ std::move(name) }
, LowerCaseName{ cmSystemTools::LowerCase(this->OriginalName) }
, Line{ line }
+ , LineEnd{ lineEnd }
, Arguments{ std::move(args) }
{
}
@@ -90,6 +92,7 @@ private:
std::string OriginalName;
std::string LowerCaseName;
long Line = 0;
+ long LineEnd = 0;
std::vector<cmListFileArgument> Arguments;
};
diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx
index 154df63f07..ef1248792e 100644
--- a/Source/cmMacroCommand.cxx
+++ b/Source/cmMacroCommand.cxx
@@ -116,7 +116,7 @@ bool cmMacroHelperCommand::operator()(
newLFFArgs.push_back(std::move(arg));
}
cmListFileFunction newLFF{ func.OriginalName(), func.Line(),
- std::move(newLFFArgs) };
+ func.LineEnd(), std::move(newLFFArgs) };
cmExecutionStatus status(makefile);
if (!makefile.ExecuteCommand(newLFF, status) || status.GetNestedError()) {
// The error message should have already included the call stack
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 934a6f4dcc..77dbcfb2a7 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -291,6 +291,9 @@ void cmMakefile::PrintCommandTrace(
builder["indentation"] = "";
val["file"] = full_path;
val["line"] = static_cast<Json::Value::Int64>(lff.Line());
+ if (lff.Line() != lff.LineEnd()) {
+ val["line_end"] = static_cast<Json::Value::Int64>(lff.LineEnd());
+ }
if (deferId) {
val["defer"] = *deferId;
}
@@ -1665,6 +1668,7 @@ void cmMakefile::Configure()
this->Backtrace);
cmListFileFunction project{ "project",
0,
+ 0,
{ { "Project", cmListFileArgument::Unquoted,
0 },
{ "__CMAKE_INJECTED_PROJECT_COMMAND__",
diff --git a/Source/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx
index fd5402cf68..24394d9698 100644
--- a/Source/cmVariableWatchCommand.cxx
+++ b/Source/cmVariableWatchCommand.cxx
@@ -58,7 +58,7 @@ void cmVariableWatchCommandVariableAccessed(const std::string& variable,
{ stack, cmListFileArgument::Quoted, fakeLineNo }
};
- cmListFileFunction newLFF{ data->Command, fakeLineNo,
+ cmListFileFunction newLFF{ data->Command, fakeLineNo, fakeLineNo,
std::move(newLFFArgs) };
cmExecutionStatus status(*makefile);
if (!makefile->ExecuteCommand(newLFF, status)) {
diff --git a/Tests/RunCMake/CommandLine/trace-json-v1-check.py b/Tests/RunCMake/CommandLine/trace-json-v1-check.py
index 995cfad32f..2ef14955b1 100755
--- a/Tests/RunCMake/CommandLine/trace-json-v1-check.py
+++ b/Tests/RunCMake/CommandLine/trace-json-v1-check.py
@@ -30,6 +30,8 @@ required_traces = [
{
'args': ['STATUS', 'JSON-V1 str', 'spaces'],
'cmd': 'message',
+ 'line': 1,
+ 'line_end': 5
},
{
'args': ['ASDF', 'fff', 'sss', ' SPACES !!! '],
@@ -57,6 +59,24 @@ required_traces = [
}
]
+def assert_fields_look_good(line):
+ expected_fields = {'args', 'cmd', 'file', 'frame', 'global_frame','line', 'time'}
+ if "line_end" in line:
+ assert isinstance(line['line_end'], int)
+ assert line['line'] != line['line_end']
+ expected_fields.add("line_end")
+
+ assert set(line.keys()) == expected_fields
+
+ assert isinstance(line['args'], list)
+ assert isinstance(line['cmd'], unicode)
+ assert isinstance(line['file'], unicode)
+ assert isinstance(line['frame'], int)
+ assert isinstance(line['global_frame'], int)
+ assert isinstance(line['line'], int)
+ assert isinstance(line['time'], float)
+
+
with open(trace_file, 'r') as fp:
# Check for version (must be the first document)
vers = json.loads(fp.readline())
@@ -67,18 +87,15 @@ with open(trace_file, 'r') as fp:
for i in fp.readlines():
line = json.loads(i)
- assert sorted(line.keys()) == ['args', 'cmd', 'file', 'frame', 'global_frame','line', 'time']
- assert isinstance(line['args'], list)
- assert isinstance(line['cmd'], unicode)
- assert isinstance(line['file'], unicode)
- assert isinstance(line['frame'], int)
- assert isinstance(line['global_frame'], int)
- assert isinstance(line['line'], int)
- assert isinstance(line['time'], float)
-
+ assert_fields_look_good(line)
for j in required_traces:
# Compare the subset of required keys with line
- if {k: line[k] for k in j} == j:
+ subset = {
+ k: line[k]
+ for k in j
+ if k in line
+ }
+ if subset == j:
required_traces.remove(j)
assert not required_traces
diff --git a/Tests/RunCMake/CommandLine/trace-json-v1.cmake b/Tests/RunCMake/CommandLine/trace-json-v1.cmake
index 871746da23..4ed61608b9 100644
--- a/Tests/RunCMake/CommandLine/trace-json-v1.cmake
+++ b/Tests/RunCMake/CommandLine/trace-json-v1.cmake
@@ -1,4 +1,8 @@
-message(STATUS "JSON-V1 str" "spaces")
+message(
+ STATUS
+ "JSON-V1 str"
+ "spaces"
+ )
set(ASDF fff sss " SPACES !!! ")
set(FOO 42)
set(BAR " space in string!")