예제 #1
0
파일: clangindex.cpp 프로젝트: KDE/kdevelop
QSharedPointer<const ClangPCH> ClangIndex::pch(const ClangParsingEnvironment& environment)
{
    const auto& pchInclude = environment.pchInclude();
    if (!pchInclude.isValid()) {
        return {};
    }

    UrlParseLock pchLock(IndexedString(pchInclude.pathOrUrl()));

    static const QString pchExt = QStringLiteral(".pch");

    if (QFile::exists(pchInclude.toLocalFile() + pchExt)) {
        QReadLocker lock(&m_pchLock);
        auto pch = m_pch.constFind(pchInclude);
        if (pch != m_pch.constEnd()) {
            return pch.value();
        }
    }

    auto pch = QSharedPointer<ClangPCH>::create(environment, this);
    QWriteLocker lock(&m_pchLock);
    m_pch.insert(pchInclude, pch);
    return pch;
}
예제 #2
0
ParseSessionData::ParseSessionData(const QVector<UnsavedFile>& unsavedFiles, ClangIndex* index,
                                   const ClangParsingEnvironment& environment, Options options)
    : m_file(nullptr)
    , m_unit(nullptr)
{
    unsigned int flags = CXTranslationUnit_CXXChainedPCH
        | CXTranslationUnit_DetailedPreprocessingRecord
#if CINDEX_VERSION_MINOR >= 34
        | CXTranslationUnit_KeepGoing
#endif
    ;
    if (options.testFlag(SkipFunctionBodies)) {
        flags |= CXTranslationUnit_SkipFunctionBodies;
    }
    if (options.testFlag(PrecompiledHeader)) {
        flags |= CXTranslationUnit_ForSerialization;
    } else {
        flags |= CXTranslationUnit_CacheCompletionResults
              |  CXTranslationUnit_PrecompiledPreamble;
        if (environment.quality() == ClangParsingEnvironment::Unknown) {
            flags |= CXTranslationUnit_Incomplete;
        }
    }

    const auto tuUrl = environment.translationUnitUrl();
    Q_ASSERT(!tuUrl.isEmpty());

    const auto arguments = argsForSession(tuUrl.str(), options, environment.parserSettings());
    QVector<const char*> clangArguments;

    const auto& includes = environment.includes();
    const auto& pchInclude = environment.pchInclude();

    // uses QByteArray as smart-pointer for const char* ownership
    QVector<QByteArray> smartArgs;
    smartArgs.reserve(includes.system.size() + includes.project.size()
                      + pchInclude.isValid() + arguments.size() + 1);
    clangArguments.reserve(smartArgs.size());

    std::transform(arguments.constBegin(), arguments.constEnd(),
                   std::back_inserter(clangArguments),
                   [] (const QByteArray &argument) { return argument.constData(); });

    // NOTE: the PCH include must come before all other includes!
    if (pchInclude.isValid()) {
        clangArguments << "-include";
        QByteArray pchFile = pchInclude.toLocalFile().toUtf8();
        smartArgs << pchFile;
        clangArguments << pchFile.constData();
    }

    if (needGccCompatibility(environment)) {
        const auto compatFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kdevclangsupport/gcc_compat.h")).toUtf8();
        if (!compatFile.isEmpty()) {
            smartArgs << compatFile;
            clangArguments << "-include" << compatFile.constData();
        }
    }

    if (hasQtIncludes(includes.system)) {
        const auto wrappedQtHeaders = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
                                                             QStringLiteral("kdevclangsupport/wrappedQtHeaders"),
                                                             QStandardPaths::LocateDirectory).toUtf8();
        if (!wrappedQtHeaders.isEmpty()) {
            smartArgs << wrappedQtHeaders;
            clangArguments << "-isystem" << wrappedQtHeaders.constData();
            const auto qtCore = wrappedQtHeaders + "/QtCore";
            smartArgs << qtCore;
            clangArguments << "-isystem" << qtCore.constData();
        }
    }

    addIncludes(&clangArguments, &smartArgs, includes.system, "-isystem");
    addIncludes(&clangArguments, &smartArgs, includes.project, "-I");

    const auto& frameworkDirectories = environment.frameworkDirectories();
    addFrameworkDirectories(&clangArguments, &smartArgs, frameworkDirectories.system, "-iframework");
    addFrameworkDirectories(&clangArguments, &smartArgs, frameworkDirectories.project, "-F");

    smartArgs << writeDefinesFile(environment.defines());
    clangArguments << "-imacros" << smartArgs.last().constData();

    // append extra args from environment variable
    static const auto extraArgs = ::extraArgs();
    foreach (const QByteArray& arg, extraArgs) {
        clangArguments << arg.constData();
    }

    QVector<CXUnsavedFile> unsaved;
    //For PrecompiledHeader, we don't want unsaved contents (and contents.isEmpty())
    if (!options.testFlag(PrecompiledHeader)) {
        unsaved = toClangApi(unsavedFiles);
    }

    // debugging: print hypothetical clang invocation including args (for easy c&p for local testing)
    if (qEnvironmentVariableIsSet("KDEV_CLANG_DISPLAY_ARGS")) {
        QTextStream out(stdout);
        out << "Invocation: clang";
        foreach (const auto& arg, clangArguments) {
            out << " " << arg;
        }
        out << " " << tuUrl.byteArray().constData() << "\n";
    }