blob: 282593cebc02c434229668e53c1c2df160077a3a [file] [log] [blame]
// Copyright 2022 The Fuchsia 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 TOOLS_FIDL_FIDLC_INCLUDE_FIDL_FLAT_AVAILABILITY_STEP_H_
#define TOOLS_FIDL_FIDLC_INCLUDE_FIDL_FLAT_AVAILABILITY_STEP_H_
#include "fidl/flat/compiler.h"
namespace fidl::flat {
// The AvailabilityStep sets element->availability for every element in the
// library based on @available attributes and inheritance rules. If the library
// is versioned, it sets library->platform. Otherwise, it leaves it null, and
// all element availabilities will be unbounded. This step also checks for name
// collisions on overlapping availabilities for top level declarations (but not
// their members; they are checked in the CompileStep).
class AvailabilityStep : public Compiler::Step {
public:
using Step::Step;
private:
void RunImpl() override;
void PopulateLexicalParents();
// Sets `element->availability` from the @available attribute, inheriting
// unset fields from `AvailabilityToInheritFrom(element)`.
void CompileAvailability(Element* element);
// Helper function for `CompileAvailability`.
void CompileAvailabilityFromAttribute(Element* element, Attribute* attribute);
// Returns the default platform (the first component of the library name).
Platform GetDefaultPlatform();
// Parses the argument value as a platform. Reports an error on failure.
std::optional<Platform> GetPlatform(const AttributeArg* maybe_arg);
// Parses the argument value as a version. Reports an error on failure.
std::optional<Version> GetVersion(const AttributeArg* maybe_arg);
// Returns the availability that `element` should inherit from, or null
// if it should not attempt inheriting.
std::optional<Availability> AvailabilityToInheritFrom(const Element* element);
// Given an argument name, returns the nearest ancestor argument that
// `element` inherited its value from. Requires that such an argument exists.
// For example, consider this FIDL:
//
// 1 | @available(added=2) // <-- ancestor
// 2 | library test;
// 3 | type Foo = struct {
// 4 | @available(added=1) // <-- arg
// 5 | bar uint32;
// 6 | };
//
// The `added=2` flows from `library test` to `type Foo` to `bar uint32`. But
// we want the error ("can't add bar at version 1 when its parent isn't added
// until version 2") to point to line 1, not to line 3.
const AttributeArg* AncestorArgument(const Element* element, std::string_view arg_name);
// Returns the lexical parent of `element`, or null for the root.
//
// The lexical parent differs from the scope in which an `element` exists
// in the case of anonymous layouts: the lexical parent is the direct
// container in which an `element` was defined, whereas they are hoisted
// to library-scope. For example:
//
// @available(added=1)
// library test; // scope: null, lexical parent: null
// @available(added=2)
// type Foo = struct { // scope: library, lexical parent: library
// @available(added=3)
// bar // scope: Foo, lexical parent: Foo
// struct {}; // scope: library, lexical parent: bar
// };
//
// After consuming the raw AST, the anonymous layout `struct {}` gets treated
// like a top-level declaration alongside `Foo`. But we inherit from its
// lexical parent, the member `bar` (added at version 3).
Element* LexicalParent(const Element* element);
// Reports errors for all decl name collisions on overlapping availabilities.
void VerifyNoDeclOverlaps();
// Maps members to the Decl they occur in, and anonymous layouts to the
// struct/table/union member whose type constructor they occur in.
std::map<const Element*, Element*> lexical_parents_;
};
} // namespace fidl::flat
#endif // TOOLS_FIDL_FIDLC_INCLUDE_FIDL_FLAT_AVAILABILITY_STEP_H_