mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 08:14:43 +01:00
Diagnose repeat Main//default files as a redundant api file. (#3408)
This commit is contained in:
+39
-25
@@ -8,6 +8,7 @@
|
||||
#include "toolchain/base/pretty_stack_trace_function.h"
|
||||
#include "toolchain/base/value_store.h"
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/diagnostics/diagnostic_emitter.h"
|
||||
#include "toolchain/parse/tree.h"
|
||||
#include "toolchain/parse/tree_node_location_translator.h"
|
||||
#include "toolchain/sem_ir/file.h"
|
||||
@@ -17,7 +18,7 @@ namespace Carbon::Check {
|
||||
struct UnitInfo {
|
||||
explicit UnitInfo(Unit& unit)
|
||||
: unit(&unit),
|
||||
translator(unit.tokens, unit.parse_tree),
|
||||
translator(unit.tokens, unit.tokens->filename(), unit.parse_tree),
|
||||
err_tracker(*unit.consumer),
|
||||
emitter(translator, err_tracker) {}
|
||||
|
||||
@@ -258,33 +259,46 @@ auto CheckParseTrees(const SemIR::File& builtin_ir,
|
||||
// put .impl.carbon on almost all tests (which are in `Main//default`). We
|
||||
// should probably get leads direction on filenames before enforcing.
|
||||
const auto& packaging = unit_info.unit->parse_tree->packaging_directive();
|
||||
if (packaging) {
|
||||
auto import_key =
|
||||
GetImportKey(unit_info, IdentifierId::Invalid, packaging->names);
|
||||
// Diagnose explicit `Main` uses before they become marked as possible
|
||||
// APIs.
|
||||
if (import_key.first == ExplicitMainName) {
|
||||
CARBON_DIAGNOSTIC(ExplicitMainPackage, Error,
|
||||
"`Main//default` must omit `package` directive.");
|
||||
CARBON_DIAGNOSTIC(
|
||||
ExplicitMainLibrary, Error,
|
||||
"Use `library` directive in `Main` package libraries.");
|
||||
unit_info.emitter.Emit(packaging->names.node,
|
||||
import_key.second.empty() ? ExplicitMainPackage
|
||||
: ExplicitMainLibrary);
|
||||
continue;
|
||||
}
|
||||
// An import key formed from the `package` or `library` directive. Or, for
|
||||
// Main//default, a placeholder key.
|
||||
auto import_key = packaging ? GetImportKey(unit_info, IdentifierId::Invalid,
|
||||
packaging->names)
|
||||
// Construct a boring key for Main//default.
|
||||
: ImportKey{"", ""};
|
||||
|
||||
if (packaging->api_or_impl == Parse::Tree::ApiOrImpl::Impl) {
|
||||
continue;
|
||||
}
|
||||
// Diagnose explicit `Main` uses before they become marked as possible
|
||||
// APIs.
|
||||
if (import_key.first == ExplicitMainName) {
|
||||
CARBON_DIAGNOSTIC(ExplicitMainPackage, Error,
|
||||
"`Main//default` must omit `package` directive.");
|
||||
CARBON_DIAGNOSTIC(ExplicitMainLibrary, Error,
|
||||
"Use `library` directive in `Main` package libraries.");
|
||||
unit_info.emitter.Emit(packaging->names.node, import_key.second.empty()
|
||||
? ExplicitMainPackage
|
||||
: ExplicitMainLibrary);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto [entry, success] = api_map.insert({import_key, &unit_info});
|
||||
if (!success) {
|
||||
// TODO: Cross-reference the source, deal with library, etc.
|
||||
if (packaging && packaging->api_or_impl == Parse::Tree::ApiOrImpl::Impl) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto [entry, success] = api_map.insert({import_key, &unit_info});
|
||||
if (!success) {
|
||||
llvm::StringRef prev_filename = entry->second->unit->tokens->filename();
|
||||
if (packaging) {
|
||||
CARBON_DIAGNOSTIC(DuplicateLibraryApi, Error,
|
||||
"Library's API declared in more than one file.");
|
||||
unit_info.emitter.Emit(packaging->names.node, DuplicateLibraryApi);
|
||||
"Library's API previously provided by `{0}`.",
|
||||
llvm::StringRef);
|
||||
unit_info.emitter.Emit(packaging->names.node, DuplicateLibraryApi,
|
||||
prev_filename);
|
||||
} else {
|
||||
CARBON_DIAGNOSTIC(DuplicateMainApi, Error,
|
||||
"Main//default previously provided by `{0}`.",
|
||||
llvm::StringRef);
|
||||
// Use the invalid node because there's no node to associate with.
|
||||
unit_info.emitter.Emit(Parse::Node::Invalid, DuplicateMainApi,
|
||||
prev_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,13 @@
|
||||
// AUTOUPDATE
|
||||
|
||||
// --- a.carbon
|
||||
package A api;
|
||||
|
||||
fn A() {}
|
||||
|
||||
// --- b.carbon
|
||||
package B api;
|
||||
|
||||
fn B() {}
|
||||
|
||||
// CHECK:STDOUT: file "a.carbon" {
|
||||
|
||||
@@ -9,9 +9,13 @@
|
||||
// AUTOUPDATE
|
||||
|
||||
// --- a.carbon
|
||||
package A api;
|
||||
|
||||
fn A() {}
|
||||
|
||||
// --- b.carbon
|
||||
package B api;
|
||||
|
||||
fn B() {}
|
||||
|
||||
// CHECK:STDOUT: ---
|
||||
|
||||
@@ -9,9 +9,13 @@
|
||||
// AUTOUPDATE
|
||||
|
||||
// --- a.carbon
|
||||
package A api;
|
||||
|
||||
fn A() {}
|
||||
|
||||
// --- b.carbon
|
||||
package B api;
|
||||
|
||||
fn B() {}
|
||||
|
||||
// CHECK:STDOUT: ---
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// CHECK:STDERR: main2.carbon: ERROR: Main//default previously provided by `main1.carbon`.
|
||||
|
||||
// --- main1.carbon
|
||||
|
||||
// --- main2.carbon
|
||||
|
||||
// --- main_lib1.carbon
|
||||
|
||||
library "lib" api;
|
||||
|
||||
// --- main_lib2.carbon
|
||||
|
||||
// CHECK:STDERR: main_lib2.carbon:[[@LINE+3]]:1: ERROR: Library's API previously provided by `main_lib1.carbon`.
|
||||
// CHECK:STDERR: library "lib" api;
|
||||
// CHECK:STDERR: ^
|
||||
library "lib" api;
|
||||
|
||||
// --- package1.carbon
|
||||
|
||||
package Package api;
|
||||
|
||||
// --- package2.carbon
|
||||
|
||||
// CHECK:STDERR: package2.carbon:[[@LINE+3]]:1: ERROR: Library's API previously provided by `package1.carbon`.
|
||||
// CHECK:STDERR: package Package api;
|
||||
// CHECK:STDERR: ^
|
||||
package Package api;
|
||||
|
||||
// --- package_lib1.carbon
|
||||
|
||||
package Package library "lib" api;
|
||||
|
||||
// --- package_lib2.carbon
|
||||
|
||||
// CHECK:STDERR: package_lib2.carbon:[[@LINE+3]]:1: ERROR: Library's API previously provided by `package_lib1.carbon`.
|
||||
// CHECK:STDERR: package Package library "lib" api;
|
||||
// CHECK:STDERR: ^
|
||||
package Package library "lib" api;
|
||||
|
||||
// CHECK:STDOUT: file "main1.carbon" {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: file "main2.carbon" {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: file "main_lib1.carbon" {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: file "main_lib2.carbon" {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: file "package1.carbon" {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: file "package2.carbon" {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: file "package_lib1.carbon" {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: file "package_lib2.carbon" {
|
||||
// CHECK:STDOUT: }
|
||||
@@ -11,9 +11,7 @@
|
||||
// CHECK:STDERR: ^
|
||||
import Main;
|
||||
|
||||
// --- main_lib.carbon
|
||||
|
||||
// CHECK:STDERR: main_lib.carbon:[[@LINE+3]]:1: ERROR: Imports from the current package must omit the package name.
|
||||
// CHECK:STDERR: main.carbon:[[@LINE+3]]:1: ERROR: Imports from the current package must omit the package name.
|
||||
// CHECK:STDERR: import Main library "lib";
|
||||
// CHECK:STDERR: ^
|
||||
import Main library "lib";
|
||||
@@ -77,16 +75,15 @@ package Implicit library "lib" impl;
|
||||
import Implicit library "lib";
|
||||
|
||||
// --- not_found.carbon
|
||||
package NotFound api;
|
||||
|
||||
// CHECK:STDERR: not_found.carbon:[[@LINE+3]]:1: ERROR: Imported API not found.
|
||||
// CHECK:STDERR: import NotFound;
|
||||
// CHECK:STDERR: import ImportNotFound;
|
||||
// CHECK:STDERR: ^
|
||||
import NotFound;
|
||||
import ImportNotFound;
|
||||
|
||||
// CHECK:STDOUT: file "main.carbon" {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: file "main_lib.carbon" {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: file "not_main.carbon" {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: file "this.carbon" {
|
||||
|
||||
@@ -118,6 +118,7 @@ CARBON_DIAGNOSTIC_KIND(SemanticsTodo)
|
||||
|
||||
// Package/import checking diagnostics.
|
||||
CARBON_DIAGNOSTIC_KIND(DuplicateLibraryApi)
|
||||
CARBON_DIAGNOSTIC_KIND(DuplicateMainApi)
|
||||
CARBON_DIAGNOSTIC_KIND(LibraryApiNotFound)
|
||||
CARBON_DIAGNOSTIC_KIND(ImportNotFound)
|
||||
CARBON_DIAGNOSTIC_KIND(ImportCycleDetected)
|
||||
|
||||
@@ -12,16 +12,25 @@ namespace Carbon::Parse {
|
||||
class NodeLocationTranslator : public DiagnosticLocationTranslator<Node> {
|
||||
public:
|
||||
explicit NodeLocationTranslator(const Lex::TokenizedBuffer* tokens,
|
||||
llvm::StringRef filename,
|
||||
const Tree* parse_tree)
|
||||
: token_translator_(tokens), parse_tree_(parse_tree) {}
|
||||
: token_translator_(tokens),
|
||||
filename_(filename),
|
||||
parse_tree_(parse_tree) {}
|
||||
|
||||
// Map the given token into a diagnostic location.
|
||||
auto GetLocation(Node node) -> DiagnosticLocation override {
|
||||
// Support the invalid token as a way to emit only the filename, when there
|
||||
// is no line association.
|
||||
if (!node.is_valid()) {
|
||||
return {.file_name = filename_};
|
||||
}
|
||||
return token_translator_.GetLocation(parse_tree_->node_token(node));
|
||||
}
|
||||
|
||||
private:
|
||||
Lex::TokenLocationTranslator token_translator_;
|
||||
llvm::StringRef filename_;
|
||||
const Tree* parse_tree_;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user