aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupValue.java
blob: e42ba4efac4a9e261ff74ae03fef61ccb103400b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright 2014 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.devtools.build.lib.skyframe;

import com.google.common.base.Preconditions;
import com.google.common.collect.Interner;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.concurrent.BlazeInterners;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.lib.syntax.BuildFileAST;
import com.google.devtools.build.skyframe.AbstractSkyKey;
import com.google.devtools.build.skyframe.NotComparableSkyValue;
import com.google.devtools.build.skyframe.SkyFunctionName;

/**
 * A value that represents an AST file lookup result. There are two subclasses: one for the case
 * where the file is found, and another for the case where the file is missing (but there are no
 * other errors).
 */
// In practice, if a ASTFileLookupValue is re-computed (i.e. not changed pruned), then it will
// almost certainly be unequal to the previous value. This is because of (i) the change-pruning
// semantics of the PackageLookupValue dep and the FileValue dep; consider the latter: if the
// FileValue for the bzl file has changed, then the contents of the bzl file probably changed and
// (ii) we don't currently have skylark-semantic-equality in BuildFileAST, so two BuildFileAST
// instances representing two different contents of a bzl file will be different.
// TODO(bazel-team): Consider doing better here. As a pre-req, we would need
// skylark-semantic-equality in BuildFileAST, rather than equality naively based on the contents of
// the bzl file. For a concrete example, the contents of comment lines do not currently impact
// skylark semantics.
public abstract class ASTFileLookupValue implements NotComparableSkyValue {
  public abstract boolean lookupSuccessful();
  public abstract BuildFileAST getAST();
  public abstract String getErrorMsg();

  /** If the file is found, this class encapsulates the parsed AST. */
  @AutoCodec.VisibleForSerialization
  public static class ASTLookupWithFile extends ASTFileLookupValue {
    private final BuildFileAST ast;

    private ASTLookupWithFile(BuildFileAST ast) {
      Preconditions.checkNotNull(ast);
      this.ast = ast;
    }

    @Override
    public boolean lookupSuccessful() {
      return true;
    }

    @Override
    public BuildFileAST getAST() {
      return this.ast;
    }

    @Override
    public String getErrorMsg() {
      throw new IllegalStateException(
          "attempted to retrieve unsuccessful lookup reason for successful lookup");
    }
  }

  /** If the file isn't found, this class encapsulates a message with the reason. */
  @AutoCodec.VisibleForSerialization
  public static class ASTLookupNoFile extends ASTFileLookupValue {
    private final String errorMsg;

    private ASTLookupNoFile(String errorMsg) {
      this.errorMsg = Preconditions.checkNotNull(errorMsg);
    }

    @Override
    public boolean lookupSuccessful() {
      return false;
    }

    @Override
    public BuildFileAST getAST() {
      throw new IllegalStateException("attempted to retrieve AST from an unsuccessful lookup");
    }

    @Override
    public String getErrorMsg() {
      return this.errorMsg;
    }
  }

  static ASTFileLookupValue forBadPackage(Label fileLabel, String reason) {
    return new ASTLookupNoFile(
        String.format("Unable to load package for '%s': %s", fileLabel, reason));
  }

  static ASTFileLookupValue forBadFile(Label fileLabel) {
    return new ASTLookupNoFile(
        String.format("Unable to load file '%s': file doesn't exist or isn't a file", fileLabel));
  }

  public static ASTFileLookupValue withFile(BuildFileAST ast) {
    return new ASTLookupWithFile(ast);
  }

  public static Key key(Label astFileLabel) {
    return ASTFileLookupValue.Key.create(astFileLabel);
  }

  @AutoCodec.VisibleForSerialization
  @AutoCodec
  static class Key extends AbstractSkyKey<Label> {
    private static final Interner<Key> interner = BlazeInterners.newWeakInterner();

    private Key(Label arg) {
      super(arg);
    }

    @AutoCodec.VisibleForSerialization
    @AutoCodec.Instantiator
    static Key create(Label arg) {
      return interner.intern(new Key(arg));
    }

    @Override
    public SkyFunctionName functionName() {
      return SkyFunctions.AST_FILE_LOOKUP;
    }
  }
}