1
/******************************************************************************
2
 *
3
 * C++ Insights, copyright (C) by Andreas Fertig
4
 * Distributed under an MIT license. See LICENSE for details
5
 *
6
 ****************************************************************************/
7

8
#include "clang/AST/AST.h"
9
#include "clang/AST/ASTContext.h"
10
#include "clang/ASTMatchers/ASTMatchFinder.h"
11
#include "clang/ASTMatchers/ASTMatchers.h"
12
#include "clang/Frontend/CompilerInstance.h"
13 1
#include "clang/Frontend/FrontendActions.h"
14 1
#include "clang/Lex/Lexer.h"
15
#include "clang/Rewrite/Core/Rewriter.h"
16
#include "clang/Tooling/CommonOptionsParser.h"
17
#include "clang/Tooling/Tooling.h"
18 1
#include "llvm/Support/Format.h"
19 1
#include "llvm/Support/MemoryBuffer.h"
20
#include "llvm/Support/Path.h"
21
#include "llvm/Support/Signals.h"
22
#include "llvm/Support/raw_ostream.h"
23

24
#include "CodeGenerator.h"
25
#include "DPrint.h"
26
#include "FunctionDeclHandler.h"
27
#include "GlobalVariableHandler.h"
28
#include "Insights.h"
29
#include "RecordDeclHandler.h"
30
#include "StaticAssertHandler.h"
31
#include "TemplateHandler.h"
32
#include "version.h"
33
//-----------------------------------------------------------------------------
34

35
using namespace clang;
36
using namespace clang::ast_matchers;
37
using namespace clang::driver;
38
using namespace clang::tooling;
39
using namespace clang::insights;
40
//-----------------------------------------------------------------------------
41

42
static InsightsOptions gInsightsOptions{};
43
//-----------------------------------------------------------------------------
44

45 4
const InsightsOptions& GetInsightsOptions()
46 1
{
47 4
    return gInsightsOptions;
48
}
49
//-----------------------------------------------------------------------------
50

51 2
static llvm::cl::OptionCategory gInsightCategory("Insights");
52
//-----------------------------------------------------------------------------
53

54 2
static llvm::cl::OptionCategory gInsightEduCategory(
55 2
    "Insights- Educational",
56 2
    "This transformations are only for education purposes. The resulting code most likely does not compile.");
57
//-----------------------------------------------------------------------------
58

59 2
static llvm::cl::opt<bool> gStdinMode("stdin",
60 2
                                      llvm::cl::desc("Override source file's content (in the overlaying\n"
61
                                                     "virtual file system) with input from <stdin> and run\n"
62
                                                     "the tool on the new content with the compilation\n"
63
                                                     "options of the source file. This mode is currently\n"
64
                                                     "used for editor integration."),
65 2
                                      llvm::cl::init(false),
66 2
                                      llvm::cl::cat(gInsightCategory));
67
//-----------------------------------------------------------------------------
68

69
static llvm::cl::opt<bool>
70 2
    gUseLibCpp("use-libc++", llvm::cl::desc("Use libc++."), llvm::cl::init(false), llvm::cl::cat(gInsightCategory));
71
//-----------------------------------------------------------------------------
72

73
#define INSIGHTS_OPT(option, name, deflt, description, category)                                                       \
74
    static llvm::cl::opt<bool, true> g##name(option,                                                                   \
75
                                             llvm::cl::desc(description),                                              \
76
                                             llvm::cl::NotHidden,                                                      \
77
                                             llvm::cl::location(gInsightsOptions.name),                                \
78
                                             llvm::cl::init(deflt),                                                    \
79
                                             llvm::cl::cat(category));
80
//-----------------------------------------------------------------------------
81

82
#include "InsightsOptions.def"
83
//-----------------------------------------------------------------------------
84

85
static const ASTContext* gAST{};
86 4
const ASTContext&        GetGlobalAST()
87 1
{
88 4
    return *gAST;
89
}
90
//-----------------------------------------------------------------------------
91

92 2
class CppInsightASTConsumer final : public ASTConsumer
93
{
94
public:
95 4
    explicit CppInsightASTConsumer(Rewriter& rewriter)
96 4
    : ASTConsumer()
97 2
    , mMatcher{}
98 4
    , mRecordDeclHandler{rewriter, mMatcher}
99 4
    , mStaticAssertHandler{rewriter, mMatcher}
100 4
    , mTemplateHandler{rewriter, mMatcher}
101 4
    , mGlobalVariableHandler{rewriter, mMatcher}
102 4
    , mFunctionDeclHandler{rewriter, mMatcher}
103 4
    , mRewriter{rewriter}
104 1
    {
105 1
    }
106

107 4
    void HandleTranslationUnit(ASTContext& context) override
108 1
    {
109 4
        gAST = &context;
110 4
        mMatcher.matchAST(context);
111

112
        // Check whether we had static local variables which we transformed. Then for the placement-new we need to
113
        // include the header <new>.
114 4
        if(CodeGenerator::NeedToInsertNewHeader()) {
115 4
            const auto& sm         = context.getSourceManager();
116 4
            const auto& mainFileId = sm.getMainFileID();
117 4
            const auto  loc        = sm.translateFileLineCol(sm.getFileEntryForID(mainFileId), 1, 1);
118

119 4
            mRewriter.InsertText(loc,
120 2
                                 "#include <new> // for thread-safe static's placement new\n#include <stdint.h> // for "
121 2
                                 "uint64_t under Linux/GCC\n");
122 1
        }
123 1
    }
124

125
private:
126
    MatchFinder           mMatcher;
127
    RecordDeclHandler     mRecordDeclHandler;
128
    StaticAssertHandler   mStaticAssertHandler;
129
    TemplateHandler       mTemplateHandler;
130
    GlobalVariableHandler mGlobalVariableHandler;
131
    FunctionDeclHandler   mFunctionDeclHandler;
132
    Rewriter&             mRewriter;
133
};
134
//-----------------------------------------------------------------------------
135

