/*
 * Copyright 2015-present Facebook, Inc.
 *
 * 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.facebook.buck.parser;

import com.facebook.buck.core.cell.Cell;
import com.facebook.buck.core.description.attr.ImplicitFlavorsInferringDescription;
import com.facebook.buck.core.model.BuildTarget;
import com.facebook.buck.core.model.EmptyTargetConfiguration;
import com.facebook.buck.core.model.Flavor;
import com.facebook.buck.core.model.HasDefaultFlavors;
import com.facebook.buck.core.model.TargetConfiguration;
import com.facebook.buck.core.model.targetgraph.TargetNode;
import com.facebook.buck.core.util.log.Logger;
import com.facebook.buck.event.BuckEventBus;
import com.facebook.buck.parser.TargetSpecResolver.TargetNodeProviderForSpecResolver;
import com.facebook.buck.parser.exceptions.BuildFileParseException;
import com.facebook.buck.parser.exceptions.BuildTargetException;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.ListenableFuture;
import java.nio.file.Path;
import java.util.function.Supplier;

/**
 * Evaluates build files using one of the supported interpreters and provides information about
 * build targets defined in them.
 *
 * <p>Computed targets are cached but are automatically invalidated if Watchman reports any
 * filesystem changes that may affect computed results.
 */
// TODO: remove after migration to configurable attributes
class DefaultParser extends AbstractParser {

  private static final Logger LOG = Logger.get(Parser.class);

  protected final TargetSpecResolver targetSpecResolver;

  DefaultParser(
      DaemonicParserState daemonicParserState,
      PerBuildStateFactory perBuildStateFactory,
      TargetSpecResolver targetSpecResolver,
      BuckEventBus eventBus,
      Supplier<ImmutableList<String>> targetPlatforms) {
    super(daemonicParserState, perBuildStateFactory, eventBus, targetPlatforms);
    this.targetSpecResolver = targetSpecResolver;
  }

  @SuppressWarnings("unused")
  @Override
  protected ImmutableSet<BuildTarget> collectBuildTargetsFromTargetNodeSpecs(
      ParsingContext parsingContext,
      PerBuildState state,
      Iterable<? extends TargetNodeSpec> targetNodeSpecs,
      TargetConfiguration targetConfiguration,
      boolean excludeConfigurationTargets)
      throws InterruptedException {
    TargetNodeProviderForSpecResolver<TargetNode<?>> targetNodeProvider =
        createTargetNodeProviderForSpecResolver(state);

    return ImmutableSet.copyOf(
        Iterables.concat(
            targetSpecResolver.resolveTargetSpecs(
                parsingContext.getCell(),
                targetNodeSpecs,
                // This parser doesn't support configured targets, explicitly erase information
                // about target configuration
                EmptyTargetConfiguration.INSTANCE,
                (buildTarget, targetNode, targetType) ->
                    applyDefaultFlavors(
                        buildTarget,
                        targetNode,
                        targetType,
                        parsingContext.getApplyDefaultFlavorsMode()),
                targetNodeProvider,
                (spec, nodes) -> spec.filter(nodes))));
  }

  static TargetNodeProviderForSpecResolver<TargetNode<?>> createTargetNodeProviderForSpecResolver(
      PerBuildState state) {
    return new TargetNodeProviderForSpecResolver<TargetNode<?>>() {
      @Override
      public ListenableFuture<TargetNode<?>> getTargetNodeJob(BuildTarget target)
          throws BuildTargetException {
        return state.getTargetNodeJob(target);
      }

      @Override
      public ListenableFuture<ImmutableList<TargetNode<?>>> getAllTargetNodesJob(
          Cell cell, Path buildFile, TargetConfiguration targetConfiguration)
          throws BuildTargetException {
        return state.getAllTargetNodesJob(cell, buildFile, targetConfiguration);
      }
    };
  }

  @Override
  public ImmutableList<TargetNode<?>> getAllTargetNodesWithTargetCompatibilityFiltering(
      PerBuildState state, Cell cell, Path buildFile, TargetConfiguration targetConfiguration)
      throws BuildFileParseException {
    return getAllTargetNodes(state, cell, buildFile, targetConfiguration);
  }

  @Override
  public ImmutableList<ImmutableSet<BuildTarget>> resolveTargetSpecs(
      ParsingContext parsingContext,
      Iterable<? extends TargetNodeSpec> specs,
      TargetConfiguration targetConfiguration)
      throws BuildFileParseException, InterruptedException {

    try (PerBuildState state =
        perBuildStateFactory.create(parsingContext, permState, targetPlatforms.get())) {
      TargetNodeProviderForSpecResolver<TargetNode<?>> targetNodeProvider =
          createTargetNodeProviderForSpecResolver(state);
      return targetSpecResolver.resolveTargetSpecs(
          parsingContext.getCell(),
          specs,
          // This parser doesn't support configured targets, explicitly erase information
          // about target configuration
          EmptyTargetConfiguration.INSTANCE,
          (buildTarget, targetNode, targetType) ->
              applyDefaultFlavors(
                  buildTarget, targetNode, targetType, parsingContext.getApplyDefaultFlavorsMode()),
          targetNodeProvider,
          (spec, nodes) -> spec.filter(nodes));
    }
  }

  @VisibleForTesting
  static BuildTarget applyDefaultFlavors(
      BuildTarget target,
      TargetNode<?> targetNode,
      TargetNodeSpec.TargetType targetType,
      ParserConfig.ApplyDefaultFlavorsMode applyDefaultFlavorsMode) {
    if (target.isFlavored()
        || (targetType == TargetNodeSpec.TargetType.MULTIPLE_TARGETS
            && applyDefaultFlavorsMode == ParserConfig.ApplyDefaultFlavorsMode.SINGLE)
        || applyDefaultFlavorsMode == ParserConfig.ApplyDefaultFlavorsMode.DISABLED) {
      return target;
    }

    ImmutableSortedSet<Flavor> defaultFlavors = ImmutableSortedSet.of();
    if (targetNode.getConstructorArg() instanceof HasDefaultFlavors) {
      defaultFlavors = ((HasDefaultFlavors) targetNode.getConstructorArg()).getDefaultFlavors();
      LOG.debug("Got default flavors %s from args of %s", defaultFlavors, target);
    }

    if (targetNode.getDescription() instanceof ImplicitFlavorsInferringDescription) {
      defaultFlavors =
          ((ImplicitFlavorsInferringDescription) targetNode.getDescription())
              .addImplicitFlavors(defaultFlavors);
      LOG.debug("Got default flavors %s from description of %s", defaultFlavors, target);
    }

    return target.withFlavors(defaultFlavors);
  }
}

@@ -2668,38 +2668,8 @@
  %7D%0A%0A
-  @SuppressWarnings(%22unused%22)%0A
   @O

Remove unnecessary SuppressWarnings in DefaultParser