From patchwork Sun Nov 19 11:33:31 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 166786 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:9910:0:b0:403:3b70:6f57 with SMTP id i16csp1604677vqn; Sun, 19 Nov 2023 03:34:11 -0800 (PST) X-Google-Smtp-Source: AGHT+IEQatpJlUd/tEC8fTxz2oIwaL0VWvq6JApvQPTENke7qyWe3MKaG/GdSMqfZWP1KJGJSTaj X-Received: by 2002:a05:622a:34e:b0:418:737:87fc with SMTP id r14-20020a05622a034e00b00418073787fcmr5593209qtw.18.1700393650819; Sun, 19 Nov 2023 03:34:10 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1700393650; cv=pass; d=google.com; s=arc-20160816; b=a7uClzkMShQlaCYh1yuAqPzsp425AzrEGoA1nY+tVE6V0lwXJWMibN+aZC7DyforI9 o/P5RBrVQ/Yem6fjd6ly+y7oam1Q9JfL52fE2AviSF1UQ80OhsZ3RX4ZnA4L+GIFRpTt A0mmF4zbCfckV+9MFSecHSWyNurk4bZZucdDtALu3LGbDKKaMEkINyzYQMtOxz7pfAmP OPsPvlpIxK4iAoA2wCTMBQBxWCtmjW0xZwEeuYC/aqwBB54mrgZgtsCT0Cl2hBTT0VmR rMZg/12/R765vVWPX1WB0JwMXPiG48nX3SgjWu1xdwmyJ5zliuVZVjBGfwiD1PdkC+CW rdmQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:message-id:date:subject:cc:to:from:dkim-signature :arc-filter:dmarc-filter:delivered-to; bh=GaVQHSke+q2CnVmFW9bDVDwsIqm95CC7NIw/qWeHBqs=; fh=NXemEfxTRbZtBxUkxR2ehQUaYlcDfMdzPkO8MChVQE4=; b=xinVufZoDl5mJKw4fVCD+t5qi/BKHUxsZmAx4fN3pFbpiDZeedOnSjwGOhMsvq27eL dbJSJikONHY0A71sfHJYszeDmqU64NAHQbuD7gq7r8ALeDKAPkOokxPbRMPv6JUotVmH JgsWk/1TsXBC8jetqZ63b694wZUamV6OB4JSMZkSzPQyNj8mUsZucXyyPHch8cYwKt2n qT9ESNtuNyakGpQNWZCg3Kn+J2tE+IgPrDtCcGDWI3viAwYxeJh4Ig1Kkc1GClVLJUoq v/Dsk4iq+yPWrY5RKfHOPICOuHOVzeXr8sd4ReRO+tEwD5lb7wbRKvapQImi/mNAOkqN VkbQ== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b="RA/7MXi9"; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from server2.sourceware.org (server2.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id c21-20020ac85a95000000b00420f169ca2dsi5330104qtc.155.2023.11.19.03.34.10 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 19 Nov 2023 03:34:10 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b="RA/7MXi9"; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8CDDA3858C50 for ; Sun, 19 Nov 2023 11:34:10 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id BC8B63858D32 for ; Sun, 19 Nov 2023 11:33:34 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BC8B63858D32 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org BC8B63858D32 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700393620; cv=none; b=qXCw5wkuOdy81zMeW8yyX6VCLMt/jYkMEx89/FkeR2olyM2zOaL40tIiMiwMqFipp282n9Uv8oxMN04doBH2XudlvIFchb06Exh5VW8tA769w+Chv39psM7RSWNfAJnYlVBNLlglsgrQ14wpi78ne1abxJU944REHUs9Bb91W/M= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700393620; c=relaxed/simple; bh=BfIR+rKvNH838fiaMi8gEUfZlBHKy93XIaxgl0UXc0w=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=o1pxN/bwB8+ugIHN4eYXcZbFbCESbkZ0f4yYIqV9TJAifSqD15OWlu5+2l9aIoByVzYYHqdD1bVkGDz8Asi8FFnKf/MeAsYFPOFbA2SC9e9VoT88u0SKdt8W6Erz7e4aPFl3dfXOThT1YjG2sdrR7nunnMIqoEROwjkIamCBkVk= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1700393614; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=GaVQHSke+q2CnVmFW9bDVDwsIqm95CC7NIw/qWeHBqs=; b=RA/7MXi9v2aV549elCfKFF783u013tjnpAo4FZ1DPYKYYsfgDAqUe5POaY81IcbLYF2PJB PmLLp4BZEy+GoH6jJ251DoueRwRaDA4BaE/jkpN+b42reuagDp7VfNw3GCSnTVIHn32TRD 2K4QnInZblqywT4CXp1izcr7/ov6KSI= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-400-VCWjSIfwNVyEwZ5EtSGS0Q-1; Sun, 19 Nov 2023 06:33:32 -0500 X-MC-Unique: VCWjSIfwNVyEwZ5EtSGS0Q-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 99E9E80C343 for ; Sun, 19 Nov 2023 11:33:32 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.22.10.115]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5693B40C6EB9; Sun, 19 Nov 2023 11:33:32 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [pushed] libcpp: split decls out to rich-location.h Date: Sun, 19 Nov 2023 06:33:31 -0500 Message-Id: <20231119113331.265881-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.2 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1782991972694011388 X-GMAIL-MSGID: 1782991972694011388 The various decls relating to rich_location are in libcpp/include/line-map.h, but they don't relate to line maps. Split them out to their own header: libcpp/include/rich-location.h No functional change intended. Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Pushed to trunk as r14-5593-g78d132d73ec378. gcc/ChangeLog: * Makefile.in (CPPLIB_H): Add libcpp/include/rich-location.h. * coretypes.h (class rich_location): New forward decl. gcc/analyzer/ChangeLog: * analyzer.h: Include "rich-location.h". gcc/c-family/ChangeLog: * c-lex.cc: Include "rich-location.h". gcc/cp/ChangeLog: * mapper-client.cc: Include "rich-location.h". gcc/ChangeLog: * diagnostic.h: Include "rich-location.h". * edit-context.h (class fixit_hint): New forward decl. * gcc-rich-location.h: Include "rich-location.h". * genmatch.cc: Likewise. * pretty-print.h: Likewise. gcc/rust/ChangeLog: * rust-location.h: Include "rich-location.h". libcpp/ChangeLog: * Makefile.in (TAGS_SOURCES): Add "include/rich-location.h". * include/cpplib.h (class rich_location): New forward decl. * include/line-map.h (class range_label) (enum range_display_kind, struct location_range) (class semi_embedded_vec, class rich_location, class label_text) (class range_label, class fixit_hint): Move to... * include/rich-location.h: ...this new file. * internal.h: Include "rich-location.h". --- gcc/Makefile.in | 1 + gcc/analyzer/analyzer.h | 1 + gcc/c-family/c-lex.cc | 1 + gcc/coretypes.h | 1 + gcc/cp/mapper-client.cc | 1 + gcc/diagnostic.h | 1 + gcc/edit-context.h | 1 + gcc/gcc-rich-location.h | 2 + gcc/genmatch.cc | 1 + gcc/pretty-print.h | 1 + gcc/rust/rust-location.h | 1 + libcpp/Makefile.in | 4 +- libcpp/include/cpplib.h | 2 + libcpp/include/line-map.h | 671 ------------------------------- libcpp/include/rich-location.h | 695 +++++++++++++++++++++++++++++++++ libcpp/internal.h | 1 + 16 files changed, 713 insertions(+), 672 deletions(-) create mode 100644 libcpp/include/rich-location.h diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 7228b79f223a..753f2f36618e 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1038,6 +1038,7 @@ SYSTEM_H = system.h hwint.h $(srcdir)/../include/libiberty.h \ $(HASHTAB_H) PREDICT_H = predict.h predict.def CPPLIB_H = $(srcdir)/../libcpp/include/line-map.h \ + $(srcdir)/../libcpp/include/rich-location.h \ $(srcdir)/../libcpp/include/cpplib.h CODYLIB_H = $(srcdir)/../libcody/cody.hh INPUT_H = $(srcdir)/../libcpp/include/line-map.h input.h diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h index f08572bb633e..cf32d4b85b15 100644 --- a/gcc/analyzer/analyzer.h +++ b/gcc/analyzer/analyzer.h @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_ANALYZER_ANALYZER_H #define GCC_ANALYZER_ANALYZER_H +#include "rich-location.h" #include "function.h" #include "json.h" #include "tristate.h" diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc index 06c2453c89a6..86ec679aebfe 100644 --- a/gcc/c-family/c-lex.cc +++ b/gcc/c-family/c-lex.cc @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see #include "file-prefix-map.h" /* remap_macro_filename() */ #include "langhooks.h" #include "attribs.h" +#include "rich-location.h" /* We may keep statistics about how long which files took to compile. */ static int header_time, body_time; diff --git a/gcc/coretypes.h b/gcc/coretypes.h index 9848cde2b97b..fe5b868fb4f3 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -156,6 +156,7 @@ struct cl_optimization; struct cl_option; struct cl_decoded_option; struct cl_option_handlers; +class rich_location; class diagnostic_context; class pretty_printer; class diagnostic_event_id_t; diff --git a/gcc/cp/mapper-client.cc b/gcc/cp/mapper-client.cc index 927271952468..f1a0c4cc009a 100644 --- a/gcc/cp/mapper-client.cc +++ b/gcc/cp/mapper-client.cc @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "line-map.h" +#include "rich-location.h" #include "diagnostic-core.h" #include "mapper-client.h" #include "intl.h" diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h index dbf972d25875..cbd25541f502 100644 --- a/gcc/diagnostic.h +++ b/gcc/diagnostic.h @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_DIAGNOSTIC_H #define GCC_DIAGNOSTIC_H +#include "rich-location.h" #include "pretty-print.h" #include "diagnostic-core.h" diff --git a/gcc/edit-context.h b/gcc/edit-context.h index 3ae9ba103ca7..71735c8b9c6f 100644 --- a/gcc/edit-context.h +++ b/gcc/edit-context.h @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see #include "typed-splay-tree.h" +class fixit_hint; class edit_context; class edited_file; diff --git a/gcc/gcc-rich-location.h b/gcc/gcc-rich-location.h index ffba4b8abcfd..e42daa44b70c 100644 --- a/gcc/gcc-rich-location.h +++ b/gcc/gcc-rich-location.h @@ -20,6 +20,8 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_RICH_LOCATION_H #define GCC_RICH_LOCATION_H +#include "rich-location.h" + /* A gcc_rich_location is libcpp's rich_location with additional helper methods for working with gcc's types. The class is not copyable or assignable because rich_location isn't. */ diff --git a/gcc/genmatch.cc b/gcc/genmatch.cc index 3488764ec640..98268ee19c9b 100644 --- a/gcc/genmatch.cc +++ b/gcc/genmatch.cc @@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include +#include "rich-location.h" #include "errors.h" #include "hash-table.h" #include "hash-set.h" diff --git a/gcc/pretty-print.h b/gcc/pretty-print.h index 9ba2c0a406e1..138c582c8a79 100644 --- a/gcc/pretty-print.h +++ b/gcc/pretty-print.h @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see #define GCC_PRETTY_PRINT_H #include "obstack.h" +#include "rich-location.h" #include "diagnostic-url.h" /* Maximum number of format string arguments. */ diff --git a/gcc/rust/rust-location.h b/gcc/rust/rust-location.h index 9cb29b20919f..873b40f58c0c 100644 --- a/gcc/rust/rust-location.h +++ b/gcc/rust/rust-location.h @@ -21,6 +21,7 @@ #ifndef RUST_LOCATION_H #define RUST_LOCATION_H +#include "rich-location.h" #include "rust-system.h" // A location in an input source file. diff --git a/libcpp/Makefile.in b/libcpp/Makefile.in index faf6834f1ee7..1e063a5ac97f 100644 --- a/libcpp/Makefile.in +++ b/libcpp/Makefile.in @@ -270,7 +270,9 @@ po/$(PACKAGE).pot: $(libcpp_a_SOURCES) ETAGS = @ETAGS@ TAGS_SOURCES = $(libcpp_a_SOURCES) internal.h system.h ucnid.h \ - include/cpplib.h include/line-map.h include/mkdeps.h include/symtab.h + include/cpplib.h include/line-map.h include/mkdeps.h include/symtab.h \ + include/rich-location.h + TAGS: $(TAGS_SOURCES) cd $(srcdir) && $(ETAGS) $(TAGS_SOURCES) diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index 54814f335d73..f857ffa44796 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -38,6 +38,8 @@ typedef struct cpp_dir cpp_dir; struct _cpp_file; +class rich_location; + /* The first three groups, apart from '=', can appear in preprocessor expressions (+= and -= are used to indicate unary + and - resp.). This allows a lookup table to be implemented in _cpp_parse_expr. diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h index 615cb420adf7..72db310bfb75 100644 --- a/libcpp/include/line-map.h +++ b/libcpp/include/line-map.h @@ -1275,677 +1275,6 @@ typedef struct bool sysp; } expanded_location; -class range_label; - -/* A hint to diagnostic_show_locus on how to print a source range within a - rich_location. - - Typically this is SHOW_RANGE_WITH_CARET for the 0th range, and - SHOW_RANGE_WITHOUT_CARET for subsequent ranges, - but the Fortran frontend uses SHOW_RANGE_WITH_CARET repeatedly for - printing things like: - - x = x + y - 1 2 - Error: Shapes for operands at (1) and (2) are not conformable - - where "1" and "2" are notionally carets. */ - -enum range_display_kind -{ - /* Show the pertinent source line(s), the caret, and underline(s). */ - SHOW_RANGE_WITH_CARET, - - /* Show the pertinent source line(s) and underline(s), but don't - show the caret (just an underline). */ - SHOW_RANGE_WITHOUT_CARET, - - /* Just show the source lines; don't show the range itself. - This is for use when displaying some line-insertion fix-it hints (for - showing the user context on the change, for when it doesn't make sense - to highlight the first column on the next line). */ - SHOW_LINES_WITHOUT_RANGE -}; - -/* A location within a rich_location: a caret&range, with - the caret potentially flagged for display, and an optional - label. */ - -struct location_range -{ - location_t m_loc; - - enum range_display_kind m_range_display_kind; - - /* If non-NULL, the label for this range. */ - const range_label *m_label; -}; - -/* A partially-embedded vec for use within rich_location for storing - ranges and fix-it hints. - - Elements [0..NUM_EMBEDDED) are allocated within m_embed, after - that they are within the dynamically-allocated m_extra. - - This allows for static allocation in the common case, whilst - supporting the rarer case of an arbitrary number of elements. - - Dynamic allocation is not performed unless it's needed. */ - -template -class semi_embedded_vec -{ - public: - semi_embedded_vec (); - ~semi_embedded_vec (); - - unsigned int count () const { return m_num; } - T& operator[] (int idx); - const T& operator[] (int idx) const; - - void push (const T&); - void truncate (int len); - - private: - int m_num; - T m_embedded[NUM_EMBEDDED]; - int m_alloc; - T *m_extra; -}; - -/* Constructor for semi_embedded_vec. In particular, no dynamic allocation - is done. */ - -template -semi_embedded_vec::semi_embedded_vec () -: m_num (0), m_alloc (0), m_extra (NULL) -{ -} - -/* semi_embedded_vec's dtor. Release any dynamically-allocated memory. */ - -template -semi_embedded_vec::~semi_embedded_vec () -{ - XDELETEVEC (m_extra); -} - -/* Look up element IDX, mutably. */ - -template -T& -semi_embedded_vec::operator[] (int idx) -{ - linemap_assert (idx < m_num); - if (idx < NUM_EMBEDDED) - return m_embedded[idx]; - else - { - linemap_assert (m_extra != NULL); - return m_extra[idx - NUM_EMBEDDED]; - } -} - -/* Look up element IDX (const). */ - -template -const T& -semi_embedded_vec::operator[] (int idx) const -{ - linemap_assert (idx < m_num); - if (idx < NUM_EMBEDDED) - return m_embedded[idx]; - else - { - linemap_assert (m_extra != NULL); - return m_extra[idx - NUM_EMBEDDED]; - } -} - -/* Append VALUE to the end of the semi_embedded_vec. */ - -template -void -semi_embedded_vec::push (const T& value) -{ - int idx = m_num++; - if (idx < NUM_EMBEDDED) - m_embedded[idx] = value; - else - { - /* Offset "idx" to be an index within m_extra. */ - idx -= NUM_EMBEDDED; - if (NULL == m_extra) - { - linemap_assert (m_alloc == 0); - m_alloc = 16; - m_extra = XNEWVEC (T, m_alloc); - } - else if (idx >= m_alloc) - { - linemap_assert (m_alloc > 0); - m_alloc *= 2; - m_extra = XRESIZEVEC (T, m_extra, m_alloc); - } - linemap_assert (m_extra); - linemap_assert (idx < m_alloc); - m_extra[idx] = value; - } -} - -/* Truncate to length LEN. No deallocation is performed. */ - -template -void -semi_embedded_vec::truncate (int len) -{ - linemap_assert (len <= m_num); - m_num = len; -} - -class fixit_hint; -class diagnostic_path; - -/* A "rich" source code location, for use when printing diagnostics. - A rich_location has one or more carets&ranges, where the carets - are optional. These are referred to as "ranges" from here. - Typically the zeroth range has a caret; other ranges sometimes - have carets. - - The "primary" location of a rich_location is the caret of range 0, - used for determining the line/column when printing diagnostic - text, such as: - - some-file.c:3:1: error: ...etc... - - Additional ranges may be added to help the user identify other - pertinent clauses in a diagnostic. - - Ranges can (optionally) be given labels via class range_label. - - rich_location instances are intended to be allocated on the stack - when generating diagnostics, and to be short-lived. - - Examples of rich locations - -------------------------- - - Example A - ********* - int i = "foo"; - ^ - This "rich" location is simply a single range (range 0), with - caret = start = finish at the given point. - - Example B - ********* - a = (foo && bar) - ~~~~~^~~~~~~ - This rich location has a single range (range 0), with the caret - at the first "&", and the start/finish at the parentheses. - Compare with example C below. - - Example C - ********* - a = (foo && bar) - ~~~ ^~ ~~~ - This rich location has three ranges: - - Range 0 has its caret and start location at the first "&" and - end at the second "&. - - Range 1 has its start and finish at the "f" and "o" of "foo"; - the caret is not flagged for display, but is perhaps at the "f" - of "foo". - - Similarly, range 2 has its start and finish at the "b" and "r" of - "bar"; the caret is not flagged for display, but is perhaps at the - "b" of "bar". - Compare with example B above. - - Example D (Fortran frontend) - **************************** - x = x + y - 1 2 - This rich location has range 0 at "1", and range 1 at "2". - Both are flagged for caret display. Both ranges have start/finish - equal to their caret point. The frontend overrides the diagnostic - context's default caret character for these ranges. - - Example E (range labels) - ************************ - printf ("arg0: %i arg1: %s arg2: %i", - ^~ - | - const char * - 100, 101, 102); - ~~~ - | - int - This rich location has two ranges: - - range 0 is at the "%s" with start = caret = "%" and finish at - the "s". It has a range_label ("const char *"). - - range 1 has start/finish covering the "101" and is not flagged for - caret printing. The caret is at the start of "101", where its - range_label is printed ("int"). - - Fix-it hints - ------------ - - Rich locations can also contain "fix-it hints", giving suggestions - for the user on how to edit their code to fix a problem. These - can be expressed as insertions, replacements, and removals of text. - The edits by default are relative to the zeroth range within the - rich_location, but optionally they can be expressed relative to - other locations (using various overloaded methods of the form - rich_location::add_fixit_*). - - For example: - - Example F: fix-it hint: insert_before - ************************************* - ptr = arr[0]; - ^~~~~~ - & - This rich location has a single range (range 0) covering "arr[0]", - with the caret at the start. The rich location has a single - insertion fix-it hint, inserted before range 0, added via - richloc.add_fixit_insert_before ("&"); - - Example G: multiple fix-it hints: insert_before and insert_after - **************************************************************** - #define FN(ARG0, ARG1, ARG2) fn(ARG0, ARG1, ARG2) - ^~~~ ^~~~ ^~~~ - ( ) ( ) ( ) - This rich location has three ranges, covering "arg0", "arg1", - and "arg2", all with caret-printing enabled. - The rich location has 6 insertion fix-it hints: each arg - has a pair of insertion fix-it hints, suggesting wrapping - them with parentheses: one a '(' inserted before, - the other a ')' inserted after, added via - richloc.add_fixit_insert_before (LOC, "("); - and - richloc.add_fixit_insert_after (LOC, ")"); - - Example H: fix-it hint: removal - ******************************* - struct s {int i};; - ^ - - - This rich location has a single range at the stray trailing - semicolon, along with a single removal fix-it hint, covering - the same range, added via: - richloc.add_fixit_remove (); - - Example I: fix-it hint: replace - ******************************* - c = s.colour; - ^~~~~~ - color - This rich location has a single range (range 0) covering "colour", - and a single "replace" fix-it hint, covering the same range, - added via - richloc.add_fixit_replace ("color"); - - Example J: fix-it hint: line insertion - ************************************** - - 3 | #include - + |+#include - 4 | int the_next_line; - - This rich location has a single range at line 4 column 1, marked - with SHOW_LINES_WITHOUT_RANGE (to avoid printing a meaningless caret - on the "i" of int). It has a insertion fix-it hint of the string - "#include \n". - - Adding a fix-it hint can fail: for example, attempts to insert content - at the transition between two line maps may fail due to there being no - location_t value to express the new location. - - Attempts to add a fix-it hint within a macro expansion will fail. - - There is only limited support for newline characters in fix-it hints: - only hints with newlines which insert an entire new line are permitted, - inserting at the start of a line, and finishing with a newline - (with no interior newline characters). Other attempts to add - fix-it hints containing newline characters will fail. - Similarly, attempts to delete or replace a range *affecting* multiple - lines will fail. - - The rich_location API handles these failures gracefully, so that - diagnostics can attempt to add fix-it hints without each needing - extensive checking. - - Fix-it hints within a rich_location are "atomic": if any hints can't - be applied, none of them will be (tracked by the m_seen_impossible_fixit - flag), and no fix-its hints will be displayed for that rich_location. - This implies that diagnostic messages need to be worded in such a way - that they make sense whether or not the fix-it hints are displayed, - or that richloc.seen_impossible_fixit_p () should be checked before - issuing the diagnostics. */ - -class rich_location -{ - public: - /* Constructors. */ - - /* Constructing from a location. */ - rich_location (line_maps *set, location_t loc, - const range_label *label = NULL); - - /* Destructor. */ - ~rich_location (); - - /* The class manages the memory pointed to by the elements of - the M_FIXIT_HINTS vector and is not meant to be copied or - assigned. */ - rich_location (const rich_location &) = delete; - void operator= (const rich_location &) = delete; - - /* Accessors. */ - location_t get_loc () const { return get_loc (0); } - location_t get_loc (unsigned int idx) const; - - void - add_range (location_t loc, - enum range_display_kind range_display_kind - = SHOW_RANGE_WITHOUT_CARET, - const range_label *label = NULL); - - void - set_range (unsigned int idx, location_t loc, - enum range_display_kind range_display_kind); - - unsigned int get_num_locations () const { return m_ranges.count (); } - - const location_range *get_range (unsigned int idx) const; - location_range *get_range (unsigned int idx); - - expanded_location get_expanded_location (unsigned int idx) const; - - void - override_column (int column); - - /* Fix-it hints. */ - - /* Methods for adding insertion fix-it hints. */ - - /* Suggest inserting NEW_CONTENT immediately before the primary - range's start. */ - void - add_fixit_insert_before (const char *new_content); - - /* Suggest inserting NEW_CONTENT immediately before the start of WHERE. */ - void - add_fixit_insert_before (location_t where, - const char *new_content); - - /* Suggest inserting NEW_CONTENT immediately after the end of the primary - range. */ - void - add_fixit_insert_after (const char *new_content); - - /* Suggest inserting NEW_CONTENT immediately after the end of WHERE. */ - void - add_fixit_insert_after (location_t where, - const char *new_content); - - /* Methods for adding removal fix-it hints. */ - - /* Suggest removing the content covered by range 0. */ - void - add_fixit_remove (); - - /* Suggest removing the content covered between the start and finish - of WHERE. */ - void - add_fixit_remove (location_t where); - - /* Suggest removing the content covered by SRC_RANGE. */ - void - add_fixit_remove (source_range src_range); - - /* Methods for adding "replace" fix-it hints. */ - - /* Suggest replacing the content covered by range 0 with NEW_CONTENT. */ - void - add_fixit_replace (const char *new_content); - - /* Suggest replacing the content between the start and finish of - WHERE with NEW_CONTENT. */ - void - add_fixit_replace (location_t where, - const char *new_content); - - /* Suggest replacing the content covered by SRC_RANGE with - NEW_CONTENT. */ - void - add_fixit_replace (source_range src_range, - const char *new_content); - - unsigned int get_num_fixit_hints () const { return m_fixit_hints.count (); } - fixit_hint *get_fixit_hint (int idx) const { return m_fixit_hints[idx]; } - fixit_hint *get_last_fixit_hint () const; - bool seen_impossible_fixit_p () const { return m_seen_impossible_fixit; } - - /* Set this if the fix-it hints are not suitable to be - automatically applied. - - For example, if you are suggesting more than one - mutually exclusive solution to a problem, then - it doesn't make sense to apply all of the solutions; - manual intervention is required. - - If set, then the fix-it hints in the rich_location will - be printed, but will not be added to generated patches, - or affect the modified version of the file. */ - void fixits_cannot_be_auto_applied () - { - m_fixits_cannot_be_auto_applied = true; - } - - bool fixits_can_be_auto_applied_p () const - { - return !m_fixits_cannot_be_auto_applied; - } - - /* An optional path through the code. */ - const diagnostic_path *get_path () const { return m_path; } - void set_path (const diagnostic_path *path) { m_path = path; } - - /* A flag for hinting that the diagnostic involves character encoding - issues, and thus that it will be helpful to the user if we show some - representation of how the characters in the pertinent source lines - are encoded. - The default is false (i.e. do not escape). - When set to true, non-ASCII bytes in the pertinent source lines will - be escaped in a manner controlled by the user-supplied option - -fdiagnostics-escape-format=, so that the user can better understand - what's going on with the encoding in their source file. */ - bool escape_on_output_p () const { return m_escape_on_output; } - void set_escape_on_output (bool flag) { m_escape_on_output = flag; } - - const line_maps *get_line_table () const { return m_line_table; } - -private: - bool reject_impossible_fixit (location_t where); - void stop_supporting_fixits (); - void maybe_add_fixit (location_t start, - location_t next_loc, - const char *new_content); - -public: - static const int STATICALLY_ALLOCATED_RANGES = 3; - -protected: - line_maps * const m_line_table; - semi_embedded_vec m_ranges; - - int m_column_override; - - mutable bool m_have_expanded_location; - bool m_seen_impossible_fixit; - bool m_fixits_cannot_be_auto_applied; - bool m_escape_on_output; - - mutable expanded_location m_expanded_location; - - static const int MAX_STATIC_FIXIT_HINTS = 2; - semi_embedded_vec m_fixit_hints; - - const diagnostic_path *m_path; -}; - -/* A struct for the result of range_label::get_text: a NUL-terminated buffer - of localized text, and a flag to determine if the caller should "free" the - buffer. */ - -class label_text -{ -public: - label_text () - : m_buffer (NULL), m_owned (false) - {} - - ~label_text () - { - if (m_owned) - free (m_buffer); - } - - /* Move ctor. */ - label_text (label_text &&other) - : m_buffer (other.m_buffer), m_owned (other.m_owned) - { - other.release (); - } - - /* Move assignment. */ - label_text & operator= (label_text &&other) - { - if (m_owned) - free (m_buffer); - m_buffer = other.m_buffer; - m_owned = other.m_owned; - other.release (); - return *this; - } - - /* Delete the copy ctor and copy-assignment operator. */ - label_text (const label_text &) = delete; - label_text & operator= (const label_text &) = delete; - - /* Create a label_text instance that borrows BUFFER from a - longer-lived owner. */ - static label_text borrow (const char *buffer) - { - return label_text (const_cast (buffer), false); - } - - /* Create a label_text instance that takes ownership of BUFFER. */ - static label_text take (char *buffer) - { - return label_text (buffer, true); - } - - void release () - { - m_buffer = NULL; - m_owned = false; - } - - const char *get () const - { - return m_buffer; - } - - bool is_owner () const - { - return m_owned; - } - -private: - char *m_buffer; - bool m_owned; - - label_text (char *buffer, bool owned) - : m_buffer (buffer), m_owned (owned) - {} -}; - -/* Abstract base class for labelling a range within a rich_location - (e.g. for labelling expressions with their type). - - Generating the text could require non-trivial work, so this work - is delayed (via the "get_text" virtual function) until the diagnostic - printing code "knows" it needs it, thus avoiding doing it e.g. for - warnings that are filtered by command-line flags. This virtual - function also isolates libcpp and the diagnostics subsystem from - the front-end and middle-end-specific code for generating the text - for the labels. - - Like the rich_location instances they annotate, range_label instances - are intended to be allocated on the stack when generating diagnostics, - and to be short-lived. */ - -class range_label -{ - public: - virtual ~range_label () {} - - /* Get localized text for the label. - The RANGE_IDX is provided, allowing for range_label instances to be - shared by multiple ranges if need be (the "flyweight" design pattern). */ - virtual label_text get_text (unsigned range_idx) const = 0; -}; - -/* A fix-it hint: a suggested insertion, replacement, or deletion of text. - We handle these three types of edit with one class, by representing - them as replacement of a half-open range: - [start, next_loc) - Insertions have start == next_loc: "replace" the empty string at the - start location with the new string. - Deletions are replacement with the empty string. - - There is only limited support for newline characters in fix-it hints - as noted above in the comment for class rich_location. - A fixit_hint instance can have at most one newline character; if - present, the newline character must be the final character of - the content (preventing e.g. fix-its that split a pre-existing line). */ - -class fixit_hint -{ - public: - fixit_hint (location_t start, - location_t next_loc, - const char *new_content); - ~fixit_hint () { free (m_bytes); } - - bool affects_line_p (const line_maps *set, - const char *file, - int line) const; - location_t get_start_loc () const { return m_start; } - location_t get_next_loc () const { return m_next_loc; } - bool maybe_append (location_t start, - location_t next_loc, - const char *new_content); - - const char *get_string () const { return m_bytes; } - size_t get_length () const { return m_len; } - - bool insertion_p () const { return m_start == m_next_loc; } - - bool ends_with_newline_p () const; - - private: - /* We don't use source_range here since, unlike most places, - this is a half-open/half-closed range: - [start, next_loc) - so that we can support insertion via start == next_loc. */ - location_t m_start; - location_t m_next_loc; - char *m_bytes; - size_t m_len; -}; - - /* This is enum is used by the function linemap_resolve_location below. The meaning of the values is explained in the comment of that function. */ diff --git a/libcpp/include/rich-location.h b/libcpp/include/rich-location.h new file mode 100644 index 000000000000..878c71c8bbe8 --- /dev/null +++ b/libcpp/include/rich-location.h @@ -0,0 +1,695 @@ +/* Bundles of location information used when printing diagnostics. + Copyright (C) 2015-2023 Free Software Foundation, Inc. + +This program 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. + +This program 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 this program; see the file COPYING3. If not see +. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#ifndef LIBCPP_RICH_LOCATION_H +#define LIBCPP_RICH_LOCATION_H + +class range_label; + +/* A hint to diagnostic_show_locus on how to print a source range within a + rich_location. + + Typically this is SHOW_RANGE_WITH_CARET for the 0th range, and + SHOW_RANGE_WITHOUT_CARET for subsequent ranges, + but the Fortran frontend uses SHOW_RANGE_WITH_CARET repeatedly for + printing things like: + + x = x + y + 1 2 + Error: Shapes for operands at (1) and (2) are not conformable + + where "1" and "2" are notionally carets. */ + +enum range_display_kind +{ + /* Show the pertinent source line(s), the caret, and underline(s). */ + SHOW_RANGE_WITH_CARET, + + /* Show the pertinent source line(s) and underline(s), but don't + show the caret (just an underline). */ + SHOW_RANGE_WITHOUT_CARET, + + /* Just show the source lines; don't show the range itself. + This is for use when displaying some line-insertion fix-it hints (for + showing the user context on the change, for when it doesn't make sense + to highlight the first column on the next line). */ + SHOW_LINES_WITHOUT_RANGE +}; + +/* A location within a rich_location: a caret&range, with + the caret potentially flagged for display, and an optional + label. */ + +struct location_range +{ + location_t m_loc; + + enum range_display_kind m_range_display_kind; + + /* If non-NULL, the label for this range. */ + const range_label *m_label; +}; + +/* A partially-embedded vec for use within rich_location for storing + ranges and fix-it hints. + + Elements [0..NUM_EMBEDDED) are allocated within m_embed, after + that they are within the dynamically-allocated m_extra. + + This allows for static allocation in the common case, whilst + supporting the rarer case of an arbitrary number of elements. + + Dynamic allocation is not performed unless it's needed. */ + +template +class semi_embedded_vec +{ + public: + semi_embedded_vec (); + ~semi_embedded_vec (); + + unsigned int count () const { return m_num; } + T& operator[] (int idx); + const T& operator[] (int idx) const; + + void push (const T&); + void truncate (int len); + + private: + int m_num; + T m_embedded[NUM_EMBEDDED]; + int m_alloc; + T *m_extra; +}; + +/* Constructor for semi_embedded_vec. In particular, no dynamic allocation + is done. */ + +template +semi_embedded_vec::semi_embedded_vec () +: m_num (0), m_alloc (0), m_extra (NULL) +{ +} + +/* semi_embedded_vec's dtor. Release any dynamically-allocated memory. */ + +template +semi_embedded_vec::~semi_embedded_vec () +{ + XDELETEVEC (m_extra); +} + +/* Look up element IDX, mutably. */ + +template +T& +semi_embedded_vec::operator[] (int idx) +{ + linemap_assert (idx < m_num); + if (idx < NUM_EMBEDDED) + return m_embedded[idx]; + else + { + linemap_assert (m_extra != NULL); + return m_extra[idx - NUM_EMBEDDED]; + } +} + +/* Look up element IDX (const). */ + +template +const T& +semi_embedded_vec::operator[] (int idx) const +{ + linemap_assert (idx < m_num); + if (idx < NUM_EMBEDDED) + return m_embedded[idx]; + else + { + linemap_assert (m_extra != NULL); + return m_extra[idx - NUM_EMBEDDED]; + } +} + +/* Append VALUE to the end of the semi_embedded_vec. */ + +template +void +semi_embedded_vec::push (const T& value) +{ + int idx = m_num++; + if (idx < NUM_EMBEDDED) + m_embedded[idx] = value; + else + { + /* Offset "idx" to be an index within m_extra. */ + idx -= NUM_EMBEDDED; + if (NULL == m_extra) + { + linemap_assert (m_alloc == 0); + m_alloc = 16; + m_extra = XNEWVEC (T, m_alloc); + } + else if (idx >= m_alloc) + { + linemap_assert (m_alloc > 0); + m_alloc *= 2; + m_extra = XRESIZEVEC (T, m_extra, m_alloc); + } + linemap_assert (m_extra); + linemap_assert (idx < m_alloc); + m_extra[idx] = value; + } +} + +/* Truncate to length LEN. No deallocation is performed. */ + +template +void +semi_embedded_vec::truncate (int len) +{ + linemap_assert (len <= m_num); + m_num = len; +} + +class fixit_hint; +class diagnostic_path; + +/* A "rich" source code location, for use when printing diagnostics. + A rich_location has one or more carets&ranges, where the carets + are optional. These are referred to as "ranges" from here. + Typically the zeroth range has a caret; other ranges sometimes + have carets. + + The "primary" location of a rich_location is the caret of range 0, + used for determining the line/column when printing diagnostic + text, such as: + + some-file.c:3:1: error: ...etc... + + Additional ranges may be added to help the user identify other + pertinent clauses in a diagnostic. + + Ranges can (optionally) be given labels via class range_label. + + rich_location instances are intended to be allocated on the stack + when generating diagnostics, and to be short-lived. + + Examples of rich locations + -------------------------- + + Example A + ********* + int i = "foo"; + ^ + This "rich" location is simply a single range (range 0), with + caret = start = finish at the given point. + + Example B + ********* + a = (foo && bar) + ~~~~~^~~~~~~ + This rich location has a single range (range 0), with the caret + at the first "&", and the start/finish at the parentheses. + Compare with example C below. + + Example C + ********* + a = (foo && bar) + ~~~ ^~ ~~~ + This rich location has three ranges: + - Range 0 has its caret and start location at the first "&" and + end at the second "&. + - Range 1 has its start and finish at the "f" and "o" of "foo"; + the caret is not flagged for display, but is perhaps at the "f" + of "foo". + - Similarly, range 2 has its start and finish at the "b" and "r" of + "bar"; the caret is not flagged for display, but is perhaps at the + "b" of "bar". + Compare with example B above. + + Example D (Fortran frontend) + **************************** + x = x + y + 1 2 + This rich location has range 0 at "1", and range 1 at "2". + Both are flagged for caret display. Both ranges have start/finish + equal to their caret point. The frontend overrides the diagnostic + context's default caret character for these ranges. + + Example E (range labels) + ************************ + printf ("arg0: %i arg1: %s arg2: %i", + ^~ + | + const char * + 100, 101, 102); + ~~~ + | + int + This rich location has two ranges: + - range 0 is at the "%s" with start = caret = "%" and finish at + the "s". It has a range_label ("const char *"). + - range 1 has start/finish covering the "101" and is not flagged for + caret printing. The caret is at the start of "101", where its + range_label is printed ("int"). + + Fix-it hints + ------------ + + Rich locations can also contain "fix-it hints", giving suggestions + for the user on how to edit their code to fix a problem. These + can be expressed as insertions, replacements, and removals of text. + The edits by default are relative to the zeroth range within the + rich_location, but optionally they can be expressed relative to + other locations (using various overloaded methods of the form + rich_location::add_fixit_*). + + For example: + + Example F: fix-it hint: insert_before + ************************************* + ptr = arr[0]; + ^~~~~~ + & + This rich location has a single range (range 0) covering "arr[0]", + with the caret at the start. The rich location has a single + insertion fix-it hint, inserted before range 0, added via + richloc.add_fixit_insert_before ("&"); + + Example G: multiple fix-it hints: insert_before and insert_after + **************************************************************** + #define FN(ARG0, ARG1, ARG2) fn(ARG0, ARG1, ARG2) + ^~~~ ^~~~ ^~~~ + ( ) ( ) ( ) + This rich location has three ranges, covering "arg0", "arg1", + and "arg2", all with caret-printing enabled. + The rich location has 6 insertion fix-it hints: each arg + has a pair of insertion fix-it hints, suggesting wrapping + them with parentheses: one a '(' inserted before, + the other a ')' inserted after, added via + richloc.add_fixit_insert_before (LOC, "("); + and + richloc.add_fixit_insert_after (LOC, ")"); + + Example H: fix-it hint: removal + ******************************* + struct s {int i};; + ^ + - + This rich location has a single range at the stray trailing + semicolon, along with a single removal fix-it hint, covering + the same range, added via: + richloc.add_fixit_remove (); + + Example I: fix-it hint: replace + ******************************* + c = s.colour; + ^~~~~~ + color + This rich location has a single range (range 0) covering "colour", + and a single "replace" fix-it hint, covering the same range, + added via + richloc.add_fixit_replace ("color"); + + Example J: fix-it hint: line insertion + ************************************** + + 3 | #include + + |+#include + 4 | int the_next_line; + + This rich location has a single range at line 4 column 1, marked + with SHOW_LINES_WITHOUT_RANGE (to avoid printing a meaningless caret + on the "i" of int). It has a insertion fix-it hint of the string + "#include \n". + + Adding a fix-it hint can fail: for example, attempts to insert content + at the transition between two line maps may fail due to there being no + location_t value to express the new location. + + Attempts to add a fix-it hint within a macro expansion will fail. + + There is only limited support for newline characters in fix-it hints: + only hints with newlines which insert an entire new line are permitted, + inserting at the start of a line, and finishing with a newline + (with no interior newline characters). Other attempts to add + fix-it hints containing newline characters will fail. + Similarly, attempts to delete or replace a range *affecting* multiple + lines will fail. + + The rich_location API handles these failures gracefully, so that + diagnostics can attempt to add fix-it hints without each needing + extensive checking. + + Fix-it hints within a rich_location are "atomic": if any hints can't + be applied, none of them will be (tracked by the m_seen_impossible_fixit + flag), and no fix-its hints will be displayed for that rich_location. + This implies that diagnostic messages need to be worded in such a way + that they make sense whether or not the fix-it hints are displayed, + or that richloc.seen_impossible_fixit_p () should be checked before + issuing the diagnostics. */ + +class rich_location +{ + public: + /* Constructors. */ + + /* Constructing from a location. */ + rich_location (line_maps *set, location_t loc, + const range_label *label = NULL); + + /* Destructor. */ + ~rich_location (); + + /* The class manages the memory pointed to by the elements of + the M_FIXIT_HINTS vector and is not meant to be copied or + assigned. */ + rich_location (const rich_location &) = delete; + void operator= (const rich_location &) = delete; + + /* Accessors. */ + location_t get_loc () const { return get_loc (0); } + location_t get_loc (unsigned int idx) const; + + void + add_range (location_t loc, + enum range_display_kind range_display_kind + = SHOW_RANGE_WITHOUT_CARET, + const range_label *label = NULL); + + void + set_range (unsigned int idx, location_t loc, + enum range_display_kind range_display_kind); + + unsigned int get_num_locations () const { return m_ranges.count (); } + + const location_range *get_range (unsigned int idx) const; + location_range *get_range (unsigned int idx); + + expanded_location get_expanded_location (unsigned int idx) const; + + void + override_column (int column); + + /* Fix-it hints. */ + + /* Methods for adding insertion fix-it hints. */ + + /* Suggest inserting NEW_CONTENT immediately before the primary + range's start. */ + void + add_fixit_insert_before (const char *new_content); + + /* Suggest inserting NEW_CONTENT immediately before the start of WHERE. */ + void + add_fixit_insert_before (location_t where, + const char *new_content); + + /* Suggest inserting NEW_CONTENT immediately after the end of the primary + range. */ + void + add_fixit_insert_after (const char *new_content); + + /* Suggest inserting NEW_CONTENT immediately after the end of WHERE. */ + void + add_fixit_insert_after (location_t where, + const char *new_content); + + /* Methods for adding removal fix-it hints. */ + + /* Suggest removing the content covered by range 0. */ + void + add_fixit_remove (); + + /* Suggest removing the content covered between the start and finish + of WHERE. */ + void + add_fixit_remove (location_t where); + + /* Suggest removing the content covered by SRC_RANGE. */ + void + add_fixit_remove (source_range src_range); + + /* Methods for adding "replace" fix-it hints. */ + + /* Suggest replacing the content covered by range 0 with NEW_CONTENT. */ + void + add_fixit_replace (const char *new_content); + + /* Suggest replacing the content between the start and finish of + WHERE with NEW_CONTENT. */ + void + add_fixit_replace (location_t where, + const char *new_content); + + /* Suggest replacing the content covered by SRC_RANGE with + NEW_CONTENT. */ + void + add_fixit_replace (source_range src_range, + const char *new_content); + + unsigned int get_num_fixit_hints () const { return m_fixit_hints.count (); } + fixit_hint *get_fixit_hint (int idx) const { return m_fixit_hints[idx]; } + fixit_hint *get_last_fixit_hint () const; + bool seen_impossible_fixit_p () const { return m_seen_impossible_fixit; } + + /* Set this if the fix-it hints are not suitable to be + automatically applied. + + For example, if you are suggesting more than one + mutually exclusive solution to a problem, then + it doesn't make sense to apply all of the solutions; + manual intervention is required. + + If set, then the fix-it hints in the rich_location will + be printed, but will not be added to generated patches, + or affect the modified version of the file. */ + void fixits_cannot_be_auto_applied () + { + m_fixits_cannot_be_auto_applied = true; + } + + bool fixits_can_be_auto_applied_p () const + { + return !m_fixits_cannot_be_auto_applied; + } + + /* An optional path through the code. */ + const diagnostic_path *get_path () const { return m_path; } + void set_path (const diagnostic_path *path) { m_path = path; } + + /* A flag for hinting that the diagnostic involves character encoding + issues, and thus that it will be helpful to the user if we show some + representation of how the characters in the pertinent source lines + are encoded. + The default is false (i.e. do not escape). + When set to true, non-ASCII bytes in the pertinent source lines will + be escaped in a manner controlled by the user-supplied option + -fdiagnostics-escape-format=, so that the user can better understand + what's going on with the encoding in their source file. */ + bool escape_on_output_p () const { return m_escape_on_output; } + void set_escape_on_output (bool flag) { m_escape_on_output = flag; } + + const line_maps *get_line_table () const { return m_line_table; } + +private: + bool reject_impossible_fixit (location_t where); + void stop_supporting_fixits (); + void maybe_add_fixit (location_t start, + location_t next_loc, + const char *new_content); + +public: + static const int STATICALLY_ALLOCATED_RANGES = 3; + +protected: + line_maps * const m_line_table; + semi_embedded_vec m_ranges; + + int m_column_override; + + mutable bool m_have_expanded_location; + bool m_seen_impossible_fixit; + bool m_fixits_cannot_be_auto_applied; + bool m_escape_on_output; + + mutable expanded_location m_expanded_location; + + static const int MAX_STATIC_FIXIT_HINTS = 2; + semi_embedded_vec m_fixit_hints; + + const diagnostic_path *m_path; +}; + +/* A struct for the result of range_label::get_text: a NUL-terminated buffer + of localized text, and a flag to determine if the caller should "free" the + buffer. */ + +class label_text +{ +public: + label_text () + : m_buffer (NULL), m_owned (false) + {} + + ~label_text () + { + if (m_owned) + free (m_buffer); + } + + /* Move ctor. */ + label_text (label_text &&other) + : m_buffer (other.m_buffer), m_owned (other.m_owned) + { + other.release (); + } + + /* Move assignment. */ + label_text & operator= (label_text &&other) + { + if (m_owned) + free (m_buffer); + m_buffer = other.m_buffer; + m_owned = other.m_owned; + other.release (); + return *this; + } + + /* Delete the copy ctor and copy-assignment operator. */ + label_text (const label_text &) = delete; + label_text & operator= (const label_text &) = delete; + + /* Create a label_text instance that borrows BUFFER from a + longer-lived owner. */ + static label_text borrow (const char *buffer) + { + return label_text (const_cast (buffer), false); + } + + /* Create a label_text instance that takes ownership of BUFFER. */ + static label_text take (char *buffer) + { + return label_text (buffer, true); + } + + void release () + { + m_buffer = NULL; + m_owned = false; + } + + const char *get () const + { + return m_buffer; + } + + bool is_owner () const + { + return m_owned; + } + +private: + char *m_buffer; + bool m_owned; + + label_text (char *buffer, bool owned) + : m_buffer (buffer), m_owned (owned) + {} +}; + +/* Abstract base class for labelling a range within a rich_location + (e.g. for labelling expressions with their type). + + Generating the text could require non-trivial work, so this work + is delayed (via the "get_text" virtual function) until the diagnostic + printing code "knows" it needs it, thus avoiding doing it e.g. for + warnings that are filtered by command-line flags. This virtual + function also isolates libcpp and the diagnostics subsystem from + the front-end and middle-end-specific code for generating the text + for the labels. + + Like the rich_location instances they annotate, range_label instances + are intended to be allocated on the stack when generating diagnostics, + and to be short-lived. */ + +class range_label +{ + public: + virtual ~range_label () {} + + /* Get localized text for the label. + The RANGE_IDX is provided, allowing for range_label instances to be + shared by multiple ranges if need be (the "flyweight" design pattern). */ + virtual label_text get_text (unsigned range_idx) const = 0; +}; + +/* A fix-it hint: a suggested insertion, replacement, or deletion of text. + We handle these three types of edit with one class, by representing + them as replacement of a half-open range: + [start, next_loc) + Insertions have start == next_loc: "replace" the empty string at the + start location with the new string. + Deletions are replacement with the empty string. + + There is only limited support for newline characters in fix-it hints + as noted above in the comment for class rich_location. + A fixit_hint instance can have at most one newline character; if + present, the newline character must be the final character of + the content (preventing e.g. fix-its that split a pre-existing line). */ + +class fixit_hint +{ + public: + fixit_hint (location_t start, + location_t next_loc, + const char *new_content); + ~fixit_hint () { free (m_bytes); } + + bool affects_line_p (const line_maps *set, + const char *file, + int line) const; + location_t get_start_loc () const { return m_start; } + location_t get_next_loc () const { return m_next_loc; } + bool maybe_append (location_t start, + location_t next_loc, + const char *new_content); + + const char *get_string () const { return m_bytes; } + size_t get_length () const { return m_len; } + + bool insertion_p () const { return m_start == m_next_loc; } + + bool ends_with_newline_p () const; + + private: + /* We don't use source_range here since, unlike most places, + this is a half-open/half-closed range: + [start, next_loc) + so that we can support insertion via start == next_loc. */ + location_t m_start; + location_t m_next_loc; + char *m_bytes; + size_t m_len; +}; + +#endif /* !LIBCPP_RICH_LOCATION_H */ diff --git a/libcpp/internal.h b/libcpp/internal.h index 6a10e9de43e7..134fc33d40c2 100644 --- a/libcpp/internal.h +++ b/libcpp/internal.h @@ -24,6 +24,7 @@ along with this program; see the file COPYING3. If not see #include "symtab.h" #include "cpplib.h" +#include "rich-location.h" #if HAVE_ICONV #include