136 2
class CppInsightFrontendAction final : public ASTFrontendAction
137
{
138
public:
139 4
    CppInsightFrontendAction() = default;
140 4
    void EndSourceFileAction() override
141 1
    {
142 4
        mRewriter.getEditBuffer(mRewriter.getSourceMgr().getMainFileID()).write(llvm::outs());
143 1
    }
144

145 4
    std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance& CI, StringRef /*file*/) override
146 1
    {
147 4
        mRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
148 2
        return
149
#if IS_CLANG_NEWER_THAN(9)
150

151 2
            std
152
#else
153
            llvm
154
#endif
155

156 3
            ::make_unique<CppInsightASTConsumer>(mRewriter);
157
    }
158

159
private:
160
    Rewriter mRewriter;
161
};
162
//-----------------------------------------------------------------------------
163

164
#include "clang/Basic/Version.h"
165

166 4
static void PrintVersion(raw_ostream& ostream)
167 1
{
168 4
    ostream << "cpp-insights " << INSIGHTS_VERSION << " https://cppinsights.io (" << GIT_REPO_URL << " "
169 4
            << GIT_COMMIT_HASH << ")"
170 4
            << "\n";
171

172
#ifdef INSIGHTS_DEBUG
173 3
    ostream << "  Build with debug enabled\n";
174
#endif
175 4
    ostream << "  LLVM  Revision: " << clang::getLLVMRevision() << '\n';
176 4
    ostream << "  Clang Revision: " << clang::getClangFullCPPVersion() << '\n';
177 1
}
178
//-----------------------------------------------------------------------------
179

180 4
int main(int argc, const char** argv)
181 1
{
182 4
    llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
183 4
    llvm::cl::HideUnrelatedOptions(gInsightCategory);
184 4
    llvm::cl::SetVersionPrinter(&PrintVersion);
185

186 4
    CommonOptionsParser op(argc, argv, gInsightCategory);
187 4
    ClangTool           tool(op.getCompilations(), op.getSourcePathList());
188

189 4
    llvm::StringRef sourceFilePath = op.getSourcePathList().front();
190
    // In STDINMode, we override the file content with the <stdin> input.
191
    // Since `tool.mapVirtualFile` takes `StringRef`, we define `Code` outside of
192
    // the if-block so that `Code` is not released after the if-block.
193 4
    std::unique_ptr<llvm::MemoryBuffer> inMemoryCode{};
194

195 4
    if(gStdinMode) {
196 2
        assert(op.getSourcePathList().size() == 1 && "Expect exactly one file path in STDINMode.");
197 4
        llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> codeOrErr = llvm::MemoryBuffer::getSTDIN();
198 4
        if(const std::error_code errorCode = codeOrErr.getError()) {
199 4
            llvm::errs() << errorCode.message() << "\n";
200 4
            return 1;
201
        }
202 4
        inMemoryCode = std::move(codeOrErr.get());
203 4
        if(inMemoryCode->getBufferSize() == 0) {
204 4
            Error("empty file\n");
205 4
            return 1;  // Skip empty files.
206
        }
207

208 4
        tool.mapVirtualFile(sourceFilePath, inMemoryCode->getBuffer());
209 1
    }
210

211 4
    auto prependArgument = [&](auto arg) {
212 4
        tool.appendArgumentsAdjuster(getInsertArgumentAdjuster(arg, ArgumentInsertPosition::BEGIN));
213 4
    };
214

215
    // Special handling to spare users to figure out what include paths to add.
216

217
    // For some reason, Clang on Apple seems to require an additional hint for the C++ headers.
218
#ifdef __APPLE__
219 1
    gUseLibCpp = true;
220
#endif /* __APPLE__ */
221

222 4
    if(gUseLibCpp) {
223 2
        prependArgument(INSIGHTS_LLVM_INCLUDE_DIR);
224 2
        prependArgument("-stdlib=libc++");
225 0
    }
226

227 4
    prependArgument(INSIGHTS_CLANG_RESOURCE_INCLUDE_DIR);
228 4
    prependArgument(INSIGHTS_CLANG_RESOURCE_DIR);
229

230 4
    return tool.run(newFrontendActionFactory<CppInsightFrontendAction>().get());
231 1
}
232
//-----------------------------------------------------------------------------

Read our documentation on viewing source code .

Loading