[clang-query] Remove support for srcloc output (#92442)
This functionality was added about three years ago, but has been in a significantly broken state since it was added. It has begun to cause a maintenance burden for work in Clang (largely due to the complexity of having two levels of code generation involved), and the original author is unable to help maintain it. Because it only worked under limited circumstances and because of the maintenance burden, it is being removed. If someone wishes to resurrect the functionality, they should hopefully be able to do so from this one commit. Fixes #82591
This commit is contained in:
parent
a68d20e986
commit
371eccd5df
@ -20,7 +20,6 @@ clang_target_link_libraries(clangQuery
|
||||
clangBasic
|
||||
clangDynamicASTMatchers
|
||||
clangFrontend
|
||||
clangTooling
|
||||
clangSerialization
|
||||
)
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/Frontend/ASTUnit.h"
|
||||
#include "clang/Frontend/TextDiagnostic.h"
|
||||
#include "clang/Tooling/NodeIntrospection.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <optional>
|
||||
|
||||
@ -69,8 +68,6 @@ bool HelpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
|
||||
"Diagnostic location for bound nodes.\n"
|
||||
" detailed-ast "
|
||||
"Detailed AST output for bound nodes.\n"
|
||||
" srcloc "
|
||||
"Source locations and ranges for bound nodes.\n"
|
||||
" dump "
|
||||
"Detailed AST output for bound nodes (alias of detailed-ast).\n\n";
|
||||
return true;
|
||||
@ -91,90 +88,6 @@ struct CollectBoundNodes : MatchFinder::MatchCallback {
|
||||
}
|
||||
};
|
||||
|
||||
void dumpLocations(llvm::raw_ostream &OS, DynTypedNode Node, ASTContext &Ctx,
|
||||
const DiagnosticsEngine &Diags, SourceManager const &SM) {
|
||||
auto Locs = clang::tooling::NodeIntrospection::GetLocations(Node);
|
||||
|
||||
auto PrintLocations = [](llvm::raw_ostream &OS, auto Iter, auto End) {
|
||||
auto CommonEntry = Iter->first;
|
||||
auto Scout = Iter;
|
||||
SmallVector<std::string> LocationStrings;
|
||||
while (Scout->first == CommonEntry) {
|
||||
LocationStrings.push_back(
|
||||
tooling::LocationCallFormatterCpp::format(*Iter->second));
|
||||
if (Scout == End)
|
||||
break;
|
||||
++Scout;
|
||||
if (Scout->first == CommonEntry)
|
||||
++Iter;
|
||||
}
|
||||
llvm::sort(LocationStrings);
|
||||
for (auto &LS : LocationStrings) {
|
||||
OS << " * \"" << LS << "\"\n";
|
||||
}
|
||||
return Iter;
|
||||
};
|
||||
|
||||
TextDiagnostic TD(OS, Ctx.getLangOpts(), &Diags.getDiagnosticOptions());
|
||||
|
||||
for (auto Iter = Locs.LocationAccessors.begin();
|
||||
Iter != Locs.LocationAccessors.end(); ++Iter) {
|
||||
if (!Iter->first.isValid())
|
||||
continue;
|
||||
|
||||
TD.emitDiagnostic(FullSourceLoc(Iter->first, SM), DiagnosticsEngine::Note,
|
||||
"source locations here", std::nullopt, std::nullopt);
|
||||
|
||||
Iter = PrintLocations(OS, Iter, Locs.LocationAccessors.end());
|
||||
OS << '\n';
|
||||
}
|
||||
|
||||
for (auto Iter = Locs.RangeAccessors.begin();
|
||||
Iter != Locs.RangeAccessors.end(); ++Iter) {
|
||||
|
||||
if (!Iter->first.getBegin().isValid())
|
||||
continue;
|
||||
|
||||
if (SM.getPresumedLineNumber(Iter->first.getBegin()) !=
|
||||
SM.getPresumedLineNumber(Iter->first.getEnd()))
|
||||
continue;
|
||||
|
||||
TD.emitDiagnostic(
|
||||
FullSourceLoc(Iter->first.getBegin(), SM), DiagnosticsEngine::Note,
|
||||
"source ranges here " + Iter->first.printToString(SM),
|
||||
CharSourceRange::getTokenRange(Iter->first), std::nullopt);
|
||||
|
||||
Iter = PrintLocations(OS, Iter, Locs.RangeAccessors.end());
|
||||
}
|
||||
for (auto Iter = Locs.RangeAccessors.begin();
|
||||
Iter != Locs.RangeAccessors.end(); ++Iter) {
|
||||
|
||||
if (!Iter->first.getBegin().isValid())
|
||||
continue;
|
||||
|
||||
if (SM.getPresumedLineNumber(Iter->first.getBegin()) ==
|
||||
SM.getPresumedLineNumber(Iter->first.getEnd()))
|
||||
continue;
|
||||
|
||||
TD.emitDiagnostic(
|
||||
FullSourceLoc(Iter->first.getBegin(), SM), DiagnosticsEngine::Note,
|
||||
"source range " + Iter->first.printToString(SM) + " starting here...",
|
||||
CharSourceRange::getTokenRange(Iter->first), std::nullopt);
|
||||
|
||||
auto ColNum = SM.getPresumedColumnNumber(Iter->first.getEnd());
|
||||
auto LastLineLoc = Iter->first.getEnd().getLocWithOffset(-(ColNum - 1));
|
||||
|
||||
TD.emitDiagnostic(FullSourceLoc(Iter->first.getEnd(), SM),
|
||||
DiagnosticsEngine::Note, "... ending here",
|
||||
CharSourceRange::getTokenRange(
|
||||
SourceRange(LastLineLoc, Iter->first.getEnd())),
|
||||
std::nullopt);
|
||||
|
||||
Iter = PrintLocations(OS, Iter, Locs.RangeAccessors.end());
|
||||
}
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
|
||||
@ -195,8 +108,7 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto &Ctx = AST->getASTContext();
|
||||
const auto &SM = Ctx.getSourceManager();
|
||||
ASTContext &Ctx = AST->getASTContext();
|
||||
Ctx.getParentMapContext().setTraversalKind(QS.TK);
|
||||
Finder.matchAST(Ctx);
|
||||
|
||||
@ -244,19 +156,11 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
|
||||
}
|
||||
if (QS.DetailedASTOutput) {
|
||||
OS << "Binding for \"" << BI->first << "\":\n";
|
||||
const ASTContext &Ctx = AST->getASTContext();
|
||||
ASTDumper Dumper(OS, Ctx, AST->getDiagnostics().getShowColors());
|
||||
Dumper.SetTraversalKind(QS.TK);
|
||||
Dumper.Visit(BI->second);
|
||||
OS << "\n";
|
||||
}
|
||||
if (QS.SrcLocOutput) {
|
||||
OS << "\n \"" << BI->first << "\" Source locations\n";
|
||||
OS << " " << std::string(19 + BI->first.size(), '-') << '\n';
|
||||
|
||||
dumpLocations(OS, BI->second, Ctx, AST->getDiagnostics(), SM);
|
||||
OS << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (MI->getMap().empty())
|
||||
|
@ -17,7 +17,7 @@
|
||||
namespace clang {
|
||||
namespace query {
|
||||
|
||||
enum OutputKind { OK_Diag, OK_Print, OK_DetailedAST, OK_SrcLoc };
|
||||
enum OutputKind { OK_Diag, OK_Print, OK_DetailedAST };
|
||||
|
||||
enum QueryKind {
|
||||
QK_Invalid,
|
||||
@ -149,7 +149,6 @@ struct SetExclusiveOutputQuery : Query {
|
||||
QS.DiagOutput = false;
|
||||
QS.DetailedASTOutput = false;
|
||||
QS.PrintOutput = false;
|
||||
QS.SrcLocOutput = false;
|
||||
QS.*Var = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "QuerySession.h"
|
||||
#include "clang/ASTMatchers/Dynamic/Parser.h"
|
||||
#include "clang/Basic/CharInfo.h"
|
||||
#include "clang/Tooling/NodeIntrospection.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include <optional>
|
||||
@ -104,19 +103,16 @@ QueryRef QueryParser::parseSetBool(bool QuerySession::*Var) {
|
||||
|
||||
template <typename QueryType> QueryRef QueryParser::parseSetOutputKind() {
|
||||
StringRef ValStr;
|
||||
bool HasIntrospection = tooling::NodeIntrospection::hasIntrospectionSupport();
|
||||
unsigned OutKind =
|
||||
LexOrCompleteWord<unsigned>(this, ValStr)
|
||||
.Case("diag", OK_Diag)
|
||||
.Case("print", OK_Print)
|
||||
.Case("detailed-ast", OK_DetailedAST)
|
||||
.Case("srcloc", OK_SrcLoc, /*IsCompletion=*/HasIntrospection)
|
||||
.Case("dump", OK_DetailedAST)
|
||||
.Default(~0u);
|
||||
unsigned OutKind = LexOrCompleteWord<unsigned>(this, ValStr)
|
||||
.Case("diag", OK_Diag)
|
||||
.Case("print", OK_Print)
|
||||
.Case("detailed-ast", OK_DetailedAST)
|
||||
.Case("dump", OK_DetailedAST)
|
||||
.Default(~0u);
|
||||
if (OutKind == ~0u) {
|
||||
return new InvalidQuery("expected 'diag', 'print', 'detailed-ast'" +
|
||||
StringRef(HasIntrospection ? ", 'srcloc'" : "") +
|
||||
" or 'dump', got '" + ValStr + "'");
|
||||
return new InvalidQuery("expected 'diag', 'print', 'detailed-ast' or "
|
||||
"'dump', got '" +
|
||||
ValStr + "'");
|
||||
}
|
||||
|
||||
switch (OutKind) {
|
||||
@ -126,10 +122,6 @@ template <typename QueryType> QueryRef QueryParser::parseSetOutputKind() {
|
||||
return new QueryType(&QuerySession::DiagOutput);
|
||||
case OK_Print:
|
||||
return new QueryType(&QuerySession::PrintOutput);
|
||||
case OK_SrcLoc:
|
||||
if (HasIntrospection)
|
||||
return new QueryType(&QuerySession::SrcLocOutput);
|
||||
return new InvalidQuery("'srcloc' output support is not available.");
|
||||
}
|
||||
|
||||
llvm_unreachable("Invalid output kind");
|
||||
|
@ -25,15 +25,14 @@ class QuerySession {
|
||||
public:
|
||||
QuerySession(llvm::ArrayRef<std::unique_ptr<ASTUnit>> ASTs)
|
||||
: ASTs(ASTs), PrintOutput(false), DiagOutput(true),
|
||||
DetailedASTOutput(false), SrcLocOutput(false), BindRoot(true),
|
||||
PrintMatcher(false), Terminate(false), TK(TK_AsIs) {}
|
||||
DetailedASTOutput(false), BindRoot(true), PrintMatcher(false),
|
||||
Terminate(false), TK(TK_AsIs) {}
|
||||
|
||||
llvm::ArrayRef<std::unique_ptr<ASTUnit>> ASTs;
|
||||
|
||||
bool PrintOutput;
|
||||
bool DiagOutput;
|
||||
bool DetailedASTOutput;
|
||||
bool SrcLocOutput;
|
||||
|
||||
bool BindRoot;
|
||||
bool PrintMatcher;
|
||||
|
@ -94,6 +94,8 @@ Improvements to clang-query
|
||||
from an external file, allowing the cost of reading the compilation database
|
||||
and building the AST to be imposed just once for faster prototyping.
|
||||
|
||||
- Removed support for ``enable output srcloc``. Fixes #GH82591
|
||||
|
||||
Improvements to clang-rename
|
||||
----------------------------
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "QueryParser.h"
|
||||
#include "Query.h"
|
||||
#include "QuerySession.h"
|
||||
#include "clang/Tooling/NodeIntrospection.h"
|
||||
#include "llvm/LineEditor/LineEditor.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
@ -61,7 +60,6 @@ TEST_F(QueryParserTest, Quit) {
|
||||
|
||||
TEST_F(QueryParserTest, Set) {
|
||||
|
||||
bool HasIntrospection = tooling::NodeIntrospection::hasIntrospectionSupport();
|
||||
QueryRef Q = parse("set");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);
|
||||
@ -72,13 +70,8 @@ TEST_F(QueryParserTest, Set) {
|
||||
|
||||
Q = parse("set output");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
if (HasIntrospection)
|
||||
EXPECT_EQ(
|
||||
"expected 'diag', 'print', 'detailed-ast', 'srcloc' or 'dump', got ''",
|
||||
cast<InvalidQuery>(Q)->ErrStr);
|
||||
else
|
||||
EXPECT_EQ("expected 'diag', 'print', 'detailed-ast' or 'dump', got ''",
|
||||
cast<InvalidQuery>(Q)->ErrStr);
|
||||
EXPECT_EQ("expected 'diag', 'print', 'detailed-ast' or 'dump', got ''",
|
||||
cast<InvalidQuery>(Q)->ErrStr);
|
||||
|
||||
Q = parse("set bind-root true foo");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
@ -86,13 +79,8 @@ TEST_F(QueryParserTest, Set) {
|
||||
|
||||
Q = parse("set output foo");
|
||||
ASSERT_TRUE(isa<InvalidQuery>(Q));
|
||||
if (HasIntrospection)
|
||||
EXPECT_EQ("expected 'diag', 'print', 'detailed-ast', 'srcloc' or 'dump', "
|
||||
"got 'foo'",
|
||||
cast<InvalidQuery>(Q)->ErrStr);
|
||||
else
|
||||
EXPECT_EQ("expected 'diag', 'print', 'detailed-ast' or 'dump', got 'foo'",
|
||||
cast<InvalidQuery>(Q)->ErrStr);
|
||||
EXPECT_EQ("expected 'diag', 'print', 'detailed-ast' or 'dump', got 'foo'",
|
||||
cast<InvalidQuery>(Q)->ErrStr);
|
||||
|
||||
Q = parse("set output dump");
|
||||
ASSERT_TRUE(isa<SetExclusiveOutputQuery >(Q));
|
||||
@ -232,10 +220,8 @@ TEST_F(QueryParserTest, Complete) {
|
||||
EXPECT_EQ("output ", Comps[0].TypedText);
|
||||
EXPECT_EQ("output", Comps[0].DisplayText);
|
||||
|
||||
bool HasIntrospection = tooling::NodeIntrospection::hasIntrospectionSupport();
|
||||
|
||||
Comps = QueryParser::complete("enable output ", 14, QS);
|
||||
ASSERT_EQ(HasIntrospection ? 5u : 4u, Comps.size());
|
||||
ASSERT_EQ(4u, Comps.size());
|
||||
|
||||
EXPECT_EQ("diag ", Comps[0].TypedText);
|
||||
EXPECT_EQ("diag", Comps[0].DisplayText);
|
||||
@ -243,12 +229,8 @@ TEST_F(QueryParserTest, Complete) {
|
||||
EXPECT_EQ("print", Comps[1].DisplayText);
|
||||
EXPECT_EQ("detailed-ast ", Comps[2].TypedText);
|
||||
EXPECT_EQ("detailed-ast", Comps[2].DisplayText);
|
||||
if (HasIntrospection) {
|
||||
EXPECT_EQ("srcloc ", Comps[3].TypedText);
|
||||
EXPECT_EQ("srcloc", Comps[3].DisplayText);
|
||||
}
|
||||
EXPECT_EQ("dump ", Comps[HasIntrospection ? 4 : 3].TypedText);
|
||||
EXPECT_EQ("dump", Comps[HasIntrospection ? 4 : 3].DisplayText);
|
||||
EXPECT_EQ("dump ", Comps[3].TypedText);
|
||||
EXPECT_EQ("dump", Comps[3].DisplayText);
|
||||
|
||||
Comps = QueryParser::complete("set traversal ", 14, QS);
|
||||
ASSERT_EQ(2u, Comps.size());
|
||||
|
@ -252,7 +252,6 @@ clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h
|
||||
clang/include/clang/Tooling/DiagnosticsYaml.h
|
||||
clang/include/clang/Tooling/Execution.h
|
||||
clang/include/clang/Tooling/JSONCompilationDatabase.h
|
||||
clang/include/clang/Tooling/NodeIntrospection.h
|
||||
clang/include/clang/Tooling/Refactoring.h
|
||||
clang/include/clang/Tooling/StandaloneExecution.h
|
||||
clang/include/clang/Tooling/ToolExecutorPluginRegistry.h
|
||||
@ -562,15 +561,11 @@ clang/lib/Tooling/Execution.cpp
|
||||
clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
|
||||
clang/lib/Tooling/FixIt.cpp
|
||||
clang/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp
|
||||
clang/lib/Tooling/NodeIntrospection.cpp
|
||||
clang/lib/Tooling/StandaloneExecution.cpp
|
||||
clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
|
||||
clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
|
||||
clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
|
||||
clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
|
||||
clang/lib/Tooling/DumpTool/APIData.h
|
||||
clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.h
|
||||
clang/lib/Tooling/DumpTool/ClangSrcLocDump.cpp
|
||||
clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
|
||||
clang/lib/Tooling/Inclusions/IncludeStyle.cpp
|
||||
clang/lib/Tooling/Inclusions/StandardLibrary.cpp
|
||||
|
@ -1,101 +0,0 @@
|
||||
//===- NodeIntrospection.h ------------------------------------*- C++ -*---===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the implementation of the NodeIntrospection.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TOOLING_NODEINTROSPECTION_H
|
||||
#define LLVM_CLANG_TOOLING_NODEINTROSPECTION_H
|
||||
|
||||
#include "clang/AST/ASTTypeTraits.h"
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include <set>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Stmt;
|
||||
class Decl;
|
||||
class CXXCtorInitializer;
|
||||
class NestedNameSpecifierLoc;
|
||||
class TemplateArgumentLoc;
|
||||
class CXXBaseSpecifier;
|
||||
struct DeclarationNameInfo;
|
||||
|
||||
namespace tooling {
|
||||
|
||||
class LocationCall;
|
||||
using SharedLocationCall = llvm::IntrusiveRefCntPtr<LocationCall>;
|
||||
|
||||
class LocationCall : public llvm::ThreadSafeRefCountedBase<LocationCall> {
|
||||
public:
|
||||
enum LocationCallFlags { NoFlags, ReturnsPointer, IsCast };
|
||||
LocationCall(SharedLocationCall on, std::string name,
|
||||
LocationCallFlags flags = NoFlags)
|
||||
: m_flags(flags), m_on(std::move(on)), m_name(std::move(name)) {}
|
||||
|
||||
LocationCall *on() const { return m_on.get(); }
|
||||
StringRef name() const { return m_name; }
|
||||
bool returnsPointer() const { return m_flags & ReturnsPointer; }
|
||||
bool isCast() const { return m_flags & IsCast; }
|
||||
|
||||
private:
|
||||
LocationCallFlags m_flags;
|
||||
SharedLocationCall m_on;
|
||||
std::string m_name;
|
||||
};
|
||||
|
||||
class LocationCallFormatterCpp {
|
||||
public:
|
||||
static void print(const LocationCall &Call, llvm::raw_ostream &OS);
|
||||
static std::string format(const LocationCall &Call);
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
struct RangeLessThan {
|
||||
bool operator()(std::pair<SourceRange, SharedLocationCall> const &LHS,
|
||||
std::pair<SourceRange, SharedLocationCall> const &RHS) const;
|
||||
bool
|
||||
operator()(std::pair<SourceLocation, SharedLocationCall> const &LHS,
|
||||
std::pair<SourceLocation, SharedLocationCall> const &RHS) const;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Note that this container stores unique results in a deterministic, but
|
||||
// the location calls are in an unspecified order. Clients which desire
|
||||
// a particular order for the location calls, such as alphabetical,
|
||||
// should sort results after retrieval, because the order is dependent
|
||||
// on how the LocationCalls are formatted.
|
||||
template <typename T, typename U>
|
||||
using UniqueMultiMap = std::set<std::pair<T, U>, internal::RangeLessThan>;
|
||||
|
||||
using SourceLocationMap = UniqueMultiMap<SourceLocation, SharedLocationCall>;
|
||||
using SourceRangeMap = UniqueMultiMap<SourceRange, SharedLocationCall>;
|
||||
|
||||
struct NodeLocationAccessors {
|
||||
SourceLocationMap LocationAccessors;
|
||||
SourceRangeMap RangeAccessors;
|
||||
};
|
||||
|
||||
namespace NodeIntrospection {
|
||||
bool hasIntrospectionSupport();
|
||||
NodeLocationAccessors GetLocations(clang::Stmt const *Object);
|
||||
NodeLocationAccessors GetLocations(clang::Decl const *Object);
|
||||
NodeLocationAccessors GetLocations(clang::CXXCtorInitializer const *Object);
|
||||
NodeLocationAccessors GetLocations(clang::NestedNameSpecifierLoc const &);
|
||||
NodeLocationAccessors GetLocations(clang::TemplateArgumentLoc const &);
|
||||
NodeLocationAccessors GetLocations(clang::CXXBaseSpecifier const *);
|
||||
NodeLocationAccessors GetLocations(clang::TypeLoc const &);
|
||||
NodeLocationAccessors GetLocations(clang::DeclarationNameInfo const &);
|
||||
NodeLocationAccessors GetLocations(clang::DynTypedNode const &Node);
|
||||
} // namespace NodeIntrospection
|
||||
} // namespace tooling
|
||||
} // namespace clang
|
||||
#endif
|
@ -9,98 +9,10 @@ add_subdirectory(Core)
|
||||
add_subdirectory(Inclusions)
|
||||
add_subdirectory(Refactoring)
|
||||
add_subdirectory(ASTDiff)
|
||||
add_subdirectory(DumpTool)
|
||||
add_subdirectory(Syntax)
|
||||
add_subdirectory(DependencyScanning)
|
||||
add_subdirectory(Transformer)
|
||||
|
||||
# Replace the last lib component of the current binary directory with include
|
||||
string(FIND ${CMAKE_CURRENT_BINARY_DIR} "/lib/" PATH_LIB_START REVERSE)
|
||||
if(PATH_LIB_START EQUAL -1)
|
||||
message(FATAL_ERROR "Couldn't find lib component in binary directory")
|
||||
endif()
|
||||
math(EXPR PATH_LIB_END "${PATH_LIB_START}+5")
|
||||
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD)
|
||||
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} ${PATH_LIB_END} -1 PATH_TAIL)
|
||||
string(CONCAT BINARY_INCLUDE_DIR ${PATH_HEAD} "/include/clang/" ${PATH_TAIL})
|
||||
|
||||
if (NOT Python3_EXECUTABLE
|
||||
OR APPLE
|
||||
OR CMAKE_CROSSCOMPILING
|
||||
OR GENERATOR_IS_MULTI_CONFIG
|
||||
OR NOT LLVM_NATIVE_ARCH IN_LIST LLVM_TARGETS_TO_BUILD
|
||||
)
|
||||
configure_file(
|
||||
EmptyNodeIntrospection.inc.in
|
||||
${BINARY_INCLUDE_DIR}/NodeIntrospection.inc
|
||||
COPYONLY
|
||||
)
|
||||
set(CLANG_TOOLING_BUILD_AST_INTROSPECTION "OFF" CACHE BOOL "")
|
||||
else()
|
||||
# The generation of ASTNodeAPI.json takes a long time in a
|
||||
# Debug build due to parsing AST.h. Disable the processing
|
||||
# but setting CLANG_TOOLING_BUILD_AST_INTROSPECTION as an
|
||||
# internal hidden setting to override.
|
||||
# When the processing is disabled, a trivial/empty JSON
|
||||
# file is generated by clang-ast-dump and generate_cxx_src_locs.py
|
||||
# generates the same API, but with a trivial implementation.
|
||||
option(CLANG_TOOLING_BUILD_AST_INTROSPECTION "Enable AST introspection" TRUE)
|
||||
|
||||
set(skip_expensive_processing $<OR:$<CONFIG:Debug>,$<NOT:$<BOOL:${CLANG_TOOLING_BUILD_AST_INTROSPECTION}>>>)
|
||||
|
||||
set(implicitDirs)
|
||||
foreach(implicitDir ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
|
||||
list(APPEND implicitDirs -I ${implicitDir})
|
||||
endforeach()
|
||||
|
||||
include(GetClangResourceDir)
|
||||
get_clang_resource_dir(resource_dir PREFIX ${LLVM_BINARY_DIR})
|
||||
add_custom_command(
|
||||
COMMENT Generate ASTNodeAPI.json
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ASTNodeAPI.json
|
||||
DEPENDS clang-ast-dump clang-resource-headers
|
||||
COMMAND
|
||||
$<TARGET_FILE:clang-ast-dump>
|
||||
# Skip this in debug mode because parsing AST.h is too slow
|
||||
--skip-processing=${skip_expensive_processing}
|
||||
-I ${resource_dir}/include
|
||||
-I ${CLANG_SOURCE_DIR}/include
|
||||
-I ${LLVM_BINARY_DIR}/tools/clang/include
|
||||
-I ${LLVM_BINARY_DIR}/include
|
||||
-I ${LLVM_SOURCE_DIR}/include
|
||||
${implicitDirs}
|
||||
--json-output-path ${CMAKE_CURRENT_BINARY_DIR}/ASTNodeAPI.json
|
||||
)
|
||||
|
||||
add_custom_target(run-ast-api-dump-tool
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ASTNodeAPI.json
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
COMMENT Generate NodeIntrospection.inc
|
||||
OUTPUT ${BINARY_INCLUDE_DIR}/NodeIntrospection.inc
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ASTNodeAPI.json
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/DumpTool/generate_cxx_src_locs.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/EmptyNodeIntrospection.inc.in
|
||||
COMMAND
|
||||
${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/DumpTool/generate_cxx_src_locs.py
|
||||
--json-input-path ${CMAKE_CURRENT_BINARY_DIR}/ASTNodeAPI.json
|
||||
--output-file NodeIntrospection.inc
|
||||
--use-empty-implementation ${skip_expensive_processing}
|
||||
--empty-implementation
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/EmptyNodeIntrospection.inc.in"
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E copy_if_different
|
||||
${CMAKE_CURRENT_BINARY_DIR}/NodeIntrospection.inc
|
||||
${BINARY_INCLUDE_DIR}/NodeIntrospection.inc
|
||||
)
|
||||
|
||||
add_custom_target(run-ast-api-generate-tool
|
||||
DEPENDS
|
||||
${BINARY_INCLUDE_DIR}/NodeIntrospection.inc
|
||||
)
|
||||
endif()
|
||||
|
||||
add_clang_library(clangTooling
|
||||
AllTUsExecution.cpp
|
||||
ArgumentsAdjusters.cpp
|
||||
@ -116,8 +28,6 @@ add_clang_library(clangTooling
|
||||
Refactoring.cpp
|
||||
RefactoringCallbacks.cpp
|
||||
StandaloneExecution.cpp
|
||||
NodeIntrospection.cpp
|
||||
${BINARY_INCLUDE_DIR}/NodeIntrospection.inc
|
||||
Tooling.cpp
|
||||
|
||||
DEPENDS
|
||||
|
@ -1,31 +0,0 @@
|
||||
//===- APIData.h ---------------------------------------------*- C++ -*----===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LIB_TOOLING_DUMPTOOL_APIDATA_H
|
||||
#define LLVM_CLANG_LIB_TOOLING_DUMPTOOL_APIDATA_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
namespace tooling {
|
||||
|
||||
struct ClassData {
|
||||
std::vector<std::string> ASTClassLocations;
|
||||
std::vector<std::string> ASTClassRanges;
|
||||
std::vector<std::string> TemplateParms;
|
||||
std::vector<std::string> TypeSourceInfos;
|
||||
std::vector<std::string> TypeLocs;
|
||||
std::vector<std::string> NestedNameLocs;
|
||||
std::vector<std::string> DeclNameInfos;
|
||||
};
|
||||
|
||||
} // namespace tooling
|
||||
} // namespace clang
|
||||
|
||||
#endif
|
@ -1,271 +0,0 @@
|
||||
//===- ASTSrcLocProcessor.cpp --------------------------------*- C++ -*----===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ASTSrcLocProcessor.h"
|
||||
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "llvm/Support/JSON.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
|
||||
using namespace clang::tooling;
|
||||
using namespace llvm;
|
||||
using namespace clang::ast_matchers;
|
||||
|
||||
ASTSrcLocProcessor::ASTSrcLocProcessor(StringRef JsonPath)
|
||||
: JsonPath(JsonPath) {
|
||||
|
||||
MatchFinder::MatchFinderOptions FinderOptions;
|
||||
|
||||
Finder = std::make_unique<MatchFinder>(std::move(FinderOptions));
|
||||
Finder->addMatcher(
|
||||
cxxRecordDecl(
|
||||
isDefinition(),
|
||||
isSameOrDerivedFrom(
|
||||
namedDecl(
|
||||
hasAnyName(
|
||||
"clang::Stmt", "clang::Decl", "clang::CXXCtorInitializer",
|
||||
"clang::NestedNameSpecifierLoc",
|
||||
"clang::TemplateArgumentLoc", "clang::CXXBaseSpecifier",
|
||||
"clang::DeclarationNameInfo", "clang::TypeLoc"))
|
||||
.bind("nodeClade")),
|
||||
optionally(isDerivedFrom(cxxRecordDecl().bind("derivedFrom"))))
|
||||
.bind("className"),
|
||||
this);
|
||||
Finder->addMatcher(
|
||||
cxxRecordDecl(isDefinition(), hasAnyName("clang::PointerLikeTypeLoc",
|
||||
"clang::TypeofLikeTypeLoc"))
|
||||
.bind("templateName"),
|
||||
this);
|
||||
}
|
||||
|
||||
std::unique_ptr<clang::ASTConsumer>
|
||||
ASTSrcLocProcessor::createASTConsumer(clang::CompilerInstance &Compiler,
|
||||
StringRef File) {
|
||||
return Finder->newASTConsumer();
|
||||
}
|
||||
|
||||
llvm::json::Object toJSON(llvm::StringMap<std::vector<StringRef>> const &Obj) {
|
||||
using llvm::json::toJSON;
|
||||
|
||||
llvm::json::Object JsonObj;
|
||||
for (const auto &Item : Obj) {
|
||||
JsonObj[Item.first()] = Item.second;
|
||||
}
|
||||
return JsonObj;
|
||||
}
|
||||
|
||||
llvm::json::Object toJSON(llvm::StringMap<std::string> const &Obj) {
|
||||
using llvm::json::toJSON;
|
||||
|
||||
llvm::json::Object JsonObj;
|
||||
for (const auto &Item : Obj) {
|
||||
JsonObj[Item.first()] = Item.second;
|
||||
}
|
||||
return JsonObj;
|
||||
}
|
||||
|
||||
llvm::json::Object toJSON(ClassData const &Obj) {
|
||||
llvm::json::Object JsonObj;
|
||||
|
||||
if (!Obj.ASTClassLocations.empty())
|
||||
JsonObj["sourceLocations"] = Obj.ASTClassLocations;
|
||||
if (!Obj.ASTClassRanges.empty())
|
||||
JsonObj["sourceRanges"] = Obj.ASTClassRanges;
|
||||
if (!Obj.TemplateParms.empty())
|
||||
JsonObj["templateParms"] = Obj.TemplateParms;
|
||||
if (!Obj.TypeSourceInfos.empty())
|
||||
JsonObj["typeSourceInfos"] = Obj.TypeSourceInfos;
|
||||
if (!Obj.TypeLocs.empty())
|
||||
JsonObj["typeLocs"] = Obj.TypeLocs;
|
||||
if (!Obj.NestedNameLocs.empty())
|
||||
JsonObj["nestedNameLocs"] = Obj.NestedNameLocs;
|
||||
if (!Obj.DeclNameInfos.empty())
|
||||
JsonObj["declNameInfos"] = Obj.DeclNameInfos;
|
||||
return JsonObj;
|
||||
}
|
||||
|
||||
llvm::json::Object toJSON(llvm::StringMap<ClassData> const &Obj) {
|
||||
using llvm::json::toJSON;
|
||||
|
||||
llvm::json::Object JsonObj;
|
||||
for (const auto &Item : Obj)
|
||||
JsonObj[Item.first()] = ::toJSON(Item.second);
|
||||
return JsonObj;
|
||||
}
|
||||
|
||||
void WriteJSON(StringRef JsonPath, llvm::json::Object &&ClassInheritance,
|
||||
llvm::json::Object &&ClassesInClade,
|
||||
llvm::json::Object &&ClassEntries) {
|
||||
llvm::json::Object JsonObj;
|
||||
|
||||
using llvm::json::toJSON;
|
||||
|
||||
JsonObj["classInheritance"] = std::move(ClassInheritance);
|
||||
JsonObj["classesInClade"] = std::move(ClassesInClade);
|
||||
JsonObj["classEntries"] = std::move(ClassEntries);
|
||||
|
||||
llvm::json::Value JsonVal(std::move(JsonObj));
|
||||
|
||||
bool WriteChange = false;
|
||||
std::string OutString;
|
||||
if (auto ExistingOrErr = MemoryBuffer::getFile(JsonPath, /*IsText=*/true)) {
|
||||
raw_string_ostream Out(OutString);
|
||||
Out << formatv("{0:2}", JsonVal);
|
||||
if (ExistingOrErr.get()->getBuffer() == Out.str())
|
||||
return;
|
||||
WriteChange = true;
|
||||
}
|
||||
|
||||
std::error_code EC;
|
||||
llvm::raw_fd_ostream JsonOut(JsonPath, EC, llvm::sys::fs::OF_Text);
|
||||
if (EC)
|
||||
return;
|
||||
|
||||
if (WriteChange)
|
||||
JsonOut << OutString;
|
||||
else
|
||||
JsonOut << formatv("{0:2}", JsonVal);
|
||||
}
|
||||
|
||||
void ASTSrcLocProcessor::generate() {
|
||||
WriteJSON(JsonPath, ::toJSON(ClassInheritance), ::toJSON(ClassesInClade),
|
||||
::toJSON(ClassEntries));
|
||||
}
|
||||
|
||||
void ASTSrcLocProcessor::generateEmpty() { WriteJSON(JsonPath, {}, {}, {}); }
|
||||
|
||||
std::vector<std::string>
|
||||
CaptureMethods(std::string TypeString, const clang::CXXRecordDecl *ASTClass,
|
||||
const MatchFinder::MatchResult &Result) {
|
||||
|
||||
auto publicAccessor = [](auto... InnerMatcher) {
|
||||
return cxxMethodDecl(isPublic(), parameterCountIs(0), isConst(),
|
||||
InnerMatcher...);
|
||||
};
|
||||
|
||||
auto BoundNodesVec = match(
|
||||
findAll(
|
||||
publicAccessor(
|
||||
ofClass(cxxRecordDecl(
|
||||
equalsNode(ASTClass),
|
||||
optionally(isDerivedFrom(
|
||||
cxxRecordDecl(hasAnyName("clang::Stmt", "clang::Decl"))
|
||||
.bind("stmtOrDeclBase"))),
|
||||
optionally(isDerivedFrom(
|
||||
cxxRecordDecl(hasName("clang::Expr")).bind("exprBase"))),
|
||||
optionally(
|
||||
isDerivedFrom(cxxRecordDecl(hasName("clang::TypeLoc"))
|
||||
.bind("typeLocBase"))))),
|
||||
returns(hasCanonicalType(asString(TypeString))))
|
||||
.bind("classMethod")),
|
||||
*ASTClass, *Result.Context);
|
||||
|
||||
std::vector<std::string> Methods;
|
||||
for (const auto &BN : BoundNodesVec) {
|
||||
if (const auto *Node = BN.getNodeAs<clang::NamedDecl>("classMethod")) {
|
||||
const auto *StmtOrDeclBase =
|
||||
BN.getNodeAs<clang::CXXRecordDecl>("stmtOrDeclBase");
|
||||
const auto *TypeLocBase =
|
||||
BN.getNodeAs<clang::CXXRecordDecl>("typeLocBase");
|
||||
const auto *ExprBase = BN.getNodeAs<clang::CXXRecordDecl>("exprBase");
|
||||
// The clang AST has several methods on base classes which are overriden
|
||||
// pseudo-virtually by derived classes.
|
||||
// We record only the pseudo-virtual methods on the base classes to
|
||||
// avoid duplication.
|
||||
if (StmtOrDeclBase &&
|
||||
(Node->getName() == "getBeginLoc" || Node->getName() == "getEndLoc" ||
|
||||
Node->getName() == "getSourceRange"))
|
||||
continue;
|
||||
if (ExprBase && Node->getName() == "getExprLoc")
|
||||
continue;
|
||||
if (TypeLocBase && Node->getName() == "getLocalSourceRange")
|
||||
continue;
|
||||
if ((ASTClass->getName() == "PointerLikeTypeLoc" ||
|
||||
ASTClass->getName() == "TypeofLikeTypeLoc") &&
|
||||
Node->getName() == "getLocalSourceRange")
|
||||
continue;
|
||||
Methods.push_back(Node->getName().str());
|
||||
}
|
||||
}
|
||||
return Methods;
|
||||
}
|
||||
|
||||
void ASTSrcLocProcessor::run(const MatchFinder::MatchResult &Result) {
|
||||
|
||||
const auto *ASTClass =
|
||||
Result.Nodes.getNodeAs<clang::CXXRecordDecl>("className");
|
||||
|
||||
StringRef CladeName;
|
||||
if (ASTClass) {
|
||||
if (const auto *NodeClade =
|
||||
Result.Nodes.getNodeAs<clang::CXXRecordDecl>("nodeClade"))
|
||||
CladeName = NodeClade->getName();
|
||||
} else {
|
||||
ASTClass = Result.Nodes.getNodeAs<clang::CXXRecordDecl>("templateName");
|
||||
CladeName = "TypeLoc";
|
||||
}
|
||||
|
||||
StringRef ClassName = ASTClass->getName();
|
||||
|
||||
ClassData CD;
|
||||
|
||||
CD.ASTClassLocations =
|
||||
CaptureMethods("class clang::SourceLocation", ASTClass, Result);
|
||||
CD.ASTClassRanges =
|
||||
CaptureMethods("class clang::SourceRange", ASTClass, Result);
|
||||
CD.TypeSourceInfos =
|
||||
CaptureMethods("class clang::TypeSourceInfo *", ASTClass, Result);
|
||||
CD.TypeLocs = CaptureMethods("class clang::TypeLoc", ASTClass, Result);
|
||||
CD.NestedNameLocs =
|
||||
CaptureMethods("class clang::NestedNameSpecifierLoc", ASTClass, Result);
|
||||
CD.DeclNameInfos =
|
||||
CaptureMethods("struct clang::DeclarationNameInfo", ASTClass, Result);
|
||||
auto DI = CaptureMethods("const struct clang::DeclarationNameInfo &",
|
||||
ASTClass, Result);
|
||||
CD.DeclNameInfos.insert(CD.DeclNameInfos.end(), DI.begin(), DI.end());
|
||||
|
||||
if (const auto *DerivedFrom =
|
||||
Result.Nodes.getNodeAs<clang::CXXRecordDecl>("derivedFrom")) {
|
||||
|
||||
if (const auto *Templ =
|
||||
llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(
|
||||
DerivedFrom)) {
|
||||
|
||||
const auto &TArgs = Templ->getTemplateArgs();
|
||||
|
||||
SmallString<256> TArgsString;
|
||||
llvm::raw_svector_ostream OS(TArgsString);
|
||||
OS << DerivedFrom->getName() << '<';
|
||||
|
||||
clang::PrintingPolicy PPol(Result.Context->getLangOpts());
|
||||
PPol.TerseOutput = true;
|
||||
|
||||
for (unsigned I = 0; I < TArgs.size(); ++I) {
|
||||
if (I > 0)
|
||||
OS << ", ";
|
||||
TArgs.get(I).getAsType().print(OS, PPol);
|
||||
}
|
||||
OS << '>';
|
||||
|
||||
ClassInheritance[ClassName] = TArgsString.str().str();
|
||||
} else {
|
||||
ClassInheritance[ClassName] = DerivedFrom->getName().str();
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto *Templ = ASTClass->getDescribedClassTemplate()) {
|
||||
if (auto *TParams = Templ->getTemplateParameters()) {
|
||||
for (const auto &TParam : *TParams) {
|
||||
CD.TemplateParms.push_back(TParam->getName().str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClassEntries[ClassName] = CD;
|
||||
ClassesInClade[CladeName].push_back(ClassName);
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
//===- ASTSrcLocProcessor.h ---------------------------------*- C++ -*-----===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TOOLING_DUMPTOOL_ASTSRCLOCPROCESSOR_H
|
||||
#define LLVM_CLANG_TOOLING_DUMPTOOL_ASTSRCLOCPROCESSOR_H
|
||||
|
||||
#include "APIData.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CompilerInstance;
|
||||
|
||||
namespace tooling {
|
||||
|
||||
class ASTSrcLocProcessor : public ast_matchers::MatchFinder::MatchCallback {
|
||||
public:
|
||||
explicit ASTSrcLocProcessor(StringRef JsonPath);
|
||||
|
||||
std::unique_ptr<ASTConsumer> createASTConsumer(CompilerInstance &Compiler,
|
||||
StringRef File);
|
||||
|
||||
void generate();
|
||||
void generateEmpty();
|
||||
|
||||
private:
|
||||
void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
|
||||
|
||||
std::optional<TraversalKind> getCheckTraversalKind() const override {
|
||||
return TK_IgnoreUnlessSpelledInSource;
|
||||
}
|
||||
|
||||
llvm::StringMap<std::string> ClassInheritance;
|
||||
llvm::StringMap<std::vector<StringRef>> ClassesInClade;
|
||||
llvm::StringMap<ClassData> ClassEntries;
|
||||
|
||||
std::string JsonPath;
|
||||
std::unique_ptr<clang::ast_matchers::MatchFinder> Finder;
|
||||
};
|
||||
|
||||
} // namespace tooling
|
||||
} // namespace clang
|
||||
|
||||
#endif
|
@ -1,16 +0,0 @@
|
||||
|
||||
add_clang_executable(clang-ast-dump
|
||||
ASTSrcLocProcessor.cpp
|
||||
ClangSrcLocDump.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(clang-ast-dump
|
||||
PRIVATE
|
||||
clangAST
|
||||
clangASTMatchers
|
||||
clangBasic
|
||||
clangDriver
|
||||
clangFrontend
|
||||
clangSerialization
|
||||
clangToolingCore
|
||||
)
|
@ -1,155 +0,0 @@
|
||||
//===- ClangSrcLocDump.cpp ------------------------------------*- C++ -*---===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Driver/Compilation.h"
|
||||
#include "clang/Driver/Driver.h"
|
||||
#include "clang/Driver/Job.h"
|
||||
#include "clang/Driver/Options.h"
|
||||
#include "clang/Driver/Tool.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
#include "clang/Lex/PreprocessorOptions.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/JSON.h"
|
||||
#include "llvm/TargetParser/Host.h"
|
||||
|
||||
#include "ASTSrcLocProcessor.h"
|
||||
|
||||
using namespace clang::tooling;
|
||||
using namespace clang;
|
||||
using namespace llvm;
|
||||
|
||||
static cl::list<std::string> IncludeDirectories(
|
||||
"I", cl::desc("Include directories to use while compiling"),
|
||||
cl::value_desc("directory"), cl::Required, cl::OneOrMore, cl::Prefix);
|
||||
|
||||
static cl::opt<bool>
|
||||
SkipProcessing("skip-processing",
|
||||
cl::desc("Avoid processing the AST header file"),
|
||||
cl::Required, cl::value_desc("bool"));
|
||||
|
||||
static cl::opt<std::string> JsonOutputPath("json-output-path",
|
||||
cl::desc("json output path"),
|
||||
cl::Required,
|
||||
cl::value_desc("path"));
|
||||
|
||||
class ASTSrcLocGenerationAction : public clang::ASTFrontendAction {
|
||||
public:
|
||||
ASTSrcLocGenerationAction() : Processor(JsonOutputPath) {}
|
||||
|
||||
void ExecuteAction() override {
|
||||
clang::ASTFrontendAction::ExecuteAction();
|
||||
if (getCompilerInstance().getDiagnostics().getNumErrors() > 0)
|
||||
Processor.generateEmpty();
|
||||
else
|
||||
Processor.generate();
|
||||
}
|
||||
|
||||
std::unique_ptr<clang::ASTConsumer>
|
||||
CreateASTConsumer(clang::CompilerInstance &Compiler,
|
||||
llvm::StringRef File) override {
|
||||
return Processor.createASTConsumer(Compiler, File);
|
||||
}
|
||||
|
||||
private:
|
||||
ASTSrcLocProcessor Processor;
|
||||
};
|
||||
|
||||
static const char Filename[] = "ASTTU.cpp";
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv);
|
||||
|
||||
if (SkipProcessing) {
|
||||
std::error_code EC;
|
||||
llvm::raw_fd_ostream JsonOut(JsonOutputPath, EC, llvm::sys::fs::OF_Text);
|
||||
if (EC)
|
||||
return 1;
|
||||
JsonOut << formatv("{0:2}", llvm::json::Value(llvm::json::Object()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<std::string> Args;
|
||||
Args.push_back("-cc1");
|
||||
|
||||
llvm::transform(IncludeDirectories, std::back_inserter(Args),
|
||||
[](const std::string &IncDir) { return "-I" + IncDir; });
|
||||
|
||||
Args.push_back("-fsyntax-only");
|
||||
Args.push_back(Filename);
|
||||
|
||||
std::vector<const char *> Argv(Args.size(), nullptr);
|
||||
llvm::transform(Args, Argv.begin(),
|
||||
[](const std::string &Arg) { return Arg.c_str(); });
|
||||
|
||||
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
|
||||
CreateAndPopulateDiagOpts(Argv);
|
||||
|
||||
// Don't output diagnostics, because common scenarios such as
|
||||
// cross-compiling fail with diagnostics. This is not fatal, but
|
||||
// just causes attempts to use the introspection API to return no data.
|
||||
TextDiagnosticPrinter DiagnosticPrinter(llvm::nulls(), &*DiagOpts);
|
||||
DiagnosticsEngine Diagnostics(
|
||||
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
|
||||
&DiagnosticPrinter, false);
|
||||
|
||||
auto *OFS = new llvm::vfs::OverlayFileSystem(vfs::getRealFileSystem());
|
||||
|
||||
auto *MemFS = new llvm::vfs::InMemoryFileSystem();
|
||||
OFS->pushOverlay(MemFS);
|
||||
MemFS->addFile(Filename, 0,
|
||||
MemoryBuffer::getMemBuffer("#include \"clang/AST/AST.h\"\n"));
|
||||
|
||||
auto Files = llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions(), OFS);
|
||||
|
||||
auto Driver = std::make_unique<clang::driver::Driver>(
|
||||
"clang", llvm::sys::getDefaultTargetTriple(), Diagnostics,
|
||||
"ast-api-dump-tool", OFS);
|
||||
|
||||
std::unique_ptr<clang::driver::Compilation> Comp(
|
||||
Driver->BuildCompilation(llvm::ArrayRef(Argv)));
|
||||
if (!Comp)
|
||||
return 1;
|
||||
|
||||
const auto &Jobs = Comp->getJobs();
|
||||
if (Jobs.size() != 1 || !isa<clang::driver::Command>(*Jobs.begin())) {
|
||||
SmallString<256> error_msg;
|
||||
llvm::raw_svector_ostream error_stream(error_msg);
|
||||
Jobs.Print(error_stream, "; ", true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const auto &Cmd = cast<clang::driver::Command>(*Jobs.begin());
|
||||
const llvm::opt::ArgStringList &CC1Args = Cmd.getArguments();
|
||||
|
||||
auto Invocation = std::make_unique<CompilerInvocation>();
|
||||
CompilerInvocation::CreateFromArgs(*Invocation, CC1Args, Diagnostics);
|
||||
|
||||
CompilerInstance Compiler(std::make_shared<clang::PCHContainerOperations>());
|
||||
Compiler.setInvocation(std::move(Invocation));
|
||||
|
||||
Compiler.createDiagnostics(&DiagnosticPrinter, false);
|
||||
if (!Compiler.hasDiagnostics())
|
||||
return 1;
|
||||
|
||||
// Suppress "2 errors generated" or similar messages
|
||||
Compiler.getDiagnosticOpts().ShowCarets = false;
|
||||
Compiler.createSourceManager(*Files);
|
||||
Compiler.setFileManager(Files.get());
|
||||
|
||||
ASTSrcLocGenerationAction ScopedToolAction;
|
||||
Compiler.ExecuteAction(ScopedToolAction);
|
||||
|
||||
Files->clearStatCache();
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,452 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import filecmp
|
||||
import shutil
|
||||
import argparse
|
||||
|
||||
|
||||
class Generator(object):
|
||||
|
||||
implementationContent = ""
|
||||
|
||||
RefClades = {
|
||||
"DeclarationNameInfo",
|
||||
"NestedNameSpecifierLoc",
|
||||
"TemplateArgumentLoc",
|
||||
"TypeLoc",
|
||||
}
|
||||
|
||||
def __init__(self, templateClasses):
|
||||
self.templateClasses = templateClasses
|
||||
|
||||
def GeneratePrologue(self):
|
||||
|
||||
self.implementationContent += r"""
|
||||
/*===- Generated file -------------------------------------------*- C++ -*-===*\
|
||||
|* *|
|
||||
|* Introspection of available AST node SourceLocations *|
|
||||
|* *|
|
||||
|* Automatically generated file, do not edit! *|
|
||||
|* *|
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
|
||||
namespace clang {
|
||||
namespace tooling {
|
||||
|
||||
using LocationAndString = SourceLocationMap::value_type;
|
||||
using RangeAndString = SourceRangeMap::value_type;
|
||||
|
||||
bool NodeIntrospection::hasIntrospectionSupport() { return true; }
|
||||
|
||||
struct RecursionPopper
|
||||
{
|
||||
RecursionPopper(std::vector<clang::TypeLoc> &TypeLocRecursionGuard)
|
||||
: TLRG(TypeLocRecursionGuard)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~RecursionPopper()
|
||||
{
|
||||
TLRG.pop_back();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<clang::TypeLoc> &TLRG;
|
||||
};
|
||||
"""
|
||||
|
||||
def GenerateBaseGetLocationsDeclaration(self, CladeName):
|
||||
InstanceDecoration = "*"
|
||||
if CladeName in self.RefClades:
|
||||
InstanceDecoration = "&"
|
||||
|
||||
self.implementationContent += """
|
||||
void GetLocationsImpl(SharedLocationCall const& Prefix,
|
||||
clang::{0} const {1}Object, SourceLocationMap &Locs,
|
||||
SourceRangeMap &Rngs,
|
||||
std::vector<clang::TypeLoc> &TypeLocRecursionGuard);
|
||||
""".format(
|
||||
CladeName, InstanceDecoration
|
||||
)
|
||||
|
||||
def GenerateSrcLocMethod(self, ClassName, ClassData, CreateLocalRecursionGuard):
|
||||
|
||||
NormalClassName = ClassName
|
||||
RecursionGuardParam = (
|
||||
""
|
||||
if CreateLocalRecursionGuard
|
||||
else ", std::vector<clang::TypeLoc>& TypeLocRecursionGuard"
|
||||
)
|
||||
|
||||
if "templateParms" in ClassData:
|
||||
TemplatePreamble = "template <typename "
|
||||
ClassName += "<"
|
||||
First = True
|
||||
for TA in ClassData["templateParms"]:
|
||||
if not First:
|
||||
ClassName += ", "
|
||||
TemplatePreamble += ", typename "
|
||||
|
||||
First = False
|
||||
ClassName += TA
|
||||
TemplatePreamble += TA
|
||||
|
||||
ClassName += ">"
|
||||
TemplatePreamble += ">\n"
|
||||
self.implementationContent += TemplatePreamble
|
||||
|
||||
self.implementationContent += """
|
||||
static void GetLocations{0}(SharedLocationCall const& Prefix,
|
||||
clang::{1} const &Object,
|
||||
SourceLocationMap &Locs, SourceRangeMap &Rngs {2})
|
||||
{{
|
||||
""".format(
|
||||
NormalClassName, ClassName, RecursionGuardParam
|
||||
)
|
||||
|
||||
if "sourceLocations" in ClassData:
|
||||
for locName in ClassData["sourceLocations"]:
|
||||
self.implementationContent += """
|
||||
Locs.insert(LocationAndString(Object.{0}(),
|
||||
llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}")));
|
||||
""".format(
|
||||
locName
|
||||
)
|
||||
|
||||
self.implementationContent += "\n"
|
||||
|
||||
if "sourceRanges" in ClassData:
|
||||
for rngName in ClassData["sourceRanges"]:
|
||||
self.implementationContent += """
|
||||
Rngs.insert(RangeAndString(Object.{0}(),
|
||||
llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}")));
|
||||
""".format(
|
||||
rngName
|
||||
)
|
||||
|
||||
self.implementationContent += "\n"
|
||||
|
||||
if (
|
||||
"typeLocs" in ClassData
|
||||
or "typeSourceInfos" in ClassData
|
||||
or "nestedNameLocs" in ClassData
|
||||
or "declNameInfos" in ClassData
|
||||
):
|
||||
if CreateLocalRecursionGuard:
|
||||
self.implementationContent += (
|
||||
"std::vector<clang::TypeLoc> TypeLocRecursionGuard;\n"
|
||||
)
|
||||
|
||||
self.implementationContent += "\n"
|
||||
|
||||
if "typeLocs" in ClassData:
|
||||
for typeLoc in ClassData["typeLocs"]:
|
||||
|
||||
self.implementationContent += """
|
||||
if (Object.{0}()) {{
|
||||
GetLocationsImpl(
|
||||
llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
|
||||
Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
|
||||
}}
|
||||
""".format(
|
||||
typeLoc
|
||||
)
|
||||
|
||||
self.implementationContent += "\n"
|
||||
if "typeSourceInfos" in ClassData:
|
||||
for tsi in ClassData["typeSourceInfos"]:
|
||||
self.implementationContent += """
|
||||
if (Object.{0}()) {{
|
||||
GetLocationsImpl(llvm::makeIntrusiveRefCnt<LocationCall>(
|
||||
llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}",
|
||||
LocationCall::ReturnsPointer), "getTypeLoc"),
|
||||
Object.{0}()->getTypeLoc(), Locs, Rngs, TypeLocRecursionGuard);
|
||||
}}
|
||||
""".format(
|
||||
tsi
|
||||
)
|
||||
|
||||
self.implementationContent += "\n"
|
||||
|
||||
if "nestedNameLocs" in ClassData:
|
||||
for NN in ClassData["nestedNameLocs"]:
|
||||
self.implementationContent += """
|
||||
if (Object.{0}())
|
||||
GetLocationsImpl(
|
||||
llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
|
||||
Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
|
||||
""".format(
|
||||
NN
|
||||
)
|
||||
|
||||
if "declNameInfos" in ClassData:
|
||||
for declName in ClassData["declNameInfos"]:
|
||||
|
||||
self.implementationContent += """
|
||||
GetLocationsImpl(
|
||||
llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
|
||||
Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
|
||||
""".format(
|
||||
declName
|
||||
)
|
||||
|
||||
self.implementationContent += "}\n"
|
||||
|
||||
def GenerateFiles(self, OutputFile):
|
||||
with open(os.path.join(os.getcwd(), OutputFile), "w") as f:
|
||||
f.write(self.implementationContent)
|
||||
|
||||
def GenerateBaseGetLocationsFunction(
|
||||
self,
|
||||
ASTClassNames,
|
||||
ClassEntries,
|
||||
CladeName,
|
||||
InheritanceMap,
|
||||
CreateLocalRecursionGuard,
|
||||
):
|
||||
|
||||
MethodReturnType = "NodeLocationAccessors"
|
||||
InstanceDecoration = "*"
|
||||
if CladeName in self.RefClades:
|
||||
InstanceDecoration = "&"
|
||||
|
||||
Signature = "GetLocations(clang::{0} const {1}Object)".format(
|
||||
CladeName, InstanceDecoration
|
||||
)
|
||||
ImplSignature = """
|
||||
GetLocationsImpl(SharedLocationCall const& Prefix,
|
||||
clang::{0} const {1}Object, SourceLocationMap &Locs,
|
||||
SourceRangeMap &Rngs,
|
||||
std::vector<clang::TypeLoc> &TypeLocRecursionGuard)
|
||||
""".format(
|
||||
CladeName, InstanceDecoration
|
||||
)
|
||||
|
||||
self.implementationContent += "void {0} {{ ".format(ImplSignature)
|
||||
|
||||
if CladeName == "TypeLoc":
|
||||
self.implementationContent += "if (Object.isNull()) return;"
|
||||
|
||||
self.implementationContent += """
|
||||
if (llvm::find(TypeLocRecursionGuard, Object) != TypeLocRecursionGuard.end())
|
||||
return;
|
||||
TypeLocRecursionGuard.push_back(Object);
|
||||
RecursionPopper RAII(TypeLocRecursionGuard);
|
||||
"""
|
||||
|
||||
RecursionGuardParam = ""
|
||||
if not CreateLocalRecursionGuard:
|
||||
RecursionGuardParam = ", TypeLocRecursionGuard"
|
||||
|
||||
ArgPrefix = "*"
|
||||
if CladeName in self.RefClades:
|
||||
ArgPrefix = ""
|
||||
self.implementationContent += (
|
||||
"GetLocations{0}(Prefix, {1}Object, Locs, Rngs {2});".format(
|
||||
CladeName, ArgPrefix, RecursionGuardParam
|
||||
)
|
||||
)
|
||||
|
||||
if CladeName == "TypeLoc":
|
||||
self.implementationContent += """
|
||||
if (auto QTL = Object.getAs<clang::QualifiedTypeLoc>()) {
|
||||
auto Dequalified = QTL.getNextTypeLoc();
|
||||
return GetLocationsImpl(llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "getNextTypeLoc"),
|
||||
Dequalified,
|
||||
Locs,
|
||||
Rngs,
|
||||
TypeLocRecursionGuard);
|
||||
}"""
|
||||
|
||||
for ASTClassName in ASTClassNames:
|
||||
if ASTClassName in self.templateClasses:
|
||||
continue
|
||||
if ASTClassName == CladeName:
|
||||
continue
|
||||
if CladeName != "TypeLoc":
|
||||
self.implementationContent += """
|
||||
if (auto Derived = llvm::dyn_cast<clang::{0}>(Object)) {{
|
||||
GetLocations{0}(Prefix, *Derived, Locs, Rngs {1});
|
||||
}}
|
||||
""".format(
|
||||
ASTClassName, RecursionGuardParam
|
||||
)
|
||||
continue
|
||||
|
||||
self.GenerateBaseTypeLocVisit(
|
||||
ASTClassName, ClassEntries, RecursionGuardParam, InheritanceMap
|
||||
)
|
||||
|
||||
self.implementationContent += "}"
|
||||
|
||||
self.implementationContent += """
|
||||
{0} NodeIntrospection::{1} {{
|
||||
NodeLocationAccessors Result;
|
||||
SharedLocationCall Prefix;
|
||||
std::vector<clang::TypeLoc> TypeLocRecursionGuard;
|
||||
|
||||
GetLocationsImpl(Prefix, Object, Result.LocationAccessors,
|
||||
Result.RangeAccessors, TypeLocRecursionGuard);
|
||||
""".format(
|
||||
MethodReturnType, Signature
|
||||
)
|
||||
|
||||
self.implementationContent += "return Result; }"
|
||||
|
||||
def GenerateBaseTypeLocVisit(
|
||||
self, ASTClassName, ClassEntries, RecursionGuardParam, InheritanceMap
|
||||
):
|
||||
CallPrefix = "Prefix"
|
||||
if ASTClassName != "TypeLoc":
|
||||
CallPrefix = """llvm::makeIntrusiveRefCnt<LocationCall>(Prefix,
|
||||
"getAs<clang::{0}>", LocationCall::IsCast)
|
||||
""".format(
|
||||
ASTClassName
|
||||
)
|
||||
|
||||
if ASTClassName in ClassEntries:
|
||||
|
||||
self.implementationContent += """
|
||||
if (auto ConcreteTL = Object.getAs<clang::{0}>())
|
||||
GetLocations{1}({2}, ConcreteTL, Locs, Rngs {3});
|
||||
""".format(
|
||||
ASTClassName, ASTClassName, CallPrefix, RecursionGuardParam
|
||||
)
|
||||
|
||||
if ASTClassName in InheritanceMap:
|
||||
for baseTemplate in self.templateClasses:
|
||||
if baseTemplate in InheritanceMap[ASTClassName]:
|
||||
self.implementationContent += """
|
||||
if (auto ConcreteTL = Object.getAs<clang::{0}>())
|
||||
GetLocations{1}({2}, ConcreteTL, Locs, Rngs {3});
|
||||
""".format(
|
||||
InheritanceMap[ASTClassName],
|
||||
baseTemplate,
|
||||
CallPrefix,
|
||||
RecursionGuardParam,
|
||||
)
|
||||
|
||||
def GenerateDynNodeVisitor(self, CladeNames):
|
||||
MethodReturnType = "NodeLocationAccessors"
|
||||
|
||||
Signature = "GetLocations(clang::DynTypedNode const &Node)"
|
||||
|
||||
self.implementationContent += (
|
||||
MethodReturnType + " NodeIntrospection::" + Signature + "{"
|
||||
)
|
||||
|
||||
for CladeName in CladeNames:
|
||||
if CladeName == "DeclarationNameInfo":
|
||||
continue
|
||||
self.implementationContent += """
|
||||
if (const auto *N = Node.get<{0}>())
|
||||
""".format(
|
||||
CladeName
|
||||
)
|
||||
ArgPrefix = ""
|
||||
if CladeName in self.RefClades:
|
||||
ArgPrefix = "*"
|
||||
self.implementationContent += """
|
||||
return GetLocations({0}const_cast<{1} *>(N));""".format(
|
||||
ArgPrefix, CladeName
|
||||
)
|
||||
|
||||
self.implementationContent += "\nreturn {}; }"
|
||||
|
||||
def GenerateEpilogue(self):
|
||||
|
||||
self.implementationContent += """
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--json-input-path", help="Read API description from FILE", metavar="FILE"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output-file", help="Generate output in FILEPATH", metavar="FILEPATH"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--use-empty-implementation",
|
||||
help="Generate empty implementation",
|
||||
action="store",
|
||||
type=int,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--empty-implementation",
|
||||
help="Copy empty implementation from FILEPATH",
|
||||
action="store",
|
||||
metavar="FILEPATH",
|
||||
)
|
||||
|
||||
options = parser.parse_args()
|
||||
|
||||
use_empty_implementation = options.use_empty_implementation
|
||||
|
||||
if not use_empty_implementation and not os.path.exists(options.json_input_path):
|
||||
use_empty_implementation = True
|
||||
|
||||
if not use_empty_implementation:
|
||||
with open(options.json_input_path) as f:
|
||||
jsonData = json.load(f)
|
||||
|
||||
if not "classesInClade" in jsonData or not jsonData["classesInClade"]:
|
||||
use_empty_implementation = True
|
||||
|
||||
if use_empty_implementation:
|
||||
if not os.path.exists(options.output_file) or not filecmp.cmp(
|
||||
options.empty_implementation, options.output_file
|
||||
):
|
||||
shutil.copyfile(options.empty_implementation, options.output_file)
|
||||
sys.exit(0)
|
||||
|
||||
templateClasses = []
|
||||
for (ClassName, ClassAccessors) in jsonData["classEntries"].items():
|
||||
if "templateParms" in ClassAccessors:
|
||||
templateClasses.append(ClassName)
|
||||
|
||||
g = Generator(templateClasses)
|
||||
|
||||
g.GeneratePrologue()
|
||||
|
||||
for (CladeName, ClassNameData) in jsonData["classesInClade"].items():
|
||||
g.GenerateBaseGetLocationsDeclaration(CladeName)
|
||||
|
||||
def getCladeName(ClassName):
|
||||
for (CladeName, ClassNameData) in jsonData["classesInClade"].items():
|
||||
if ClassName in ClassNameData:
|
||||
return CladeName
|
||||
|
||||
for (ClassName, ClassAccessors) in jsonData["classEntries"].items():
|
||||
cladeName = getCladeName(ClassName)
|
||||
g.GenerateSrcLocMethod(
|
||||
ClassName, ClassAccessors, cladeName not in Generator.RefClades
|
||||
)
|
||||
|
||||
for (CladeName, ClassNameData) in jsonData["classesInClade"].items():
|
||||
g.GenerateBaseGetLocationsFunction(
|
||||
ClassNameData,
|
||||
jsonData["classEntries"],
|
||||
CladeName,
|
||||
jsonData["classInheritance"],
|
||||
CladeName not in Generator.RefClades,
|
||||
)
|
||||
|
||||
g.GenerateDynNodeVisitor(jsonData["classesInClade"].keys())
|
||||
|
||||
g.GenerateEpilogue()
|
||||
|
||||
g.GenerateFiles(options.output_file)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,48 +0,0 @@
|
||||
//===- EmptyNodeIntrospection.inc.in --------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace clang {
|
||||
namespace tooling {
|
||||
bool NodeIntrospection::hasIntrospectionSupport() { return false; }
|
||||
|
||||
NodeLocationAccessors NodeIntrospection::GetLocations(clang::Stmt const *) {
|
||||
return {};
|
||||
}
|
||||
NodeLocationAccessors NodeIntrospection::GetLocations(clang::Decl const *) {
|
||||
return {};
|
||||
}
|
||||
NodeLocationAccessors NodeIntrospection::GetLocations(
|
||||
clang::CXXCtorInitializer const *) {
|
||||
return {};
|
||||
}
|
||||
NodeLocationAccessors NodeIntrospection::GetLocations(
|
||||
clang::NestedNameSpecifierLoc const&) {
|
||||
return {};
|
||||
}
|
||||
NodeLocationAccessors NodeIntrospection::GetLocations(
|
||||
clang::TemplateArgumentLoc const&) {
|
||||
return {};
|
||||
}
|
||||
NodeLocationAccessors NodeIntrospection::GetLocations(
|
||||
clang::CXXBaseSpecifier const*) {
|
||||
return {};
|
||||
}
|
||||
NodeLocationAccessors NodeIntrospection::GetLocations(
|
||||
clang::TypeLoc const&) {
|
||||
return {};
|
||||
}
|
||||
NodeLocationAccessors NodeIntrospection::GetLocations(
|
||||
clang::DeclarationNameInfo const&) {
|
||||
return {};
|
||||
}
|
||||
NodeLocationAccessors
|
||||
NodeIntrospection::GetLocations(clang::DynTypedNode const &) {
|
||||
return {};
|
||||
}
|
||||
} // namespace tooling
|
||||
} // namespace clang
|
@ -1,88 +0,0 @@
|
||||
//===- NodeIntrospection.h -----------------------------------*- C++ -*----===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the implementation of the NodeIntrospection.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Tooling/NodeIntrospection.h"
|
||||
|
||||
#include "clang/AST/AST.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
namespace tooling {
|
||||
|
||||
void LocationCallFormatterCpp::print(const LocationCall &Call,
|
||||
llvm::raw_ostream &OS) {
|
||||
if (const LocationCall *On = Call.on()) {
|
||||
print(*On, OS);
|
||||
if (On->returnsPointer())
|
||||
OS << "->";
|
||||
else
|
||||
OS << '.';
|
||||
}
|
||||
|
||||
OS << Call.name() << "()";
|
||||
}
|
||||
|
||||
std::string LocationCallFormatterCpp::format(const LocationCall &Call) {
|
||||
std::string Result;
|
||||
llvm::raw_string_ostream OS(Result);
|
||||
print(Call, OS);
|
||||
OS.flush();
|
||||
return Result;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
static bool locationCallLessThan(const LocationCall *LHS,
|
||||
const LocationCall *RHS) {
|
||||
if (!LHS && !RHS)
|
||||
return false;
|
||||
if (LHS && !RHS)
|
||||
return true;
|
||||
if (!LHS && RHS)
|
||||
return false;
|
||||
auto compareResult = LHS->name().compare(RHS->name());
|
||||
if (compareResult < 0)
|
||||
return true;
|
||||
if (compareResult > 0)
|
||||
return false;
|
||||
return locationCallLessThan(LHS->on(), RHS->on());
|
||||
}
|
||||
|
||||
bool RangeLessThan::operator()(
|
||||
std::pair<SourceRange, SharedLocationCall> const &LHS,
|
||||
std::pair<SourceRange, SharedLocationCall> const &RHS) const {
|
||||
if (LHS.first.getBegin() < RHS.first.getBegin())
|
||||
return true;
|
||||
else if (LHS.first.getBegin() != RHS.first.getBegin())
|
||||
return false;
|
||||
|
||||
if (LHS.first.getEnd() < RHS.first.getEnd())
|
||||
return true;
|
||||
else if (LHS.first.getEnd() != RHS.first.getEnd())
|
||||
return false;
|
||||
|
||||
return locationCallLessThan(LHS.second.get(), RHS.second.get());
|
||||
}
|
||||
bool RangeLessThan::operator()(
|
||||
std::pair<SourceLocation, SharedLocationCall> const &LHS,
|
||||
std::pair<SourceLocation, SharedLocationCall> const &RHS) const {
|
||||
if (LHS.first == RHS.first)
|
||||
return locationCallLessThan(LHS.second.get(), RHS.second.get());
|
||||
return LHS.first < RHS.first;
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
} // namespace tooling
|
||||
} // namespace clang
|
||||
|
||||
#include "clang/Tooling/NodeIntrospection.inc"
|
@ -34,7 +34,6 @@ add_subdirectory(ASTMatchers)
|
||||
add_subdirectory(AST)
|
||||
add_subdirectory(CrossTU)
|
||||
add_subdirectory(Tooling)
|
||||
add_subdirectory(Introspection)
|
||||
add_subdirectory(Format)
|
||||
add_subdirectory(Frontend)
|
||||
add_subdirectory(Rewrite)
|
||||
|
@ -1,22 +0,0 @@
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
FrontendOpenMP
|
||||
Support
|
||||
)
|
||||
|
||||
add_clang_unittest(IntrospectionTests
|
||||
IntrospectionTest.cpp
|
||||
)
|
||||
|
||||
clang_target_link_libraries(IntrospectionTests
|
||||
PRIVATE
|
||||
clangAST
|
||||
clangASTMatchers
|
||||
clangBasic
|
||||
clangFrontend
|
||||
clangSerialization
|
||||
clangTooling
|
||||
)
|
||||
target_link_libraries(IntrospectionTests
|
||||
PRIVATE
|
||||
LLVMTestingSupport
|
||||
)
|
File diff suppressed because it is too large
Load Diff
@ -1,21 +1,7 @@
|
||||
# FIXME: The cmake build runs DumpTool:clang-ast-dump to generate a json
|
||||
# file and feeds it into this step in non-debug builds or if an option is set.
|
||||
action("node_introspection_inc") {
|
||||
script = "DumpTool/generate_cxx_src_locs.py"
|
||||
outputs = [ "$target_gen_dir/clang/Tooling/NodeIntrospection.inc" ]
|
||||
sources = [ "EmptyNodeIntrospection.inc.in" ]
|
||||
args = [
|
||||
"--use-empty-implementation=1",
|
||||
"--empty-implementation=" + rebase_path(sources[0], root_build_dir),
|
||||
"--output-file=" + rebase_path(outputs[0], root_build_dir),
|
||||
]
|
||||
}
|
||||
|
||||
static_library("Tooling") {
|
||||
output_name = "clangTooling"
|
||||
configs += [ "//llvm/utils/gn/build:clang_code" ]
|
||||
deps = [
|
||||
":node_introspection_inc",
|
||||
"//clang/include/clang/Driver:Options",
|
||||
"//clang/lib/AST",
|
||||
"//clang/lib/ASTMatchers",
|
||||
@ -28,7 +14,6 @@ static_library("Tooling") {
|
||||
"//clang/lib/Tooling/Core",
|
||||
"//llvm/lib/TargetParser",
|
||||
]
|
||||
include_dirs = [ target_gen_dir ]
|
||||
sources = [
|
||||
"AllTUsExecution.cpp",
|
||||
"ArgumentsAdjusters.cpp",
|
||||
@ -41,7 +26,6 @@ static_library("Tooling") {
|
||||
"GuessTargetAndModeCompilationDatabase.cpp",
|
||||
"InterpolatingCompilationDatabase.cpp",
|
||||
"JSONCompilationDatabase.cpp",
|
||||
"NodeIntrospection.cpp",
|
||||
"Refactoring.cpp",
|
||||
"RefactoringCallbacks.cpp",
|
||||
"StandaloneExecution.cpp",
|
||||
|
@ -1,20 +0,0 @@
|
||||
executable("clang-ast-dump") {
|
||||
configs += [ "//llvm/utils/gn/build:clang_code" ]
|
||||
deps = [
|
||||
"//clang/lib/AST",
|
||||
"//clang/lib/ASTMatchers",
|
||||
"//clang/lib/Basic",
|
||||
"//clang/lib/Driver",
|
||||
"//clang/lib/Format",
|
||||
"//clang/lib/Frontend",
|
||||
"//clang/lib/Lex",
|
||||
"//clang/lib/Rewrite",
|
||||
"//clang/lib/Serialization",
|
||||
"//clang/lib/Tooling/Core",
|
||||
]
|
||||
|
||||
sources = [
|
||||
"ASTSrcLocProcessor.cpp",
|
||||
"ClangSrcLocDump.cpp",
|
||||
]
|
||||
}
|
@ -15,7 +15,6 @@ group("unittests") {
|
||||
"Index:IndexTests",
|
||||
"InstallAPI:InstallAPITests",
|
||||
"Interpreter:ClangReplInterpreterTests",
|
||||
"Introspection:IntrospectionTests",
|
||||
"Lex:LexTests",
|
||||
"Rename:ClangRenameTests",
|
||||
"Rewrite:RewriteTests",
|
||||
|
@ -1,19 +0,0 @@
|
||||
import("//third-party/unittest/unittest.gni")
|
||||
|
||||
unittest("IntrospectionTests") {
|
||||
configs += [ "//llvm/utils/gn/build:clang_code" ]
|
||||
deps = [
|
||||
"//clang/lib/AST",
|
||||
"//clang/lib/ASTMatchers",
|
||||
"//clang/lib/Basic",
|
||||
"//clang/lib/Frontend",
|
||||
"//clang/lib/Serialization",
|
||||
"//clang/lib/Tooling",
|
||||
"//llvm/lib/Support",
|
||||
"//llvm/lib/Testing/Support",
|
||||
]
|
||||
|
||||
defines = [ "SKIP_INTROSPECTION_GENERATION" ]
|
||||
|
||||
sources = [ "IntrospectionTest.cpp" ]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user