CheckerRegistration.cpp revision b7b0608c3aeee3eb9f14520eb7eff159b855a34b
143dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis//===--- CheckerRegistration.cpp - Registration for the Analyzer Checkers -===//
243dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis//
343dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis//                     The LLVM Compiler Infrastructure
443dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis//
543dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis// This file is distributed under the University of Illinois Open Source
643dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis// License. See LICENSE.TXT for details.
743dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis//
843dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis//===----------------------------------------------------------------------===//
943dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis//
1043dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis// Defines the registration function for the analyzer checkers.
1143dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis//
1243dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis//===----------------------------------------------------------------------===//
1343dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis
1427af04bcca46f8a3374586be1301477f9123f5e1Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
15116f3640daee424dfcdbe55e80be5a67476be4b0Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
1608b86531ade68727c56918f162816075b87c864aJordy Rose#include "clang/StaticAnalyzer/Checkers/ClangCheckers.h"
1743dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/CheckerManager.h"
1808b86531ade68727c56918f162816075b87c864aJordy Rose#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
1908b86531ade68727c56918f162816075b87c864aJordy Rose#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
2043dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis#include "clang/Frontend/AnalyzerOptions.h"
2143dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis#include "clang/Frontend/FrontendDiagnostic.h"
2243dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis#include "clang/Basic/Diagnostic.h"
2377a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose#include "llvm/Support/DynamicLibrary.h"
24a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose#include "llvm/Support/Path.h"
25116f3640daee424dfcdbe55e80be5a67476be4b0Argyrios Kyrtzidis#include "llvm/Support/raw_ostream.h"
2643dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis#include "llvm/ADT/OwningPtr.h"
2743dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis#include "llvm/ADT/SmallVector.h"
2843dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis
2943dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidisusing namespace clang;
3043dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidisusing namespace ento;
3177a33a71701b59affb5337d9e2b57d69bc095c7dJordy Roseusing llvm::sys::DynamicLibrary;
3243dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis
3377a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rosenamespace {
3477a33a71701b59affb5337d9e2b57d69bc095c7dJordy Roseclass ClangCheckerRegistry : public CheckerRegistry {
3577a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose  typedef void (*RegisterCheckersFn)(CheckerRegistry &);
3608b86531ade68727c56918f162816075b87c864aJordy Rose
3777a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose  static bool isCompatibleAPIVersion(const char *versionString);
38a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose  static void warnIncompatible(Diagnostic *diags, StringRef pluginPath,
39a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose                               const char *pluginAPIVersion);
40a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose
41a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rosepublic:
42a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose  ClangCheckerRegistry(ArrayRef<std::string> plugins, Diagnostic *diags = 0);
4377a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose};
4477a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose
4577a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose} // end anonymous namespace
4677a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose
47a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy RoseClangCheckerRegistry::ClangCheckerRegistry(ArrayRef<std::string> plugins,
48a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose                                           Diagnostic *diags) {
4977a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose  registerBuiltinCheckers(*this);
5077a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose
5177a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose  for (ArrayRef<std::string>::iterator i = plugins.begin(), e = plugins.end();
5277a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose       i != e; ++i) {
5377a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose    // Get access to the plugin.
5477a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose    DynamicLibrary lib = DynamicLibrary::getPermanentLibrary(i->c_str());
5577a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose
5677a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose    // See if it's compatible with this build of clang.
5777a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose    const char *pluginAPIVersion =
5877a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose      (const char *) lib.getAddressOfSymbol("clang_analyzerAPIVersionString");
59a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose    if (!isCompatibleAPIVersion(pluginAPIVersion)) {
60a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose      warnIncompatible(diags, *i, pluginAPIVersion);
6177a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose      continue;
62a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose    }
6377a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose
6477a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose    // Register its checkers.
6577a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose    RegisterCheckersFn registerPluginCheckers =
666875325b6576ad6fa4fc457f251aaeccb8b3c724Benjamin Kramer      (RegisterCheckersFn) (intptr_t) lib.getAddressOfSymbol(
676875325b6576ad6fa4fc457f251aaeccb8b3c724Benjamin Kramer                                                      "clang_registerCheckers");
6877a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose    if (registerPluginCheckers)
6977a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose      registerPluginCheckers(*this);
7077a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose  }
7108b86531ade68727c56918f162816075b87c864aJordy Rose}
7208b86531ade68727c56918f162816075b87c864aJordy Rose
7377a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rosebool ClangCheckerRegistry::isCompatibleAPIVersion(const char *versionString) {
7477a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose  // If the version string is null, it's not an analyzer plugin.
7577a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose  if (versionString == 0)
7677a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose    return false;
7777a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose
7877a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose  // For now, none of the static analyzer API is considered stable.
7977a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose  // Versions must match exactly.
8077a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose  if (strcmp(versionString, CLANG_ANALYZER_API_VERSION_STRING) == 0)
8177a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose    return true;
8277a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose
8377a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose  return false;
8477a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose}
8577a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose
86a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rosevoid ClangCheckerRegistry::warnIncompatible(Diagnostic *diags,
87a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose                                            StringRef pluginPath,
88a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose                                            const char *pluginAPIVersion) {
89a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose  if (!diags)
90a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose    return;
91a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose  if (!pluginAPIVersion)
92a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose    return;
93a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose
94a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose  diags->Report(diag::warn_incompatible_analyzer_plugin_api)
95a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose      << llvm::sys::path::filename(pluginPath);
96a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose  diags->Report(diag::note_incompatible_analyzer_plugin_api)
97a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose      << CLANG_ANALYZER_API_VERSION_STRING
98a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose      << pluginAPIVersion;
99a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose}
100a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose
10177a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose
10208b86531ade68727c56918f162816075b87c864aJordy RoseCheckerManager *ento::createCheckerManager(const AnalyzerOptions &opts,
10308b86531ade68727c56918f162816075b87c864aJordy Rose                                           const LangOptions &langOpts,
10408b86531ade68727c56918f162816075b87c864aJordy Rose                                           ArrayRef<std::string> plugins,
10508b86531ade68727c56918f162816075b87c864aJordy Rose                                           Diagnostic &diags) {
1062e471a3e476396be1ddca4ab8b9df721bcfc9437Argyrios Kyrtzidis  llvm::OwningPtr<CheckerManager> checkerMgr(new CheckerManager(langOpts));
10743dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis
1085f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  SmallVector<CheckerOptInfo, 8> checkerOpts;
10943dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis  for (unsigned i = 0, e = opts.CheckersControlList.size(); i != e; ++i) {
11043dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis    const std::pair<std::string, bool> &opt = opts.CheckersControlList[i];
11143dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis    checkerOpts.push_back(CheckerOptInfo(opt.first.c_str(), opt.second));
11243dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis  }
11343dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis
114a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose  ClangCheckerRegistry allCheckers(plugins, &diags);
115a8fd0bc069275d8e7bc9fa72c2d93a76302e5e48Jordy Rose  allCheckers.initializeManager(*checkerMgr, checkerOpts);
116deb6447d0029bdb122397fafb5fa2a4e76f2e555Argyrios Kyrtzidis  checkerMgr->finishedCheckerRegistration();
117deb6447d0029bdb122397fafb5fa2a4e76f2e555Argyrios Kyrtzidis
11843dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis  for (unsigned i = 0, e = checkerOpts.size(); i != e; ++i) {
11943dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis    if (checkerOpts[i].isUnclaimed())
120b7b0608c3aeee3eb9f14520eb7eff159b855a34bJordy Rose      diags.Report(diag::warn_unknown_analyzer_checker)
12143dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis          << checkerOpts[i].getName();
12243dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis  }
12343dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis
12443dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis  return checkerMgr.take();
12543dee220252ef0b42c5f8a3bb1eca97f84f2565fArgyrios Kyrtzidis}
126116f3640daee424dfcdbe55e80be5a67476be4b0Argyrios Kyrtzidis
12708b86531ade68727c56918f162816075b87c864aJordy Rosevoid ento::printCheckerHelp(raw_ostream &out, ArrayRef<std::string> plugins) {
12808b86531ade68727c56918f162816075b87c864aJordy Rose  out << "OVERVIEW: Clang Static Analyzer Checkers List\n\n";
12908b86531ade68727c56918f162816075b87c864aJordy Rose  out << "USAGE: -analyzer-checker <CHECKER or PACKAGE,...>\n\n";
130116f3640daee424dfcdbe55e80be5a67476be4b0Argyrios Kyrtzidis
13177a33a71701b59affb5337d9e2b57d69bc095c7dJordy Rose  ClangCheckerRegistry(plugins).printHelp(out);
132116f3640daee424dfcdbe55e80be5a67476be4b0Argyrios Kyrtzidis}
133