[Torque] Add Kythe api to Torque compiler

Prepare the Torque compiler to generate Kythe artifacts to be consumed
by CodeSearch.

Drive-by changes.
* Extend SourcePosition by an offset in the input string, as this is
  required by the Kythe graph.
* Correctly set missing identifier positions in Declarations.

Bug: v8:12261
Change-Id: Ida0a4a562c99f58ab924ddde36f3146f3d3fd415
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3181102
Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
Reviewed-by: Seth Brenith <seth.brenith@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#77099}
This commit is contained in:
Nico Hartmann 2021-09-27 18:17:40 +02:00 committed by V8 LUCI CQ
parent 063384f76e
commit 6c9f799207
22 changed files with 630 additions and 126 deletions

View File

@ -4716,6 +4716,8 @@ v8_source_set("torque_base") {
"src/torque/instance-type-generator.cc",
"src/torque/instructions.cc",
"src/torque/instructions.h",
"src/torque/kythe-data.cc",
"src/torque/kythe-data.h",
"src/torque/parameter-difference.h",
"src/torque/server-data.cc",
"src/torque/server-data.h",

View File

@ -625,18 +625,18 @@ struct BasicTypeExpression : TypeExpression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(BasicTypeExpression)
BasicTypeExpression(SourcePosition pos,
std::vector<std::string> namespace_qualification,
std::string name,
Identifier* name,
std::vector<TypeExpression*> generic_arguments)
: TypeExpression(kKind, pos),
namespace_qualification(std::move(namespace_qualification)),
is_constexpr(IsConstexprName(name)),
name(std::move(name)),
is_constexpr(IsConstexprName(name->value)),
name(name),
generic_arguments(std::move(generic_arguments)) {}
BasicTypeExpression(SourcePosition pos, std::string name)
: BasicTypeExpression(pos, {}, std::move(name), {}) {}
BasicTypeExpression(SourcePosition pos, Identifier* name)
: BasicTypeExpression(pos, {}, name, {}) {}
std::vector<std::string> namespace_qualification;
bool is_constexpr;
std::string name;
Identifier* name;
std::vector<TypeExpression*> generic_arguments;
};
@ -1306,10 +1306,9 @@ inline VarDeclarationStatement* MakeConstDeclarationStatement(
}
inline BasicTypeExpression* MakeBasicTypeExpression(
std::vector<std::string> namespace_qualification, std::string name,
std::vector<std::string> namespace_qualification, Identifier* name,
std::vector<TypeExpression*> generic_arguments = {}) {
return MakeNode<BasicTypeExpression>(std::move(namespace_qualification),
std::move(name),
return MakeNode<BasicTypeExpression>(std::move(namespace_qualification), name,
std::move(generic_arguments));
}

View File

@ -5,6 +5,7 @@
#include "src/torque/declaration-visitor.h"
#include "src/torque/ast.h"
#include "src/torque/kythe-data.h"
#include "src/torque/server-data.h"
#include "src/torque/type-inference.h"
#include "src/torque/type-visitor.h"
@ -109,16 +110,20 @@ Builtin* DeclarationVisitor::CreateBuiltin(BuiltinDeclaration* decl,
Error("Builtins cannot have return type void.");
}
return Declarations::CreateBuiltin(std::move(external_name),
std::move(readable_name), kind,
std::move(signature), body);
Builtin* builtin = Declarations::CreateBuiltin(std::move(external_name),
std::move(readable_name), kind,
std::move(signature), body);
// TODO(v8:12261): Recheck this.
// builtin->SetIdentifierPosition(decl->name->pos);
return builtin;
}
void DeclarationVisitor::Visit(ExternalBuiltinDeclaration* decl) {
Declarations::Declare(
decl->name->value,
Builtin* builtin =
CreateBuiltin(decl, decl->name->value, decl->name->value,
TypeVisitor::MakeSignature(decl), base::nullopt));
TypeVisitor::MakeSignature(decl), base::nullopt);
builtin->SetIdentifierPosition(decl->name->pos);
Declarations::Declare(decl->name->value, builtin);
}
void DeclarationVisitor::Visit(ExternalRuntimeDeclaration* decl) {
@ -152,29 +157,43 @@ void DeclarationVisitor::Visit(ExternalRuntimeDeclaration* decl) {
}
}
Declarations::DeclareRuntimeFunction(decl->name->value, signature);
RuntimeFunction* function =
Declarations::DeclareRuntimeFunction(decl->name->value, signature);
function->SetIdentifierPosition(decl->name->pos);
function->SetPosition(decl->pos);
if (GlobalContext::collect_kythe_data()) {
KytheData::AddFunctionDefinition(function);
}
}
void DeclarationVisitor::Visit(ExternalMacroDeclaration* decl) {
Declarations::DeclareMacro(
Macro* macro = Declarations::DeclareMacro(
decl->name->value, true, decl->external_assembler_name,
TypeVisitor::MakeSignature(decl), base::nullopt, decl->op);
macro->SetIdentifierPosition(decl->name->pos);
macro->SetPosition(decl->pos);
if (GlobalContext::collect_kythe_data()) {
KytheData::AddFunctionDefinition(macro);
}
}
void DeclarationVisitor::Visit(TorqueBuiltinDeclaration* decl) {
Declarations::Declare(
decl->name->value,
CreateBuiltin(decl, decl->name->value, decl->name->value,
TypeVisitor::MakeSignature(decl), decl->body));
auto builtin = CreateBuiltin(decl, decl->name->value, decl->name->value,
TypeVisitor::MakeSignature(decl), decl->body);
builtin->SetIdentifierPosition(decl->name->pos);
builtin->SetPosition(decl->pos);
Declarations::Declare(decl->name->value, builtin);
}
void DeclarationVisitor::Visit(TorqueMacroDeclaration* decl) {
Macro* macro = Declarations::DeclareMacro(
decl->name->value, decl->export_to_csa, base::nullopt,
TypeVisitor::MakeSignature(decl), decl->body, decl->op);
// TODO(szuend): Set identifier_position to decl->name->pos once all callable
// names are changed from std::string to Identifier*.
macro->SetIdentifierPosition(decl->name->pos);
macro->SetPosition(decl->pos);
if (GlobalContext::collect_kythe_data()) {
KytheData::AddFunctionDefinition(macro);
}
}
void DeclarationVisitor::Visit(IntrinsicDeclaration* decl) {
@ -183,8 +202,11 @@ void DeclarationVisitor::Visit(IntrinsicDeclaration* decl) {
}
void DeclarationVisitor::Visit(ConstDeclaration* decl) {
Declarations::DeclareNamespaceConstant(
auto constant = Declarations::DeclareNamespaceConstant(
decl->name, TypeVisitor::ComputeType(decl->type), decl->expression);
if (GlobalContext::collect_kythe_data()) {
KytheData::AddConstantDefinition(constant);
}
}
void DeclarationVisitor::Visit(SpecializationDeclaration* decl) {
@ -260,7 +282,11 @@ void DeclarationVisitor::Visit(ExternConstDeclaration* decl) {
ReportError(stream.str());
}
Declarations::DeclareExternConstant(decl->name, type, decl->literal);
ExternConstant* constant =
Declarations::DeclareExternConstant(decl->name, type, decl->literal);
if (GlobalContext::collect_kythe_data()) {
KytheData::AddConstantDefinition(constant);
}
}
void DeclarationVisitor::Visit(CppIncludeDeclaration* decl) {

View File

@ -277,11 +277,12 @@ RuntimeFunction* Declarations::DeclareRuntimeFunction(
new RuntimeFunction(name, signature))));
}
void Declarations::DeclareExternConstant(Identifier* name, const Type* type,
std::string value) {
ExternConstant* Declarations::DeclareExternConstant(Identifier* name,
const Type* type,
std::string value) {
CheckAlreadyDeclared<Value>(name->value, "constant");
Declare(name->value, std::unique_ptr<ExternConstant>(
new ExternConstant(name, type, value)));
return Declare(name->value, std::unique_ptr<ExternConstant>(
new ExternConstant(name, type, value)));
}
NamespaceConstant* Declarations::DeclareNamespaceConstant(Identifier* name,

View File

@ -132,8 +132,9 @@ class Declarations {
static RuntimeFunction* DeclareRuntimeFunction(const std::string& name,
const Signature& signature);
static void DeclareExternConstant(Identifier* name, const Type* type,
std::string value);
static ExternConstant* DeclareExternConstant(Identifier* name,
const Type* type,
std::string value);
static NamespaceConstant* DeclareNamespaceConstant(Identifier* name,
const Type* type,
Expression* body);

View File

@ -18,11 +18,12 @@ namespace torque {
namespace {
struct LineAndColumnTracker {
LineAndColumn previous{0, 0};
LineAndColumn current{0, 0};
LineAndColumn previous{0, 0, 0};
LineAndColumn current{0, 0, 0};
void Advance(InputPosition from, InputPosition to) {
previous = current;
current.offset += std::distance(from, to);
while (from != to) {
if (*from == '\n') {
current.line += 1;
@ -187,7 +188,8 @@ const Item* RunEarleyAlgorithm(
// Worklist for items at the next position.
std::vector<Item> future_items;
CurrentSourcePosition::Scope source_position(
SourcePosition{CurrentSourceFile::Get(), {0, 0}, {0, 0}});
SourcePosition{CurrentSourceFile::Get(), LineAndColumn::Invalid(),
LineAndColumn::Invalid()});
std::vector<const Item*> completed_items;
std::unordered_map<std::pair<size_t, Symbol*>, std::set<const Item*>,
base::hash<std::pair<size_t, Symbol*>>>

View File

@ -13,12 +13,14 @@ DEFINE_CONTEXTUAL_VARIABLE(TargetArchitecture)
GlobalContext::GlobalContext(Ast ast)
: collect_language_server_data_(false),
collect_kythe_data_(false),
force_assert_statements_(false),
annotate_ir_(false),
ast_(std::move(ast)) {
CurrentScope::Scope current_scope(nullptr);
CurrentSourcePosition::Scope current_source_position(
SourcePosition{CurrentSourceFile::Get(), {-1, -1}, {-1, -1}});
SourcePosition{CurrentSourceFile::Get(), LineAndColumn::Invalid(),
LineAndColumn::Invalid()});
default_namespace_ =
RegisterDeclarable(std::make_unique<Namespace>(kBaseNamespaceName));
}

View File

@ -49,6 +49,8 @@ class GlobalContext : public ContextualClass<GlobalContext> {
static bool collect_language_server_data() {
return Get().collect_language_server_data_;
}
static void SetCollectKytheData() { Get().collect_kythe_data_ = true; }
static bool collect_kythe_data() { return Get().collect_kythe_data_; }
static void SetForceAssertStatements() {
Get().force_assert_statements_ = true;
}
@ -118,6 +120,7 @@ class GlobalContext : public ContextualClass<GlobalContext> {
private:
bool collect_language_server_data_;
bool collect_kythe_data_;
bool force_assert_statements_;
bool annotate_ir_;
Namespace* default_namespace_;

View File

@ -17,6 +17,7 @@
#include "src/torque/csa-generator.h"
#include "src/torque/declaration-visitor.h"
#include "src/torque/global-context.h"
#include "src/torque/kythe-data.h"
#include "src/torque/parameter-difference.h"
#include "src/torque/server-data.h"
#include "src/torque/source-positions.h"
@ -29,6 +30,8 @@ namespace v8 {
namespace internal {
namespace torque {
uint64_t next_unique_binding_index = 0;
// Sadly, 'using std::string_literals::operator""s;' is bugged in MSVC (see
// https://developercommunity.visualstudio.com/t/Incorrect-warning-when-using-standard-st/673948).
// TODO(nicohartmann@): Change to 'using std::string_literals::operator""s;'
@ -291,6 +294,8 @@ VisitResult ImplementationVisitor::InlineMacro(
DCHECK(macro->IsMethod());
parameter_bindings.Add(kThisParameterName, LocalValue{*this_reference},
true);
// TODO(v8:12261): Tracking 'this'-binding for kythe led to a few weird
// issues. Review to fully support 'this' in methods.
}
size_t count = 0;
@ -298,17 +303,24 @@ VisitResult ImplementationVisitor::InlineMacro(
if (this_reference && count == signature.implicit_count) count++;
const bool mark_as_used = signature.implicit_count > count;
const Identifier* name = macro->parameter_names()[count++];
parameter_bindings.Add(name,
LocalValue{LocationReference::Temporary(
arg, "parameter " + name->value)},
mark_as_used);
Binding<LocalValue>* binding =
parameter_bindings.Add(name,
LocalValue{LocationReference::Temporary(
arg, "parameter " + name->value)},
mark_as_used);
if (GlobalContext::collect_kythe_data()) {
KytheData::AddBindingDefinition(binding);
}
}
DCHECK_EQ(label_blocks.size(), signature.labels.size());
for (size_t i = 0; i < signature.labels.size(); ++i) {
const LabelDeclaration& label_info = signature.labels[i];
label_bindings.Add(label_info.name,
LocalLabel{label_blocks[i], label_info.types});
Binding<LocalLabel>* binding = label_bindings.Add(
label_info.name, LocalLabel{label_blocks[i], label_info.types});
if (GlobalContext::collect_kythe_data()) {
KytheData::AddBindingDefinition(binding);
}
}
Block* macro_end;
@ -542,11 +554,14 @@ std::string AddParameter(size_t i, Builtin* builtin,
std::string external_name = "parameter" + std::to_string(i);
parameters->Push(external_name);
StackRange range = parameter_types->PushMany(LowerType(type));
parameter_bindings->Add(
Binding<LocalValue>* binding = parameter_bindings->Add(
name,
LocalValue{LocationReference::Temporary(VisitResult(type, range),
"parameter " + name->value)},
mark_as_used);
if (GlobalContext::collect_kythe_data()) {
KytheData::AddBindingDefinition(binding);
}
return external_name;
}
@ -1005,6 +1020,9 @@ const Type* ImplementationVisitor::Visit(GotoStatement* stmt) {
LanguageServerData::AddDefinition(stmt->label->pos,
label->declaration_position());
}
if (GlobalContext::collect_kythe_data()) {
KytheData::AddBindingUse(stmt->label->pos, label);
}
size_t i = 0;
StackRange arguments = assembler().TopRange(0);
@ -2230,6 +2248,9 @@ LocationReference ImplementationVisitor::GenerateFieldAccess(
if (GlobalContext::collect_language_server_data() && pos.has_value()) {
LanguageServerData::AddDefinition(*pos, field.pos);
}
if (GlobalContext::collect_kythe_data() && pos.has_value()) {
KytheData::AddClassFieldUse(*pos, &field);
}
if (field.const_qualified) {
VisitResult t_value = ProjectStructField(reference.variable(), fieldname);
return LocationReference::Temporary(
@ -2326,6 +2347,9 @@ LocationReference ImplementationVisitor::GenerateFieldAccess(
if (GlobalContext::collect_language_server_data() && pos.has_value()) {
LanguageServerData::AddDefinition(*pos, field.pos);
}
if (GlobalContext::collect_kythe_data()) {
KytheData::AddClassFieldUse(*pos, &field);
}
return GenerateFieldReference(object_result, field, *class_type);
}
}
@ -2367,6 +2391,13 @@ LocationReference ImplementationVisitor::GetLocationReference(
LanguageServerData::AddDefinition(expr->name->pos,
(*value)->declaration_position());
}
if (GlobalContext::collect_kythe_data()) {
if (!expr->IsThis()) {
DCHECK_EQ(expr->name->pos.end.column - expr->name->pos.start.column,
expr->name->value.length());
KytheData::AddBindingUse(expr->name->pos, *value);
}
}
if (expr->generic_arguments.size() != 0) {
ReportError("cannot have generic parameters on local name ",
expr->name);
@ -2385,6 +2416,7 @@ LocationReference ImplementationVisitor::GetLocationReference(
LanguageServerData::AddDefinition(expr->name->pos,
(*builtin)->Position());
}
// TODO(v8:12261): Consider collecting KytheData here.
return LocationReference::Temporary(GetBuiltinCode(*builtin),
"builtin " + expr->name->value);
}
@ -2411,6 +2443,9 @@ LocationReference ImplementationVisitor::GetLocationReference(
LanguageServerData::AddDefinition(expr->name->pos, value->name()->pos);
}
if (auto* constant = NamespaceConstant::DynamicCast(value)) {
if (GlobalContext::collect_kythe_data()) {
KytheData::AddConstantUse(expr->name->pos, constant);
}
if (constant->type()->IsConstexpr()) {
return LocationReference::Temporary(
VisitResult(constant->type(), constant->external_name() + "(state_)"),
@ -2424,6 +2459,9 @@ LocationReference ImplementationVisitor::GetLocationReference(
"namespace constant " + expr->name->value);
}
ExternConstant* constant = ExternConstant::cast(value);
if (GlobalContext::collect_kythe_data()) {
KytheData::AddConstantUse(expr->name->pos, constant);
}
return LocationReference::Temporary(constant->value(),
"extern value " + expr->name->value);
}
@ -3135,6 +3173,12 @@ VisitResult ImplementationVisitor::Visit(CallExpression* expr,
LanguageServerData::AddDefinition(expr->callee->name->pos,
callable->IdentifierPosition());
}
if (GlobalContext::collect_kythe_data()) {
Callable* callable = LookupCallable(name, Declarations::Lookup(name),
arguments, specialization_types);
Callable* caller = CurrentCallable::Get();
KytheData::AddCall(caller, expr->callee->name->pos, callable);
}
if (expr->callee->name->value == "!" && arguments.parameters.size() == 1) {
PropagateBitfieldMark(expr->arguments[0], expr);
}
@ -3178,6 +3222,10 @@ VisitResult ImplementationVisitor::Visit(CallMethodExpression* expr) {
LanguageServerData::AddDefinition(expr->method->name->pos,
callable->IdentifierPosition());
}
if (GlobalContext::collect_kythe_data()) {
Callable* caller = CurrentCallable::Get();
KytheData::AddCall(caller, expr->method->name->pos, callable);
}
return scope.Yield(GenerateCall(callable, target, arguments, {}, false));
}
@ -3268,6 +3316,7 @@ std::vector<Binding<LocalLabel>*> ImplementationVisitor::LabelsFromIdentifiers(
LanguageServerData::AddDefinition(name->pos,
label->declaration_position());
}
// TODO(v8:12261): Might have to track KytheData here.
}
return result;
}
@ -3548,7 +3597,8 @@ void ImplementationVisitor::GenerateBuiltinDefinitionsAndInterfaceDescriptors(
Declarations::FindSomeInternalBuiltinWithType(type);
if (!example_builtin) {
CurrentSourcePosition::Scope current_source_position(
SourcePosition{CurrentSourceFile::Get(), {-1, -1}, {-1, -1}});
SourcePosition{CurrentSourceFile::Get(), LineAndColumn::Invalid(),
LineAndColumn::Invalid()});
ReportError("unable to find any builtin with type \"", *type, "\"");
}
builtin_definitions << " V(" << type->function_pointer_type_id() << ","

View File

@ -228,6 +228,8 @@ struct LayoutForInitialization {
VisitResult size;
};
extern uint64_t next_unique_binding_index;
template <class T>
class Binding;
@ -262,7 +264,8 @@ class Binding : public T {
name_(name),
previous_binding_(this),
used_(false),
written_(false) {
written_(false),
unique_index_(next_unique_binding_index++) {
std::swap(previous_binding_, manager_->current_bindings_[name]);
}
template <class... Args>
@ -300,6 +303,8 @@ class Binding : public T {
bool Written() const { return written_; }
void SetWritten() { written_ = true; }
uint64_t unique_index() const { return unique_index_; }
private:
bool SkipLintCheck() const { return name_.length() > 0 && name_[0] == '_'; }
@ -309,26 +314,31 @@ class Binding : public T {
SourcePosition declaration_position_ = CurrentSourcePosition::Get();
bool used_;
bool written_;
uint64_t unique_index_;
};
template <class T>
class BlockBindings {
public:
explicit BlockBindings(BindingsManager<T>* manager) : manager_(manager) {}
void Add(std::string name, T value, bool mark_as_used = false) {
Binding<T>* Add(std::string name, T value, bool mark_as_used = false) {
ReportErrorIfAlreadyBound(name);
auto binding =
std::make_unique<Binding<T>>(manager_, name, std::move(value));
Binding<T>* result = binding.get();
if (mark_as_used) binding->SetUsed();
bindings_.push_back(std::move(binding));
return result;
}
void Add(const Identifier* name, T value, bool mark_as_used = false) {
Binding<T>* Add(const Identifier* name, T value, bool mark_as_used = false) {
ReportErrorIfAlreadyBound(name->value);
auto binding =
std::make_unique<Binding<T>>(manager_, name, std::move(value));
Binding<T>* result = binding.get();
if (mark_as_used) binding->SetUsed();
bindings_.push_back(std::move(binding));
return result;
}
std::vector<Binding<T>*> bindings() const {

187
src/torque/kythe-data.cc Normal file
View File

@ -0,0 +1,187 @@
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/torque/kythe-data.h"
namespace v8 {
namespace internal {
namespace torque {
DEFINE_CONTEXTUAL_VARIABLE(KytheData)
namespace {
KythePosition MakeKythePosition(const SourcePosition& pos) {
KythePosition p;
if (pos.source.IsValid()) {
p.file_path = SourceFileMap::PathFromV8Root(pos.source);
} else {
p.file_path = "UNKNOWN";
}
p.start_offset = pos.start.offset;
p.end_offset = pos.end.offset;
return p;
}
} // namespace
// Constants
kythe_entity_t KytheData::AddConstantDefinition(const Value* constant) {
DCHECK(constant->IsNamespaceConstant() || constant->IsExternConstant());
KytheData* that = &KytheData::Get();
// Check if we know the constant already.
auto it = that->constants_.find(constant);
if (it != that->constants_.end()) return it->second;
// Register this constant.
KythePosition pos = MakeKythePosition(constant->name()->pos);
kythe_entity_t constant_id = that->consumer_->AddDefinition(
KytheConsumer::Kind::Constant, constant->name()->value, pos);
that->constants_.insert(it, std::make_pair(constant, constant_id));
return constant_id;
}
void KytheData::AddConstantUse(SourcePosition use_position,
const Value* constant) {
DCHECK(constant->IsNamespaceConstant() || constant->IsExternConstant());
KytheData* that = &Get();
kythe_entity_t constant_id = AddConstantDefinition(constant);
KythePosition use_pos = MakeKythePosition(use_position);
that->consumer_->AddUse(KytheConsumer::Kind::Constant, constant_id, use_pos);
}
// Callables
kythe_entity_t KytheData::AddFunctionDefinition(Callable* callable) {
KytheData* that = &KytheData::Get();
// Check if we know the caller already.
auto it = that->callables_.find(callable);
if (it != that->callables_.end()) return it->second;
// Register this callable.
auto ident_pos = callable->IdentifierPosition();
kythe_entity_t callable_id = that->consumer_->AddDefinition(
KytheConsumer::Kind::Function, callable->ExternalName(),
MakeKythePosition(ident_pos));
that->callables_.insert(it, std::make_pair(callable, callable_id));
return callable_id;
}
void KytheData::AddCall(Callable* caller, SourcePosition call_position,
Callable* callee) {
if (!caller) return; // Ignore those for now.
DCHECK_NOT_NULL(caller);
DCHECK_NOT_NULL(callee);
KytheData* that = &Get();
if (call_position.source.IsValid()) {
kythe_entity_t caller_id = AddFunctionDefinition(caller);
kythe_entity_t callee_id = AddFunctionDefinition(callee);
KythePosition call_pos = MakeKythePosition(call_position);
that->consumer_->AddCall(KytheConsumer::Kind::Function, caller_id, call_pos,
callee_id);
}
}
// Class fields
kythe_entity_t KytheData::AddClassFieldDefinition(const Field* field) {
DCHECK(field);
KytheData* that = &KytheData::Get();
// Check if we know that field already.
auto it = that->class_fields_.find(field);
if (it != that->class_fields_.end()) return it->second;
// Register this field.
KythePosition pos = MakeKythePosition(field->pos);
kythe_entity_t field_id = that->consumer_->AddDefinition(
KytheConsumer::Kind::ClassField, field->name_and_type.name, pos);
that->class_fields_.insert(it, std::make_pair(field, field_id));
return field_id;
}
void KytheData::AddClassFieldUse(SourcePosition use_position,
const Field* field) {
DCHECK(field);
KytheData* that = &KytheData::Get();
kythe_entity_t field_id = AddClassFieldDefinition(field);
KythePosition use_pos = MakeKythePosition(use_position);
that->consumer_->AddUse(KytheConsumer::Kind::ClassField, field_id, use_pos);
}
// Bindings
kythe_entity_t KytheData::AddBindingDefinition(Binding<LocalValue>* binding) {
CHECK(binding);
const uint64_t binding_index = binding->unique_index();
return AddBindingDefinitionImpl(binding_index, binding->name(),
binding->declaration_position());
}
kythe_entity_t KytheData::AddBindingDefinition(Binding<LocalLabel>* binding) {
CHECK(binding);
const uint64_t binding_index = binding->unique_index();
return AddBindingDefinitionImpl(binding_index, binding->name(),
binding->declaration_position());
}
kythe_entity_t KytheData::AddBindingDefinitionImpl(
uint64_t binding_index, const std::string& name,
const SourcePosition& ident_pos) {
KytheData* that = &KytheData::Get();
// Check if we know the binding already.
auto it = that->local_bindings_.find(binding_index);
if (it != that->local_bindings_.end()) return it->second;
// Register this binding.
kythe_entity_t binding_id = that->consumer_->AddDefinition(
KytheConsumer::Kind::Variable, name, MakeKythePosition(ident_pos));
that->local_bindings_.insert(it, std::make_pair(binding_index, binding_id));
return binding_id;
}
void KytheData::AddBindingUse(SourcePosition use_position,
Binding<LocalValue>* binding) {
CHECK(binding);
KytheData* that = &KytheData::Get();
kythe_entity_t binding_id = AddBindingDefinition(binding);
KythePosition use_pos = MakeKythePosition(use_position);
that->consumer_->AddUse(KytheConsumer::Kind::Variable, binding_id, use_pos);
}
void KytheData::AddBindingUse(SourcePosition use_position,
Binding<LocalLabel>* binding) {
CHECK(binding);
KytheData* that = &KytheData::Get();
kythe_entity_t binding_id = AddBindingDefinition(binding);
KythePosition use_pos = MakeKythePosition(use_position);
that->consumer_->AddUse(KytheConsumer::Kind::Variable, binding_id, use_pos);
}
// Types
kythe_entity_t KytheData::AddTypeDefinition(const Declarable* type_decl) {
CHECK(type_decl);
KytheData* that = &KytheData::Get();
// Check if we know that type already.
auto it = that->types_.find(type_decl);
if (it != that->types_.end()) return it->second;
// Register this type.
KythePosition pos = MakeKythePosition(type_decl->IdentifierPosition());
kythe_entity_t type_id = that->consumer_->AddDefinition(
KytheConsumer::Kind::Type, type_decl->type_name(), pos);
that->types_.insert(it, std::make_pair(type_decl, type_id));
return type_id;
}
void KytheData::AddTypeUse(SourcePosition use_position,
const Declarable* type_decl) {
CHECK(type_decl);
KytheData* that = &KytheData::Get();
kythe_entity_t type_id = AddTypeDefinition(type_decl);
KythePosition use_pos = MakeKythePosition(use_position);
that->consumer_->AddUse(KytheConsumer::Kind::Type, type_id, use_pos);
}
} // namespace torque
} // namespace internal
} // namespace v8

110
src/torque/kythe-data.h Normal file
View File

@ -0,0 +1,110 @@
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_TORQUE_KYTHE_DATA_H_
#define V8_TORQUE_KYTHE_DATA_H_
#include <map>
#include "src/torque/ast.h"
#include "src/torque/contextual.h"
#include "src/torque/global-context.h"
#include "src/torque/implementation-visitor.h"
namespace v8 {
namespace internal {
namespace torque {
struct KythePosition {
std::string file_path;
uint64_t start_offset;
uint64_t end_offset;
};
using kythe_entity_t = uint64_t;
class KytheConsumer {
public:
enum class Kind {
Unspecified,
Constant,
Function,
ClassField,
Variable,
Type,
};
virtual ~KytheConsumer() = 0;
virtual kythe_entity_t AddDefinition(Kind kind, std::string name,
KythePosition pos) = 0;
virtual void AddUse(Kind kind, kythe_entity_t entity,
KythePosition use_pos) = 0;
virtual void AddCall(Kind kind, kythe_entity_t caller_entity,
KythePosition call_pos,
kythe_entity_t callee_entity) = 0;
};
inline KytheConsumer::~KytheConsumer() = default;
class KytheData : public ContextualClass<KytheData> {
public:
KytheData() = default;
static void SetConsumer(KytheConsumer* consumer) {
Get().consumer_ = consumer;
}
// Constants
V8_EXPORT_PRIVATE static kythe_entity_t AddConstantDefinition(
const Value* constant);
V8_EXPORT_PRIVATE static void AddConstantUse(SourcePosition use_position,
const Value* constant);
// Callables
V8_EXPORT_PRIVATE static kythe_entity_t AddFunctionDefinition(
Callable* callable);
V8_EXPORT_PRIVATE static void AddCall(Callable* caller,
SourcePosition call_position,
Callable* callee);
// Class fields
V8_EXPORT_PRIVATE static kythe_entity_t AddClassFieldDefinition(
const Field* field);
V8_EXPORT_PRIVATE static void AddClassFieldUse(SourcePosition use_position,
const Field* field);
// Bindings
V8_EXPORT_PRIVATE static kythe_entity_t AddBindingDefinition(
Binding<LocalValue>* binding);
V8_EXPORT_PRIVATE static kythe_entity_t AddBindingDefinition(
Binding<LocalLabel>* binding);
V8_EXPORT_PRIVATE static void AddBindingUse(SourcePosition use_position,
Binding<LocalValue>* binding);
V8_EXPORT_PRIVATE static void AddBindingUse(SourcePosition use_position,
Binding<LocalLabel>* binding);
// Types
V8_EXPORT_PRIVATE static kythe_entity_t AddTypeDefinition(
const Declarable* type_decl);
V8_EXPORT_PRIVATE static void AddTypeUse(SourcePosition use_position,
const Declarable* type_decl);
private:
static kythe_entity_t AddBindingDefinitionImpl(
uint64_t binding_index, const std::string& name,
const SourcePosition& ident_pos);
KytheConsumer* consumer_;
std::unordered_map<const Value*, kythe_entity_t> constants_;
std::unordered_map<Callable*, kythe_entity_t> callables_;
std::unordered_map<const Field*, std::set<SourcePosition>> field_uses_;
std::unordered_map<uint64_t, kythe_entity_t> local_bindings_;
std::unordered_map<const Declarable*, kythe_entity_t> types_;
std::unordered_map<const Field*, kythe_entity_t> class_fields_;
};
} // namespace torque
} // namespace internal
} // namespace v8
#endif // V8_TORQUE_KYTHE_DATA_H_

View File

@ -279,8 +279,9 @@ void HandleGotoDefinitionRequest(GotoDefinitionRequest request,
return;
}
LineAndColumn pos{request.params().position().line(),
request.params().position().character()};
auto pos =
LineAndColumn::WithUnknownOffset(request.params().position().line(),
request.params().position().character());
if (auto maybe_definition = LanguageServerData::FindDefinition(id, pos)) {
SourcePosition definition = *maybe_definition;

View File

@ -30,16 +30,27 @@ class SourceId {
};
struct LineAndColumn {
static constexpr int kUnknownOffset = -1;
int offset;
int line;
int column;
static LineAndColumn Invalid() { return {-1, -1}; }
static LineAndColumn Invalid() { return {-1, -1, -1}; }
static LineAndColumn WithUnknownOffset(int line, int column) {
return {kUnknownOffset, line, column};
}
bool operator==(const LineAndColumn& other) const {
return line == other.line && column == other.column;
if (offset == kUnknownOffset || other.offset == kUnknownOffset) {
return line == other.line && column == other.column;
}
DCHECK_EQ(offset == other.offset,
line == other.line && column == other.column);
return offset == other.offset;
}
bool operator!=(const LineAndColumn& other) const {
return !(*this == other);
return !operator==(other);
}
};

View File

@ -50,6 +50,9 @@ void CompileCurrentAst(TorqueCompilerOptions options) {
if (options.collect_language_server_data) {
GlobalContext::SetCollectLanguageServerData();
}
if (options.collect_kythe_data) {
GlobalContext::SetCollectKytheData();
}
if (options.force_assert_statements) {
GlobalContext::SetForceAssertStatements();
}
@ -161,6 +164,38 @@ TorqueCompilerResult CompileTorque(std::vector<std::string> files,
return result;
}
TorqueCompilerResult CompileTorqueForKythe(
std::vector<TorqueCompilationUnit> units, TorqueCompilerOptions options,
KytheConsumer* consumer) {
SourceFileMap::Scope source_map_scope(options.v8_root);
CurrentSourceFile::Scope unknown_source_file_scope(SourceId::Invalid());
CurrentAst::Scope ast_scope;
TorqueMessages::Scope messages_scope;
LanguageServerData::Scope server_data_scope;
KytheData::Scope kythe_scope;
KytheData::Get().SetConsumer(consumer);
TorqueCompilerResult result;
try {
for (const auto& unit : units) {
SourceId source_id = SourceFileMap::AddSource(unit.source_file_path);
CurrentSourceFile::Scope source_id_scope(source_id);
ParseTorque(unit.file_content);
}
CompileCurrentAst(options);
} catch (TorqueAbortCompilation&) {
// Do nothing. The relevant TorqueMessage is part of the
// TorqueMessages contextual.
}
result.source_file_map = SourceFileMap::Get();
result.language_server_data = std::move(LanguageServerData::Get());
result.messages = std::move(TorqueMessages::Get());
return result;
}
} // namespace torque
} // namespace internal
} // namespace v8

View File

@ -7,6 +7,7 @@
#include "src/torque/ast.h"
#include "src/torque/contextual.h"
#include "src/torque/kythe-data.h"
#include "src/torque/server-data.h"
#include "src/torque/source-positions.h"
#include "src/torque/utils.h"
@ -19,6 +20,7 @@ struct TorqueCompilerOptions {
std::string output_directory = "";
std::string v8_root = "";
bool collect_language_server_data = false;
bool collect_kythe_data = false;
// assert(...) are only generated for debug builds. The provide
// language server support for statements inside asserts, this flag
@ -52,10 +54,18 @@ struct TorqueCompilerResult {
std::vector<TorqueMessage> messages;
};
struct TorqueCompilationUnit {
std::string source_file_path;
std::string file_content;
};
V8_EXPORT_PRIVATE TorqueCompilerResult
CompileTorque(const std::string& source, TorqueCompilerOptions options);
TorqueCompilerResult CompileTorque(std::vector<std::string> files,
TorqueCompilerOptions options);
V8_EXPORT_PRIVATE TorqueCompilerResult CompileTorqueForKythe(
std::vector<TorqueCompilationUnit> units, TorqueCompilerOptions options,
KytheConsumer* kythe_consumer);
} // namespace torque
} // namespace internal

View File

@ -32,7 +32,7 @@ struct ExpressionWithSource {
struct TypeswitchCase {
SourcePosition pos;
base::Optional<std::string> name;
base::Optional<Identifier*> name;
TypeExpression* type;
Statement* block;
};
@ -313,9 +313,10 @@ void CheckNotDeferredStatement(Statement* statement) {
TypeExpression* AddConstexpr(TypeExpression* type) {
BasicTypeExpression* basic = BasicTypeExpression::DynamicCast(type);
if (!basic) Error("Unsupported extends clause.").Throw();
return MakeNode<BasicTypeExpression>(basic->namespace_qualification,
CONSTEXPR_TYPE_PREFIX + basic->name,
basic->generic_arguments);
return MakeNode<BasicTypeExpression>(
basic->namespace_qualification,
MakeNode<Identifier>(CONSTEXPR_TYPE_PREFIX + basic->name->value),
basic->generic_arguments);
}
Expression* MakeCall(IdentifierExpression* callee,
@ -382,12 +383,11 @@ base::Optional<ParseResult> MakeCall(ParseResultIterator* child_results) {
base::Optional<ParseResult> MakeMethodCall(ParseResultIterator* child_results) {
auto this_arg = child_results->NextAs<Expression*>();
auto callee = child_results->NextAs<std::string>();
auto callee = child_results->NextAs<Identifier*>();
auto args = child_results->NextAs<std::vector<Expression*>>();
auto otherwise = child_results->NextAs<std::vector<Statement*>>();
return ParseResult{
MakeCall(MakeNode<IdentifierExpression>(MakeNode<Identifier>(callee)),
this_arg, args, otherwise)};
return ParseResult{MakeCall(MakeNode<IdentifierExpression>(callee), this_arg,
args, otherwise)};
}
base::Optional<ParseResult> MakeNewExpression(
@ -525,7 +525,8 @@ base::Optional<ParseResult> MakeDebugStatement(
base::Optional<ParseResult> MakeVoidType(ParseResultIterator* child_results) {
TypeExpression* result = MakeNode<BasicTypeExpression>(
std::vector<std::string>{}, "void", std::vector<TypeExpression*>{});
std::vector<std::string>{}, MakeNode<Identifier>("void"),
std::vector<TypeExpression*>{});
return ParseResult{result};
}
@ -1009,16 +1010,15 @@ base::Optional<ParseResult> MakeClassDeclaration(
(flags & ClassFlag::kIsShape) == 0) {
ParameterList parameters;
parameters.names.push_back(MakeNode<Identifier>("obj"));
parameters.types.push_back(
MakeNode<BasicTypeExpression>(std::vector<std::string>{}, "HeapObject",
std::vector<TypeExpression*>{}));
parameters.types.push_back(MakeNode<BasicTypeExpression>(
std::vector<std::string>{}, MakeNode<Identifier>("HeapObject"),
std::vector<TypeExpression*>{}));
LabelAndTypesVector labels;
labels.push_back(LabelAndTypes{MakeNode<Identifier>("CastError"),
std::vector<TypeExpression*>{}});
TypeExpression* class_type =
MakeNode<BasicTypeExpression>(std::vector<std::string>{}, name->value,
std::vector<TypeExpression*>{});
TypeExpression* class_type = MakeNode<BasicTypeExpression>(
std::vector<std::string>{}, name, std::vector<TypeExpression*>{});
std::vector<std::string> namespace_qualification{
TORQUE_INTERNAL_NAMESPACE_STRING};
@ -1043,9 +1043,8 @@ base::Optional<ParseResult> MakeClassDeclaration(
auto cast_body = MakeNode<ReturnStatement>(value);
std::vector<TypeExpression*> generic_parameters;
generic_parameters.push_back(
MakeNode<BasicTypeExpression>(std::vector<std::string>{}, name->value,
std::vector<TypeExpression*>{}));
generic_parameters.push_back(MakeNode<BasicTypeExpression>(
std::vector<std::string>{}, name, std::vector<TypeExpression*>{}));
Declaration* specialization = MakeNode<SpecializationDeclaration>(
false, MakeNode<Identifier>("Cast"), generic_parameters,
@ -1194,7 +1193,8 @@ base::Optional<ParseResult> MakeBasicTypeExpression(
child_results->NextAs<std::vector<TypeExpression*>>();
TypeExpression* result = MakeNode<BasicTypeExpression>(
std::move(namespace_qualification),
is_constexpr ? GetConstexprName(name) : std::move(name),
MakeNode<Identifier>(is_constexpr ? GetConstexprName(name)
: std::move(name)),
std::move(generic_arguments));
return ParseResult{result};
}
@ -1217,7 +1217,8 @@ base::Optional<ParseResult> MakeReferenceTypeExpression(
std::vector<TypeExpression*> generic_arguments{referenced_type};
TypeExpression* result = MakeNode<BasicTypeExpression>(
namespace_qualification,
is_const ? CONST_REFERENCE_TYPE_STRING : MUTABLE_REFERENCE_TYPE_STRING,
MakeNode<Identifier>(is_const ? CONST_REFERENCE_TYPE_STRING
: MUTABLE_REFERENCE_TYPE_STRING),
generic_arguments);
return ParseResult{result};
}
@ -1315,7 +1316,7 @@ base::Optional<ParseResult> MakeEnumDeclaration(
base::nullopt);
TypeExpression* name_type_expression =
MakeNode<BasicTypeExpression>(name_identifier->value);
MakeNode<BasicTypeExpression>(name_identifier);
name_type_expression->pos = name_identifier->pos;
std::vector<Declaration*> entry_decls;
@ -1346,7 +1347,7 @@ base::Optional<ParseResult> MakeEnumDeclaration(
entry.type.value_or(*base_type_expression), base::nullopt));
auto entry_type = MakeNode<BasicTypeExpression>(
std::vector<std::string>{name}, entry.name->value,
std::vector<std::string>{name}, entry.name,
std::vector<TypeExpression*>{});
if (union_type) {
union_type = MakeNode<UnionTypeExpression>(union_type, entry_type);
@ -1374,7 +1375,7 @@ base::Optional<ParseResult> MakeEnumDeclaration(
Identifier* constexpr_type_identifier =
MakeNode<Identifier>(std::string(CONSTEXPR_TYPE_PREFIX) + name);
TypeExpression* constexpr_type_expression = MakeNode<BasicTypeExpression>(
std::string(CONSTEXPR_TYPE_PREFIX) + name);
MakeNode<Identifier>(std::string(CONSTEXPR_TYPE_PREFIX) + name));
base::Optional<TypeExpression*> base_constexpr_type_expression =
base::nullopt;
if (base_type_expression) {
@ -1390,8 +1391,9 @@ base::Optional<ParseResult> MakeEnumDeclaration(
Statement* fromconstexpr_body = nullptr;
if (generate_nonconstexpr) {
DCHECK(base_type_expression.has_value());
type_expr = MakeNode<BasicTypeExpression>(
std::vector<std::string>{}, name, std::vector<TypeExpression*>{});
type_expr = MakeNode<BasicTypeExpression>(std::vector<std::string>{},
MakeNode<Identifier>(name),
std::vector<TypeExpression*>{});
// return %RawDownCast<Enum>(%FromConstexpr<Base>(o)))
fromconstexpr_identifier = MakeNode<Identifier>("FromConstexpr");
@ -1440,9 +1442,10 @@ base::Optional<ParseResult> MakeEnumDeclaration(
MakeNode<Identifier>("constexpr constant " + entry_name);
entry_decls.push_back(MakeNode<ExternConstDeclaration>(
constexpr_constant_name,
MakeNode<BasicTypeExpression>(std::vector<std::string>{},
entry_constexpr_type,
std::vector<TypeExpression*>{}),
MakeNode<BasicTypeExpression>(
std::vector<std::string>{},
MakeNode<Identifier>(entry_constexpr_type),
std::vector<TypeExpression*>{}),
constexpr_generates + "::" + entry_name));
entry_decls.push_back(MakeNode<ConstDeclaration>(
entry.name, *entry.type,
@ -1461,9 +1464,10 @@ base::Optional<ParseResult> MakeEnumDeclaration(
// }
entry_decls.push_back(MakeNode<ExternConstDeclaration>(
entry.name,
MakeNode<BasicTypeExpression>(std::vector<std::string>{},
entry_constexpr_type,
std::vector<TypeExpression*>{}),
MakeNode<BasicTypeExpression>(
std::vector<std::string>{},
MakeNode<Identifier>(entry_constexpr_type),
std::vector<TypeExpression*>{}),
constexpr_generates + "::" + entry_name));
}
@ -1471,9 +1475,10 @@ base::Optional<ParseResult> MakeEnumDeclaration(
// : Enum::constexpr kEntry0): Enum
if (generate_nonconstexpr) {
TypeExpression* entry_constexpr_type_expr =
MakeNode<BasicTypeExpression>(std::vector<std::string>{name},
entry_constexpr_type,
std::vector<TypeExpression*>{});
MakeNode<BasicTypeExpression>(
std::vector<std::string>{name},
MakeNode<Identifier>(entry_constexpr_type),
std::vector<TypeExpression*>{});
ParameterList parameters;
parameters.names.push_back(fromconstexpr_parameter_identifier);
@ -1556,10 +1561,11 @@ base::Optional<ParseResult> MakeTypeswitchStatement(
} else {
case_block = current_block;
}
std::string name = "__case_value";
Identifier* name =
cases[i].name ? *cases[i].name : MakeNode<Identifier>("__case_value");
if (cases[i].name) name = *cases[i].name;
case_block->statements.push_back(MakeNode<VarDeclarationStatement>(
true, MakeNode<Identifier>(name), cases[i].type, value));
case_block->statements.push_back(
MakeNode<VarDeclarationStatement>(true, name, cases[i].type, value));
case_block->statements.push_back(cases[i].block);
if (i < cases.size() - 1) {
BlockStatement* next_block = MakeNode<BlockStatement>();
@ -1580,11 +1586,11 @@ base::Optional<ParseResult> MakeTypeswitchStatement(
base::Optional<ParseResult> MakeTypeswitchCase(
ParseResultIterator* child_results) {
auto name = child_results->NextAs<base::Optional<std::string>>();
auto name = child_results->NextAs<base::Optional<Identifier*>>();
auto type = child_results->NextAs<TypeExpression*>();
auto block = child_results->NextAs<Statement*>();
return ParseResult{TypeswitchCase{child_results->matched_input().pos,
std::move(name), type, block}};
return ParseResult{
TypeswitchCase{child_results->matched_input().pos, name, type, block}};
}
base::Optional<ParseResult> MakeWhileStatement(
@ -1722,7 +1728,8 @@ base::Optional<ParseResult> MakeCatchBlock(ParseResultIterator* child_results) {
ParameterList parameters;
parameters.names.push_back(MakeNode<Identifier>(variable));
parameters.types.push_back(MakeNode<BasicTypeExpression>(
std::vector<std::string>{}, "JSAny", std::vector<TypeExpression*>{}));
std::vector<std::string>{}, MakeNode<Identifier>("JSAny"),
std::vector<TypeExpression*>{}));
parameters.has_varargs = false;
TryHandler* result = MakeNode<TryHandler>(
TryHandler::HandlerKind::kCatch, MakeNode<Identifier>(kCatchLabelName),
@ -2364,10 +2371,9 @@ struct TorqueGrammar : Grammar {
{&identifierExpression, &argumentList, optionalOtherwise}, MakeCall)};
// Result: Expression*
Symbol callMethodExpression = {
Rule({&primaryExpression, Token("."), &identifier, &argumentList,
optionalOtherwise},
MakeMethodCall)};
Symbol callMethodExpression = {Rule(
{&primaryExpression, Token("."), &name, &argumentList, optionalOtherwise},
MakeMethodCall)};
// Result: NameAndExpression
Symbol namedExpression = {
@ -2569,7 +2575,7 @@ struct TorqueGrammar : Grammar {
// Result: TypeswitchCase
Symbol typeswitchCase = {
Rule({Token("case"), Token("("),
Optional<std::string>(Sequence({&identifier, Token(":")})), &type,
Optional<Identifier*>(Sequence({&name, Token(":")})), &type,
Token(")"), Token(":"), &block},
MakeTypeswitchCase)};

View File

@ -61,7 +61,7 @@ void TypeArgumentInference::Match(TypeExpression* parameter,
BasicTypeExpression::DynamicCast(parameter)) {
// If the parameter is referring to one of the type parameters, substitute
if (basic->namespace_qualification.empty() && !basic->is_constexpr) {
auto result = type_parameter_from_name_.find(basic->name);
auto result = type_parameter_from_name_.find(basic->name->value);
if (result != type_parameter_from_name_.end()) {
size_t type_parameter_index = result->second;
if (type_parameter_index < num_explicit_) {
@ -92,7 +92,7 @@ void TypeArgumentInference::Match(TypeExpression* parameter,
void TypeArgumentInference::MatchGeneric(BasicTypeExpression* parameter,
const Type* argument_type) {
QualifiedName qualified_name{parameter->namespace_qualification,
parameter->name};
parameter->name->value};
GenericType* generic_type =
Declarations::LookupUniqueGenericType(qualified_name);
auto& specialized_from = argument_type->GetSpecializedFrom();

View File

@ -7,6 +7,7 @@
#include "src/common/globals.h"
#include "src/torque/declarable.h"
#include "src/torque/global-context.h"
#include "src/torque/kythe-data.h"
#include "src/torque/server-data.h"
#include "src/torque/type-inference.h"
#include "src/torque/type-oracle.h"
@ -117,7 +118,10 @@ void DeclareMethods(AggregateType* container_type,
signature.parameter_types.types.insert(
signature.parameter_types.types.begin() + signature.implicit_count,
container_type);
Declarations::CreateMethod(container_type, method_name, signature, body);
Method* m = Declarations::CreateMethod(container_type, method_name,
signature, body);
m->SetPosition(method->pos);
m->SetIdentifierPosition(method->name->pos);
}
}
@ -334,7 +338,8 @@ const ClassType* TypeVisitor::ComputeType(
const Type* TypeVisitor::ComputeType(TypeExpression* type_expression) {
if (auto* basic = BasicTypeExpression::DynamicCast(type_expression)) {
QualifiedName qualified_name{basic->namespace_qualification, basic->name};
QualifiedName qualified_name{basic->namespace_qualification,
basic->name->value};
auto& args = basic->generic_arguments;
const Type* type;
SourcePosition pos = SourcePosition::Invalid();
@ -343,12 +348,20 @@ const Type* TypeVisitor::ComputeType(TypeExpression* type_expression) {
auto* alias = Declarations::LookupTypeAlias(qualified_name);
type = alias->type();
pos = alias->GetDeclarationPosition();
if (GlobalContext::collect_kythe_data()) {
if (alias->IsUserDefined()) {
KytheData::AddTypeUse(basic->name->pos, alias);
}
}
} else {
auto* generic_type =
Declarations::LookupUniqueGenericType(qualified_name);
type = TypeOracle::GetGenericTypeInstance(generic_type,
ComputeTypeVector(args));
pos = generic_type->declaration()->name->pos;
if (GlobalContext::collect_kythe_data()) {
KytheData::AddTypeUse(basic->name->pos, generic_type);
}
}
if (GlobalContext::collect_language_server_data()) {
@ -482,7 +495,8 @@ const Type* TypeVisitor::ComputeTypeForStructExpression(
ReportError("expected basic type expression referring to struct");
}
QualifiedName qualified_name{basic->namespace_qualification, basic->name};
QualifiedName qualified_name{basic->namespace_qualification,
basic->name->value};
base::Optional<GenericType*> maybe_generic_type =
Declarations::TryLookupGenericType(qualified_name);

View File

@ -86,8 +86,11 @@ TEST(LanguageServerMessage, GotoDefinition) {
SourceId definition_id = SourceFileMap::AddSource("file://base.tq");
LanguageServerData::Scope server_data_scope;
LanguageServerData::AddDefinition({test_id, {1, 0}, {1, 10}},
{definition_id, {4, 1}, {4, 5}});
LanguageServerData::AddDefinition(
{test_id, LineAndColumn::WithUnknownOffset(1, 0),
LineAndColumn::WithUnknownOffset(1, 10)},
{definition_id, LineAndColumn::WithUnknownOffset(4, 1),
LineAndColumn::WithUnknownOffset(4, 5)});
// First, check a unknown definition. The result must be null.
GotoDefinitionRequest request;
@ -171,8 +174,10 @@ TEST(LanguageServerMessage, LintErrorSendsDiagnostics) {
// No compilation errors but two lint warnings.
{
SourcePosition pos1{test_id, {0, 0}, {0, 1}};
SourcePosition pos2{test_id, {1, 0}, {1, 1}};
SourcePosition pos1{test_id, LineAndColumn::WithUnknownOffset(0, 0),
LineAndColumn::WithUnknownOffset(0, 1)};
SourcePosition pos2{test_id, LineAndColumn::WithUnknownOffset(1, 0),
LineAndColumn::WithUnknownOffset(1, 1)};
Lint("lint error 1").Position(pos1);
Lint("lint error 2").Position(pos2);
}

View File

@ -43,14 +43,20 @@ TEST(LanguageServer, GotoTypeDefinition) {
// Find the definition for type 'T1' of argument 'a' on line 4.
const SourceId id = SourceFileMap::GetSourceId("dummy-filename.tq");
auto maybe_position = LanguageServerData::FindDefinition(id, {4, 19});
auto maybe_position = LanguageServerData::FindDefinition(
id, LineAndColumn::WithUnknownOffset(4, 19));
ASSERT_TRUE(maybe_position.has_value());
EXPECT_EQ(*maybe_position, (SourcePosition{id, {2, 5}, {2, 7}}));
EXPECT_EQ(*maybe_position,
(SourcePosition{id, LineAndColumn::WithUnknownOffset(2, 5),
LineAndColumn::WithUnknownOffset(2, 7)}));
// Find the defintion for type 'T2' of argument 'b' on line 4.
maybe_position = LanguageServerData::FindDefinition(id, {4, 26});
maybe_position = LanguageServerData::FindDefinition(
id, LineAndColumn::WithUnknownOffset(4, 26));
ASSERT_TRUE(maybe_position.has_value());
EXPECT_EQ(*maybe_position, (SourcePosition{id, {3, 5}, {3, 7}}));
EXPECT_EQ(*maybe_position,
(SourcePosition{id, LineAndColumn::WithUnknownOffset(3, 5),
LineAndColumn::WithUnknownOffset(3, 7)}));
}
TEST(LanguageServer, GotoTypeDefinitionExtends) {
@ -65,9 +71,12 @@ TEST(LanguageServer, GotoTypeDefinitionExtends) {
// Find the definition for 'T1' of the extends clause on line 3.
const SourceId id = SourceFileMap::GetSourceId("dummy-filename.tq");
auto maybe_position = LanguageServerData::FindDefinition(id, {3, 16});
auto maybe_position = LanguageServerData::FindDefinition(
id, LineAndColumn::WithUnknownOffset(3, 16));
ASSERT_TRUE(maybe_position.has_value());
EXPECT_EQ(*maybe_position, (SourcePosition{id, {2, 5}, {2, 7}}));
EXPECT_EQ(*maybe_position,
(SourcePosition{id, LineAndColumn::WithUnknownOffset(2, 5),
LineAndColumn::WithUnknownOffset(2, 7)}));
}
TEST(LanguageServer, GotoTypeDefinitionNoDataForFile) {
@ -76,7 +85,8 @@ TEST(LanguageServer, GotoTypeDefinitionNoDataForFile) {
SourceId test_id = SourceFileMap::AddSource("test.tq");
// Regression test, this step should not crash.
EXPECT_FALSE(LanguageServerData::FindDefinition(test_id, {0, 0}));
EXPECT_FALSE(LanguageServerData::FindDefinition(
test_id, LineAndColumn::WithUnknownOffset(0, 0)));
}
// TODO(almuthanna): This test was skipped because it causes a crash when it is
@ -99,9 +109,12 @@ TEST(LanguageServer, GotoLabelDefinitionInSignature) {
// Find the definition for 'Bailout' of the otherwise clause on line 6.
const SourceId id = SourceFileMap::GetSourceId("dummy-filename.tq");
auto maybe_position = LanguageServerData::FindDefinition(id, {6, 18});
auto maybe_position = LanguageServerData::FindDefinition(
id, LineAndColumn::WithUnknownOffset(6, 18));
ASSERT_TRUE(maybe_position.has_value());
EXPECT_EQ(*maybe_position, (SourcePosition{id, {5, 19}, {5, 26}}));
EXPECT_EQ(*maybe_position,
(SourcePosition{id, LineAndColumn::WithUnknownOffset(5, 19),
LineAndColumn::WithUnknownOffset(5, 26)}));
}
#endif
@ -122,9 +135,12 @@ TEST(LanguageServer, GotoLabelDefinitionInTryBlock) {
// Find the definition for 'Bailout' of the otherwise clause on line 6.
const SourceId id = SourceFileMap::GetSourceId("dummy-filename.tq");
auto maybe_position = LanguageServerData::FindDefinition(id, {6, 25});
auto maybe_position = LanguageServerData::FindDefinition(
id, LineAndColumn::WithUnknownOffset(6, 25));
ASSERT_TRUE(maybe_position.has_value());
EXPECT_EQ(*maybe_position, (SourcePosition{id, {7, 8}, {7, 15}}));
EXPECT_EQ(*maybe_position,
(SourcePosition{id, LineAndColumn::WithUnknownOffset(7, 8),
LineAndColumn::WithUnknownOffset(7, 15)}));
}
// TODO(almuthanna): This test was skipped because it causes a crash when it is
@ -143,9 +159,12 @@ TEST(LanguageServer, GotoDefinitionClassSuperType) {
// Find the definition for 'Tagged' of the 'extends' on line 3.
const SourceId id = SourceFileMap::GetSourceId("dummy-filename.tq");
auto maybe_position = LanguageServerData::FindDefinition(id, {3, 33});
auto maybe_position = LanguageServerData::FindDefinition(
id, LineAndColumn::WithUnknownOffset(3, 33));
ASSERT_TRUE(maybe_position.has_value());
EXPECT_EQ(*maybe_position, (SourcePosition{id, {2, 5}, {2, 11}}));
EXPECT_EQ(*maybe_position,
(SourcePosition{id, LineAndColumn::WithUnknownOffset(2, 5),
LineAndColumn::WithUnknownOffset(2, 11)}));
}
#endif
@ -162,9 +181,12 @@ TEST(LanguageServer, GotoLabelDefinitionInSignatureGotoStmt) {
// Find the definition for 'Fail' of the goto statement on line 3.
const SourceId id = SourceFileMap::GetSourceId("dummy-filename.tq");
auto maybe_position = LanguageServerData::FindDefinition(id, {3, 7});
auto maybe_position = LanguageServerData::FindDefinition(
id, LineAndColumn::WithUnknownOffset(3, 7));
ASSERT_TRUE(maybe_position.has_value());
EXPECT_EQ(*maybe_position, (SourcePosition{id, {2, 26}, {2, 30}}));
EXPECT_EQ(*maybe_position,
(SourcePosition{id, LineAndColumn::WithUnknownOffset(2, 26),
LineAndColumn::WithUnknownOffset(2, 30)}));
}
TEST(LanguageServer, GotoLabelDefinitionInTryBlockGoto) {
@ -181,9 +203,12 @@ TEST(LanguageServer, GotoLabelDefinitionInTryBlockGoto) {
// Find the definition for 'Bailout' of the goto statement on line 3.
const SourceId id = SourceFileMap::GetSourceId("dummy-filename.tq");
auto maybe_position = LanguageServerData::FindDefinition(id, {3, 13});
auto maybe_position = LanguageServerData::FindDefinition(
id, LineAndColumn::WithUnknownOffset(3, 13));
ASSERT_TRUE(maybe_position.has_value());
EXPECT_EQ(*maybe_position, (SourcePosition{id, {4, 8}, {4, 15}}));
EXPECT_EQ(*maybe_position,
(SourcePosition{id, LineAndColumn::WithUnknownOffset(4, 8),
LineAndColumn::WithUnknownOffset(4, 15)}));
}
TEST(LanguageServer, GotoLabelDefinitionGotoInOtherwise) {
@ -203,9 +228,12 @@ TEST(LanguageServer, GotoLabelDefinitionGotoInOtherwise) {
// Find the definition for 'Bailout' of the otherwise clause on line 6.
const SourceId id = SourceFileMap::GetSourceId("dummy-filename.tq");
auto maybe_position = LanguageServerData::FindDefinition(id, {6, 30});
auto maybe_position = LanguageServerData::FindDefinition(
id, LineAndColumn::WithUnknownOffset(6, 30));
ASSERT_TRUE(maybe_position.has_value());
EXPECT_EQ(*maybe_position, (SourcePosition{id, {7, 8}, {7, 15}}));
EXPECT_EQ(*maybe_position,
(SourcePosition{id, LineAndColumn::WithUnknownOffset(7, 8),
LineAndColumn::WithUnknownOffset(7, 15)}));
}
TEST(LanguageServer, SymbolsArePopulated) {

View File

@ -224,7 +224,8 @@ using SubstrWithPosition =
SubstrWithPosition SubstrTester(const std::string& message, int line, int col) {
// Change line and column from 1-based to 0-based.
return {::testing::HasSubstr(message),
LineAndColumn{line + CountPreludeLines() - 1, col - 1}};
LineAndColumn::WithUnknownOffset(line + CountPreludeLines() - 1,
col - 1)};
}
#endif