Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ce53fde authored by Kadir Çetinkaya's avatar Kadir Çetinkaya Committed by Automerger Merge Worker
Browse files

Merge "Add CC analysis support to ide_query" into main am: 1ffcbde2 am: 2d708e54

parents 65428f5a 2d708e54
Loading
Loading
Loading
Loading
+80 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * 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 {
    default_applicable_licenses: ["Android-Apache-2.0"],
}

cc_defaults {
    name: "ide_query_cc_analyzer_defaults",
    compile_multilib: "64",
    defaults: [
        "llvm-build-host-tools-defaults",
    ],
    cflags: [
        // LLVM Sources do have unused parameters :(
        "-Wno-unused-parameter",
    ],
    target: {
        host: {
            cppflags: [
                "-fno-rtti",
            ],
        },
    },
}

cc_library_host_static {
    name: "builtin_headers",
    srcs: ["builtin_headers.cc"],
    generated_headers: ["clang_builtin_headers_resources"],
    defaults: ["ide_query_cc_analyzer_defaults"],
}

cc_library_host_static {
    name: "include_scanner",
    srcs: ["include_scanner.cc"],
    shared_libs: ["libclang-cpp_host"],
    static_libs: ["builtin_headers"],
    defaults: ["ide_query_cc_analyzer_defaults"],
}

cc_library_host_static {
    name: "analyzer",
    srcs: ["analyzer.cc"],
    shared_libs: ["libclang-cpp_host"],
    static_libs: [
        "include_scanner",
        "ide_query_proto",
    ],
    defaults: ["ide_query_cc_analyzer_defaults"],
}

cc_binary_host {
    name: "ide_query_cc_analyzer",
    defaults: ["ide_query_cc_analyzer_defaults"],
    srcs: ["main.cc"],
    shared_libs: [
        "libclang-cpp_host",
        "libprotobuf-cpp-full",
    ],
    static_libs: [
        "ide_query_proto",
        "builtin_headers",
        "include_scanner",
        "analyzer",
    ],
}
+147 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * 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.
 */
#include "analyzer.h"

#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/JSONCompilationDatabase.h"
#include "ide_query.pb.h"
#include "include_scanner.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/VirtualFileSystem.h"

namespace tools::ide_query::cc_analyzer {
namespace {
llvm::Expected<std::unique_ptr<clang::tooling::CompilationDatabase>> LoadCompDB(
    llvm::StringRef comp_db_path) {
  std::string err;
  std::unique_ptr<clang::tooling::CompilationDatabase> db =
      clang::tooling::JSONCompilationDatabase::loadFromFile(
          comp_db_path, err, clang::tooling::JSONCommandLineSyntax::AutoDetect);
  if (!db) {
    return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                   "Failed to load CDB: " + err);
  }
  // Provide some heuristic support for missing files.
  return inferMissingCompileCommands(std::move(db));
}
}  // namespace

::ide_query::DepsResponse GetDeps(::ide_query::RepoState state) {
  ::ide_query::DepsResponse results;
  auto db = LoadCompDB(state.comp_db_path());
  if (!db) {
    results.mutable_status()->set_code(::ide_query::Status::FAILURE);
    results.mutable_status()->set_message(llvm::toString(db.takeError()));
    return results;
  }
  for (llvm::StringRef active_file : state.active_file_path()) {
    auto& result = *results.add_deps();

    llvm::SmallString<256> abs_file(state.repo_dir());
    llvm::sys::path::append(abs_file, active_file);
    auto cmds = db->get()->getCompileCommands(active_file);
    if (cmds.empty()) {
      result.mutable_status()->set_code(::ide_query::Status::FAILURE);
      result.mutable_status()->set_message(
          llvm::Twine("Can't find compile flags for file: ", abs_file).str());
      continue;
    }
    result.set_source_file(active_file.str());
    llvm::StringRef file = cmds[0].Filename;
    if (llvm::StringRef actual_file(cmds[0].Heuristic);
        actual_file.consume_front("inferred from ")) {
      file = actual_file;
    }
    // TODO: Query ninja graph to figure out a minimal set of targets to build.
    result.add_build_target(file.str() + "^");
  }
  return results;
}

