Index: lib/StaticAnalyzer/Core/ExprEngineC.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -649,6 +649,12 @@ (void) P; assert(N->pred_size() == 1); N = *N->pred_begin(); + if (N->pred_size() != 1) { + // FIXME: The CFG-based reasoning below does not apply. + // Do not set the value for the expression. It'd be UnknownVal by default. + Bldr.generateNode(B, Pred, state); + return; + } } assert(N->pred_size() == 1); N = *N->pred_begin(); Index: tools/extra/clang-tidy/ClangTidy.h =================================================================== --- tools/extra/clang-tidy/ClangTidy.h +++ tools/extra/clang-tidy/ClangTidy.h @@ -235,7 +235,7 @@ const tooling::CompilationDatabase &Compilations, ArrayRef InputFiles, llvm::IntrusiveRefCntPtr BaseFS, - bool EnableCheckProfile = false, + bool FixResolutions, bool EnableCheckProfile = false, llvm::StringRef StoreCheckProfile = StringRef()); // FIXME: This interface will need to be significantly extended to be useful. Index: tools/extra/clang-tidy/ClangTidy.cpp =================================================================== --- tools/extra/clang-tidy/ClangTidy.cpp +++ tools/extra/clang-tidy/ClangTidy.cpp @@ -507,7 +507,8 @@ const CompilationDatabase &Compilations, ArrayRef InputFiles, llvm::IntrusiveRefCntPtr BaseFS, - bool EnableCheckProfile, llvm::StringRef StoreCheckProfile) { + bool FixResolutions, bool EnableCheckProfile, + llvm::StringRef StoreCheckProfile) { ClangTool Tool(Compilations, InputFiles, std::make_shared(), BaseFS); @@ -550,7 +551,7 @@ Context.setEnableProfiling(EnableCheckProfile); Context.setProfileStoragePrefix(StoreCheckProfile); - ClangTidyDiagnosticConsumer DiagConsumer(Context); + ClangTidyDiagnosticConsumer DiagConsumer(Context, true, FixResolutions); DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions(), &DiagConsumer, /*ShouldOwnClient=*/false); Context.setDiagnosticsEngine(&DE); Index: tools/extra/clang-tidy/ClangTidyDiagnosticConsumer.h =================================================================== --- tools/extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ tools/extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -226,7 +226,8 @@ class ClangTidyDiagnosticConsumer : public DiagnosticConsumer { public: ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx, - bool RemoveIncompatibleErrors = true); + bool RemoveIncompatibleErrors = true, + bool FixResolutions = false); // FIXME: The concept of converting between FixItHints and Replacements is // more generic and should be pulled out into a more useful Diagnostics @@ -252,6 +253,7 @@ ClangTidyContext &Context; bool RemoveIncompatibleErrors; + bool FixResolutions; std::vector Errors; std::unique_ptr HeaderFilter; bool LastErrorRelatesToUserCode; Index: tools/extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp =================================================================== --- tools/extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ tools/extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -33,8 +33,10 @@ public: ClangTidyDiagnosticRenderer(const LangOptions &LangOpts, DiagnosticOptions *DiagOpts, - ClangTidyError &Error) - : DiagnosticRenderer(LangOpts, DiagOpts), Error(Error) {} + ClangTidyError &Error, + bool FixResolutions) + : DiagnosticRenderer(LangOpts, DiagOpts), Error(Error), + FixResolutions(FixResolutions) {} protected: void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, @@ -81,10 +83,13 @@ llvm::Error Err = Error.Fix[Replacement.getFilePath()].add(Replacement); // FIXME: better error handling (at least, don't let other replacements be // applied). - if (Err) { + if (Err && FixResolutions) { llvm::errs() << "Fix conflicts with existing fix! " << llvm::toString(std::move(Err)) << "\n"; assert(false && "Fix conflicts with existing fix!"); + } else if (Err) { + // Replacements wont be used for fixing anything. + consumeError(std::move(Err)); } } } @@ -104,6 +109,7 @@ private: ClangTidyError &Error; + bool FixResolutions; }; } // end anonymous namespace @@ -264,10 +270,10 @@ } ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer( - ClangTidyContext &Ctx, bool RemoveIncompatibleErrors) + ClangTidyContext &Ctx, bool RemoveIncompatibleErrors , bool FixResolutions ) : Context(Ctx), RemoveIncompatibleErrors(RemoveIncompatibleErrors), - LastErrorRelatesToUserCode(false), LastErrorPassesLineFilter(false), - LastErrorWasIgnored(false) {} + FixResolutions(FixResolutions), LastErrorRelatesToUserCode(false), + LastErrorPassesLineFilter(false), LastErrorWasIgnored(false) {} void ClangTidyDiagnosticConsumer::finalizeLastError() { if (!Errors.empty()) { @@ -444,7 +450,7 @@ ClangTidyDiagnosticRenderer Converter( Context.getLangOpts(), &Context.DiagEngine->getDiagnosticOptions(), - Errors.back()); + Errors.back(), FixResolutions); SmallString<100> Message; Info.FormatDiagnostic(Message); FullSourceLoc Loc; Index: tools/extra/clang-tidy/tool/ClangTidyMain.cpp =================================================================== --- tools/extra/clang-tidy/tool/ClangTidyMain.cpp +++ tools/extra/clang-tidy/tool/ClangTidyMain.cpp @@ -426,7 +426,7 @@ AllowEnablingAnalyzerAlphaCheckers); std::vector Errors = runClangTidy(Context, OptionsParser.getCompilations(), PathList, BaseFS, - EnableCheckProfile, ProfilePrefix); + (Fix || FixErrors), EnableCheckProfile, ProfilePrefix); bool FoundErrors = llvm::find_if(Errors, [](const ClangTidyError &E) { return E.DiagLevel == ClangTidyError::Error; }) != Errors.end(); Index: tools/extra/test/clang-tidy/clang-tidy-logicalexpr-crash.c =================================================================== --- /dev/null +++ tools/extra/test/clang-tidy/clang-tidy-logicalexpr-crash.c @@ -0,0 +1,7 @@ +// RUN: clang-tidy -checks='-*,clang-analyzer-*' %s + +a; +fn1() { + int b = -a ?: a; + (b || 0) && 9; +}