Hi Ted,
On 20 August 2014 07:18, Ted Kremenek <[email protected]> wrote:
>
> On Aug 16, 2014, at 5:47 AM, Gábor Horváth <[email protected]> wrote:
>
> Sorry for my oversight about the turned off asserts, I guess we need to
> iterate a bit more on the patch.
>
>
> Hi Gábor,
>
> Sounds good!
>
> The attached patch appears to generate new warnings when compiled:
>
> lib/StaticAnalyzer/Core/BugReporter.cpp:3091:30: warning: unused
> variable 'LCtx' [-Wunused-variable]
> const LocationContext *LCtx = E->getLocationContext();
> ^
>
>
Fixed.
> I'm also still seeing assertion failures, but this time in other tests:
>
> Assertion failed: (NumEnteredSourceFiles == 0 && "Cannot reenter the main
> file!"), function EnterMainSourceFile, file lib/Lex/Preprocessor.cpp, line
> 484.
> 0 clang 0x000000010cfcb668
> llvm::sys::PrintStackTrace(__sFILE*) + 40
> 1 clang 0x000000010cfcbb54 SignalHandler(int) + 564
> 2 libsystem_platform.dylib 0x00007fff8f835f1a _sigtramp + 26
> 3 clang 0x000000010e7775e9 guard variable for
> isAllowedIDChar(unsigned int, clang::LangOptions const&)::C99AllowedIDChars
> + 58369
> 4 clang 0x000000010cfcb906 abort + 22
> 5 clang 0x000000010cfcb8e1 __assert_rtn + 81
> 6 clang 0x000000010e27c449
> clang::Preprocessor::EnterMainSourceFile() + 537
> 7 clang 0x000000010d874e7b
> clang::ParseAST(clang::Sema&, bool, bool) + 187
> 8 clang 0x000000010d1ce1d3
> clang::FrontendAction::Execute() + 67
> 9 clang 0x000000010d1a1b7c
> clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) + 972
> 10 clang 0x000000010d208bc5
> clang::ExecuteCompilerInvocation(clang::CompilerInstance*) + 4149
> 11 clang 0x000000010c699834
> cc1_main(llvm::ArrayRef<char const*>, char const*, void*) + 804
> 12 clang 0x000000010c697fa4 main + 8788
> 13 libdyld.dylib 0x00007fff97fa15c9 start + 1
> Stack dump:
> 0. Program arguments:/trunk-RelWithDebInfo/./bin/clang -cc1
> -internal-isystem/trunk-RelWithDebInfo/bin/../lib/clang/3.6.0/include -Wall
> -fsyntax-only clang/test/Misc/serialized-diags-single-issue.c
> /clang/test/Misc/serialized-diags-single-issue.c
> -serialize-diagnostic-file/trunk-RelWithDebInfo/tools/clang/test/Misc/Output/serialized-diags-single-issue.c.tmp
> 1. <eof> parser at end of file
> /cmake-make/trunk-RelWithDebInfo/tools/clang/test/Misc/Output/serialized-diags-single-issue.c.script:
> line 6: 56078 Illegal instruction: 4 trunk-RelWithDebInfo/./bin/clang -cc1
> -internal-isystem/trunk-RelWithDebInfo/bin/../lib/clang/3.6.0/include -Wall
> -fsyntax-only /clang/test/Misc/serialized-diags-single-issue.c
> /clang/test/Misc/serialized-diags-single-issue.c
> -serialize-diagnostic-file/trunk-RelWithDebInfo/tools/clang/test/Misc/Output/serialized-diags-single-issue.c.tmp
>
>
> and
>
> Assertion failed: (NumEnteredSourceFiles == 0 && "Cannot reenter the main
> file!"), function EnterMainSourceFile,
> file /llvm-trunk/tools/clang/lib/Lex/Preprocessor.cpp, line 484.
> 0 clang 0x00000001105fa668
> llvm::sys::PrintStackTrace(__sFILE*) + 40
> 1 clang 0x00000001105fab54 SignalHandler(int) + 564
> 2 libsystem_platform.dylib 0x00007fff8f835f1a _sigtramp + 26
> 3 libsystem_platform.dylib 0x00007fff65330764 _sigtramp + 3585058916
> 4 clang 0x00000001105fa906 abort + 22
> 5 clang 0x00000001105fa8e1 __assert_rtn + 81
> 6 clang 0x00000001118ab449
> clang::Preprocessor::EnterMainSourceFile() + 537
> 7 clang 0x0000000110ea3e7b
> clang::ParseAST(clang::Sema&, bool, bool) + 187
> 8 clang 0x0000000110b48c7b
> clang::CodeGenAction::ExecuteAction() + 123
> 9 clang 0x00000001107fd1d3
> clang::FrontendAction::Execute() + 67
> 10 clang 0x00000001107d0b7c
> clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) + 972
> 11 clang 0x0000000110837bc5
> clang::ExecuteCompilerInvocation(clang::CompilerInstance*) + 4149
> 12 clang 0x000000010fcc8834
> cc1_main(llvm::ArrayRef<char const*>, char const*, void*) + 804
> 13 clang 0x000000010fcc6fa4 main + 8788
> 14 libdyld.dylib 0x00007fff97fa15c9 start + 1
> Stack dump:
> 0. Program arguments: /cmake-make/trunk-RelWithDebInfo/./bin/clang -cc1
> -internal-isystem
> cmake-make/trunk-RelWithDebInfo/bin/../lib/clang/3.6.0/include
> -triple x86_64-apple-macosx10.9.0 -include /clang/test/PCH/local_static.h
> -fsyntax-only clang/test/PCH/local_static.cpp -emit-llvm
> -o
> cmake-make/trunk-RelWithDebInfo/tools/clang/test/PCH/Output/local_static.cpp.tmp.no_pch.ll
> /clang/test/PCH/local_static.cpp
> 1. <eof> parser at end of file
> /cmake-make/trunk-RelWithDebInfo/tools/clang/test/PCH/Output/local_static.cpp.script:
> line 5: 57780 Illegal instruction: 4
> /cmake-make/trunk-RelWithDebInfo/./bin/clang -cc1
> -internal-isystem
> /cmake-make/trunk-RelWithDebInfo/bin/../lib/clang/3.6.0/include
> -triple x86_64-apple-macosx10.9.0 -include clang/test/PCH/local_static.h
> -fsyntax-only /clang/test/PCH/local_static.cpp -emit-llvm
> -o
> /cmake-make/trunk-RelWithDebInfo/tools/clang/test/PCH/Output/local_static.cpp.tmp.no_pch.ll
> /clang/test/PCH/local_static.cpp
>
> Are you seeing these failures as well?
>
>
It looks like in some scenarios the preprocessor was reused even though the
source file was not a model file. I have fixed this issue as well.
Thanks,
Gábor
> Thanks,
> Ted
>
>
>
Index: include/clang/Analysis/AnalysisContext.h
===================================================================
--- include/clang/Analysis/AnalysisContext.h (revision 216044)
+++ include/clang/Analysis/AnalysisContext.h (working copy)
@@ -17,8 +17,10 @@
#include "clang/AST/Decl.h"
#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/CodeInjector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/Allocator.h"
#include <memory>
@@ -143,6 +145,14 @@
/// \sa getBody
bool isBodyAutosynthesized() const;
+ /// \brief Checks if the body of the Decl is generated by the BodyFarm from a
+ /// model file.
+ ///
+ /// Note, the lookup is not free. We are going to call getBody behind
+ /// the scenes.
+ /// \sa getBody
+ bool isBodyAutosynthesizedFromModelFile() const;
+
CFG *getCFG();
CFGStmtMap *getCFGStmtMap();
@@ -398,6 +408,10 @@
ContextMap Contexts;
LocationContextManager LocContexts;
CFG::BuildOptions cfgBuildOptions;
+
+ /// Pointer to an interface that can provide function bodies for
+ /// declarations from external source.
+ llvm::OwningPtr<CodeInjector> Injector;
/// Flag to indicate whether or not bodies should be synthesized
/// for well-known functions.
@@ -410,7 +424,8 @@
bool addTemporaryDtors = false,
bool synthesizeBodies = false,
bool addStaticInitBranches = false,
- bool addCXXNewAllocator = true);
+ bool addCXXNewAllocator = true,
+ CodeInjector* injector = nullptr);
~AnalysisDeclContextManager();
Index: include/clang/Analysis/CodeInjector.h
===================================================================
--- include/clang/Analysis/CodeInjector.h (revision 0)
+++ include/clang/Analysis/CodeInjector.h (working copy)
@@ -0,0 +1,46 @@
+//===-- CodeInjector.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines the clang::CodeInjector interface which is responsible for
+/// injecting AST of function definitions that may not be available in the
+/// original source.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CODEINJECTOR_H
+#define LLVM_CLANG_ANALYSIS_CODEINJECTOR_H
+
+namespace clang {
+
+class Stmt;
+class FunctionDecl;
+class ObjCMethodDecl;
+
+/// \brief CodeInjector is an interface which is responsible for injecting AST
+/// of function definitions that may not be available in the original source.
+///
+/// The getBody function will be called each time the static analyzer examines a
+/// function call that has no definition available in the current translation
+/// unit. If the returned statement is not a null pointer, it is assumed to be
+/// the body of a function which will be used for the analysis. The source of
+/// the body can be arbitrary, but it is advised to use memoization to avoid
+/// unnecessary reparsing of the external source that provides the body of the
+/// functions.
+class CodeInjector {
+public:
+ CodeInjector();
+ virtual ~CodeInjector();
+
+ virtual Stmt *getBody(const FunctionDecl *D) = 0;
+ virtual Stmt *getBody(const ObjCMethodDecl *D) = 0;
+};
+}
+
+#endif
\ No newline at end of file
Index: include/clang/Basic/SourceManager.h
===================================================================
--- include/clang/Basic/SourceManager.h (revision 216044)
+++ include/clang/Basic/SourceManager.h (working copy)
@@ -754,7 +754,6 @@
/// \brief Set the file ID for the main source file.
void setMainFileID(FileID FID) {
- assert(MainFileID.isInvalid() && "MainFileID already set!");
MainFileID = FID;
}
Index: include/clang/Frontend/FrontendAction.h
===================================================================
--- include/clang/Frontend/FrontendAction.h (revision 216044)
+++ include/clang/Frontend/FrontendAction.h (working copy)
@@ -157,6 +157,13 @@
/// @name Supported Modes
/// @{
+ /// \brief Is this action invoked on a model file?
+ ///
+ /// Model files are incomplete translation units that relies on type
+ /// information from another translation unit. Check ParseModelFileAction for
+ /// details.
+ virtual bool isModelParsingAction() const { return false; }
+
/// \brief Does this action only use the preprocessor?
///
/// If so no AST context will be created and this action will be invalid
@@ -224,6 +231,7 @@
void ExecuteAction() override;
public:
+ ASTFrontendAction() {}
bool usesPreprocessorOnly() const override { return false; }
};
Index: include/clang/Lex/Preprocessor.h
===================================================================
--- include/clang/Lex/Preprocessor.h (revision 216044)
+++ include/clang/Lex/Preprocessor.h (working copy)
@@ -194,6 +194,10 @@
/// with this preprocessor.
PragmaNamespace *PragmaHandlers;
+ /// \brief Pragma handlers of the original source is stored here during the
+ /// parsing of a model file.
+ PragmaNamespace *PragmaHandlersBackup;
+
/// \brief Tracks all of the comment handlers that the client registered
/// with this preprocessor.
std::vector<CommentHandler *> CommentHandlers;
@@ -464,6 +468,17 @@
/// lifetime of the preprocessor.
void Initialize(const TargetInfo &Target);
+ /// \brief Initialize the preprocessor to parse a model file
+ ///
+ /// To parse model files the preprocessor of the original source is reused to
+ /// preserver the identifier table. However to avoid some duplicate
+ /// information in the preprocessor some cleanup is needed before it is used
+ /// to parse model files. This method does that cleanup.
+ void InitializeForModelFile();
+
+ /// \brief Cleanup after model file parsing
+ void FinalizeForModelFile();
+
/// \brief Retrieve the preprocessor options used to initialize this
/// preprocessor.
PreprocessorOptions &getPreprocessorOpts() const { return *PPOpts; }
Index: include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h (revision 216044)
+++ include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h (working copy)
@@ -23,6 +23,8 @@
namespace clang {
+class CodeInjector;
+
namespace ento {
class CheckerManager;
@@ -50,7 +52,8 @@
StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr,
CheckerManager *checkerMgr,
- AnalyzerOptions &Options);
+ AnalyzerOptions &Options,
+ CodeInjector* injector = nullptr);
~AnalysisManager();
Index: include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h
===================================================================
--- include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h (revision 216044)
+++ include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h (working copy)
@@ -25,6 +25,8 @@
class Preprocessor;
class DiagnosticsEngine;
+class CodeInjector;
+class CompilerInstance;
namespace ento {
class CheckerManager;
@@ -38,8 +40,7 @@
/// analysis passes. (The set of analyses run is controlled by command-line
/// options.)
std::unique_ptr<AnalysisASTConsumer>
-CreateAnalysisConsumer(const Preprocessor &pp, const std::string &output,
- AnalyzerOptionsRef opts, ArrayRef<std::string> plugins);
+CreateAnalysisConsumer(CompilerInstance &CI);
} // end GR namespace
Index: include/clang/StaticAnalyzer/Frontend/FrontendActions.h
===================================================================
--- include/clang/StaticAnalyzer/Frontend/FrontendActions.h (revision 216044)
+++ include/clang/StaticAnalyzer/Frontend/FrontendActions.h (working copy)
@@ -11,9 +11,13 @@
#define LLVM_CLANG_STATICANALYZER_FRONTEND_FRONTENDACTIONS_H
#include "clang/Frontend/FrontendAction.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringMap.h"
namespace clang {
+class Stmt;
+
namespace ento {
//===----------------------------------------------------------------------===//
@@ -26,6 +30,27 @@
StringRef InFile) override;
};
+/// \brief Frontend action to parse model files.
+///
+/// This frontend action is responsible for parsing model files. Model files can
+/// not be parsed on their own, they rely on type information that is available
+/// in another translation unit. The parsing of model files is done by a
+/// separate compiler instance that reuses the ASTContext and othen information
+/// from the main translation unit that is being compiled. After a model file is
+/// parsed, the function definitions will be collected into a StringMap.
+class ParseModelFileAction : public ASTFrontendAction {
+public:
+ ParseModelFileAction(llvm::StringMap<Stmt *> &Bodies);
+ bool isModelParsingAction() const override { return true; }
+
+protected:
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
+
+private:
+ llvm::StringMap<Stmt *> &Bodies;
+};
+
void printCheckerHelp(raw_ostream &OS, ArrayRef<std::string> plugins);
} // end GR namespace
Index: include/clang/StaticAnalyzer/Frontend/ModelConsumer.h
===================================================================
--- include/clang/StaticAnalyzer/Frontend/ModelConsumer.h (revision 0)
+++ include/clang/StaticAnalyzer/Frontend/ModelConsumer.h (working copy)
@@ -0,0 +1,44 @@
+//===-- ModelConsumer.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements clang::ento::ModelConsumer which is an
+/// ASTConsumer for model files.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_MODELCONSUMER_H
+#define LLVM_CLANG_GR_MODELCONSUMER_H
+
+#include "clang/AST/ASTConsumer.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace clang {
+
+class Stmt;
+
+namespace ento {
+
+/// \brief ASTConsumer to consume model files' AST.
+///
+/// This consumer collects the bodies of function definitions into a StringMap
+/// from a model file.
+class ModelConsumer : public ASTConsumer {
+public:
+ ModelConsumer(llvm::StringMap<Stmt *> &Bodies);
+
+ bool HandleTopLevelDecl(DeclGroupRef D) override;
+
+private:
+ llvm::StringMap<Stmt *> &Bodies;
+};
+}
+}
+
+#endif
Index: lib/Analysis/AnalysisDeclContext.cpp
===================================================================
--- lib/Analysis/AnalysisDeclContext.cpp (revision 216044)
+++ lib/Analysis/AnalysisDeclContext.cpp (working copy)
@@ -69,8 +69,9 @@
bool addTemporaryDtors,
bool synthesizeBodies,
bool addStaticInitBranch,
- bool addCXXNewAllocator)
- : SynthesizeBodies(synthesizeBodies)
+ bool addCXXNewAllocator,
+ CodeInjector *injector)
+ : Injector(injector), SynthesizeBodies(synthesizeBodies)
{
cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
@@ -84,8 +85,8 @@
llvm::DeleteContainerSeconds(Contexts);
}
-static BodyFarm &getBodyFarm(ASTContext &C) {
- static BodyFarm *BF = new BodyFarm(C);
+static BodyFarm &getBodyFarm(ASTContext &C, CodeInjector *injector = nullptr) {
+ static BodyFarm *BF = new BodyFarm(C, injector);
return *BF;
}
@@ -94,7 +95,7 @@
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Stmt *Body = FD->getBody();
if (!Body && Manager && Manager->synthesizeBodies()) {
- Body = getBodyFarm(getASTContext()).getBody(FD);
+ Body = getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(FD);
if (Body)
IsAutosynthesized = true;
}
@@ -103,7 +104,7 @@
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
Stmt *Body = MD->getBody();
if (!Body && Manager && Manager->synthesizeBodies()) {
- Body = getBodyFarm(getASTContext()).getBody(MD);
+ Body = getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(MD);
if (Body)
IsAutosynthesized = true;
}
@@ -128,6 +129,13 @@
return Tmp;
}
+bool AnalysisDeclContext::isBodyAutosynthesizedFromModelFile() const {
+ bool Tmp;
+ Stmt *Body = getBody(Tmp);
+ return Tmp && Body->getLocStart().isValid();
+}
+
+
const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
return MD->getSelfDecl();
Index: lib/Analysis/BodyFarm.cpp
===================================================================
--- lib/Analysis/BodyFarm.cpp (revision 216044)
+++ lib/Analysis/BodyFarm.cpp (working copy)
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "BodyFarm.h"
+#include "clang/Analysis/CodeInjector.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
@@ -383,6 +384,7 @@
}
if (FF) { Val = FF(C, D); }
+ else if (Injector) { Val = Injector->getBody(D); }
return Val.getValue();
}
Index: lib/Analysis/BodyFarm.h
===================================================================
--- lib/Analysis/BodyFarm.h (revision 216044)
+++ lib/Analysis/BodyFarm.h (working copy)
@@ -27,10 +27,11 @@
class ObjCMethodDecl;
class ObjCPropertyDecl;
class Stmt;
+class CodeInjector;
class BodyFarm {
public:
- BodyFarm(ASTContext &C) : C(C) {}
+ BodyFarm(ASTContext &C, CodeInjector *injector) : C(C), Injector(injector) {}
/// Factory method for creating bodies for ordinary functions.
Stmt *getBody(const FunctionDecl *D);
@@ -43,6 +44,7 @@
ASTContext &C;
BodyMap Bodies;
+ CodeInjector *Injector;
};
}
Index: lib/Analysis/CMakeLists.txt
===================================================================
--- lib/Analysis/CMakeLists.txt (revision 216044)
+++ lib/Analysis/CMakeLists.txt (working copy)
@@ -11,6 +11,7 @@
CallGraph.cpp
CocoaConventions.cpp
Consumed.cpp
+ CodeInjector.cpp
Dominators.cpp
DataflowWorklist.cpp
FormatString.cpp
Index: lib/Analysis/CodeInjector.cpp
===================================================================
--- lib/Analysis/CodeInjector.cpp (revision 0)
+++ lib/Analysis/CodeInjector.cpp (working copy)
@@ -0,0 +1,15 @@
+//===-- CodeInjector.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/CodeInjector.h"
+
+using namespace clang;
+
+CodeInjector::CodeInjector() {}
+CodeInjector::~CodeInjector() {}
\ No newline at end of file
Index: lib/Frontend/CompilerInstance.cpp
===================================================================
--- lib/Frontend/CompilerInstance.cpp (revision 216044)
+++ lib/Frontend/CompilerInstance.cpp (working copy)
@@ -806,8 +806,9 @@
llvm::EnableStatistics();
for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) {
- // Reset the ID tables if we are reusing the SourceManager.
- if (hasSourceManager())
+ // Reset the ID tables if we are reusing the SourceManager and parsing
+ // regular files.
+ if (hasSourceManager() && !Act.isModelParsingAction())
getSourceManager().clearIDTables();
if (Act.BeginSourceFile(*this, getFrontendOpts().Inputs[i])) {
Index: lib/Frontend/FrontendAction.cpp
===================================================================
--- lib/Frontend/FrontendAction.cpp (revision 216044)
+++ lib/Frontend/FrontendAction.cpp (working copy)
@@ -287,8 +287,10 @@
}
}
- // Set up the preprocessor.
- CI.createPreprocessor(getTranslationUnitKind());
+ // Set up the preprocessor if needed. When parsing model files the
+ // preprocessor of the original source is reused.
+ if (!isModelParsingAction())
+ CI.createPreprocessor(getTranslationUnitKind());
// Inform the diagnostic client we are processing a source file.
CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
@@ -307,7 +309,9 @@
// Create the AST context and consumer unless this is a preprocessor only
// action.
if (!usesPreprocessorOnly()) {
- CI.createASTContext();
+ // Parsing a model file should reuse the existing ASTContext.
+ if (!isModelParsingAction())
+ CI.createASTContext();
std::unique_ptr<ASTConsumer> Consumer =
CreateWrappedASTConsumer(CI, InputFile);
@@ -314,7 +318,9 @@
if (!Consumer)
goto failure;
- CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
+ // FIXME: should not overwrite ASTMutationListener when parsing model files?
+ if (!isModelParsingAction())
+ CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
// Convert headers to PCH and chain them.
Index: lib/Lex/Preprocessor.cpp
===================================================================
--- lib/Lex/Preprocessor.cpp (revision 216044)
+++ lib/Lex/Preprocessor.cpp (working copy)
@@ -187,6 +187,25 @@
HeaderInfo.setTarget(Target);
}
+void Preprocessor::InitializeForModelFile() {
+ NumEnteredSourceFiles = 0;
+
+ // Reset pragmas
+ PragmaHandlersBackup = PragmaHandlers;
+ PragmaHandlers = new PragmaNamespace(StringRef());
+ RegisterBuiltinPragmas();
+
+ // Reset PredefinesFileID
+ PredefinesFileID = FileID();
+}
+
+void Preprocessor::FinalizeForModelFile() {
+ NumEnteredSourceFiles = 1;
+
+ delete PragmaHandlers;
+ PragmaHandlers = PragmaHandlersBackup;
+}
+
void Preprocessor::setPTHManager(PTHManager* pm) {
PTH.reset(pm);
FileMgr.addStatCache(PTH->createStatCache());
Index: lib/StaticAnalyzer/Core/AnalysisManager.cpp
===================================================================
--- lib/StaticAnalyzer/Core/AnalysisManager.cpp (revision 216044)
+++ lib/StaticAnalyzer/Core/AnalysisManager.cpp (working copy)
@@ -20,13 +20,16 @@
StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr,
CheckerManager *checkerMgr,
- AnalyzerOptions &Options)
+ AnalyzerOptions &Options,
+ CodeInjector *injector)
: AnaCtxMgr(Options.UnoptimizedCFG,
/*AddImplicitDtors=*/true,
/*AddInitializers=*/true,
Options.includeTemporaryDtorsInCFG(),
Options.shouldSynthesizeBodies(),
- Options.shouldConditionalizeStaticInitializers()),
+ Options.shouldConditionalizeStaticInitializers(),
+ /*addCXXNewAllocator=*/true,
+ injector),
Ctx(ctx),
Diags(diags),
LangOpts(lang),
Index: lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
===================================================================
--- lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (revision 216044)
+++ lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (working copy)
@@ -18,6 +18,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/CodeInjector.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CallGraph.h"
@@ -33,6 +34,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
+#include "clang/Frontend/CompilerInstance.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -42,6 +44,7 @@
#include "llvm/Support/Program.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
+#include "ModelInjector.h"
#include <memory>
#include <queue>
@@ -157,6 +160,7 @@
const std::string OutDir;
AnalyzerOptionsRef Opts;
ArrayRef<std::string> Plugins;
+ CodeInjector *Injector;
/// \brief Stores the declarations from the local translation unit.
/// Note, we pre-compute the local declarations at parse time as an
@@ -184,9 +188,10 @@
AnalysisConsumer(const Preprocessor& pp,
const std::string& outdir,
AnalyzerOptionsRef opts,
- ArrayRef<std::string> plugins)
- : RecVisitorMode(0), RecVisitorBR(nullptr),
- Ctx(nullptr), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins) {
+ ArrayRef<std::string> plugins,
+ CodeInjector *injector)
+ : RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr), PP(pp),
+ OutDir(outdir), Opts(opts), Plugins(plugins), Injector(injector) {
DigestAnalyzerOptions();
if (Opts->PrintStats) {
llvm::EnableStatistics();
@@ -286,6 +291,7 @@
Ctx = &Context;
checkerMgr.reset(createCheckerManager(*Opts, PP.getLangOpts(), Plugins,
PP.getDiagnostics()));
+
Mgr.reset(new AnalysisManager(*Ctx,
PP.getDiagnostics(),
PP.getLangOpts(),
@@ -293,7 +299,8 @@
CreateStoreMgr,
CreateConstraintMgr,
checkerMgr.get(),
- *Opts));
+ *Opts,
+ Injector));
}
/// \brief Store the top level decls in the set to be processed later on.
@@ -688,13 +695,17 @@
//===----------------------------------------------------------------------===//
std::unique_ptr<AnalysisASTConsumer>
-ento::CreateAnalysisConsumer(const Preprocessor &pp, const std::string &outDir,
- AnalyzerOptionsRef opts,
- ArrayRef<std::string> plugins) {
+ento::CreateAnalysisConsumer(CompilerInstance &CI) {
// Disable the effects of '-Werror' when using the AnalysisConsumer.
- pp.getDiagnostics().setWarningsAsErrors(false);
+ CI.getPreprocessor().getDiagnostics().setWarningsAsErrors(false);
- return llvm::make_unique<AnalysisConsumer>(pp, outDir, opts, plugins);
+ AnalyzerOptionsRef analyzerOpts = CI.getAnalyzerOpts();
+ bool hasModelPath = analyzerOpts->Config.count("model-path") > 0;
+
+ return llvm::make_unique<AnalysisConsumer>(
+ CI.getPreprocessor(), CI.getFrontendOpts().OutputFile, analyzerOpts,
+ CI.getFrontendOpts().Plugins,
+ hasModelPath ? new ModelInjector(CI) : nullptr);
}
//===----------------------------------------------------------------------===//
Index: lib/StaticAnalyzer/Frontend/CMakeLists.txt
===================================================================
--- lib/StaticAnalyzer/Frontend/CMakeLists.txt (revision 216044)
+++ lib/StaticAnalyzer/Frontend/CMakeLists.txt (working copy)
@@ -7,7 +7,9 @@
add_clang_library(clangStaticAnalyzerFrontend
AnalysisConsumer.cpp
CheckerRegistration.cpp
+ ModelConsumer.cpp
FrontendActions.cpp
+ ModelInjector.cpp
LINK_LIBS
clangAST
Index: lib/StaticAnalyzer/Frontend/FrontendActions.cpp
===================================================================
--- lib/StaticAnalyzer/Frontend/FrontendActions.cpp (revision 216044)
+++ lib/StaticAnalyzer/Frontend/FrontendActions.cpp (working copy)
@@ -8,16 +8,21 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
-#include "clang/Frontend/CompilerInstance.h"
#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
+#include "clang/StaticAnalyzer/Frontend/ModelConsumer.h"
using namespace clang;
using namespace ento;
std::unique_ptr<ASTConsumer>
AnalysisAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
- return CreateAnalysisConsumer(CI.getPreprocessor(),
- CI.getFrontendOpts().OutputFile,
- CI.getAnalyzerOpts(),
- CI.getFrontendOpts().Plugins);
+ return CreateAnalysisConsumer(CI);
}
+ParseModelFileAction::ParseModelFileAction(llvm::StringMap<Stmt *> &Bodies)
+ : Bodies(Bodies) {}
+
+std::unique_ptr<ASTConsumer>
+ParseModelFileAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ return llvm::make_unique<ModelConsumer>(Bodies);
+}
Index: lib/StaticAnalyzer/Frontend/ModelConsumer.cpp
===================================================================
--- lib/StaticAnalyzer/Frontend/ModelConsumer.cpp (revision 0)
+++ lib/StaticAnalyzer/Frontend/ModelConsumer.cpp (working copy)
@@ -0,0 +1,42 @@
+//===--- ModelConsumer.cpp - ASTConsumer for consuming model files --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements an ASTConsumer for consuming model files.
+///
+/// This ASTConsumer handles the AST of a parsed model file. All top level
+/// function definitions will be collected from that model file for later
+/// retrieval during the static analysis. The body of these functions will not
+/// be injected into the ASTUnit of the analyzed translation unit. It will be
+/// available through the BodyFarm which is utilized by the AnalysisDeclContext
+/// class.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Frontend/ModelConsumer.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclGroup.h"
+
+using namespace clang;
+using namespace ento;
+
+ModelConsumer::ModelConsumer(llvm::StringMap<Stmt *> &Bodies)
+ : Bodies(Bodies) {}
+
+bool ModelConsumer::HandleTopLevelDecl(DeclGroupRef D) {
+ for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
+
+ // Only interested in definitions.
+ const FunctionDecl *func = llvm::dyn_cast<FunctionDecl>(*I);
+ if (func && func->hasBody()) {
+ Bodies.insert(std::make_pair(func->getName(), func->getBody()));
+ }
+ }
+ return true;
+}
\ No newline at end of file
Index: lib/StaticAnalyzer/Frontend/ModelInjector.cpp
===================================================================
--- lib/StaticAnalyzer/Frontend/ModelInjector.cpp (revision 0)
+++ lib/StaticAnalyzer/Frontend/ModelInjector.cpp (working copy)
@@ -0,0 +1,119 @@
+//===-- ModelInjector.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ModelInjector.h"
+
+#include <string>
+#include <utility>
+
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
+#include "clang/Serialization/ASTReader.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/AST/Decl.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace clang;
+using namespace ento;
+
+ModelInjector::ModelInjector(CompilerInstance &CI) : CI(CI) {}
+
+Stmt *ModelInjector::getBody(const FunctionDecl *D) {
+ onBodySynthesis(D);
+ return Bodies[D->getName()];
+}
+
+Stmt *ModelInjector::getBody(const ObjCMethodDecl *D) {
+ onBodySynthesis(D);
+ return Bodies[D->getName()];
+}
+
+void ModelInjector::onBodySynthesis(const NamedDecl *D) {
+
+ // FIXME: what about overloads? Declarations can be used as keys but what
+ // about file name index? Mangled names may not be suitable for that either.
+ if (Bodies.count(D->getName()) != 0)
+ return;
+
+ SourceManager &SM = CI.getSourceManager();
+ FileID mainFileID = SM.getMainFileID();
+
+ AnalyzerOptionsRef analyzerOpts = CI.getAnalyzerOpts();
+ llvm::StringRef modelPath = analyzerOpts->Config["model-path"];
+
+ llvm::SmallString<128> fileName;
+
+ if (!modelPath.empty())
+ fileName =
+ llvm::StringRef(modelPath.str() + "/" + D->getName().str() + ".model");
+ else
+ fileName = llvm::StringRef(D->getName().str() + ".model");
+
+ if (!llvm::sys::fs::exists(fileName.str())) {
+ Bodies[D->getName()] = nullptr;
+ return;
+ }
+
+ IntrusiveRefCntPtr<CompilerInvocation> Invocation(
+ new CompilerInvocation(CI.getInvocation()));
+
+ FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
+ InputKind IK = IK_CXX; // FIXME
+ FrontendOpts.Inputs.clear();
+ FrontendOpts.Inputs.push_back(FrontendInputFile(fileName, IK));
+ FrontendOpts.DisableFree = true;
+
+ Invocation->getDiagnosticOpts().VerifyDiagnostics = 0;
+
+ // Modules are parsed by a separate CompilerInstance, so this code mimics that
+ // behavior for models
+ CompilerInstance Instance;
+ Instance.setInvocation(&*Invocation);
+ Instance.createDiagnostics(
+ new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
+ /*ShouldOwnClient=*/true);
+
+ Instance.getDiagnostics().setSourceManager(&SM);
+
+ Instance.setVirtualFileSystem(&CI.getVirtualFileSystem());
+
+ // The instance wants to take ownership, however DisableFree frontend option
+ // is set to true to avoid double free issues
+ Instance.setFileManager(&CI.getFileManager());
+ Instance.setSourceManager(&SM);
+ Instance.setPreprocessor(&CI.getPreprocessor());
+ Instance.setASTContext(&CI.getASTContext());
+
+ Instance.getPreprocessor().InitializeForModelFile();
+
+ ParseModelFileAction parseModelFile(Bodies);
+
+ const unsigned ThreadStackSize = 8 << 20;
+ llvm::CrashRecoveryContext CRC;
+
+ CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(parseModelFile); },
+ ThreadStackSize);
+
+ Instance.getPreprocessor().FinalizeForModelFile();
+
+ Instance.resetAndLeakSourceManager();
+ Instance.resetAndLeakFileManager();
+ Instance.resetAndLeakPreprocessor();
+
+ // The preprocessor enters to the main file id when parsing is started, so
+ // the main file id is changed to the model file during parsing and it needs
+ // to be reseted to the former main file id after parsing of the model file
+ // is done.
+ SM.setMainFileID(mainFileID);
+}
Index: lib/StaticAnalyzer/Frontend/ModelInjector.h
===================================================================
--- lib/StaticAnalyzer/Frontend/ModelInjector.h (revision 0)
+++ lib/StaticAnalyzer/Frontend/ModelInjector.h (working copy)
@@ -0,0 +1,75 @@
+//===-- ModelInjector.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file defines the clang::ento::ModelInjector class which implements the
+/// clang::CodeInjector interface. This class is responsible for injecting
+/// function definitions that were synthesized from model files.
+///
+/// Model files allow definitions of functions to be lazily constituted for functions
+/// which lack bodies in the original source code. This allows the analyzer
+/// to more precisely analyze code that calls such functions, analyzing the
+/// artificial definitions (which typically approximate the semantics of the
+/// called function) when called by client code. These definitions are
+/// reconstituted lazily, on-demand, by the static analyzer engine.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SA_FRONTEND_MODELINJECTOR_H
+#define LLVM_CLANG_SA_FRONTEND_MODELINJECTOR_H
+
+#include <map>
+#include <vector>
+#include <memory>
+
+#include "clang/Analysis/CodeInjector.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace clang {
+
+class CompilerInstance;
+class ASTUnit;
+class ASTReader;
+class NamedDecl;
+class Module;
+
+namespace ento {
+class ModelInjector : public CodeInjector {
+public:
+ ModelInjector(CompilerInstance &CI);
+ Stmt *getBody(const FunctionDecl *D);
+ Stmt *getBody(const ObjCMethodDecl *D);
+
+private:
+ /// \brief Synthesize a body for a declaration
+ ///
+ /// This method first looks up the appropriate model file based on the
+ /// model-path configuration option and the name of the declaration that is
+ /// looked up. If no model were synthesized yet for a function with that name
+ /// it will create a new compiler instance to parse the model file using the
+ /// ASTContext, Preprocessor, SourceManager of the original compiler instance.
+ /// The former resources are shared between the two compiler instance, so the
+ /// newly created instance have to "leak" these objects, since they are owned
+ /// by the original instance.
+ ///
+ /// The model-path should be either an absolute path or relative to the
+ /// working directory of the compiler.
+ void onBodySynthesis(const NamedDecl *D);
+
+ CompilerInstance &CI;
+
+ // FIXME: double memoization is redundant, with memoization both here and in
+ // BodyFarm.
+ llvm::StringMap<Stmt *> Bodies;
+};
+}
+}
+
+#endif
\ No newline at end of file
Index: test/Analysis/Inputs/Models/modeledFunction.model
===================================================================
--- test/Analysis/Inputs/Models/modeledFunction.model (revision 0)
+++ test/Analysis/Inputs/Models/modeledFunction.model (working copy)
@@ -0,0 +1,3 @@
+void modelled(intptr p) {
+ ++*p;
+}
\ No newline at end of file
Index: test/Analysis/Inputs/Models/notzero.model
===================================================================
--- test/Analysis/Inputs/Models/notzero.model (revision 0)
+++ test/Analysis/Inputs/Models/notzero.model (working copy)
@@ -0,0 +1,3 @@
+bool notzero(int i) {
+ return i != 0;
+}
\ No newline at end of file
Index: test/Analysis/model-file.cpp
===================================================================
--- test/Analysis/model-file.cpp (revision 0)
+++ test/Analysis/model-file.cpp (working copy)
@@ -0,0 +1,288 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config faux-bodies=true,model-path=%S/Inputs/Models -analyzer-output=plist-multi-file -verify %s -o %t
+// RUN: FileCheck --input-file=%t %s
+
+typedef int* intptr;
+
+// This function is modeled and the p pointer is dereferenced in the model
+// function and there is no function definition available. The modeled
+// function can use any types that are available in the original translation
+// unit, for example intptr in this case.
+void modeledFunction(intptr p);
+
+// This function is modeled and returns true if the parameter is not zero
+// and there is no function definition available.
+bool notzero(int i);
+
+// This functions is not modeled and there is no function definition.
+// available
+bool notzero_notmodeled(int i);
+
+int main() {
+ // There is a nullpointer dereference inside this function.
+ modeledFunction(0);
+
+ int p = 0;
+ if (notzero(p)) {
+ // It is known that p != 0 because of the information provided by the
+ // model of the notzero function.
+ int j = 5 / p;
+ }
+
+ if (notzero_notmodeled(p)) {
+ // There is no information about the value of p, because
+ // notzero_notmodeled is not modeled and the function definition
+ // is not available.
+ int j = 5 / p; // expected-warning {{Division by zero}}
+ }
+
+ return 0;
+}
+
+// CHECK: <key>diagnostics</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>'p' initialized to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>'p' initialized to 0</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Division by zero</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Division by zero</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>main</string>
+// CHECK-NEXT: <key>issue_hash</key><string>15</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
\ No newline at end of file
Index: lib/StaticAnalyzer/Core/BugReporter.cpp
===================================================================
--- lib/StaticAnalyzer/Core/BugReporter.cpp (revision 216044)
+++ lib/StaticAnalyzer/Core/BugReporter.cpp (working copy)
@@ -3247,15 +3247,15 @@
// To guarantee memory release.
std::unique_ptr<BugReport> UniqueR(R);
- // Defensive checking: throw the bug away if it comes from a BodyFarm-
- // generated body. We do this very early because report processing relies
- // on the report's location being valid.
- // FIXME: Valid bugs can occur in BodyFarm-generated bodies, so really we
- // need to just find a reasonable location like we do later on with the path
- // pieces.
if (const ExplodedNode *E = R->getErrorNode()) {
- const LocationContext *LCtx = E->getLocationContext();
- if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized())
+ const AnalysisDeclContext *DeclCtx =
+ E->getLocationContext()->getAnalysisDeclContext();
+ // The source of autosynthesized body can be handcrafted AST or a model
+ // file. The locations from handcrafted ASTs have no valid source locations
+ // and have to be discarded. Locations from model files should be preserved
+ // for processing and reporting.
+ if (DeclCtx->isBodyAutosynthesized() &&
+ !DeclCtx->isBodyAutosynthesizedFromModelFile())
return;
}
Index: clang-tidy/ClangTidy.cpp
===================================================================
--- clang-tidy/ClangTidy.cpp (revision 215559)
+++ clang-tidy/ClangTidy.cpp (working copy)
@@ -241,9 +241,7 @@
AnalyzerOptions->AnalyzeNestedBlocks = true;
AnalyzerOptions->eagerlyAssumeBinOpBifurcation = true;
std::unique_ptr<ento::AnalysisASTConsumer> AnalysisConsumer =
- ento::CreateAnalysisConsumer(
- Compiler.getPreprocessor(), Compiler.getFrontendOpts().OutputFile,
- AnalyzerOptions, Compiler.getFrontendOpts().Plugins);
+ ento::CreateAnalysisConsumer(Compiler);
AnalysisConsumer->AddDiagnosticConsumer(
new AnalyzerDiagnosticConsumer(Context));
Consumers.push_back(std::move(AnalysisConsumer));
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits