From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 120122 invoked by alias); 24 Jul 2017 19:41:20 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 119520 invoked by uid 89); 24 Jul 2017 19:41:19 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_LAZY_DOMAIN_SECURITY,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=ham version=3.3.2 spammy= X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 24 Jul 2017 19:41:14 +0000 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C6AD97DCFA for ; Mon, 24 Jul 2017 19:31:14 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com C6AD97DCFA Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=dmalcolm@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com C6AD97DCFA Received: from c64.redhat.com (ovpn-112-25.phx2.redhat.com [10.3.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id F0B2169719; Mon, 24 Jul 2017 19:31:13 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [PATCH 16/17] Language Server Protocol: proof-of-concept GCC implementation Date: Mon, 24 Jul 2017 19:41:00 -0000 Message-Id: <1500926714-56988-17-git-send-email-dmalcolm@redhat.com> In-Reply-To: <1500926714-56988-1-git-send-email-dmalcolm@redhat.com> References: <1500926714-56988-1-git-send-email-dmalcolm@redhat.com> X-IsSubscribed: yes X-SW-Source: 2017-07/txt/msg01465.txt.bz2 This patch implements a concrete subclass of the lsp::server class implemented in the previous patch, wiring it up to GCC's internal representation. The patch is very much just a proof-of-concept; the only method it implements is "textDocument/definition" i.e. "report the definition of the symbol at source location ($FILE, $ROW, $COL)"; this is currently only implemented when clicking on a struct-or-union-specifier ("struct foo" or "union foo" in the C frontend). Notable other limitations include the complete absense of support for change-monitoring, or the idea of where the "truth" of the source is (filesystem vs memory). Also, this can only cope with one source file and language at a time; a real implementation would presumably need some kind of multiplexing to cope with a project consisting of multiple source files (and perhaps mixing C and C++). gcc/ChangeLog: * Makefile.in (OBJS): Add lsp-main.o. * common.opt (-flsp): New option. * lsp-main.c: New file. * lsp-main.h: New file. * toplev.c: Include "lsp-main.h". (compile_file): Call serve_lsp if -flsp was used. --- gcc/Makefile.in | 1 + gcc/common.opt | 4 ++ gcc/lsp-main.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gcc/lsp-main.h | 25 +++++++++ gcc/toplev.c | 4 ++ 5 files changed, 202 insertions(+) create mode 100644 gcc/lsp-main.c create mode 100644 gcc/lsp-main.h diff --git a/gcc/Makefile.in b/gcc/Makefile.in index e5120c2..69e5fec 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1383,6 +1383,7 @@ OBJS = \ loop-unroll.o \ lower-subreg.o \ lsp.o \ + lsp-main.o \ lra.o \ lra-assigns.o \ lra-coalesce.o \ diff --git a/gcc/common.opt b/gcc/common.opt index e81165c..7c4be65 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1746,6 +1746,10 @@ flra-remat Common Report Var(flag_lra_remat) Optimization Do CFG-sensitive rematerialization in LRA. +flsp= +Common Joined RejectNegative UInteger Var(flag_lsp) Init(-1) +-flsp= Serve the Language Server Protocol on the given port. + flto Common Enable link-time optimization. diff --git a/gcc/lsp-main.c b/gcc/lsp-main.c new file mode 100644 index 0000000..3f8cc0f --- /dev/null +++ b/gcc/lsp-main.c @@ -0,0 +1,168 @@ +/* Language Server Protocol implementation. + Copyright (C) 2017 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "http-server.h" +#include "json.h" +#include "json-rpc.h" +#include "lsp.h" +#include "blt.h" +#include "tree.h" + +using namespace lsp; + +class is_record_definition : public blt_predicate +{ + public: + is_record_definition (tree record_type) : m_record_type (record_type) {} + + bool satisfied_by_node_p (const blt_node &node) FINAL OVERRIDE + { + if (node.get_kind () == BLT_STRUCT_CONTENTS + && node.get_tree () == m_record_type) + return true; + return false; + } + + private: + tree m_record_type; +}; + +static bool +Location_from_blt_node (const blt_node *node, Location &out) +{ + if (!node) + return false; + + location_t start = node->get_start (); + if (start == UNKNOWN_LOCATION) + return false; + location_t finish = node->get_finish (); + if (finish == UNKNOWN_LOCATION) + return false; + + expanded_location el_start = expand_location (start); + expanded_location el_finish = expand_location (finish); + if (el_start.file != el_finish.file) + return false; + + out.uri = el_start.file; + /* Convert from GCC's 1-based lines and columns to LSP's + 0-based lines and columns. + Offset the end column back by 1 since blt_node finish + locations are inclusive, whereas in LSP the endpoint of a Range + is exclusive. */ + out.range.start.line = el_start.line - 1; + out.range.start.character = el_start.column - 1; + out.range.end.line = el_finish.line - 1; + out.range.end.character = el_finish.column - 1 + 1; + return true; +} + +/* Implementation of lsp::server, wired up to GCC's IR. */ + +class gcc_lsp_server : public lsp::noop_server +{ + /* Implementation of "textDocument/definition": + find the definition of the symbol at a given source location. */ + + void + do_text_document_definition (const TextDocumentPositionParams &p, + vec &out) OVERRIDE; +}; + + +/* class gcc_lsp_server : public lsp::noop_server. */ + +/* Implementation of "textDocument/definition": + find the definition of the symbol at a given source location. */ + +void +gcc_lsp_server::do_text_document_definition (const TextDocumentPositionParams &p, + vec &out) +{ + /* TODO. */ + /* Convert from LSP's 0-based lines and columns to GCC's + 1-based lines and columns. */ + blt_node *blt + = the_blt_root_node->get_descendant_at_location (p.textDocument.uri, + p.position.line + 1, + p.position.character + 1); + if (!blt) + /* No results. */ + return; + + blt->dump (stderr); + + switch (blt->get_kind ()) + { + case BLT_STRUCT_OR_UNION_SPECIFIER: + { + /* Attempt to locate the RECORD_TYPE for the + struct-or-union-specifier. */ + tree record_type = blt->get_tree (); + if (!record_type) + return; + + if (1) + the_blt_root_node->dump (stderr); + + /* Find a struct-contents with tree == record_type. */ + is_record_definition pred (record_type); + blt_node *blt_struct_contents + = the_blt_root_node->find_descendant_satisfying (pred); + if (!blt_struct_contents) + return; + + if (1) + blt_struct_contents->dump (stderr); + blt_node *blt_struct_defn = blt_struct_contents->get_parent (); + + Location result; + if (Location_from_blt_node (blt_struct_defn, result)) + out.safe_push (result); + } + break; + + default: + { + /* Just show the blt_node itself. */ + Location result; + if (Location_from_blt_node (blt, result)) + out.safe_push (result); + } + break; + } +} + +/* Serve LSP on PORT. */ + +void +serve_lsp (int port) +{ + // FIXME + gcc_lsp_server lsp_server; + lsp::jsonrpc_server json_lsp_server (true, lsp_server); + jsonrpc::http_server http_server (json_lsp_server); + + fprintf (stderr, "serving on port %i\n", port); + http_server.serve (port); +} diff --git a/gcc/lsp-main.h b/gcc/lsp-main.h new file mode 100644 index 0000000..ec57201 --- /dev/null +++ b/gcc/lsp-main.h @@ -0,0 +1,25 @@ +/* Entrypoint to Language Server Protocol implementation. + Copyright (C) 2017 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_LSP_MAIN_H +#define GCC_LSP_MAIN_H + +extern void serve_lsp (int port); + +#endif /* GCC_LSP_MAIN_H */ diff --git a/gcc/toplev.c b/gcc/toplev.c index e6c69a4..716f906 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -80,6 +80,7 @@ along with GCC; see the file COPYING3. If not see #include "hsa-common.h" #include "edit-context.h" #include "tree-pass.h" +#include "lsp-main.h" #if defined(DBX_DEBUGGING_INFO) || defined(XCOFF_DEBUGGING_INFO) #include "dbxout.h" @@ -470,6 +471,9 @@ compile_file (void) timevar_pop (TV_PARSE_GLOBAL); timevar_stop (TV_PHASE_PARSING); + if (flag_lsp != -1) + serve_lsp (flag_lsp); + if (flag_dump_locations) dump_location_info (stderr); -- 1.8.5.3