Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/../Checkers )
set(LLVM_LINK_COMPONENTS
Support
)
add_clang_library(clangStaticAnalyzerFrontend
AnalysisConsumer.cpp
CheckerRegistration.cpp
ModelConsumer.cpp
FrontendActions.cpp
ModelInjector.cpp
LINK_LIBS
clangAST
clangAnalysis
clangBasic
clangFrontend
clangLex
clangStaticAnalyzerCheckers
clangStaticAnalyzerCore
)

View File

@ -0,0 +1,154 @@
//===--- CheckerRegistration.cpp - Registration for the Analyzer Checkers -===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Defines the registration function for the analyzer checkers.
//
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/StaticAnalyzer/Checkers/ClangCheckers.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
using namespace clang;
using namespace ento;
using llvm::sys::DynamicLibrary;
namespace {
class ClangCheckerRegistry : public CheckerRegistry {
typedef void (*RegisterCheckersFn)(CheckerRegistry &);
static bool isCompatibleAPIVersion(const char *versionString);
static void warnIncompatible(DiagnosticsEngine *diags, StringRef pluginPath,
const char *pluginAPIVersion);
public:
ClangCheckerRegistry(ArrayRef<std::string> plugins,
DiagnosticsEngine *diags = nullptr);
};
} // end anonymous namespace
ClangCheckerRegistry::ClangCheckerRegistry(ArrayRef<std::string> plugins,
DiagnosticsEngine *diags) {
registerBuiltinCheckers(*this);
for (ArrayRef<std::string>::iterator i = plugins.begin(), e = plugins.end();
i != e; ++i) {
// Get access to the plugin.
std::string err;
DynamicLibrary lib = DynamicLibrary::getPermanentLibrary(i->c_str(), &err);
if (!lib.isValid()) {
diags->Report(diag::err_fe_unable_to_load_plugin) << *i << err;
continue;
}
// See if it's compatible with this build of clang.
const char *pluginAPIVersion =
(const char *) lib.getAddressOfSymbol("clang_analyzerAPIVersionString");
if (!isCompatibleAPIVersion(pluginAPIVersion)) {
warnIncompatible(diags, *i, pluginAPIVersion);
continue;
}
// Register its checkers.
RegisterCheckersFn registerPluginCheckers =
(RegisterCheckersFn) (intptr_t) lib.getAddressOfSymbol(
"clang_registerCheckers");
if (registerPluginCheckers)
registerPluginCheckers(*this);
}
}
bool ClangCheckerRegistry::isCompatibleAPIVersion(const char *versionString) {
// If the version string is null, it's not an analyzer plugin.
if (!versionString)
return false;
// For now, none of the static analyzer API is considered stable.
// Versions must match exactly.
return strcmp(versionString, CLANG_ANALYZER_API_VERSION_STRING) == 0;
}
void ClangCheckerRegistry::warnIncompatible(DiagnosticsEngine *diags,
StringRef pluginPath,
const char *pluginAPIVersion) {
if (!diags)
return;
if (!pluginAPIVersion)
return;
diags->Report(diag::warn_incompatible_analyzer_plugin_api)
<< llvm::sys::path::filename(pluginPath);
diags->Report(diag::note_incompatible_analyzer_plugin_api)
<< CLANG_ANALYZER_API_VERSION_STRING
<< pluginAPIVersion;
}
static SmallVector<CheckerOptInfo, 8>
getCheckerOptList(const AnalyzerOptions &opts) {
SmallVector<CheckerOptInfo, 8> checkerOpts;
for (unsigned i = 0, e = opts.CheckersControlList.size(); i != e; ++i) {
const std::pair<std::string, bool> &opt = opts.CheckersControlList[i];
checkerOpts.push_back(CheckerOptInfo(opt.first, opt.second));
}
return checkerOpts;
}
std::unique_ptr<CheckerManager>
ento::createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts,
ArrayRef<std::string> plugins,
DiagnosticsEngine &diags) {
std::unique_ptr<CheckerManager> checkerMgr(
new CheckerManager(langOpts, opts));
SmallVector<CheckerOptInfo, 8> checkerOpts = getCheckerOptList(opts);
ClangCheckerRegistry allCheckers(plugins, &diags);
allCheckers.initializeManager(*checkerMgr, checkerOpts);
allCheckers.validateCheckerOptions(opts, diags);
checkerMgr->finishedCheckerRegistration();
for (unsigned i = 0, e = checkerOpts.size(); i != e; ++i) {
if (checkerOpts[i].isUnclaimed()) {
diags.Report(diag::err_unknown_analyzer_checker)
<< checkerOpts[i].getName();
diags.Report(diag::note_suggest_disabling_all_checkers);
}
}
return checkerMgr;
}
void ento::printCheckerHelp(raw_ostream &out, ArrayRef<std::string> plugins) {
out << "OVERVIEW: Clang Static Analyzer Checkers List\n\n";
out << "USAGE: -analyzer-checker <CHECKER or PACKAGE,...>\n\n";
ClangCheckerRegistry(plugins).printHelp(out);
}
void ento::printEnabledCheckerList(raw_ostream &out,
ArrayRef<std::string> plugins,
const AnalyzerOptions &opts) {
out << "OVERVIEW: Clang Static Analyzer Enabled Checkers List\n\n";
SmallVector<CheckerOptInfo, 8> checkerOpts = getCheckerOptList(opts);
ClangCheckerRegistry(plugins).printList(out, checkerOpts);
}

View File

@ -0,0 +1,28 @@
//===--- FrontendActions.cpp ----------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Frontend/FrontendActions.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);
}
ParseModelFileAction::ParseModelFileAction(llvm::StringMap<Stmt *> &Bodies)
: Bodies(Bodies) {}
std::unique_ptr<ASTConsumer>
ParseModelFileAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
return llvm::make_unique<ModelConsumer>(Bodies);
}

View File

@ -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;
}

View File

@ -0,0 +1,115 @@
//===-- 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 "clang/AST/Decl.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/FileSystem.h"
#include <utility>
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;
}
auto Invocation = std::make_shared<CompilerInvocation>(CI.getInvocation());
FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
InputKind IK = InputKind::CXX; // FIXME
FrontendOpts.Inputs.clear();
FrontendOpts.Inputs.emplace_back(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(CI.getPCHContainerOperations());
Instance.setInvocation(std::move(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.getPreprocessorPtr());
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);
}

View File

@ -0,0 +1,70 @@
//===-- 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 "clang/Analysis/CodeInjector.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) override;
Stmt *getBody(const ObjCMethodDecl *D) override;
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