Teach Zeekygen to produce source-code-range information

Related to https://github.com/zeek/zeek-docs/issues/56
This commit is contained in:
Jon Siwek 2021-02-26 14:55:59 -08:00
parent c95a364ff7
commit 6ac499882c
16 changed files with 147 additions and 7 deletions

View file

@ -18,6 +18,7 @@
#include "zeek/zeekygen/Manager.h"
#include "zeek/zeekygen/IdentifierInfo.h"
#include "zeek/zeekygen/ScriptInfo.h"
#include "zeek/zeekygen/utils.h"
#include "zeek/module_util.h"
namespace zeek {
@ -492,7 +493,15 @@ void ID::DescribeReST(ODesc* d, bool roles_only) const
d->Add(".. zeek:type:: ");
else
d->Add(".. zeek:id:: ");
d->Add(name);
if ( auto sc = zeek::zeekygen::detail::source_code_range(this) )
{
d->PushIndent();
d->Add(util::fmt(":source-code: %s", sc->data()));
d->PopIndentNoNL();
}
}
d->PushIndent();

View file

@ -6,6 +6,8 @@
#include <errno.h>
#include "zeek/ID.h"
#include "zeek/Val.h"
#include "zeek/Func.h"
#include "zeek/Scope.h"
#include "zeek/Reporter.h"
#include "zeek/plugin/Manager.h"
@ -149,4 +151,68 @@ std::string normalize_script_path(std::string_view path)
return util::detail::without_zeekpath_component(path);
}
std::optional<std::string> source_code_range(const zeek::detail::ID* id)
{
const auto& type = id->GetType();
if ( ! type )
return {};
// Some object locations won't end up capturing concrete syntax of closing
// braces on subsequent line -- of course that doesn't have to always be
// case, but it's true for current code style and the possibility of
// capturing an extra line of context is not harmful (human reader shouldn't
// be too confused by it).
int extra_lines = 0;
const zeek::detail::Location* loc = &zeek::detail::no_location;
switch ( type->Tag() ) {
case TYPE_FUNC:
{
const auto& v = id->GetVal();
if ( v && v->AsFunc()->GetBodies().size() == 1 )
{
// Either a function or an event/hook with single body can
// report that single, contiguous range.
loc = v->AsFunc()->GetBodies()[0].stmts->GetLocationInfo();
++extra_lines;
}
else
loc = id->GetLocationInfo();
}
break;
case TYPE_ENUM:
// Fallthrough
case TYPE_RECORD:
if ( id->IsType() )
{
loc = type->GetLocationInfo();
if ( zeek::util::ends_with(loc->filename, ".bif.zeek") )
// Source code won't be availabel to reference, so fall back
// to identifier location which may actually be in a regular
// .zeek script.
loc = id->GetLocationInfo();
else
++extra_lines;
}
else
loc = id->GetLocationInfo();
break;
default:
loc = id->GetLocationInfo();
break;
}
if ( loc == &zeek::detail::no_location )
return {};
return util::fmt("%s %d %d",
normalize_script_path(loc->filename).data(),
loc->first_line, loc->last_line + extra_lines);
}
} // namespace zeek::zeekygen::detail

View file

@ -6,6 +6,7 @@
#include <time.h> // for time_t
#include <string>
#include <optional>
namespace zeek::detail { class ID; }
@ -74,4 +75,18 @@ std::string redef_indication(const std::string& from_script);
*
*/
std::string normalize_script_path(std::string_view path);
/**
* Determines the associated section of source code associated with an
* identifier's definition.
*
* @param id identifier for which obtain source code location info is obtained
*
* @return a nil value if source code location could not be determined, else
* a space-separated string with 3 components. The 1st component is a path
* relative to the "scripts/" directory, the 2nd and 3rd components are
* line numbers denoting the start and end of the relevant source code.
*/
std::optional<std::string> source_code_range(const zeek::detail::ID* id);
} // namespace zeek::zeekygen::detail