::ide_query::IdeAnalysis GetBuildInputs(::ide_query::RepoState state) {
  auto db = LoadCompDB(state.comp_db_path());
  ::ide_query::IdeAnalysis results;
  if (!db) {
    results.mutable_status()->set_code(::ide_query::Status::FAILURE);
    results.mutable_status()->set_message(llvm::toString(db.takeError()));
    return results;
  }
  std::string repo_dir = state.repo_dir();
  if (!repo_dir.empty() && repo_dir.back() == '/') repo_dir.pop_back();

  llvm::SmallString<256> genfile_root_abs(repo_dir);
  llvm::sys::path::append(genfile_root_abs, state.out_dir());
  if (genfile_root_abs.empty() || genfile_root_abs.back() != '/') {
    genfile_root_abs.push_back('/');
  }

  results.set_build_artifact_root(state.out_dir());
  for (llvm::StringRef active_file : state.active_file_path()) {
    auto& result = *results.add_sources();
    result.set_path(active_file.str());

    llvm::SmallString<256> abs_file(repo_dir);
    llvm::sys::path::append(abs_file, active_file);
    auto cmds = db->get()->getCompileCommands(abs_file);
    if (cmds.empty()) {
      result.mutable_status()->set_code(::ide_query::Status::FAILURE);
      result.mutable_status()->set_message(
          llvm::Twine("Can't find compile flags for file: ", abs_file).str());
      continue;
    }
    const auto& cmd = cmds.front();
    llvm::StringRef working_dir = cmd.Directory;
    if (!working_dir.consume_front(repo_dir)) {
      result.mutable_status()->set_code(::ide_query::Status::FAILURE);
      result.mutable_status()->set_message("Command working dir " +
                                           working_dir.str() +
                                           "outside repository " + repo_dir);
      continue;
    }
    working_dir = working_dir.ltrim('/');
    result.set_working_dir(working_dir.str());
    for (auto& arg : cmd.CommandLine) result.add_compiler_arguments(arg);

    auto includes =
        ScanIncludes(cmds.front(), llvm::vfs::createPhysicalFileSystem());
    if (!includes) {
      result.mutable_status()->set_code(::ide_query::Status::FAILURE);
      result.mutable_status()->set_message(
          llvm::toString(includes.takeError()));
      continue;
    }

    for (auto& [req_input, contents] : *includes) {
      llvm::StringRef req_input_ref(req_input);
      // We're only interested in generated files.
      if (!req_input_ref.consume_front(genfile_root_abs)) continue;
      auto& genfile = *result.add_generated();
      genfile.set_path(req_input_ref.str());
      genfile.set_contents(std::move(contents));
    }
  }
  return results;
}
}  // namespace tools::ide_query::cc_analyzer
+34 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * 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.
 */

#ifndef _TOOLS_IDE_QUERY_CC_ANALYZER_ANALYZER_H_
#define _TOOLS_IDE_QUERY_CC_ANALYZER_ANALYZER_H_

#include "ide_query.pb.h"

namespace tools::ide_query::cc_analyzer {

// Scans the build graph and returns target names from the build graph to
// generate all the dependencies for the active files.
::ide_query::DepsResponse GetDeps(::ide_query::RepoState state);

// Scans the sources and returns all the source files required for analyzing the
// active files.
::ide_query::IdeAnalysis GetBuildInputs(::ide_query::RepoState state);

}  // namespace tools::ide_query::cc_analyzer

#endif
+25 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * 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.
 */
#include "builtin_headers.h"

#include <cstddef>

#include "clang_builtin_headers_resources.inc"

const struct FileToc *builtin_headers_create() { return kPackedFiles; }
size_t builtin_headers_size() {
  return sizeof(kPackedFiles) / sizeof(FileToc) - 1;
}
+29 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * 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.
 */
#ifndef _TOOLS_IDE_QUERY_CC_ANALYZER_BUILTIN_HEADERS_H_
#define _TOOLS_IDE_QUERY_CC_ANALYZER_BUILTIN_HEADERS_H_

#include <cstddef>

struct FileToc {
  const char *name;
  const char *data;
};

const struct FileToc *builtin_headers_create();
size_t builtin_headers_size();

#endif
Loading