Index: include/clang-c/Index.h =================================================================== --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -32,7 +32,7 @@ * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable. */ #define CINDEX_VERSION_MAJOR 0 -#define CINDEX_VERSION_MINOR 57 +#define CINDEX_VERSION_MINOR 58 #define CINDEX_VERSION_ENCODE(major, minor) ( \ ((major) * 10000) \ @@ -1341,7 +1341,17 @@ /** * Used to indicate that implicit attributes should be visited. */ - CXTranslationUnit_VisitImplicitAttributes = 0x2000 + CXTranslationUnit_VisitImplicitAttributes = 0x2000, + + /** + * Used to indicate that non-errors from included files should be ignored. + * + * If set, clang_getDiagnosticSetFromTU() will not report e.g. warnings from + * included files anymore. This speeds up clang_getDiagnosticSetFromTU() for + * the case where these warnings are not of interest, as for an IDE for + * example, which typically shows only the diagnostics in the main file. + */ + CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles = 0x4000 }; /** Index: include/clang/Frontend/ASTUnit.h =================================================================== --- include/clang/Frontend/ASTUnit.h +++ include/clang/Frontend/ASTUnit.h @@ -82,6 +82,9 @@ /// \brief Enumerates the available scopes for skipping function bodies. enum class SkipFunctionBodiesScope { None, Preamble, PreambleAndMainFile }; +/// \brief Enumerates the available kinds for capturing diagnostics. +enum class CaptureDiagsKind { None, All, AllWithoutNonErrorsFromIncludes }; + /// Utility class for loading a ASTContext from an AST file. class ASTUnit { public: @@ -144,7 +147,7 @@ bool OnlyLocalDecls = false; /// Whether to capture any diagnostics produced. - bool CaptureDiagnostics = false; + CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None; /// Track whether the main file was loaded from an AST or not. bool MainFileIsAST; @@ -247,7 +250,7 @@ bool UserFilesAreVolatile : 1; static void ConfigureDiags(IntrusiveRefCntPtr Diags, - ASTUnit &AST, bool CaptureDiagnostics); + ASTUnit &AST, CaptureDiagsKind CaptureDiagnostics); void TranslateStoredDiagnostics(FileManager &FileMgr, SourceManager &SrcMan, @@ -656,8 +659,8 @@ /// Create a ASTUnit. Gets ownership of the passed CompilerInvocation. static std::unique_ptr create(std::shared_ptr CI, - IntrusiveRefCntPtr Diags, bool CaptureDiagnostics, - bool UserFilesAreVolatile); + IntrusiveRefCntPtr Diags, + CaptureDiagsKind CaptureDiagnostics, bool UserFilesAreVolatile); enum WhatToLoad { /// Load options and the preprocessor state. @@ -685,7 +688,8 @@ WhatToLoad ToLoad, IntrusiveRefCntPtr Diags, const FileSystemOptions &FileSystemOpts, bool UseDebugInfo = false, bool OnlyLocalDecls = false, ArrayRef RemappedFiles = None, - bool CaptureDiagnostics = false, bool AllowPCHWithCompilerErrors = false, + CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, + bool AllowPCHWithCompilerErrors = false, bool UserFilesAreVolatile = false); private: @@ -743,7 +747,8 @@ IntrusiveRefCntPtr Diags, FrontendAction *Action = nullptr, ASTUnit *Unit = nullptr, bool Persistent = true, StringRef ResourceFilesPath = StringRef(), - bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, + bool OnlyLocalDecls = false, + CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, unsigned PrecompilePreambleAfterNParses = 0, bool CacheCodeCompletionResults = false, bool IncludeBriefCommentsInCodeCompletion = false, @@ -768,7 +773,8 @@ std::shared_ptr CI, std::shared_ptr PCHContainerOps, IntrusiveRefCntPtr Diags, FileManager *FileMgr, - bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, + bool OnlyLocalDecls = false, + CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, unsigned PrecompilePreambleAfterNParses = 0, TranslationUnitKind TUKind = TU_Complete, bool CacheCodeCompletionResults = false, @@ -808,7 +814,8 @@ const char **ArgBegin, const char **ArgEnd, std::shared_ptr PCHContainerOps, IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, - bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, + bool OnlyLocalDecls = false, + CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, ArrayRef RemappedFiles = None, bool RemappedFilesKeepOriginalName = true, unsigned PrecompilePreambleAfterNParses = 0, Index: lib/Frontend/ASTUnit.cpp =================================================================== --- lib/Frontend/ASTUnit.cpp +++ lib/Frontend/ASTUnit.cpp @@ -608,17 +608,20 @@ }; /// Diagnostic consumer that saves each diagnostic it is given. -class StoredDiagnosticConsumer : public DiagnosticConsumer { +class FilterAndStoreDiagnosticConsumer : public DiagnosticConsumer { SmallVectorImpl *StoredDiags; SmallVectorImpl *StandaloneDiags; + bool CaptureNonErrorsFromIncludes = true; const LangOptions *LangOpts = nullptr; SourceManager *SourceMgr = nullptr; public: - StoredDiagnosticConsumer( + FilterAndStoreDiagnosticConsumer( SmallVectorImpl *StoredDiags, - SmallVectorImpl *StandaloneDiags) - : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags) { + SmallVectorImpl *StandaloneDiags, + bool CaptureNonErrorsFromIncludes) + : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags), + CaptureNonErrorsFromIncludes(CaptureNonErrorsFromIncludes) { assert((StoredDiags || StandaloneDiags) && "No output collections were passed to StoredDiagnosticConsumer."); } @@ -634,21 +637,25 @@ const Diagnostic &Info) override; }; -/// RAII object that optionally captures diagnostics, if +/// RAII object that optionally captures and filters diagnostics, if /// there is no diagnostic client to capture them already. class CaptureDroppedDiagnostics { DiagnosticsEngine &Diags; - StoredDiagnosticConsumer Client; + FilterAndStoreDiagnosticConsumer Client; DiagnosticConsumer *PreviousClient = nullptr; std::unique_ptr OwningPreviousClient; public: CaptureDroppedDiagnostics( - bool RequestCapture, DiagnosticsEngine &Diags, + CaptureDiagsKind CaptureDiagnostics, DiagnosticsEngine &Diags, SmallVectorImpl *StoredDiags, SmallVectorImpl *StandaloneDiags) - : Diags(Diags), Client(StoredDiags, StandaloneDiags) { - if (RequestCapture || Diags.getClient() == nullptr) { + : Diags(Diags), + Client(StoredDiags, StandaloneDiags, + CaptureDiagnostics != + CaptureDiagsKind::AllWithoutNonErrorsFromIncludes) { + if (CaptureDiagnostics != CaptureDiagsKind::None || + Diags.getClient() == nullptr) { OwningPreviousClient = Diags.takeClient(); PreviousClient = Diags.getClient(); Diags.setClient(&Client, false); @@ -667,8 +674,16 @@ makeStandaloneDiagnostic(const LangOptions &LangOpts, const StoredDiagnostic &InDiag); -void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level, - const Diagnostic &Info) { +static bool isInMainFile(const clang::Diagnostic &D) { + if (!D.hasSourceManager() || !D.getLocation().isValid()) + return false; + + auto &M = D.getSourceManager(); + return M.isWrittenInMainFile(M.getExpansionLoc(D.getLocation())); +} + +void FilterAndStoreDiagnosticConsumer::HandleDiagnostic( + DiagnosticsEngine::Level Level, const Diagnostic &Info) { // Default implementation (Warnings/errors count). DiagnosticConsumer::HandleDiagnostic(Level, Info); @@ -676,6 +691,11 @@ // about. This effectively drops diagnostics from modules we're building. // FIXME: In the long run, ee don't want to drop source managers from modules. if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr) { + if (!CaptureNonErrorsFromIncludes && Level <= DiagnosticsEngine::Warning && + !isInMainFile(Info)) { + return; + } + StoredDiagnostic *ResultDiag = nullptr; if (StoredDiags) { StoredDiags->emplace_back(Level, Info); @@ -723,10 +743,13 @@ /// Configure the diagnostics object for use with ASTUnit. void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr Diags, - ASTUnit &AST, bool CaptureDiagnostics) { + ASTUnit &AST, + CaptureDiagsKind CaptureDiagnostics) { assert(Diags.get() && "no DiagnosticsEngine was provided"); - if (CaptureDiagnostics) - Diags->setClient(new StoredDiagnosticConsumer(&AST.StoredDiagnostics, nullptr)); + if (CaptureDiagnostics != CaptureDiagsKind::None) + Diags->setClient(new FilterAndStoreDiagnosticConsumer( + &AST.StoredDiagnostics, nullptr, + CaptureDiagnostics != CaptureDiagsKind::AllWithoutNonErrorsFromIncludes)); } std::unique_ptr ASTUnit::LoadFromASTFile( @@ -734,7 +757,7 @@ WhatToLoad ToLoad, IntrusiveRefCntPtr Diags, const FileSystemOptions &FileSystemOpts, bool UseDebugInfo, bool OnlyLocalDecls, ArrayRef RemappedFiles, - bool CaptureDiagnostics, bool AllowPCHWithCompilerErrors, + CaptureDiagsKind CaptureDiagnostics, bool AllowPCHWithCompilerErrors, bool UserFilesAreVolatile) { std::unique_ptr AST(new ASTUnit(true)); @@ -1334,8 +1357,8 @@ ASTUnitPreambleCallbacks Callbacks; { llvm::Optional Capture; - if (CaptureDiagnostics) - Capture.emplace(/*RequestCapture=*/true, *Diagnostics, &NewPreambleDiags, + if (CaptureDiagnostics != CaptureDiagsKind::None) + Capture.emplace(CaptureDiagnostics, *Diagnostics, &NewPreambleDiags, &NewPreambleDiagsStandalone); // We did not previously compute a preamble, or it can't be reused anyway. @@ -1462,7 +1485,8 @@ std::unique_ptr ASTUnit::create(std::shared_ptr CI, IntrusiveRefCntPtr Diags, - bool CaptureDiagnostics, bool UserFilesAreVolatile) { + CaptureDiagsKind CaptureDiagnostics, + bool UserFilesAreVolatile) { std::unique_ptr AST(new ASTUnit(false)); ConfigureDiags(Diags, *AST, CaptureDiagnostics); IntrusiveRefCntPtr VFS = @@ -1484,7 +1508,7 @@ std::shared_ptr PCHContainerOps, IntrusiveRefCntPtr Diags, FrontendAction *Action, ASTUnit *Unit, bool Persistent, StringRef ResourceFilesPath, - bool OnlyLocalDecls, bool CaptureDiagnostics, + bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, unsigned PrecompilePreambleAfterNParses, bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile, std::unique_ptr *ErrAST) { @@ -1662,7 +1686,7 @@ std::shared_ptr CI, std::shared_ptr PCHContainerOps, IntrusiveRefCntPtr Diags, FileManager *FileMgr, - bool OnlyLocalDecls, bool CaptureDiagnostics, + bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile) { @@ -1699,7 +1723,7 @@ const char **ArgBegin, const char **ArgEnd, std::shared_ptr PCHContainerOps, IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, - bool OnlyLocalDecls, bool CaptureDiagnostics, + bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, ArrayRef RemappedFiles, bool RemappedFilesKeepOriginalName, unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, @@ -2156,7 +2180,7 @@ // Set up diagnostics, capturing any diagnostics produced. Clang->setDiagnostics(&Diag); - CaptureDroppedDiagnostics Capture(true, + CaptureDroppedDiagnostics Capture(CaptureDiagsKind::All, Clang->getDiagnostics(), &StoredDiagnostics, nullptr); ProcessWarningOptions(Diag, Inv.getDiagnosticOpts()); Index: test/Index/ignore-warnings-from-headers.h =================================================================== --- /dev/null +++ test/Index/ignore-warnings-from-headers.h @@ -0,0 +1 @@ +void f(int unusedInHeader) {} Index: test/Index/ignore-warnings-from-headers.cpp =================================================================== --- /dev/null +++ test/Index/ignore-warnings-from-headers.cpp @@ -0,0 +1,7 @@ +#include "ignore-warnings-from-headers.h" + +void g(int unusedInMainFile) {} + +// RUN: env CINDEXTEST_IGNORE_NONERRORS_FROM_INCLUDED_FILES=1 c-index-test -test-load-source function %s -Wunused-parameter 2>&1 | FileCheck %s +// CHECK-NOT: warning: unused parameter 'unusedInHeader' +// CHECK: warning: unused parameter 'unusedInMainFile' Index: tools/c-index-test/c-index-test.c =================================================================== --- tools/c-index-test/c-index-test.c +++ tools/c-index-test/c-index-test.c @@ -88,6 +88,8 @@ options |= CXTranslationUnit_IncludeAttributedTypes; if (getenv("CINDEXTEST_VISIT_IMPLICIT_ATTRIBUTES")) options |= CXTranslationUnit_VisitImplicitAttributes; + if (getenv("CINDEXTEST_IGNORE_NONERRORS_FROM_INCLUDED_FILES")) + options |= CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles; return options; } Index: tools/c-index-test/core_main.cpp =================================================================== --- tools/c-index-test/core_main.cpp +++ tools/c-index-test/core_main.cpp @@ -264,7 +264,7 @@ modulePath, *pchRdr, ASTUnit::LoadASTOnly, Diags, FileSystemOpts, /*UseDebugInfo=*/false, /*OnlyLocalDecls=*/true, None, - /*CaptureDiagnostics=*/false, + CaptureDiagsKind::None, /*AllowPCHWithCompilerErrors=*/true, /*UserFilesAreVolatile=*/false); if (!AU) { Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -3352,7 +3352,7 @@ ASTUnit::LoadEverything, Diags, FileSystemOpts, /*UseDebugInfo=*/false, CXXIdx->getOnlyLocalDecls(), None, - /*CaptureDiagnostics=*/true, + CaptureDiagsKind::All, /*AllowPCHWithCompilerErrors=*/true, /*UserFilesAreVolatile=*/true); *out_TU = MakeCXTranslationUnit(CXXIdx, std::move(AU)); @@ -3425,6 +3425,10 @@ if (options & CXTranslationUnit_KeepGoing) Diags->setFatalsAsError(true); + CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::All; + if (options & CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles) + CaptureDiagnostics = CaptureDiagsKind::AllWithoutNonErrorsFromIncludes; + // Recover resources if we crash before exiting this function. llvm::CrashRecoveryContextCleanupRegistrar > @@ -3502,7 +3506,7 @@ Args->data(), Args->data() + Args->size(), CXXIdx->getPCHContainerOperations(), Diags, CXXIdx->getClangResourcesPath(), CXXIdx->getOnlyLocalDecls(), - /*CaptureDiagnostics=*/true, *RemappedFiles.get(), + CaptureDiagnostics, *RemappedFiles.get(), /*RemappedFilesKeepOriginalName=*/true, PrecompilePreambleAfterNParses, TUKind, CacheCodeCompletionResults, IncludeBriefCommentsInCodeCompletion, /*AllowPCHWithCompilerErrors=*/true, SkipFunctionBodies, SingleFileParse, Index: tools/libclang/Indexing.cpp =================================================================== --- tools/libclang/Indexing.cpp +++ tools/libclang/Indexing.cpp @@ -443,10 +443,14 @@ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) setThreadBackgroundPriority(); - bool CaptureDiagnostics = !Logger::isLoggingEnabled(); + CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::All; + if (TU_options & CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles) + CaptureDiagnostics = CaptureDiagsKind::AllWithoutNonErrorsFromIncludes; + if (Logger::isLoggingEnabled()) + CaptureDiagnostics = CaptureDiagsKind::None; CaptureDiagnosticConsumer *CaptureDiag = nullptr; - if (CaptureDiagnostics) + if (CaptureDiagnostics != CaptureDiagsKind::None) CaptureDiag = new CaptureDiagnosticConsumer(); // Configure the diagnostics. Index: unittests/Frontend/ASTUnitTest.cpp =================================================================== --- unittests/Frontend/ASTUnitTest.cpp +++ unittests/Frontend/ASTUnitTest.cpp @@ -51,8 +51,8 @@ PCHContainerOps = std::make_shared(); return ASTUnit::LoadFromCompilerInvocation( - CInvok, PCHContainerOps, Diags, FileMgr, false, false, 0, TU_Complete, - false, false, isVolatile); + CInvok, PCHContainerOps, Diags, FileMgr, false, CaptureDiagsKind::None, + 0, TU_Complete, false, false, isVolatile); } }; Index: unittests/Frontend/PCHPreambleTest.cpp =================================================================== --- unittests/Frontend/PCHPreambleTest.cpp +++ unittests/Frontend/PCHPreambleTest.cpp @@ -96,8 +96,8 @@ FileManager *FileMgr = new FileManager(FSOpts, VFS); std::unique_ptr AST = ASTUnit::LoadFromCompilerInvocation( - CI, PCHContainerOpts, Diags, FileMgr, false, false, - /*PrecompilePreambleAfterNParses=*/1); + CI, PCHContainerOpts, Diags, FileMgr, false, CaptureDiagsKind::None, + /*PrecompilePreambleAfterNParses=*/1); return AST; }