blob: 02ada8c55d49a8634faa396c82157d221f571ba3 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.packages;
16
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000017import static com.google.devtools.build.lib.packages.BuildType.DISTRIBUTIONS;
18import static com.google.devtools.build.lib.packages.BuildType.FILESET_ENTRY_LIST;
19import static com.google.devtools.build.lib.packages.BuildType.LABEL;
20import static com.google.devtools.build.lib.packages.BuildType.LABEL_DICT_UNARY;
21import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
22import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST_DICT;
23import static com.google.devtools.build.lib.packages.BuildType.LICENSE;
24import static com.google.devtools.build.lib.packages.BuildType.NODEP_LABEL;
25import static com.google.devtools.build.lib.packages.BuildType.NODEP_LABEL_LIST;
26import static com.google.devtools.build.lib.packages.BuildType.OUTPUT;
27import static com.google.devtools.build.lib.packages.BuildType.OUTPUT_LIST;
28import static com.google.devtools.build.lib.packages.BuildType.TRISTATE;
29import static com.google.devtools.build.lib.syntax.Type.BOOLEAN;
30import static com.google.devtools.build.lib.syntax.Type.INTEGER;
31import static com.google.devtools.build.lib.syntax.Type.INTEGER_LIST;
32import static com.google.devtools.build.lib.syntax.Type.STRING;
33import static com.google.devtools.build.lib.syntax.Type.STRING_DICT;
34import static com.google.devtools.build.lib.syntax.Type.STRING_DICT_UNARY;
35import static com.google.devtools.build.lib.syntax.Type.STRING_LIST;
36import static com.google.devtools.build.lib.syntax.Type.STRING_LIST_DICT;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010037
Mark Schaller4fa83ac2015-07-10 16:59:37 +000038import com.google.common.base.Optional;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010039import com.google.common.base.Preconditions;
Mark Schaller4fa83ac2015-07-10 16:59:37 +000040import com.google.common.base.Predicates;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010041import com.google.common.collect.ImmutableMap;
Mark Schaller4fa83ac2015-07-10 16:59:37 +000042import com.google.common.collect.ImmutableSet;
43import com.google.common.collect.ImmutableSetMultimap;
44import com.google.common.collect.Iterables;
45import com.google.common.collect.Sets;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010046import com.google.devtools.build.lib.query2.proto.proto2api.Build.Attribute.Discriminator;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000047import com.google.devtools.build.lib.syntax.Type;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010048
Mark Schaller4fa83ac2015-07-10 16:59:37 +000049import java.util.Set;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010050
51/**
52 * Shared code used in proto buffer output for rules and rule classes.
53 */
54public class ProtoUtils {
55 /**
56 * This map contains all attribute types that are recognized by the protocol
57 * output formatter.
Mark Schaller4fa83ac2015-07-10 16:59:37 +000058 *
59 * <p>If you modify this map, please ensure that {@link #getTypeFromDiscriminator} can still
60 * resolve a {@link Discriminator} value to exactly one {@link Type} (using an optional nodep
61 * hint, as described below).
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010062 */
Mark Schaller4fa83ac2015-07-10 16:59:37 +000063 static final ImmutableMap<Type<?>, Discriminator> TYPE_MAP =
64 new ImmutableMap.Builder<Type<?>, Discriminator>()
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010065 .put(INTEGER, Discriminator.INTEGER)
66 .put(DISTRIBUTIONS, Discriminator.DISTRIBUTION_SET)
67 .put(LABEL, Discriminator.LABEL)
68 // NODEP_LABEL attributes are not really strings. This is implemented
69 // this way for the sake of backward compatibility.
70 .put(NODEP_LABEL, Discriminator.STRING)
71 .put(LABEL_LIST, Discriminator.LABEL_LIST)
72 .put(NODEP_LABEL_LIST, Discriminator.STRING_LIST)
73 .put(STRING, Discriminator.STRING)
74 .put(STRING_LIST, Discriminator.STRING_LIST)
75 .put(OUTPUT, Discriminator.OUTPUT)
76 .put(OUTPUT_LIST, Discriminator.OUTPUT_LIST)
77 .put(LICENSE, Discriminator.LICENSE)
78 .put(STRING_DICT, Discriminator.STRING_DICT)
79 .put(FILESET_ENTRY_LIST, Discriminator.FILESET_ENTRY_LIST)
Lukacs Berkif0cf38d2015-06-09 09:38:36 +000080 .put(LABEL_DICT_UNARY, Discriminator.LABEL_DICT_UNARY)
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010081 .put(LABEL_LIST_DICT, Discriminator.LABEL_LIST_DICT)
82 .put(STRING_LIST_DICT, Discriminator.STRING_LIST_DICT)
83 .put(BOOLEAN, Discriminator.BOOLEAN)
84 .put(TRISTATE, Discriminator.TRISTATE)
85 .put(INTEGER_LIST, Discriminator.INTEGER_LIST)
86 .put(STRING_DICT_UNARY, Discriminator.STRING_DICT_UNARY)
87 .build();
88
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000089 static final ImmutableSet<Type<?>> NODEP_TYPES = ImmutableSet.of(NODEP_LABEL, NODEP_LABEL_LIST);
Mark Schaller4fa83ac2015-07-10 16:59:37 +000090
91 static final ImmutableSetMultimap<Discriminator, Type<?>> INVERSE_TYPE_MAP =
92 TYPE_MAP.asMultimap().inverse();
93
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010094 /**
95 * Returns the appropriate Attribute.Discriminator value from an internal attribute type.
96 */
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000097 public static Discriminator getDiscriminatorFromType(
98 Type<?> type) {
Mark Schaller4fa83ac2015-07-10 16:59:37 +000099 Preconditions.checkArgument(TYPE_MAP.containsKey(type), type);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100100 return TYPE_MAP.get(type);
101 }
Mark Schaller4fa83ac2015-07-10 16:59:37 +0000102
103 /**
104 * Returns the appropriate set of internal attribute types from an Attribute.Discriminator value.
105 */
106 public static ImmutableSet<Type<?>> getTypesFromDiscriminator(Discriminator discriminator) {
107 Preconditions.checkArgument(INVERSE_TYPE_MAP.containsKey(discriminator), discriminator);
108 return INVERSE_TYPE_MAP.get(discriminator);
109 }
110
111 /**
112 * Returns the appropriate internal attribute type from an Attribute.Discriminator value, given
113 * an optional nodeps hint.
114 */
115 public static Type<?> getTypeFromDiscriminator(Discriminator discriminator,
116 Optional<Boolean> nodeps, String ruleClassName, String attrName) {
117 Preconditions.checkArgument(INVERSE_TYPE_MAP.containsKey(discriminator));
118 ImmutableSet<Type<?>> possibleTypes = ProtoUtils.getTypesFromDiscriminator(discriminator);
119 Type<?> preciseType;
120 if (possibleTypes.size() == 1) {
121 preciseType = Iterables.getOnlyElement(possibleTypes);
122 } else {
123 // If there is more than one possible type associated with the discriminator, then the
124 // discriminator must be either Discriminator.STRING or Discriminator.STRING_LIST.
125 //
126 // If it is Discriminator.STRING, then its possible Type<?>s are {NODEP_LABEL, STRING}. The
127 // nodeps hint must be present in order to distinguish between them. If nodeps is true,
128 // then the Type<?> must be NODEP_LABEL, and if false, it must be STRING.
129 //
130 // A similar relation holds for the Discriminator value STRING_LIST, and its possible
131 // Type<?>s {NODEP_LABEL_LIST, STRING_LIST}.
132
133 Preconditions.checkArgument(nodeps.isPresent(),
134 "Nodeps hint is required when discriminator is associated with more than one type."
135 + " Discriminator: \"%s\", Rule class: \"%s\", Attr: \"%s\"", discriminator,
136 ruleClassName, attrName);
137 if (nodeps.get()) {
138 Set<Type<?>> nodepType = Sets.filter(possibleTypes, Predicates.in(NODEP_TYPES));
139 Preconditions.checkState(nodepType.size() == 1,
140 "There should be exactly one NODEP type associated with discriminator \"%s\""
141 + ", but found these: %s. Rule class: \"%s\", Attr: \"%s\"", discriminator,
142 nodepType, ruleClassName, attrName);
143 preciseType = Iterables.getOnlyElement(nodepType);
144 } else {
145 Set<Type<?>> notNodepType =
146 Sets.filter(possibleTypes, Predicates.not(Predicates.in(NODEP_TYPES)));
147 Preconditions.checkState(notNodepType.size() == 1,
148 "There should be exactly one non-NODEP type associated with discriminator \"%s\""
149 + ", but found these: %s. Rule class: \"%s\", Attr: \"%s\"", discriminator,
150 notNodepType, ruleClassName, attrName);
151 preciseType = Iterables.getOnlyElement(notNodepType);
152 }
153 }
154 return preciseType;
155 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100156}