diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:04:05 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:04:05 +0000 |
| commit | 676fbe8105eeb6ff4bb2ed261cb212fcfdbe7b63 (patch) | |
| tree | 02a1ac369cb734d0abfa5000dd86e5b7797e6a74 /tools | |
| parent | c7e70c433efc6953dc3888b9fbf9f3512d7da2b0 (diff) | |
Notes
Diffstat (limited to 'tools')
63 files changed, 1339 insertions, 433 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 9f76d36dba0e..43dfffe1492e 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -21,7 +21,7 @@ endif() if(CLANG_ENABLE_STATIC_ANALYZER) add_clang_subdirectory(clang-check) - add_clang_subdirectory(clang-func-mapping) + add_clang_subdirectory(clang-extdef-mapping) add_clang_subdirectory(scan-build) add_clang_subdirectory(scan-view) endif() diff --git a/tools/arcmt-test/CMakeLists.txt b/tools/arcmt-test/CMakeLists.txt index 2b456be2fcdd..c4c1463241b4 100644 --- a/tools/arcmt-test/CMakeLists.txt +++ b/tools/arcmt-test/CMakeLists.txt @@ -12,4 +12,5 @@ target_link_libraries(arcmt-test clangBasic clangFrontend clangLex + clangSerialization ) diff --git a/tools/arcmt-test/arcmt-test.cpp b/tools/arcmt-test/arcmt-test.cpp index e57d69fddbe2..80354788a30c 100644 --- a/tools/arcmt-test/arcmt-test.cpp +++ b/tools/arcmt-test/arcmt-test.cpp @@ -130,7 +130,7 @@ static bool checkForMigration(StringRef resourcesPath, return true; } - if (!CI.getLangOpts()->ObjC1) + if (!CI.getLangOpts()->ObjC) return false; arcmt::checkForManualIssues(CI, CI.getFrontendOpts().Inputs[0], @@ -170,7 +170,7 @@ static bool performTransformations(StringRef resourcesPath, return true; } - if (!origCI.getLangOpts()->ObjC1) + if (!origCI.getLangOpts()->ObjC) return false; MigrationProcess migration(origCI, std::make_shared<PCHContainerOperations>(), diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 70ab11866edd..fc6ba46fd6f2 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -84,6 +84,10 @@ static unsigned getDefaultParsingOptions() { options |= CXTranslationUnit_KeepGoing; if (getenv("CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_PREAMBLE")) options |= CXTranslationUnit_LimitSkipFunctionBodiesToPreamble; + if (getenv("CINDEXTEST_INCLUDE_ATTRIBUTED_TYPES")) + options |= CXTranslationUnit_IncludeAttributedTypes; + if (getenv("CINDEXTEST_VISIT_IMPLICIT_ATTRIBUTES")) + options |= CXTranslationUnit_VisitImplicitAttributes; return options; } @@ -1099,6 +1103,34 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) { } } + if (Cursor.kind == CXCursor_ObjCPropertyDecl) { + CXString Name = clang_Cursor_getObjCPropertyGetterName(Cursor); + CXString Spelling = clang_getCursorSpelling(Cursor); + const char *CName = clang_getCString(Name); + const char *CSpelling = clang_getCString(Spelling); + if (CName && strcmp(CName, CSpelling)) { + printf(" (getter=%s)", CName); + } + clang_disposeString(Spelling); + clang_disposeString(Name); + } + + if (Cursor.kind == CXCursor_ObjCPropertyDecl) { + CXString Name = clang_Cursor_getObjCPropertySetterName(Cursor); + CXString Spelling = clang_getCursorSpelling(Cursor); + const char *CName = clang_getCString(Name); + const char *CSpelling = clang_getCString(Spelling); + char *DefaultSetter = malloc(strlen(CSpelling) + 5); + sprintf(DefaultSetter, "set%s:", CSpelling); + DefaultSetter[3] &= ~(1 << 5); /* Make uppercase */ + if (CName && strcmp(CName, DefaultSetter)) { + printf(" (setter=%s)", CName); + } + free(DefaultSetter); + clang_disposeString(Spelling); + clang_disposeString(Name); + } + { unsigned QT = clang_Cursor_getObjCDeclQualifiers(Cursor); if (QT != CXObjCDeclQualifier_None) { @@ -1496,13 +1528,31 @@ static void PrintTypeTemplateArgs(CXType T, const char *Format) { } } +static void PrintNullabilityKind(CXType T, const char *Format) { + enum CXTypeNullabilityKind N = clang_Type_getNullability(T); + + const char *nullability = 0; + switch (N) { + case CXTypeNullability_NonNull: nullability = "nonnull"; break; + case CXTypeNullability_Nullable: nullability = "nullable"; break; + case CXTypeNullability_Unspecified: nullability = "unspecified"; break; + case CXTypeNullability_Invalid: break; + } + + if (nullability) { + printf(Format, nullability); + } +} + static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p, CXClientData d) { if (!clang_isInvalid(clang_getCursorKind(cursor))) { CXType T = clang_getCursorType(cursor); + CXType PT = clang_getPointeeType(T); enum CXRefQualifierKind RQ = clang_Type_getCXXRefQualifier(T); PrintCursor(cursor, NULL); PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]"); + PrintNullabilityKind(T, " [nullability=%s]"); if (clang_isConstQualifiedType(T)) printf(" const"); if (clang_isVolatileQualifiedType(T)) @@ -1523,12 +1573,20 @@ static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p, PrintTypeTemplateArgs(CT, " [canonicaltemplateargs/%d="); } } + /* Print the modified type if it exists. */ + { + CXType MT = clang_Type_getModifiedType(T); + if (MT.kind != CXType_Invalid) { + PrintTypeAndTypeKind(MT, " [modifiedtype=%s] [modifiedtypekind=%s]"); + } + } /* Print the return type if it exists. */ { CXType RT = clang_getCursorResultType(cursor); if (RT.kind != CXType_Invalid) { PrintTypeAndTypeKind(RT, " [resulttype=%s] [resulttypekind=%s]"); } + PrintNullabilityKind(RT, " [resultnullability=%s]"); } /* Print the argument types if they exist. */ { @@ -1540,6 +1598,42 @@ static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p, CXType T = clang_getCursorType(clang_Cursor_getArgument(cursor, i)); if (T.kind != CXType_Invalid) { PrintTypeAndTypeKind(T, " [%s] [%s]"); + PrintNullabilityKind(T, " [%s]"); + } + } + printf("]"); + } + } + /* Print ObjC base types, type arguments, and protocol list if available. */ + { + CXType BT = clang_Type_getObjCObjectBaseType(PT); + if (BT.kind != CXType_Invalid) { + PrintTypeAndTypeKind(BT, " [basetype=%s] [basekind=%s]"); + } + } + { + unsigned NumTypeArgs = clang_Type_getNumObjCTypeArgs(PT); + if (NumTypeArgs > 0) { + unsigned i; + printf(" [typeargs="); + for (i = 0; i < NumTypeArgs; ++i) { + CXType TA = clang_Type_getObjCTypeArg(PT, i); + if (TA.kind != CXType_Invalid) { + PrintTypeAndTypeKind(TA, " [%s] [%s]"); + } + } + printf("]"); + } + } + { + unsigned NumProtocols = clang_Type_getNumObjCProtocolRefs(PT); + if (NumProtocols > 0) { + unsigned i; + printf(" [protocols="); + for (i = 0; i < NumProtocols; ++i) { + CXCursor P = clang_Type_getObjCProtocolDecl(PT, i); + if (!clang_isInvalid(clang_getCursorKind(P))) { + PrintCursor(P, NULL); } } printf("]"); @@ -1549,7 +1643,6 @@ static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p, printf(" [isPOD=%d]", clang_isPODType(T)); /* Print the pointee type. */ { - CXType PT = clang_getPointeeType(T); if (PT.kind != CXType_Invalid) { PrintTypeAndTypeKind(PT, " [pointeetype=%s] [pointeekind=%s]"); } @@ -1561,13 +1654,14 @@ static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p, if (numFields != 0) { printf(" [nbFields=%d]", numFields); } - /* Print if it is an anonymous record. */ - { - unsigned isAnon = clang_Cursor_isAnonymous(cursor); - if (isAnon != 0) { - printf(" [isAnon=%d]", isAnon); - } - } + } + } + + /* Print if it is an anonymous record or namespace. */ + { + unsigned isAnon = clang_Cursor_isAnonymous(cursor); + if (isAnon != 0) { + printf(" [isAnon=%d]", isAnon); } } @@ -1720,6 +1814,23 @@ static enum CXChildVisitResult PrintTypeDeclaration(CXCursor cursor, CXCursor p, } /******************************************************************************/ +/* Declaration attributes testing */ +/******************************************************************************/ + +static enum CXChildVisitResult PrintDeclAttributes(CXCursor cursor, CXCursor p, + CXClientData d) { + if (clang_isDeclaration(cursor.kind)) { + printf("\n"); + PrintCursor(cursor, NULL); + return CXChildVisit_Recurse; + } else if (clang_isAttribute(cursor.kind)) { + printf(" "); + PrintCursor(cursor, NULL); + } + return CXChildVisit_Continue; +} + +/******************************************************************************/ /* Target information testing. */ /******************************************************************************/ @@ -4730,6 +4841,9 @@ int cindextest_main(int argc, const char **argv) { else if (argc > 2 && strcmp(argv[1], "-test-print-type-declaration") == 0) return perform_test_load_source(argc - 2, argv + 2, "all", PrintTypeDeclaration, 0); + else if (argc > 2 && strcmp(argv[1], "-test-print-decl-attributes") == 0) + return perform_test_load_source(argc - 2, argv + 2, "all", + PrintDeclAttributes, 0); else if (argc > 2 && strcmp(argv[1], "-test-print-bitwidth") == 0) return perform_test_load_source(argc - 2, argv + 2, "all", PrintBitWidth, 0); diff --git a/tools/c-index-test/core_main.cpp b/tools/c-index-test/core_main.cpp index a7732c09d5b0..b9c0f19a7fcc 100644 --- a/tools/c-index-test/core_main.cpp +++ b/tools/c-index-test/core_main.cpp @@ -20,6 +20,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Serialization/ASTReader.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/PrettyStackTrace.h" @@ -73,6 +74,7 @@ static cl::opt<std::string> static void printSymbolInfo(SymbolInfo SymInfo, raw_ostream &OS); static void printSymbolNameAndUSR(const Decl *D, ASTContext &Ctx, raw_ostream &OS); +static void printSymbolNameAndUSR(const clang::Module *Mod, raw_ostream &OS); namespace { @@ -131,8 +133,9 @@ public: return true; } - bool handleModuleOccurence(const ImportDecl *ImportD, SymbolRoleSet Roles, - SourceLocation Loc) override { + bool handleModuleOccurence(const ImportDecl *ImportD, + const clang::Module *Mod, + SymbolRoleSet Roles, SourceLocation Loc) override { ASTContext &Ctx = ImportD->getASTContext(); SourceManager &SM = Ctx.getSourceManager(); @@ -145,7 +148,8 @@ public: printSymbolInfo(getSymbolInfo(ImportD), OS); OS << " | "; - OS << ImportD->getImportedModule()->getFullModuleName() << " | "; + printSymbolNameAndUSR(Mod, OS); + OS << " | "; printSymbolRoles(Roles, OS); OS << " |\n"; @@ -202,11 +206,11 @@ static void dumpModuleFileInputs(serialization::ModuleFile &Mod, }); } -static bool printSourceSymbols(ArrayRef<const char *> Args, - bool dumpModuleImports, - bool indexLocals) { +static bool printSourceSymbols(const char *Executable, + ArrayRef<const char *> Args, + bool dumpModuleImports, bool indexLocals) { SmallVector<const char *, 4> ArgsWithProgName; - ArgsWithProgName.push_back("clang"); + ArgsWithProgName.push_back(Executable); ArgsWithProgName.append(Args.begin(), Args.end()); IntrusiveRefCntPtr<DiagnosticsEngine> Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions)); @@ -307,6 +311,12 @@ static void printSymbolNameAndUSR(const Decl *D, ASTContext &Ctx, } } +static void printSymbolNameAndUSR(const clang::Module *Mod, raw_ostream &OS) { + assert(Mod); + OS << Mod->getFullModuleName() << " | "; + generateFullUSRForModule(Mod, OS); +} + //===----------------------------------------------------------------------===// // Command line processing. //===----------------------------------------------------------------------===// @@ -314,6 +324,8 @@ static void printSymbolNameAndUSR(const Decl *D, ASTContext &Ctx, int indextest_core_main(int argc, const char **argv) { sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); + void *MainAddr = (void*) (intptr_t) indextest_core_main; + std::string Executable = llvm::sys::fs::getMainExecutable(argv[0], MainAddr); assert(argv[1] == StringRef("core")); ++argv; @@ -343,7 +355,9 @@ int indextest_core_main(int argc, const char **argv) { errs() << "error: missing compiler args; pass '-- <compiler arguments>'\n"; return 1; } - return printSourceSymbols(CompArgs, options::DumpModuleImports, options::IncludeLocals); + return printSourceSymbols(Executable.c_str(), CompArgs, + options::DumpModuleImports, + options::IncludeLocals); } return 0; diff --git a/tools/clang-check/CMakeLists.txt b/tools/clang-check/CMakeLists.txt index c5ace26c2914..b837b0a0a5d9 100644 --- a/tools/clang-check/CMakeLists.txt +++ b/tools/clang-check/CMakeLists.txt @@ -15,6 +15,7 @@ target_link_libraries(clang-check clangDriver clangFrontend clangRewriteFrontend + clangSerialization clangStaticAnalyzerFrontend clangTooling ) diff --git a/tools/clang-check/ClangCheck.cpp b/tools/clang-check/ClangCheck.cpp index f00e9a3df0ad..66d865b749a1 100644 --- a/tools/clang-check/ClangCheck.cpp +++ b/tools/clang-check/ClangCheck.cpp @@ -122,7 +122,7 @@ public: /// Subclasses \c clang::FixItAction so that we can install the custom /// \c FixItRewriter. -class FixItAction : public clang::FixItAction { +class ClangCheckFixItAction : public clang::FixItAction { public: bool BeginSourceFileAction(clang::CompilerInstance& CI) override { FixItOpts.reset(new FixItOptions); @@ -167,6 +167,7 @@ int main(int argc, const char **argv) { // Clear adjusters because -fsyntax-only is inserted by the default chain. Tool.clearArgumentsAdjusters(); Tool.appendArgumentsAdjuster(getClangStripOutputAdjuster()); + Tool.appendArgumentsAdjuster(getClangStripDependencyFileAdjuster()); // Running the analyzer requires --analyze. Other modes can work with the // -fsyntax-only option. @@ -180,7 +181,7 @@ int main(int argc, const char **argv) { if (Analyze) FrontendFactory = newFrontendActionFactory<clang::ento::AnalysisAction>(); else if (Fixit) - FrontendFactory = newFrontendActionFactory<FixItAction>(); + FrontendFactory = newFrontendActionFactory<ClangCheckFixItAction>(); else FrontendFactory = newFrontendActionFactory(&CheckFactory); diff --git a/tools/clang-diff/CMakeLists.txt b/tools/clang-diff/CMakeLists.txt index 09bebf2cb6e5..ab9a5bbbe916 100644 --- a/tools/clang-diff/CMakeLists.txt +++ b/tools/clang-diff/CMakeLists.txt @@ -10,6 +10,7 @@ target_link_libraries(clang-diff PRIVATE clangBasic clangFrontend + clangSerialization clangTooling clangToolingASTDiff ) diff --git a/tools/clang-func-mapping/CMakeLists.txt b/tools/clang-extdef-mapping/CMakeLists.txt index ae28e28d532d..6c81689a831a 100644 --- a/tools/clang-func-mapping/CMakeLists.txt +++ b/tools/clang-extdef-mapping/CMakeLists.txt @@ -1,23 +1,21 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} - asmparser support - mc ) -add_clang_executable(clang-func-mapping - ClangFnMapGen.cpp +add_clang_executable(clang-extdef-mapping + ClangExtDefMapGen.cpp ) -target_link_libraries(clang-func-mapping +target_link_libraries(clang-extdef-mapping PRIVATE clangAST clangBasic clangCrossTU clangFrontend - clangIndex + clangSerialization clangTooling ) -install(TARGETS clang-func-mapping +install(TARGETS clang-extdef-mapping RUNTIME DESTINATION bin) diff --git a/tools/clang-func-mapping/ClangFnMapGen.cpp b/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp index 4bf812fffe34..7885f3901897 100644 --- a/tools/clang-func-mapping/ClangFnMapGen.cpp +++ b/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp @@ -14,61 +14,53 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/GlobalDecl.h" -#include "clang/AST/Mangle.h" -#include "clang/AST/StmtVisitor.h" #include "clang/Basic/SourceManager.h" -#include "clang/Basic/TargetInfo.h" #include "clang/CrossTU/CrossTranslationUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" -#include "clang/Index/USRGeneration.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" #include <sstream> #include <string> -#include <vector> using namespace llvm; using namespace clang; using namespace clang::cross_tu; using namespace clang::tooling; -static cl::OptionCategory ClangFnMapGenCategory("clang-fnmapgen options"); +static cl::OptionCategory ClangExtDefMapGenCategory("clang-extdefmapgen options"); -class MapFunctionNamesConsumer : public ASTConsumer { +class MapExtDefNamesConsumer : public ASTConsumer { public: - MapFunctionNamesConsumer(ASTContext &Context) : Ctx(Context) {} + MapExtDefNamesConsumer(ASTContext &Context) + : SM(Context.getSourceManager()) {} - ~MapFunctionNamesConsumer() { + ~MapExtDefNamesConsumer() { // Flush results to standard output. llvm::outs() << createCrossTUIndexString(Index); } - virtual void HandleTranslationUnit(ASTContext &Ctx) { + void HandleTranslationUnit(ASTContext &Ctx) override { handleDecl(Ctx.getTranslationUnitDecl()); } private: void handleDecl(const Decl *D); - ASTContext &Ctx; + SourceManager &SM; llvm::StringMap<std::string> Index; std::string CurrentFileName; }; -void MapFunctionNamesConsumer::handleDecl(const Decl *D) { +void MapExtDefNamesConsumer::handleDecl(const Decl *D) { if (!D) return; if (const auto *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isThisDeclarationADefinition()) { if (const Stmt *Body = FD->getBody()) { - std::string LookupName = CrossTranslationUnitContext::getLookupName(FD); - const SourceManager &SM = Ctx.getSourceManager(); if (CurrentFileName.empty()) { CurrentFileName = SM.getFileEntryForID(SM.getMainFileID())->tryGetRealPathName(); @@ -80,8 +72,12 @@ void MapFunctionNamesConsumer::handleDecl(const Decl *D) { case ExternalLinkage: case VisibleNoLinkage: case UniqueExternalLinkage: - if (SM.isInMainFile(Body->getLocStart())) + if (SM.isInMainFile(Body->getBeginLoc())) { + std::string LookupName = + CrossTranslationUnitContext::getLookupName(FD); Index[LookupName] = CurrentFileName; + } + break; default: break; } @@ -94,13 +90,11 @@ void MapFunctionNamesConsumer::handleDecl(const Decl *D) { handleDecl(D); } -class MapFunctionNamesAction : public ASTFrontendAction { +class MapExtDefNamesAction : public ASTFrontendAction { protected: std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, llvm::StringRef) { - std::unique_ptr<ASTConsumer> PFC( - new MapFunctionNamesConsumer(CI.getASTContext())); - return PFC; + return llvm::make_unique<MapExtDefNamesConsumer>(CI.getASTContext()); } }; @@ -112,13 +106,13 @@ int main(int argc, const char **argv) { PrettyStackTraceProgram X(argc, argv); const char *Overview = "\nThis tool collects the USR name and location " - "of all functions definitions in the source files " + "of external definitions in the source files " "(excluding headers).\n"; - CommonOptionsParser OptionsParser(argc, argv, ClangFnMapGenCategory, + CommonOptionsParser OptionsParser(argc, argv, ClangExtDefMapGenCategory, cl::ZeroOrMore, Overview); ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList()); - Tool.run(newFrontendActionFactory<MapFunctionNamesAction>().get()); - return 0; + + return Tool.run(newFrontendActionFactory<MapExtDefNamesAction>().get()); } diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp index de2f9d7fe76e..49162d0d910e 100644 --- a/tools/clang-format/ClangFormat.cpp +++ b/tools/clang-format/ClangFormat.cpp @@ -116,7 +116,7 @@ namespace format { static FileID createInMemoryFile(StringRef FileName, MemoryBuffer *Source, SourceManager &Sources, FileManager &Files, - vfs::InMemoryFileSystem *MemFS) { + llvm::vfs::InMemoryFileSystem *MemFS) { MemFS->addFileNoOwn(FileName, 0, Source); return Sources.createFileID(Files.getFile(FileName), SourceLocation(), SrcMgr::C_User); @@ -133,8 +133,8 @@ static bool parseLineRange(StringRef Input, unsigned &FromLine, static bool fillRanges(MemoryBuffer *Code, std::vector<tooling::Range> &Ranges) { - IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( - new vfs::InMemoryFileSystem); + IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); FileManager Files(FileSystemOptions(), InMemoryFileSystem); DiagnosticsEngine Diagnostics( IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), @@ -301,8 +301,8 @@ static bool format(StringRef FileName) { outputReplacementsXML(Replaces); outs() << "</replacements>\n"; } else { - IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( - new vfs::InMemoryFileSystem); + IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); FileManager Files(FileSystemOptions(), InMemoryFileSystem); DiagnosticsEngine Diagnostics( IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), diff --git a/tools/clang-format/clang-format-diff.py b/tools/clang-format/clang-format-diff.py index ffa30e70ddc3..d6d351041611 100755 --- a/tools/clang-format/clang-format-diff.py +++ b/tools/clang-format/clang-format-diff.py @@ -21,15 +21,19 @@ Example usage for git/svn users: svn diff --diff-cmd=diff -x-U0 | clang-format-diff.py -i """ +from __future__ import absolute_import, division, print_function import argparse import difflib import re -import string import subprocess -import StringIO import sys +if sys.version_info.major >= 3: + from io import StringIO +else: + from io import BytesIO as StringIO + def main(): parser = argparse.ArgumentParser(description= @@ -84,14 +88,14 @@ def main(): line_count = int(match.group(3)) if line_count == 0: continue - end_line = start_line + line_count - 1; + end_line = start_line + line_count - 1 lines_by_file.setdefault(filename, []).extend( ['-lines', str(start_line) + ':' + str(end_line)]) # Reformat files containing changes in place. - for filename, lines in lines_by_file.iteritems(): + for filename, lines in lines_by_file.items(): if args.i and args.verbose: - print 'Formatting', filename + print('Formatting {}'.format(filename)) command = [args.binary, filename] if args.i: command.append('-i') @@ -100,20 +104,23 @@ def main(): command.extend(lines) if args.style: command.extend(['-style', args.style]) - p = subprocess.Popen(command, stdout=subprocess.PIPE, - stderr=None, stdin=subprocess.PIPE) + p = subprocess.Popen(command, + stdout=subprocess.PIPE, + stderr=None, + stdin=subprocess.PIPE, + universal_newlines=True) stdout, stderr = p.communicate() if p.returncode != 0: - sys.exit(p.returncode); + sys.exit(p.returncode) if not args.i: with open(filename) as f: code = f.readlines() - formatted_code = StringIO.StringIO(stdout).readlines() + formatted_code = StringIO(stdout).readlines() diff = difflib.unified_diff(code, formatted_code, filename, filename, '(before formatting)', '(after formatting)') - diff_string = string.join(diff, '') + diff_string = ''.join(diff) if len(diff_string) > 0: sys.stdout.write(diff_string) diff --git a/tools/clang-format/clang-format-sublime.py b/tools/clang-format/clang-format-sublime.py index 16ff56e502c6..5ea9a27825cb 100644 --- a/tools/clang-format/clang-format-sublime.py +++ b/tools/clang-format/clang-format-sublime.py @@ -12,7 +12,7 @@ # It operates on the current, potentially unsaved buffer and does not create # or save any files. To revert a formatting, just undo. -from __future__ import print_function +from __future__ import absolute_import, division, print_function import sublime import sublime_plugin import subprocess diff --git a/tools/clang-format/clang-format.py b/tools/clang-format/clang-format.py index 5fe592a9202b..fe068bd41c18 100644 --- a/tools/clang-format/clang-format.py +++ b/tools/clang-format/clang-format.py @@ -25,7 +25,7 @@ # # It operates on the current, potentially unsaved buffer and does not create # or save any files. To revert a formatting, just undo. -from __future__ import print_function +from __future__ import absolute_import, division, print_function import difflib import json diff --git a/tools/clang-format/git-clang-format b/tools/clang-format/git-clang-format index 0b2103962a31..96e3b4e8a2c1 100755 --- a/tools/clang-format/git-clang-format +++ b/tools/clang-format/git-clang-format @@ -23,7 +23,7 @@ git clang-format -h Requires Python 2.7 or Python 3 """ -from __future__ import print_function +from __future__ import absolute_import, division, print_function import argparse import collections import contextlib diff --git a/tools/clang-fuzzer/Dockerfile b/tools/clang-fuzzer/Dockerfile index 1946b8bf88da..9f6336c4798b 100644 --- a/tools/clang-fuzzer/Dockerfile +++ b/tools/clang-fuzzer/Dockerfile @@ -35,3 +35,7 @@ RUN mkdir build1 && cd build1 && cmake -GNinja -DCMAKE_BUILD_TYPE=Release ../llv RUN cd build1 && ninja clang-fuzzer RUN cd build1 && ninja clang-proto-fuzzer RUN cd build1 && ninja clang-proto-to-cxx +RUN cd build1 && ninja clang-loop-proto-to-cxx +RUN cd build1 && ninja clang-loop-proto-to-llvm +RUN cd build1 && ninja clang-loop-proto-fuzzer +RUN cd build1 && ninja clang-llvm-proto-fuzzer diff --git a/tools/clang-fuzzer/README.txt b/tools/clang-fuzzer/README.txt index 66a6a6332cd7..9c25afdb22ae 100644 --- a/tools/clang-fuzzer/README.txt +++ b/tools/clang-fuzzer/README.txt @@ -80,3 +80,37 @@ custom optimization level and target triple: To translate a clang-proto-fuzzer corpus output to C++: bin/clang-proto-to-cxx CORPUS_OUTPUT_FILE + +=================== + llvm-proto-fuzzer +=================== +Like, clang-proto-fuzzer, llvm-proto-fuzzer is also a protobuf-mutator based +fuzzer. It receives as input a cxx_loop_proto which it then converts into a +string of valid LLVM IR: a function with either a single loop or two nested +loops. It then creates a new string of IR by running optimization passes over +the original IR. Currently, it only runs a loop-vectorize pass but more passes +can easily be added to the fuzzer. Once there are two versions of the input +function (optimized and not), llvm-proto-fuzzer uses LLVM's JIT Engine to +compile both functions. Lastly, it runs both functions on a suite of inputs and +checks that both functions behave the same on all inputs. In this way, +llvm-proto-fuzzer can find not only compiler crashes, but also miscompiles +originating from LLVM's optimization passes. + +llvm-proto-fuzzer is built very similarly to clang-proto-fuzzer. You can run the +fuzzer with the following command: + bin/clang-llvm-proto-fuzzer CORPUS_DIR + +To translate a cxx_loop_proto file into LLVM IR do: + bin/clang-loop-proto-to-llvm CORPUS_OUTPUT_FILE +To translate a cxx_loop_proto file into C++ do: + bin/clang-loop-proto-to-cxx CORPUS_OUTPUT_FILE + +Note: To get a higher number of executions per second with llvm-proto-fuzzer it +helps to build it without ASan instrumentation and with the -O2 flag. Because +the fuzzer is not only compiling code, but also running it, as the inputs get +large, the time necessary to fuzz one input can get very high. +Example: + cmake .. -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \ + -DCLANG_ENABLE_PROTO_FUZZER=ON -DLLVM_USE_SANITIZE_COVERAGE=YES \ + -DCMAKE_CXX_FLAGS="-O2" + ninja clang-llvm-proto-fuzzer clang-loop-proto-to-llvm diff --git a/tools/clang-fuzzer/cxx_loop_proto.proto b/tools/clang-fuzzer/cxx_loop_proto.proto index f2b47ed43d89..760904b579a8 100644 --- a/tools/clang-fuzzer/cxx_loop_proto.proto +++ b/tools/clang-fuzzer/cxx_loop_proto.proto @@ -9,10 +9,11 @@ /// /// \file /// This file describes a subset of C++ as a protobuf. It is used to -/// more easily find interesting inputs for fuzzing Clang. This subset -/// differs from the one defined in cxx_proto.proto by eliminating while -/// loops and conditionals. The goal is that the C++ code generated will be -/// more likely to stress the LLVM loop vectorizer. +/// more easily find interesting inputs for fuzzing LLVM's vectorizer. +/// This subset differs from the one defined in cxx_proto.proto by eliminating +/// while loops and conditionals. The goal is that the C++ code generated will +/// be more likely to stress the LLVM loop vectorizer. The code generated will +/// contain either a single loop or two nested loops. /// //===----------------------------------------------------------------------===// @@ -74,7 +75,8 @@ message StatementSeq { } message LoopFunction { - required StatementSeq statements = 1; + optional StatementSeq inner_statements = 1; + required StatementSeq outer_statements = 2; } package clang_fuzzer; diff --git a/tools/clang-fuzzer/handle-cxx/CMakeLists.txt b/tools/clang-fuzzer/handle-cxx/CMakeLists.txt index caf1dba7af67..6d62421d9a69 100644 --- a/tools/clang-fuzzer/handle-cxx/CMakeLists.txt +++ b/tools/clang-fuzzer/handle-cxx/CMakeLists.txt @@ -8,5 +8,6 @@ add_clang_library(clangHandleCXX clangCodeGen clangFrontend clangLex + clangSerialization clangTooling ) diff --git a/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp b/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp index ef544ae711ab..86df06ab8b4b 100644 --- a/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp +++ b/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// #include "handle_llvm.h" +#include "input_arrays.h" #include "llvm/ADT/Triple.h" #include "llvm/Analysis/TargetLibraryInfo.h" @@ -48,6 +49,9 @@ using namespace llvm; +// Define a type for the functions that are compiled and executed +typedef void (*LLVMFunc)(int*, int*, int*, int); + // Helper function to parse command line args and find the optimization level static void getOptLevel(const std::vector<const char *> &ExtraArgs, CodeGenOpt::Level &OLvl) { @@ -68,7 +72,7 @@ static void getOptLevel(const std::vector<const char *> &ExtraArgs, } } -void ErrorAndExit(std::string message) { +static void ErrorAndExit(std::string message) { errs()<< "ERROR: " << message << "\n"; std::exit(1); } @@ -88,7 +92,7 @@ static void AddOptimizationPasses(legacy::PassManagerBase &MPM, } // Mimics the opt tool to run an optimization pass over the provided IR -std::string OptLLVM(const std::string &IR, CodeGenOpt::Level OLvl) { +static std::string OptLLVM(const std::string &IR, CodeGenOpt::Level OLvl) { // Create a module that will run the optimization passes SMDiagnostic Err; LLVMContext Context; @@ -96,17 +100,29 @@ std::string OptLLVM(const std::string &IR, CodeGenOpt::Level OLvl) { if (!M || verifyModule(*M, &errs())) ErrorAndExit("Could not parse IR"); + Triple ModuleTriple(M->getTargetTriple()); + const TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); + std::string E; + const Target *TheTarget = TargetRegistry::lookupTarget(MArch, ModuleTriple, E); + TargetMachine *Machine = + TheTarget->createTargetMachine(M->getTargetTriple(), getCPUStr(), + getFeaturesStr(), Options, getRelocModel(), + getCodeModel(), OLvl); + std::unique_ptr<TargetMachine> TM(Machine); setFunctionAttributes(getCPUStr(), getFeaturesStr(), *M); - + legacy::PassManager Passes; - Triple ModuleTriple(M->getTargetTriple()); Passes.add(new TargetLibraryInfoWrapperPass(ModuleTriple)); - Passes.add(createTargetTransformInfoWrapperPass(TargetIRAnalysis())); + Passes.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis())); + + LLVMTargetMachine <M = static_cast<LLVMTargetMachine &>(*TM); + Passes.add(LTM.createPassConfig(Passes)); + Passes.add(createVerifierPass()); AddOptimizationPasses(Passes, OLvl, 0); - + // Add a pass that writes the optimized IR to an output stream std::string outString; raw_string_ostream OS(outString); @@ -117,11 +133,19 @@ std::string OptLLVM(const std::string &IR, CodeGenOpt::Level OLvl) { return OS.str(); } -void CreateAndRunJITFun(const std::string &IR, CodeGenOpt::Level OLvl) { +// Takes a function and runs it on a set of inputs +// First determines whether f is the optimized or unoptimized function +static void RunFuncOnInputs(LLVMFunc f, int Arr[kNumArrays][kArraySize]) { + for (int i = 0; i < kNumArrays / 3; i++) + f(Arr[i], Arr[i + (kNumArrays / 3)], Arr[i + (2 * kNumArrays / 3)], + kArraySize); +} + +// Takes a string of IR and compiles it using LLVM's JIT Engine +static void CreateAndRunJITFunc(const std::string &IR, CodeGenOpt::Level OLvl) { SMDiagnostic Err; LLVMContext Context; - std::unique_ptr<Module> M = parseIR(MemoryBufferRef(IR, "IR"), Err, - Context); + std::unique_ptr<Module> M = parseIR(MemoryBufferRef(IR, "IR"), Err, Context); if (!M) ErrorAndExit("Could not parse IR"); @@ -148,14 +172,26 @@ void CreateAndRunJITFun(const std::string &IR, CodeGenOpt::Level OLvl) { EE->finalizeObject(); EE->runStaticConstructorsDestructors(false); - typedef void (*func)(int*, int*, int*, int); - func f = reinterpret_cast<func>(EE->getPointerToFunction(EntryFunc)); +#if defined(__GNUC__) && !defined(__clang) && \ + ((__GNUC__ == 4) && (__GNUC_MINOR__ < 9)) +// Silence +// +// warning: ISO C++ forbids casting between pointer-to-function and +// pointer-to-object [-Wpedantic] +// +// Since C++11 this casting is conditionally supported and GCC versions +// starting from 4.9.0 don't warn about the cast. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#endif + LLVMFunc f = reinterpret_cast<LLVMFunc>(EE->getPointerToFunction(EntryFunc)); +#if defined(__GNUC__) && !defined(__clang) && \ + ((__GNUC__ == 4) && (__GNUC_MINOR__ < 9)) +#pragma GCC diagnostic pop +#endif - // Define some dummy arrays to use an input for now - int a[] = {1}; - int b[] = {1}; - int c[] = {1}; - f(a, b, c, 1); + // Figure out if we are running the optimized func or the unoptimized func + RunFuncOnInputs(f, (OLvl == CodeGenOpt::None) ? UnoptArrays : OptArrays); EE->runStaticConstructorsDestructors(true); } @@ -164,6 +200,10 @@ void CreateAndRunJITFun(const std::string &IR, CodeGenOpt::Level OLvl) { // Mimics the lli tool to JIT the LLVM IR code and execute it void clang_fuzzer::HandleLLVM(const std::string &IR, const std::vector<const char *> &ExtraArgs) { + // Populate OptArrays and UnoptArrays with the arrays from InputArrays + memcpy(OptArrays, InputArrays, kTotalSize); + memcpy(UnoptArrays, InputArrays, kTotalSize); + // Parse ExtraArgs to set the optimization level CodeGenOpt::Level OLvl; getOptLevel(ExtraArgs, OLvl); @@ -171,8 +211,11 @@ void clang_fuzzer::HandleLLVM(const std::string &IR, // First we optimize the IR by running a loop vectorizer pass std::string OptIR = OptLLVM(IR, OLvl); - CreateAndRunJITFun(OptIR, OLvl); - CreateAndRunJITFun(IR, CodeGenOpt::None); - + CreateAndRunJITFunc(OptIR, OLvl); + CreateAndRunJITFunc(IR, CodeGenOpt::None); + + if (memcmp(OptArrays, UnoptArrays, kTotalSize)) + ErrorAndExit("!!!BUG!!!"); + return; } diff --git a/tools/clang-fuzzer/handle-llvm/handle_llvm.h b/tools/clang-fuzzer/handle-llvm/handle_llvm.h index 38aec6799490..1149c29cef32 100644 --- a/tools/clang-fuzzer/handle-llvm/handle_llvm.h +++ b/tools/clang-fuzzer/handle-llvm/handle_llvm.h @@ -19,7 +19,7 @@ namespace clang_fuzzer { void HandleLLVM(const std::string &S, - const std::vector<const char *> &ExtraArgs); + const std::vector<const char *> &ExtraArgs); } // namespace clang_fuzzer #endif diff --git a/tools/clang-fuzzer/handle-llvm/input_arrays.h b/tools/clang-fuzzer/handle-llvm/input_arrays.h new file mode 100644 index 000000000000..b60e3e1b2e7d --- /dev/null +++ b/tools/clang-fuzzer/handle-llvm/input_arrays.h @@ -0,0 +1,118 @@ +//==-- input_arrays.h - Helper function for LLVM fuzzer inputs -------------==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Define a few static variables used by the LLVM Proto Fuzzer +// +//===----------------------------------------------------------------------===// + +#include <climits> + +static const int kArraySize = 64; +static const int kNumArrays = 93; +static const int kTotalSize = sizeof(int) * kArraySize * kNumArrays; + +// Define two arrays that will hold the input and output for the two functions +static int OptArrays[kNumArrays][kArraySize]; +static int UnoptArrays[kNumArrays][kArraySize]; + +// Define a corpus of possible inputs +static int InputArrays[kNumArrays][kArraySize] = +{ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX}, + {INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN}, + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, + {1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024}, + {65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 0, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535}, + {-1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023}, + {INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX}, + {0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, }, + {1, 1, 0, 3, 2, 5, 6, 2, 6, 3, 0, 19, 18, 17, 16, 0, 13, 11, 9, 7, 5, 3, 1, -3000, -3000, -3000, -3000, -3000, -3000, -3000, 0, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000}, + {1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824}, + {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0}, + {0, -1, -2, -4, -8, -16, -32, -64, -128, -256, -512, -1024, -2048, -4096, -8192, -16384, 0, -1, -2, -4, -8, -16, -32, -64, -128, -256, -512, -1024, -2048, -4096, -8192, -16384, 0, -1, -2, -4, -8, -16, -32, -64, -128, -256, -512, -1024, -2048, -4096, -8192, -16384, 0, -1, -2, -4, -8, -16, -32, -64, -128, -256, -512, -1024, -2048, -4096, -8192, -16384, }, + {-0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0}, + {1, 1, 2, 1, 6, 9, 10, 7, 2, 10, 4, 11, 10, 11, 0, 19, 26, 18, 10, 2, 14, 7, 0, 39, 34, 29, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 37, 34, 31, 28, 25, 22, 19, 16, 13, 10, 7, 4, 1, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91}, + {0, 0, 2, 0, 0, 1, 6, 9, 4, 12, 6, 13, 12, 0, 2, 21, 28, 20, 12, 4, 16, 9, 2, 41, 36, 31, 26, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93}, + {1, 1, 0, 2, 2, 3, 8, 11, 6, 14, 8, 15, 14, 2, 4, 23, 30, 22, 14, 6, 18, 11, 4, 43, 38, 33, 28, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 38, 35, 32, 29, 26, 23, 20, 17, 14, 11, 8, 5, 2, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95}, + {0, 0, 0, 4, 0, 0, 10, 13, 0, 16, 0, 17, 16, 4, 6, 25, 16, 24, 16, 8, 0, 13, 6, 45, 40, 35, 30, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 37, 34, 31, 28, 25, 22, 19, 16, 13, 10, 7, 4, 1, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97}, + {1, 1, 2, 3, 2, 2, 0, 1, 2, 9, 2, 19, 18, 6, 8, 27, 18, 26, 18, 10, 2, 15, 8, 1, 42, 37, 32, 27, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0, 107, 106, 105, 104, 103, 102, 101, 100, 99}, + {0, 0, 2, 5, 4, 4, 2, 3, 4, 11, 4, 21, 20, 8, 10, 29, 20, 28, 20, 12, 4, 17, 10, 3, 44, 39, 34, 29, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 38, 35, 32, 29, 26, 23, 20, 17, 14, 11, 8, 5, 2, 109, 108, 107, 106, 105, 104, 103, 102, 101}, + {1, 1, 0, 1, 6, 6, 4, 5, 6, 13, 6, 1, 22, 10, 12, 1, 22, 30, 22, 14, 6, 19, 12, 5, 46, 41, 36, 31, 54, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 40, 37, 34, 31, 28, 25, 22, 19, 16, 13, 10, 7, 4, 1, 110, 109, 108, 107, 106, 105, 104, 103}, + {0, 0, 0, 0, 4, 8, 0, 0, 8, 15, 8, 3, 12, 12, 0, 3, 24, 32, 24, 16, 8, 0, 14, 7, 0, 43, 38, 33, 28, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0, 111, 110, 109, 108, 107, 106, 105}, + {1, 1, 2, 2, 6, 5, 2, 2, 10, 17, 10, 5, 14, 14, 2, 5, 26, 17, 26, 18, 10, 2, 16, 9, 2, 45, 40, 35, 30, 54, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 41, 38, 35, 32, 29, 26, 23, 20, 17, 14, 11, 8, 5, 2, 113, 112, 111, 110, 109, 108, 107}, + {0, 0, 2, 4, 0, 7, 4, 4, 12, 1, 12, 7, 16, 16, 4, 7, 28, 19, 28, 20, 12, 4, 18, 11, 4, 47, 42, 37, 32, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 40, 37, 34, 31, 28, 25, 22, 19, 16, 13, 10, 7, 4, 1, 114, 113, 112, 111, 110, 109}, + {1, 1, 0, 3, 2, 9, 6, 6, 14, 3, 14, 9, 18, 18, 6, 9, 30, 21, 30, 22, 14, 6, 20, 13, 6, 49, 44, 39, 34, 29, 54, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 42, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0, 115, 114, 113, 112, 111}, + {1, 1, 0, 3, 2, 5, 6, 2, 6, 3, 0, 19, 18, 17, 16, 0, 13, 11, 9, 7, 5, 3, 1, -3000, -3000, -3000, -3000, -3000, -3000, -3000, 0, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000}, + {1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824}, + {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0}, + {0, -1, -2, -4, -8, -16, -32, -64, -128, -256, -512, -1024, -2048, -4096, -8192, -16384, 0, -1, -2, -4, -8, -16, -32, -64, -128, -256, -512, -1024, -2048, -4096, -8192, -16384, 0, -1, -2, -4, -8, -16, -32, -64, -128, -256, -512, -1024, -2048, -4096, -8192, -16384, 0, -1, -2, -4, -8, -16, -32, -64, -128, -256, -512, -1024, -2048, -4096, -8192, -16384, }, + {-0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0}, + {1, 1, 2, 1, 6, 9, 10, 7, 2, 10, 4, 11, 10, 11, 0, 19, 26, 18, 10, 2, 14, 7, 0, 39, 34, 29, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 37, 34, 31, 28, 25, 22, 19, 16, 13, 10, 7, 4, 1, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91}, + {0, 0, 2, 0, 0, 1, 6, 9, 4, 12, 6, 13, 12, 0, 2, 21, 28, 20, 12, 4, 16, 9, 2, 41, 36, 31, 26, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93}, + {1, 1, 0, 2, 2, 3, 8, 11, 6, 14, 8, 15, 14, 2, 4, 23, 30, 22, 14, 6, 18, 11, 4, 43, 38, 33, 28, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 38, 35, 32, 29, 26, 23, 20, 17, 14, 11, 8, 5, 2, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95}, + {0, 0, 0, 4, 0, 0, 10, 13, 0, 16, 0, 17, 16, 4, 6, 25, 16, 24, 16, 8, 0, 13, 6, 45, 40, 35, 30, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 37, 34, 31, 28, 25, 22, 19, 16, 13, 10, 7, 4, 1, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97}, + {1, 1, 2, 3, 2, 2, 0, 1, 2, 9, 2, 19, 18, 6, 8, 27, 18, 26, 18, 10, 2, 15, 8, 1, 42, 37, 32, 27, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0, 107, 106, 105, 104, 103, 102, 101, 100, 99}, + {0, 0, 2, 5, 4, 4, 2, 3, 4, 11, 4, 21, 20, 8, 10, 29, 20, 28, 20, 12, 4, 17, 10, 3, 44, 39, 34, 29, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 38, 35, 32, 29, 26, 23, 20, 17, 14, 11, 8, 5, 2, 109, 108, 107, 106, 105, 104, 103, 102, 101}, + {1, 1, 0, 1, 6, 6, 4, 5, 6, 13, 6, 1, 22, 10, 12, 1, 22, 30, 22, 14, 6, 19, 12, 5, 46, 41, 36, 31, 54, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 40, 37, 34, 31, 28, 25, 22, 19, 16, 13, 10, 7, 4, 1, 110, 109, 108, 107, 106, 105, 104, 103}, + {0, 0, 0, 0, 4, 8, 0, 0, 8, 15, 8, 3, 12, 12, 0, 3, 24, 32, 24, 16, 8, 0, 14, 7, 0, 43, 38, 33, 28, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0, 111, 110, 109, 108, 107, 106, 105}, + {1, 1, 2, 2, 6, 5, 2, 2, 10, 17, 10, 5, 14, 14, 2, 5, 26, 17, 26, 18, 10, 2, 16, 9, 2, 45, 40, 35, 30, 54, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 41, 38, 35, 32, 29, 26, 23, 20, 17, 14, 11, 8, 5, 2, 113, 112, 111, 110, 109, 108, 107}, + {0, 0, 2, 4, 0, 7, 4, 4, 12, 1, 12, 7, 16, 16, 4, 7, 28, 19, 28, 20, 12, 4, 18, 11, 4, 47, 42, 37, 32, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 40, 37, 34, 31, 28, 25, 22, 19, 16, 13, 10, 7, 4, 1, 114, 113, 112, 111, 110, 109}, + {1, 1, 0, 3, 2, 9, 6, 6, 14, 3, 14, 9, 18, 18, 6, 9, 30, 21, 30, 22, 14, 6, 20, 13, 6, 49, 44, 39, 34, 29, 54, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 42, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0, 115, 114, 113, 112, 111}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX}, + {INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN}, + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, + {1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024}, + {65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 0, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535}, + {-1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023}, + {INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX}, + {0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, }, + {0, 0, 2, 0, 0, 1, 6, 9, 4, 12, 6, 13, 12, 0, 2, 21, 28, 20, 12, 4, 16, 9, 2, 41, 36, 31, 26, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93}, + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 0, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535}, + {INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX}, + {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, + {0, -1, -2, -4, -8, -16, -32, -64, -128, -256, -512, -1024, -2048, -4096, -8192, -16384, 0, -1, -2, -4, -8, -16, -32, -64, -128, -256, -512, -1024, -2048, -4096, -8192, -16384, 0, -1, -2, -4, -8, -16, -32, -64, -128, -256, -512, -1024, -2048, -4096, -8192, -16384, 0, -1, -2, -4, -8, -16, -32, -64, -128, -256, -512, -1024, -2048, -4096, -8192, -16384, }, + {1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, }, + {1, 1, 0, 3, 2, 5, 6, 2, 6, 3, 0, 19, 18, 17, 16, 0, 13, 11, 9, 7, 5, 3, 1, -3000, -3000, -3000, -3000, -3000, -3000, -3000, 0, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000, -3000}, + {0, 0, 2, 5, 4, 4, 2, 3, 4, 11, 4, 21, 20, 8, 10, 29, 20, 28, 20, 12, 4, 17, 10, 3, 44, 39, 34, 29, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 38, 35, 32, 29, 26, 23, 20, 17, 14, 11, 8, 5, 2, 109, 108, 107, 106, 105, 104, 103, 102, 101}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0}, + {-0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0}, + {1, 1, 2, 1, 6, 9, 10, 7, 2, 10, 4, 11, 10, 11, 0, 19, 26, 18, 10, 2, 14, 7, 0, 39, 34, 29, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 37, 34, 31, 28, 25, 22, 19, 16, 13, 10, 7, 4, 1, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91}, + {0, 0, 2, 4, 0, 7, 4, 4, 12, 1, 12, 7, 16, 16, 4, 7, 28, 19, 28, 20, 12, 4, 18, 11, 4, 47, 42, 37, 32, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 40, 37, 34, 31, 28, 25, 22, 19, 16, 13, 10, 7, 4, 1, 114, 113, 112, 111, 110, 109}, + {1, 1, 0, 2, 2, 3, 8, 11, 6, 14, 8, 15, 14, 2, 4, 23, 30, 22, 14, 6, 18, 11, 4, 43, 38, 33, 28, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 38, 35, 32, 29, 26, 23, 20, 17, 14, 11, 8, 5, 2, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN, INT_MIN}, + {0, 0, 0, 4, 0, 0, 10, 13, 0, 16, 0, 17, 16, 4, 6, 25, 16, 24, 16, 8, 0, 13, 6, 45, 40, 35, 30, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 37, 34, 31, 28, 25, 22, 19, 16, 13, 10, 7, 4, 1, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97}, + {1, 1, 2, 3, 2, 2, 0, 1, 2, 9, 2, 19, 18, 6, 8, 27, 18, 26, 18, 10, 2, 15, 8, 1, 42, 37, 32, 27, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0, 107, 106, 105, 104, 103, 102, 101, 100, 99}, + {1, 1, 0, 1, 6, 6, 4, 5, 6, 13, 6, 1, 22, 10, 12, 1, 22, 30, 22, 14, 6, 19, 12, 5, 46, 41, 36, 31, 54, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 40, 37, 34, 31, 28, 25, 22, 19, 16, 13, 10, 7, 4, 1, 110, 109, 108, 107, 106, 105, 104, 103}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {-1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023, -1023}, + {0, 0, 0, 0, 4, 8, 0, 0, 8, 15, 8, 3, 12, 12, 0, 3, 24, 32, 24, 16, 8, 0, 14, 7, 0, 43, 38, 33, 28, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0, 111, 110, 109, 108, 107, 106, 105}, + {1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824, 1073741824}, + {1, 1, 2, 2, 6, 5, 2, 2, 10, 17, 10, 5, 14, 14, 2, 5, 26, 17, 26, 18, 10, 2, 16, 9, 2, 45, 40, 35, 30, 54, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 41, 38, 35, 32, 29, 26, 23, 20, 17, 14, 11, 8, 5, 2, 113, 112, 111, 110, 109, 108, 107}, + {1, 1, 0, 3, 2, 9, 6, 6, 14, 3, 14, 9, 18, 18, 6, 9, 30, 21, 30, 22, 14, 6, 20, 13, 6, 49, 44, 39, 34, 29, 54, 50, 46, 42, 38, 34, 30, 26, 22, 18, 14, 10, 6, 2, 42, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0, 115, 114, 113, 112, 111}, + {INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MAX, INT_MAX, INT_MAX} }; diff --git a/tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx.cpp b/tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx.cpp index 7d8f6650aadb..698e0fed8ba1 100644 --- a/tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx.cpp +++ b/tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx.cpp @@ -8,10 +8,10 @@ //===----------------------------------------------------------------------===// // // Implements functions for converting between protobufs and C++. Differs from -// proto_to_cxx.cpp by wrapping all the generated C++ code in a single for -// loop. Also coutputs a different function signature that includes a -// size_t parameter for the loop to use. The C++ code generated is meant to -// stress the LLVM loop vectorizer. +// proto_to_cxx.cpp by wrapping all the generated C++ code in either a single +// for loop or two nested loops. Also outputs a different function signature +// that includes a size_t parameter for the loop to use. The C++ code generated +// is meant to stress the LLVM loop vectorizer. // // Still a work in progress. // @@ -28,6 +28,17 @@ namespace clang_fuzzer { +static bool inner_loop = false; +class InnerLoop { + public: + InnerLoop() { + inner_loop = true; + } + ~InnerLoop() { + inner_loop = false; + } +}; + // Forward decls. std::ostream &operator<<(std::ostream &os, const BinaryOp &x); std::ostream &operator<<(std::ostream &os, const StatementSeq &x); @@ -37,13 +48,14 @@ std::ostream &operator<<(std::ostream &os, const Const &x) { return os << "(" << x.val() << ")"; } std::ostream &operator<<(std::ostream &os, const VarRef &x) { + std::string which_loop = inner_loop ? "j" : "i"; switch (x.arr()) { case VarRef::ARR_A: - return os << "a[i]"; + return os << "a[" << which_loop << "]"; case VarRef::ARR_B: - return os << "b[i]"; + return os << "b[" << which_loop << "]"; case VarRef::ARR_C: - return os << "c[i]"; + return os << "c[" << which_loop << "]"; } } std::ostream &operator<<(std::ostream &os, const Rvalue &x) { @@ -108,10 +120,27 @@ std::ostream &operator<<(std::ostream &os, const StatementSeq &x) { os << st; return os; } +void NestedLoopToString(std::ostream &os, const LoopFunction &x) { + os << "void foo(int *a, int *b, int *__restrict__ c, size_t s) {\n" + << "for (int i=0; i<s; i++){\n" + << "for (int j=0; j<s; j++){\n"; + { + InnerLoop IL; + os << x.inner_statements() << "}\n"; + } + os << x.outer_statements() << "}\n}\n"; +} +void SingleLoopToString(std::ostream &os, const LoopFunction &x) { + os << "void foo(int *a, int *b, int *__restrict__ c, size_t s) {\n" + << "for (int i=0; i<s; i++){\n" + << x.outer_statements() << "}\n}\n"; +} std::ostream &operator<<(std::ostream &os, const LoopFunction &x) { - return os << "void foo(int *a, int *b, int *__restrict__ c, size_t s) {\n" - << "for (int i=0; i<s; i++){\n" - << x.statements() << "}\n}\n"; + if (x.has_inner_statements()) + NestedLoopToString(os, x); + else + SingleLoopToString(os, x); + return os; } // --------------------------------- diff --git a/tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm.cpp b/tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm.cpp index 16dbcb7b49b2..ffbb1c9f0d1f 100644 --- a/tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm.cpp +++ b/tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm.cpp @@ -15,6 +15,7 @@ #include "loop_proto_to_llvm.h" #include "cxx_loop_proto.pb.h" +#include "../handle-llvm/input_arrays.h" // The following is needed to convert protos in human-readable form #include <google/protobuf/text_format.h> @@ -29,17 +30,30 @@ std::string BinopToString(std::ostream &os, const BinaryOp &x); std::string StateSeqToString(std::ostream &os, const StatementSeq &x); // Counter variable to generate new LLVM IR variable names and wrapper function -std::string get_var() { +static std::string get_var() { static int ctr = 0; return "%var" + std::to_string(ctr++); } +static bool inner_loop = false; +class InnerLoop { + public: + InnerLoop() { + inner_loop = true; + } + ~InnerLoop() { + inner_loop = false; + } +}; + + // Proto to LLVM. std::string ConstToString(const Const &x) { return std::to_string(x.val()); } std::string VarRefToString(std::ostream &os, const VarRef &x) { + std::string which_loop = inner_loop ? "inner" : "outer"; std::string arr; switch(x.arr()) { case VarRef::ARR_A: @@ -53,7 +67,8 @@ std::string VarRefToString(std::ostream &os, const VarRef &x) { break; } std::string ptr_var = get_var(); - os << ptr_var << " = getelementptr i32, i32* " << arr << ", i64 %ct\n"; + os << ptr_var << " = getelementptr inbounds i32, i32* " << arr + << ", i64 %" << which_loop << "_ct\n"; return ptr_var; } std::string RvalueToString(std::ostream &os, const Rvalue &x) { @@ -121,22 +136,61 @@ std::ostream &operator<<(std::ostream &os, const StatementSeq &x) { } return os; } +void NestedLoopToString(std::ostream &os, const LoopFunction &x) { + os << "target triple = \"x86_64-unknown-linux-gnu\"\n" + << "define void @foo(i32* %a, i32* %b, i32* noalias %c, i64 %s) {\n" + << "outer_loop_start:\n" + << "%cmp = icmp sgt i64 %s, 0\n" + << "br i1 %cmp, label %inner_loop_start, label %end\n" + << "outer_loop:\n" + << x.outer_statements() + << "%o_ct_new = add i64 %outer_ct, 1\n" + << "%jmp_outer = icmp eq i64 %o_ct_new, %s\n" + << "br i1 %jmp_outer, label %end, label %inner_loop_start\n" + << "inner_loop_start:\n" + << "%outer_ct = phi i64 [%o_ct_new, %outer_loop], [0, %outer_loop_start]\n" + << "br label %inner_loop\n" + << "inner_loop:\n" + << "%inner_ct = phi i64 [0, %inner_loop_start], [%i_ct_new, %inner_loop]\n"; + { + InnerLoop IL; + os << x.inner_statements(); + } + os << "%i_ct_new = add i64 %inner_ct, 1\n" + << "%jmp_inner = icmp eq i64 %i_ct_new, %s\n" + << "br i1 %jmp_inner, label %outer_loop, label %inner_loop, !llvm.loop !0\n" + << "end:\n" + << "ret void\n" + << "}\n" + << "!0 = distinct !{!0, !1, !2}\n" + << "!1 = !{!\"llvm.loop.vectorize.enable\", i1 true}\n" + << "!2 = !{!\"llvm.loop.vectorize.width\", i32 " << kArraySize << "}\n"; +} +void SingleLoopToString(std::ostream &os, const LoopFunction &x) { + os << "target triple = \"x86_64-unknown-linux-gnu\"\n" + << "define void @foo(i32* %a, i32* %b, i32* noalias %c, i64 %s) {\n" + << "%cmp = icmp sgt i64 %s, 0\n" + << "br i1 %cmp, label %start, label %end\n" + << "start:\n" + << "br label %loop\n" + << "end:\n" + << "ret void\n" + << "loop:\n" + << "%outer_ct = phi i64 [ %ctnew, %loop ], [ 0, %start ]\n" + << x.outer_statements() + << "%ctnew = add i64 %outer_ct, 1\n" + << "%j = icmp eq i64 %ctnew, %s\n" + << "br i1 %j, label %end, label %loop, !llvm.loop !0\n}\n" + << "!0 = distinct !{!0, !1, !2}\n" + << "!1 = !{!\"llvm.loop.vectorize.enable\", i1 true}\n" + << "!2 = !{!\"llvm.loop.vectorize.width\", i32 " << kArraySize << "}\n"; +} std::ostream &operator<<(std::ostream &os, const LoopFunction &x) { - return os << "define void @foo(i32* %a, i32* %b, i32* noalias %c, i64 %s) {\n" - << "%i = alloca i64\n" - << "store i64 0, i64* %i\n" - << "br label %loop\n\n" - << "loop:\n" - << "%ct = load i64, i64* %i\n" - << "%comp = icmp eq i64 %ct, %s\n" - << "br i1 %comp, label %endloop, label %body\n\n" - << "body:\n" - << x.statements() - << "%z = add i64 1, %ct\n" - << "store i64 %z, i64* %i\n" - << "br label %loop\n\n" - << "endloop:\n" - << "ret void\n}\n"; + if (x.has_inner_statements()) + NestedLoopToString(os, x); + else + SingleLoopToString(os, x); + return os; } // --------------------------------- diff --git a/tools/clang-import-test/CMakeLists.txt b/tools/clang-import-test/CMakeLists.txt index dfccfe2304bd..ee1bdab64a5d 100644 --- a/tools/clang-import-test/CMakeLists.txt +++ b/tools/clang-import-test/CMakeLists.txt @@ -21,6 +21,7 @@ set(CLANG_IMPORT_TEST_LIB_DEPS clangFrontend clangLex clangParse + clangSerialization ) target_link_libraries(clang-import-test diff --git a/tools/clang-import-test/clang-import-test.cpp b/tools/clang-import-test/clang-import-test.cpp index 106f3d1d150d..a7e749c6468a 100644 --- a/tools/clang-import-test/clang-import-test.cpp +++ b/tools/clang-import-test/clang-import-test.cpp @@ -182,8 +182,7 @@ std::unique_ptr<CompilerInstance> BuildCompilerInstance() { Inv->getHeaderSearchOpts().UseLibcxx = true; } if (isObjC(Id)) { - Inv->getLangOpts()->ObjC1 = 1; - Inv->getLangOpts()->ObjC2 = 1; + Inv->getLangOpts()->ObjC = 1; } } Inv->getLangOpts()->Bool = true; @@ -194,6 +193,10 @@ std::unique_ptr<CompilerInstance> BuildCompilerInstance() { Inv->getLangOpts()->ThreadsafeStatics = false; Inv->getLangOpts()->AccessControl = false; Inv->getLangOpts()->DollarIdents = true; + Inv->getLangOpts()->Exceptions = true; + Inv->getLangOpts()->CXXExceptions = true; + // Needed for testing dynamic_cast. + Inv->getLangOpts()->RTTI = true; Inv->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo); Inv->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple(); diff --git a/tools/clang-refactor/CMakeLists.txt b/tools/clang-refactor/CMakeLists.txt index b435744ca4bd..48206e730658 100644 --- a/tools/clang-refactor/CMakeLists.txt +++ b/tools/clang-refactor/CMakeLists.txt @@ -16,6 +16,7 @@ target_link_libraries(clang-refactor clangFrontend clangLex clangRewrite + clangSerialization clangTooling clangToolingCore clangToolingRefactor diff --git a/tools/clang-refactor/TestSupport.h b/tools/clang-refactor/TestSupport.h index 61aa660733fb..779006b0c502 100644 --- a/tools/clang-refactor/TestSupport.h +++ b/tools/clang-refactor/TestSupport.h @@ -59,9 +59,6 @@ struct TestSelectionRangesInFile { }; std::vector<RangeGroup> GroupedRanges; - TestSelectionRangesInFile(TestSelectionRangesInFile &&) = default; - TestSelectionRangesInFile &operator=(TestSelectionRangesInFile &&) = default; - bool foreachRange(const SourceManager &SM, llvm::function_ref<void(SourceRange)> Callback) const; diff --git a/tools/clang-rename/CMakeLists.txt b/tools/clang-rename/CMakeLists.txt index 3b3ab1540a80..45cbd763425c 100644 --- a/tools/clang-rename/CMakeLists.txt +++ b/tools/clang-rename/CMakeLists.txt @@ -12,6 +12,7 @@ target_link_libraries(clang-rename clangBasic clangFrontend clangRewrite + clangSerialization clangTooling clangToolingCore clangToolingRefactor diff --git a/tools/clang-rename/clang-rename.py b/tools/clang-rename/clang-rename.py index 3cc6644ff8f0..3381c5267f1c 100644 --- a/tools/clang-rename/clang-rename.py +++ b/tools/clang-rename/clang-rename.py @@ -7,10 +7,14 @@ Before installing make sure one of the following is satisfied: * `g:clang_rename_path` in ~/.vimrc points to valid clang-rename executable * `binary` in clang-rename.py points to valid to clang-rename executable -To install, simply put this into your ~/.vimrc +To install, simply put this into your ~/.vimrc for python2 support noremap <leader>cr :pyf <path-to>/clang-rename.py<cr> +For python3 use the following command (note the change from :pyf to :py3f) + + noremap <leader>cr :py3f <path-to>/clang-rename.py<cr> + IMPORTANT NOTE: Before running the tool, make sure you saved the file. All you have to do now is to place a cursor on a variable/function/class which @@ -18,6 +22,7 @@ you would like to rename and press '<leader>cr'. You will be prompted for a new name if the cursor points to a valid symbol. ''' +from __future__ import absolute_import, division, print_function import vim import subprocess import sys @@ -30,8 +35,8 @@ def main(): # Get arguments for clang-rename binary. offset = int(vim.eval('line2byte(line("."))+col(".")')) - 2 if offset < 0: - print >> sys.stderr, '''Couldn\'t determine cursor position. - Is your file empty?''' + print('Couldn\'t determine cursor position. Is your file empty?', + file=sys.stderr) return filename = vim.current.buffer.name @@ -51,7 +56,7 @@ def main(): stdout, stderr = p.communicate() if stderr: - print stderr + print(stderr) # Reload all buffers in Vim. vim.command("checktime") diff --git a/tools/diagtool/DiagTool.cpp b/tools/diagtool/DiagTool.cpp index d9086af8e989..1690a4456cc1 100644 --- a/tools/diagtool/DiagTool.cpp +++ b/tools/diagtool/DiagTool.cpp @@ -48,7 +48,7 @@ void DiagTools::printCommands(llvm::raw_ostream &out) { if (len > maxName) maxName = len; } - llvm::sort(toolNames.begin(), toolNames.end()); + llvm::sort(toolNames); for (std::vector<llvm::StringRef>::iterator it = toolNames.begin(), ei = toolNames.end(); it != ei; ++it) { diff --git a/tools/diagtool/ListWarnings.cpp b/tools/diagtool/ListWarnings.cpp index 8bf9df94011c..eae630125084 100644 --- a/tools/diagtool/ListWarnings.cpp +++ b/tools/diagtool/ListWarnings.cpp @@ -14,7 +14,6 @@ #include "DiagTool.h" #include "DiagnosticNames.h" -#include "clang/AST/ASTDiagnostic.h" #include "clang/Basic/AllDiagnostics.h" #include "clang/Basic/Diagnostic.h" #include "llvm/ADT/StringMap.h" diff --git a/tools/diagtool/TreeView.cpp b/tools/diagtool/TreeView.cpp index b4846b557444..4919c1728236 100644 --- a/tools/diagtool/TreeView.cpp +++ b/tools/diagtool/TreeView.cpp @@ -9,7 +9,6 @@ #include "DiagTool.h" #include "DiagnosticNames.h" -#include "clang/AST/ASTDiagnostic.h" #include "clang/Basic/AllDiagnostics.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index 15b0519e4111..89a3aa3ced85 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -46,6 +46,7 @@ target_link_libraries(clang clangDriver clangFrontend clangFrontendTool + clangSerialization ) if(WIN32 AND NOT CYGWIN) diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp index ef5a191bda0a..7d21c6a671d2 100644 --- a/tools/driver/cc1_main.cpp +++ b/tools/driver/cc1_main.cpp @@ -13,10 +13,9 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Option/Arg.h" +#include "clang/Basic/Stack.h" #include "clang/CodeGen/ObjectFilePCHContainerOperations.h" #include "clang/Config/config.h" -#include "clang/Basic/Stack.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "clang/Frontend/CompilerInstance.h" @@ -29,8 +28,10 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Config/llvm-config.h" #include "llvm/LinkAllPasses.h" +#include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptTable.h" +#include "llvm/Support/BuryPointer.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" @@ -228,7 +229,7 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { // When running with -disable-free, don't do any destruction or shutdown. if (Clang->getFrontendOpts().DisableFree) { - BuryPointer(std::move(Clang)); + llvm::BuryPointer(std::move(Clang)); return !Success; } diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp index 09db014019bf..be4f174ed412 100644 --- a/tools/driver/cc1as_main.cpp +++ b/tools/driver/cc1as_main.cpp @@ -33,6 +33,7 @@ #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCTargetOptions.h" @@ -132,6 +133,7 @@ struct AssemblerInvocation { unsigned NoExecStack : 1; unsigned FatalWarnings : 1; unsigned IncrementalLinkerCompatible : 1; + unsigned EmbedBitcode : 1; /// The name of the relocation model to use. std::string RelocationModel; @@ -153,6 +155,7 @@ public: FatalWarnings = 0; IncrementalLinkerCompatible = 0; DwarfVersion = 0; + EmbedBitcode = 0; } static bool CreateFromArgs(AssemblerInvocation &Res, @@ -284,6 +287,16 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, Args.hasArg(OPT_mincremental_linker_compatible); Opts.SymbolDefs = Args.getAllArgValues(OPT_defsym); + // EmbedBitcode Option. If -fembed-bitcode is enabled, set the flag. + // EmbedBitcode behaves the same for all embed options for assembly files. + if (auto *A = Args.getLastArg(OPT_fembed_bitcode_EQ)) { + Opts.EmbedBitcode = llvm::StringSwitch<unsigned>(A->getValue()) + .Case("all", 1) + .Case("bitcode", 1) + .Case("marker", 1) + .Default(0); + } + return Success; } @@ -449,6 +462,16 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Str.get()->InitSections(Opts.NoExecStack); } + // When -fembed-bitcode is passed to clang_as, a 1-byte marker + // is emitted in __LLVM,__asm section if the object file is MachO format. + if (Opts.EmbedBitcode && Ctx.getObjectFileInfo()->getObjectFileType() == + MCObjectFileInfo::IsMachO) { + MCSection *AsmLabel = Ctx.getMachOSection( + "__LLVM", "__asm", MachO::S_REGULAR, 4, SectionKind::getReadOnly()); + Str.get()->SwitchSection(AsmLabel); + Str.get()->EmitZeros(1); + } + // Assembly to object compilation should leverage assembly info. Str->setUseAssemblerInfoForParsing(true); @@ -534,7 +557,8 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { if (Asm.ShowHelp) { std::unique_ptr<OptTable> Opts(driver::createDriverOptTable()); - Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler", + Opts->PrintHelp(llvm::outs(), "clang -cc1as [options] file...", + "Clang Integrated Assembler", /*Include=*/driver::options::CC1AsOption, /*Exclude=*/0, /*ShowAllAliases=*/false); return 0; diff --git a/tools/driver/cc1gen_reproducer_main.cpp b/tools/driver/cc1gen_reproducer_main.cpp index a4c034d8d357..2d7ea86f7486 100644 --- a/tools/driver/cc1gen_reproducer_main.cpp +++ b/tools/driver/cc1gen_reproducer_main.cpp @@ -14,13 +14,13 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/LLVM.h" -#include "clang/Basic/VirtualFileSystem.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index 0455ba029c65..51143e3d8cb7 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -260,9 +260,9 @@ static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient, const std::string &Path) { // If the clang binary happens to be named cl.exe for compatibility reasons, // use clang-cl.exe as the prefix to avoid confusion between clang and MSVC. - StringRef ExeBasename(llvm::sys::path::filename(Path)); - if (ExeBasename.equals_lower("cl.exe")) - ExeBasename = "clang-cl.exe"; + StringRef ExeBasename(llvm::sys::path::stem(Path)); + if (ExeBasename.equals_lower("cl")) + ExeBasename = "clang-cl"; DiagClient->setPrefix(ExeBasename); } diff --git a/tools/libclang/BuildSystem.cpp b/tools/libclang/BuildSystem.cpp index 79fa69c40bae..6c1f2c145b0a 100644 --- a/tools/libclang/BuildSystem.cpp +++ b/tools/libclang/BuildSystem.cpp @@ -13,12 +13,12 @@ #include "clang-c/BuildSystem.h" #include "CXString.h" -#include "clang/Basic/VirtualFileSystem.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -28,11 +28,11 @@ unsigned long long clang_getBuildSessionTimestamp(void) { return llvm::sys::toTimeT(std::chrono::system_clock::now()); } -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(clang::vfs::YAMLVFSWriter, +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(llvm::vfs::YAMLVFSWriter, CXVirtualFileOverlay) CXVirtualFileOverlay clang_VirtualFileOverlay_create(unsigned) { - return wrap(new clang::vfs::YAMLVFSWriter()); + return wrap(new llvm::vfs::YAMLVFSWriter()); } enum CXErrorCode diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 499d9abf9a8e..a9c3077e5fa2 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -31,14 +31,12 @@ #include "clang/Basic/Version.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Index/CodegenNameGenerator.h" #include "clang/Index/CommentToXML.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" -#include "clang/Serialization/SerializationDiagnostic.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" @@ -565,7 +563,7 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) { if (const ObjCObjectType *ObjT = A->getInterface()->getAs<ObjCObjectType>()) return Visit(cxcursor::MakeCursorObjCClassRef( ObjT->getInterface(), - A->getInterfaceLoc()->getTypeLoc().getLocStart(), TU)); + A->getInterfaceLoc()->getTypeLoc().getBeginLoc(), TU)); } // If pointing inside a macro definition, check if the token is an identifier @@ -993,7 +991,7 @@ static void addRangedDeclsInContainer(DeclIt *DI_current, DeclIt DE_current, Decl *D_next = *next; if (!D_next) break; - SourceLocation L = D_next->getLocStart(); + SourceLocation L = D_next->getBeginLoc(); if (!L.isValid()) break; if (SM.isBeforeInTranslationUnit(L, EndLoc)) { @@ -1038,20 +1036,20 @@ bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) { // additional ones we've collected. Then visit them. for (auto *SubDecl : D->decls()) { if (!SubDecl || SubDecl->getLexicalDeclContext() != D || - SubDecl->getLocStart().isInvalid()) + SubDecl->getBeginLoc().isInvalid()) continue; DeclsInContainer.push_back(SubDecl); } // Now sort the Decls so that they appear in lexical order. - llvm::sort(DeclsInContainer.begin(), DeclsInContainer.end(), + llvm::sort(DeclsInContainer, [&SM](Decl *A, Decl *B) { - SourceLocation L_A = A->getLocStart(); - SourceLocation L_B = B->getLocStart(); - return L_A != L_B ? - SM.isBeforeInTranslationUnit(L_A, L_B) : - SM.isBeforeInTranslationUnit(A->getLocEnd(), B->getLocEnd()); - }); + SourceLocation L_A = A->getBeginLoc(); + SourceLocation L_B = B->getBeginLoc(); + return L_A != L_B ? SM.isBeforeInTranslationUnit(L_A, L_B) + : SM.isBeforeInTranslationUnit(A->getEndLoc(), + B->getEndLoc()); + }); // Now visit the decls. for (SmallVectorImpl<Decl*>::iterator I = DeclsInContainer.begin(), @@ -1519,6 +1517,9 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: #include "clang/Basic/OpenCLImageTypes.def" +#define EXT_OPAQUE_TYPE(ExtTYpe, Id, Ext) \ + case BuiltinType::Id: +#include "clang/Basic/OpenCLExtensionTypes.def" case BuiltinType::OCLSampler: case BuiltinType::OCLEvent: case BuiltinType::OCLClkEvent: @@ -1578,7 +1579,7 @@ bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { } bool CursorVisitor::VisitObjCTypeParamTypeLoc(ObjCTypeParamTypeLoc TL) { - if (Visit(MakeCursorTypeRef(TL.getDecl(), TL.getLocStart(), TU))) + if (Visit(MakeCursorTypeRef(TL.getDecl(), TL.getBeginLoc(), TU))) return true; for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), TL.getProtocolLoc(I), @@ -1802,7 +1803,9 @@ bool CursorVisitor::VisitCXXRecordDecl(CXXRecordDecl *D) { bool CursorVisitor::VisitAttributes(Decl *D) { for (const auto *I : D->attrs()) - if (!I->isImplicit() && Visit(MakeCXCursor(I, D, TU))) + if ((TU->ParsingOptions & CXTranslationUnit_VisitImplicitAttributes || + !I->isImplicit()) && + Visit(MakeCXCursor(I, D, TU))) return true; return false; @@ -2205,6 +2208,21 @@ void OMPClauseEnqueue::VisitOMPSIMDClause(const OMPSIMDClause *) {} void OMPClauseEnqueue::VisitOMPNogroupClause(const OMPNogroupClause *) {} +void OMPClauseEnqueue::VisitOMPUnifiedAddressClause( + const OMPUnifiedAddressClause *) {} + +void OMPClauseEnqueue::VisitOMPUnifiedSharedMemoryClause( + const OMPUnifiedSharedMemoryClause *) {} + +void OMPClauseEnqueue::VisitOMPReverseOffloadClause( + const OMPReverseOffloadClause *) {} + +void OMPClauseEnqueue::VisitOMPDynamicAllocatorsClause( + const OMPDynamicAllocatorsClause *) {} + +void OMPClauseEnqueue::VisitOMPAtomicDefaultMemOrderClause( + const OMPAtomicDefaultMemOrderClause *) {} + void OMPClauseEnqueue::VisitOMPDeviceClause(const OMPDeviceClause *C) { Visitor->AddStmt(C->getDevice()); } @@ -3117,25 +3135,19 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) { return true; } + TypeLoc TL = E->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); // Visit parameters and return type, if present. - if (E->hasExplicitParameters() || E->hasExplicitResultType()) { - TypeLoc TL = E->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); - if (E->hasExplicitParameters() && E->hasExplicitResultType()) { - // Visit the whole type. - if (Visit(TL)) - return true; - } else if (FunctionProtoTypeLoc Proto = - TL.getAs<FunctionProtoTypeLoc>()) { - if (E->hasExplicitParameters()) { - // Visit parameters. - for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) - if (Visit(MakeCXCursor(Proto.getParam(I), TU))) - return true; - } else { - // Visit result type. - if (Visit(Proto.getReturnLoc())) + if (FunctionTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) { + if (E->hasExplicitParameters()) { + // Visit parameters. + for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) + if (Visit(MakeCXCursor(Proto.getParam(I), TU))) return true; - } + } + if (E->hasExplicitResultType()) { + // Visit result type. + if (Visit(Proto.getReturnLoc())) + return true; } } break; @@ -3682,7 +3694,7 @@ struct ExprEvalResult { ~ExprEvalResult() { if (EvalType != CXEval_UnExposed && EvalType != CXEval_Float && EvalType != CXEval_Int) { - delete EvalData.stringVal; + delete[] EvalData.stringVal; } } }; @@ -3890,36 +3902,35 @@ static const ExprEvalResult* evaluateExpr(Expr *expr, CXCursor C) { return nullptr; } -CXEvalResult clang_Cursor_Evaluate(CXCursor C) { - const Decl *D = getCursorDecl(C); - if (D) { - const Expr *expr = nullptr; - if (auto *Var = dyn_cast<VarDecl>(D)) { - expr = Var->getInit(); - } else if (auto *Field = dyn_cast<FieldDecl>(D)) { - expr = Field->getInClassInitializer(); - } - if (expr) - return const_cast<CXEvalResult>(reinterpret_cast<const void *>( - evaluateExpr(const_cast<Expr *>(expr), C))); +static const Expr *evaluateDeclExpr(const Decl *D) { + if (!D) return nullptr; - } + if (auto *Var = dyn_cast<VarDecl>(D)) + return Var->getInit(); + else if (auto *Field = dyn_cast<FieldDecl>(D)) + return Field->getInClassInitializer(); + return nullptr; +} - const CompoundStmt *compoundStmt = dyn_cast_or_null<CompoundStmt>(getCursorStmt(C)); - if (compoundStmt) { - Expr *expr = nullptr; - for (auto *bodyIterator : compoundStmt->body()) { - if ((expr = dyn_cast<Expr>(bodyIterator))) { - break; - } - } - if (expr) - return const_cast<CXEvalResult>( - reinterpret_cast<const void *>(evaluateExpr(expr, C))); +static const Expr *evaluateCompoundStmtExpr(const CompoundStmt *CS) { + assert(CS && "invalid compound statement"); + for (auto *bodyIterator : CS->body()) { + if (const auto *E = dyn_cast<Expr>(bodyIterator)) + return E; } return nullptr; } +CXEvalResult clang_Cursor_Evaluate(CXCursor C) { + if (const Expr *E = + clang_getCursorKind(C) == CXCursor_CompoundStmt + ? evaluateCompoundStmtExpr(cast<CompoundStmt>(getCursorStmt(C))) + : evaluateDeclExpr(getCursorDecl(C))) + return const_cast<CXEvalResult>( + reinterpret_cast<const void *>(evaluateExpr(const_cast<Expr *>(E), C))); + return nullptr; +} + unsigned clang_Cursor_hasAttrs(CXCursor C) { const Decl *D = getCursorDecl(C); if (!D) { @@ -4340,8 +4351,8 @@ static SourceLocation getLocationFromExpr(const Expr *E) { return SizeOfPack->getPackLoc(); if (const ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E)) return PropRef->getLocation(); - - return E->getLocStart(); + + return E->getBeginLoc(); } extern "C" { @@ -5277,6 +5288,42 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return cxstring::createRef("attribute(dllexport)"); case CXCursor_DLLImport: return cxstring::createRef("attribute(dllimport)"); + case CXCursor_NSReturnsRetained: + return cxstring::createRef("attribute(ns_returns_retained)"); + case CXCursor_NSReturnsNotRetained: + return cxstring::createRef("attribute(ns_returns_not_retained)"); + case CXCursor_NSReturnsAutoreleased: + return cxstring::createRef("attribute(ns_returns_autoreleased)"); + case CXCursor_NSConsumesSelf: + return cxstring::createRef("attribute(ns_consumes_self)"); + case CXCursor_NSConsumed: + return cxstring::createRef("attribute(ns_consumed)"); + case CXCursor_ObjCException: + return cxstring::createRef("attribute(objc_exception)"); + case CXCursor_ObjCNSObject: + return cxstring::createRef("attribute(NSObject)"); + case CXCursor_ObjCIndependentClass: + return cxstring::createRef("attribute(objc_independent_class)"); + case CXCursor_ObjCPreciseLifetime: + return cxstring::createRef("attribute(objc_precise_lifetime)"); + case CXCursor_ObjCReturnsInnerPointer: + return cxstring::createRef("attribute(objc_returns_inner_pointer)"); + case CXCursor_ObjCRequiresSuper: + return cxstring::createRef("attribute(objc_requires_super)"); + case CXCursor_ObjCRootClass: + return cxstring::createRef("attribute(objc_root_class)"); + case CXCursor_ObjCSubclassingRestricted: + return cxstring::createRef("attribute(objc_subclassing_restricted)"); + case CXCursor_ObjCExplicitProtocolImpl: + return cxstring::createRef("attribute(objc_protocol_requires_explicit_implementation)"); + case CXCursor_ObjCDesignatedInitializer: + return cxstring::createRef("attribute(objc_designated_initializer)"); + case CXCursor_ObjCRuntimeVisible: + return cxstring::createRef("attribute(objc_runtime_visible)"); + case CXCursor_ObjCBoxable: + return cxstring::createRef("attribute(objc_boxable)"); + case CXCursor_FlagEnum: + return cxstring::createRef("attribute(flag_enum)"); case CXCursor_PreprocessingDirective: return cxstring::createRef("preprocessing directive"); case CXCursor_MacroDefinition: @@ -5752,9 +5799,9 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { if (TypeSourceInfo *TSInfo = BaseSpec->getTypeSourceInfo()) return cxloc::translateSourceLocation(getCursorContext(C), TSInfo->getTypeLoc().getBeginLoc()); - + return cxloc::translateSourceLocation(getCursorContext(C), - BaseSpec->getLocStart()); + BaseSpec->getBeginLoc()); } case CXCursor_LabelRef: { @@ -5778,7 +5825,7 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { if (clang_isStatement(C.kind)) return cxloc::translateSourceLocation(getCursorContext(C), - getCursorStmt(C)->getLocStart()); + getCursorStmt(C)->getBeginLoc()); if (C.kind == CXCursor_PreprocessingDirective) { SourceLocation L = cxcursor::getCursorPreprocessingDirective(C).getBegin(); @@ -5978,10 +6025,10 @@ static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) { SourceLocation StartLoc; if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) { if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) - StartLoc = TI->getTypeLoc().getLocStart(); + StartLoc = TI->getTypeLoc().getBeginLoc(); } else if (const TypedefDecl *Typedef = dyn_cast<TypedefDecl>(D)) { if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo()) - StartLoc = TI->getTypeLoc().getLocStart(); + StartLoc = TI->getTypeLoc().getBeginLoc(); } if (StartLoc.isValid() && R.getBegin().isValid() && @@ -6182,6 +6229,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::Import: case Decl::OMPThreadPrivate: case Decl::OMPDeclareReduction: + case Decl::OMPRequires: case Decl::ObjCTypeParam: case Decl::BuiltinTemplate: case Decl::PragmaComment: @@ -6756,11 +6804,18 @@ class AnnotateTokensWorker { SourceManager &SrcMgr; bool HasContextSensitiveKeywords; + struct PostChildrenAction { + CXCursor cursor; + enum Action { Invalid, Ignore, Postpone } action; + }; + using PostChildrenActions = SmallVector<PostChildrenAction, 0>; + struct PostChildrenInfo { CXCursor Cursor; SourceRange CursorRange; unsigned BeforeReachingCursorIdx; unsigned BeforeChildrenTokenIdx; + PostChildrenActions ChildActions; }; SmallVector<PostChildrenInfo, 8> PostChildrenInfos; @@ -6806,7 +6861,13 @@ public: void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); } enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent); + bool IsIgnoredChildCursor(CXCursor cursor) const; + PostChildrenActions DetermineChildActions(CXCursor Cursor) const; + bool postVisitChildren(CXCursor cursor); + void HandlePostPonedChildCursors(const PostChildrenInfo &Info); + void HandlePostPonedChildCursor(CXCursor Cursor, unsigned StartTokenIndex); + void AnnotateTokens(); /// Determine whether the annotator saw any cursors that have @@ -6827,6 +6888,67 @@ void AnnotateTokensWorker::AnnotateTokens() { AnnotateVis.visitFileRegion(); } +bool AnnotateTokensWorker::IsIgnoredChildCursor(CXCursor cursor) const { + if (PostChildrenInfos.empty()) + return false; + + for (const auto &ChildAction : PostChildrenInfos.back().ChildActions) { + if (ChildAction.cursor == cursor && + ChildAction.action == PostChildrenAction::Ignore) { + return true; + } + } + + return false; +} + +const CXXOperatorCallExpr *GetSubscriptOrCallOperator(CXCursor Cursor) { + if (!clang_isExpression(Cursor.kind)) + return nullptr; + + const Expr *E = getCursorExpr(Cursor); + if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(E)) { + const OverloadedOperatorKind Kind = OCE->getOperator(); + if (Kind == OO_Call || Kind == OO_Subscript) + return OCE; + } + + return nullptr; +} + +AnnotateTokensWorker::PostChildrenActions +AnnotateTokensWorker::DetermineChildActions(CXCursor Cursor) const { + PostChildrenActions actions; + + // The DeclRefExpr of CXXOperatorCallExpr refering to the custom operator is + // visited before the arguments to the operator call. For the Call and + // Subscript operator the range of this DeclRefExpr includes the whole call + // expression, so that all tokens in that range would be mapped to the + // operator function, including the tokens of the arguments. To avoid that, + // ensure to visit this DeclRefExpr as last node. + if (const auto *OCE = GetSubscriptOrCallOperator(Cursor)) { + const Expr *Callee = OCE->getCallee(); + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Callee)) { + const Expr *SubExpr = ICE->getSubExpr(); + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr)) { + const Decl *parentDecl = getCursorDecl(Cursor); + CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor); + + // Visit the DeclRefExpr as last. + CXCursor cxChild = MakeCXCursor(DRE, parentDecl, TU); + actions.push_back({cxChild, PostChildrenAction::Postpone}); + + // The parent of the DeclRefExpr, an ImplicitCastExpr, has an equally + // wide range as the DeclRefExpr. We can skip visiting this entirely. + cxChild = MakeCXCursor(ICE, parentDecl, TU); + actions.push_back({cxChild, PostChildrenAction::Ignore}); + } + } + } + + return actions; +} + static inline void updateCursorAnnotation(CXCursor &Cursor, const CXCursor &updateC) { if (clang_isInvalid(updateC.kind) || !clang_isInvalid(Cursor.kind)) @@ -6903,7 +7025,10 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { SourceRange cursorRange = getRawCursorExtent(cursor); if (cursorRange.isInvalid()) return CXChildVisit_Recurse; - + + if (IsIgnoredChildCursor(cursor)) + return CXChildVisit_Continue; + if (!HasContextSensitiveKeywords) { // Objective-C properties can have context-sensitive keywords. if (cursor.kind == CXCursor_ObjCPropertyDecl) { @@ -7029,11 +7154,11 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { // MyCXXClass foo; // Make sure we don't annotate 'foo' as a CallExpr cursor. if (clang_isExpression(cursorK) && MoreTokens()) { const Expr *E = getCursorExpr(cursor); - if (const Decl *D = getCursorParentDecl(cursor)) { + if (const Decl *D = getCursorDecl(cursor)) { const unsigned I = NextToken(); - if (E->getLocStart().isValid() && D->getLocation().isValid() && - E->getLocStart() == D->getLocation() && - E->getLocStart() == GetTokenLoc(I)) { + if (E->getBeginLoc().isValid() && D->getLocation().isValid() && + E->getBeginLoc() == D->getLocation() && + E->getBeginLoc() == GetTokenLoc(I)) { updateCursorAnnotation(Cursors[I], updateC); AdvanceToken(); } @@ -7051,6 +7176,7 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { Info.CursorRange = cursorRange; Info.BeforeReachingCursorIdx = BeforeReachingCursorIdx; Info.BeforeChildrenTokenIdx = NextToken(); + Info.ChildActions = DetermineChildActions(cursor); PostChildrenInfos.push_back(Info); return CXChildVisit_Recurse; @@ -7063,6 +7189,8 @@ bool AnnotateTokensWorker::postVisitChildren(CXCursor cursor) { if (!clang_equalCursors(Info.Cursor, cursor)) return false; + HandlePostPonedChildCursors(Info); + const unsigned BeforeChildren = Info.BeforeChildrenTokenIdx; const unsigned AfterChildren = NextToken(); SourceRange cursorRange = Info.CursorRange; @@ -7089,6 +7217,56 @@ bool AnnotateTokensWorker::postVisitChildren(CXCursor cursor) { return false; } +void AnnotateTokensWorker::HandlePostPonedChildCursors( + const PostChildrenInfo &Info) { + for (const auto &ChildAction : Info.ChildActions) { + if (ChildAction.action == PostChildrenAction::Postpone) { + HandlePostPonedChildCursor(ChildAction.cursor, + Info.BeforeChildrenTokenIdx); + } + } +} + +void AnnotateTokensWorker::HandlePostPonedChildCursor( + CXCursor Cursor, unsigned StartTokenIndex) { + const auto flags = CXNameRange_WantQualifier | CXNameRange_WantQualifier; + unsigned I = StartTokenIndex; + + // The bracket tokens of a Call or Subscript operator are mapped to + // CallExpr/CXXOperatorCallExpr because we skipped visiting the corresponding + // DeclRefExpr. Remap these tokens to the DeclRefExpr cursors. + for (unsigned RefNameRangeNr = 0; I < NumTokens; RefNameRangeNr++) { + const CXSourceRange CXRefNameRange = + clang_getCursorReferenceNameRange(Cursor, flags, RefNameRangeNr); + if (clang_Range_isNull(CXRefNameRange)) + break; // All ranges handled. + + SourceRange RefNameRange = cxloc::translateCXSourceRange(CXRefNameRange); + while (I < NumTokens) { + const SourceLocation TokenLocation = GetTokenLoc(I); + if (!TokenLocation.isValid()) + break; + + // Adapt the end range, because LocationCompare() reports + // RangeOverlap even for the not-inclusive end location. + const SourceLocation fixedEnd = + RefNameRange.getEnd().getLocWithOffset(-1); + RefNameRange = SourceRange(RefNameRange.getBegin(), fixedEnd); + + const RangeComparisonResult ComparisonResult = + LocationCompare(SrcMgr, TokenLocation, RefNameRange); + + if (ComparisonResult == RangeOverlap) { + Cursors[I++] = Cursor; + } else if (ComparisonResult == RangeBefore) { + ++I; // Not relevant token, check next one. + } else if (ComparisonResult == RangeAfter) { + break; // All tokens updated for current range, check next. + } + } + } +} + static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, CXCursor parent, CXClientData client_data) { @@ -7631,11 +7809,11 @@ static void getCursorPlatformAvailabilityForDecl( if (AvailabilityAttrs.empty()) return; - llvm::sort(AvailabilityAttrs.begin(), AvailabilityAttrs.end(), + llvm::sort(AvailabilityAttrs, [](AvailabilityAttr *LHS, AvailabilityAttr *RHS) { return LHS->getPlatform()->getName() < RHS->getPlatform()->getName(); - }); + }); ASTContext &Ctx = D->getASTContext(); auto It = std::unique( AvailabilityAttrs.begin(), AvailabilityAttrs.end(), @@ -7877,6 +8055,30 @@ unsigned clang_Cursor_getObjCPropertyAttributes(CXCursor C, unsigned reserved) { return Result; } +CXString clang_Cursor_getObjCPropertyGetterName(CXCursor C) { + if (C.kind != CXCursor_ObjCPropertyDecl) + return cxstring::createNull(); + + const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(getCursorDecl(C)); + Selector sel = PD->getGetterName(); + if (sel.isNull()) + return cxstring::createNull(); + + return cxstring::createDup(sel.getAsString()); +} + +CXString clang_Cursor_getObjCPropertySetterName(CXCursor C) { + if (C.kind != CXCursor_ObjCPropertyDecl) + return cxstring::createNull(); + + const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(getCursorDecl(C)); + Selector sel = PD->getSetterName(); + if (sel.isNull()) + return cxstring::createNull(); + + return cxstring::createDup(sel.getAsString()); +} + unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C) { if (!clang_isDeclaration(C.kind)) return CXObjCDeclQualifier_None; @@ -8159,7 +8361,7 @@ unsigned clang_CXXMethod_isConst(CXCursor C) { const Decl *D = cxcursor::getCursorDecl(C); const CXXMethodDecl *Method = D ? dyn_cast_or_null<CXXMethodDecl>(D->getAsFunction()) : nullptr; - return (Method && (Method->getTypeQualifiers() & Qualifiers::Const)) ? 1 : 0; + return (Method && Method->getTypeQualifiers().hasConst()) ? 1 : 0; } unsigned clang_CXXMethod_isDefaulted(CXCursor C) { diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index f49f9763c362..c5cece52ac6b 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -26,7 +26,6 @@ #include "clang/Basic/SourceManager.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Sema/Sema.h" #include "llvm/ADT/SmallString.h" @@ -487,7 +486,8 @@ static unsigned long long getContextsForContextKind( contexts = CXCompletionContext_Namespace; break; } - case CodeCompletionContext::CCC_PotentiallyQualifiedName: { + case CodeCompletionContext::CCC_SymbolOrNewName: + case CodeCompletionContext::CCC_Symbol: { contexts = CXCompletionContext_NestedNameSpecifier; break; } @@ -499,6 +499,10 @@ static unsigned long long getContextsForContextKind( contexts = CXCompletionContext_NaturalLanguage; break; } + case CodeCompletionContext::CCC_IncludedFile: { + contexts = CXCompletionContext_IncludedFile; + break; + } case CodeCompletionContext::CCC_SelectorName: { contexts = CXCompletionContext_ObjCSelectorName; break; @@ -535,7 +539,7 @@ static unsigned long long getContextsForContextKind( case CodeCompletionContext::CCC_Other: case CodeCompletionContext::CCC_ObjCInterface: case CodeCompletionContext::CCC_ObjCImplementation: - case CodeCompletionContext::CCC_Name: + case CodeCompletionContext::CCC_NewName: case CodeCompletionContext::CCC_MacroName: case CodeCompletionContext::CCC_PreprocessorExpression: case CodeCompletionContext::CCC_PreprocessorDirective: @@ -653,7 +657,8 @@ namespace { void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, OverloadCandidate *Candidates, - unsigned NumCandidates) override { + unsigned NumCandidates, + SourceLocation OpenParLoc) override { StoredResults.reserve(StoredResults.size() + NumCandidates); for (unsigned I = 0; I != NumCandidates; ++I) { CodeCompletionString *StoredCompletion diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp index 4e47b25a4bf0..a4e75e2aae31 100644 --- a/tools/libclang/CIndexDiagnostic.cpp +++ b/tools/libclang/CIndexDiagnostic.cpp @@ -19,7 +19,6 @@ #include "clang/Basic/DiagnosticOptions.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/DiagnosticRenderer.h" -#include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt index e539c8308e75..32333b011ad1 100644 --- a/tools/libclang/CMakeLists.txt +++ b/tools/libclang/CMakeLists.txt @@ -40,6 +40,7 @@ set(LIBS clangIndex clangLex clangSema + clangSerialization clangTooling ) @@ -151,3 +152,22 @@ if (NOT CMAKE_CONFIGURATION_TYPES) # don't add this for IDE's. add_llvm_install_targets(install-libclang-headers COMPONENT libclang-headers) endif() + +# Create a target to install the python bindings to make them easier to +# distribute. Since the bindings are over libclang, which is installed +# unbundled to the clang version, follow suit. +foreach(PythonVersion ${CLANG_PYTHON_BINDINGS_VERSIONS}) + install(DIRECTORY + ${CMAKE_CURRENT_SOURCE_DIR}/../../bindings/python/clang + COMPONENT + libclang-python-bindings + DESTINATION + "lib${LLVM_LIBDIR_SUFFIX}/python${PythonVersion}/site-packages") +endforeach() +if(NOT CMAKE_CONFIGURATION_TYPES) + add_custom_target(libclang-python-bindings) + add_llvm_install_targets(install-libclang-python-bindings + COMPONENT + libclang-python-bindings) +endif() + diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index b4ad0595cc53..99e4319fc1fa 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -61,6 +61,24 @@ static CXCursorKind GetCursorKind(const Attr *A) { case attr::Visibility: return CXCursor_VisibilityAttr; case attr::DLLExport: return CXCursor_DLLExport; case attr::DLLImport: return CXCursor_DLLImport; + case attr::NSReturnsRetained: return CXCursor_NSReturnsRetained; + case attr::NSReturnsNotRetained: return CXCursor_NSReturnsNotRetained; + case attr::NSReturnsAutoreleased: return CXCursor_NSReturnsAutoreleased; + case attr::NSConsumesSelf: return CXCursor_NSConsumesSelf; + case attr::NSConsumed: return CXCursor_NSConsumed; + case attr::ObjCException: return CXCursor_ObjCException; + case attr::ObjCNSObject: return CXCursor_ObjCNSObject; + case attr::ObjCIndependentClass: return CXCursor_ObjCIndependentClass; + case attr::ObjCPreciseLifetime: return CXCursor_ObjCPreciseLifetime; + case attr::ObjCReturnsInnerPointer: return CXCursor_ObjCReturnsInnerPointer; + case attr::ObjCRequiresSuper: return CXCursor_ObjCRequiresSuper; + case attr::ObjCRootClass: return CXCursor_ObjCRootClass; + case attr::ObjCSubclassingRestricted: return CXCursor_ObjCSubclassingRestricted; + case attr::ObjCExplicitProtocolImpl: return CXCursor_ObjCExplicitProtocolImpl; + case attr::ObjCDesignatedInitializer: return CXCursor_ObjCDesignatedInitializer; + case attr::ObjCRuntimeVisible: return CXCursor_ObjCRuntimeVisible; + case attr::ObjCBoxable: return CXCursor_ObjCBoxable; + case attr::FlagEnum: return CXCursor_FlagEnum; } return CXCursor_UnexposedAttr; @@ -223,16 +241,19 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::SEHLeaveStmtClass: K = CXCursor_SEHLeaveStmt; break; - + + case Stmt::CoroutineBodyStmtClass: + case Stmt::CoreturnStmtClass: + K = CXCursor_UnexposedStmt; + break; + case Stmt::ArrayTypeTraitExprClass: case Stmt::AsTypeExprClass: case Stmt::AtomicExprClass: case Stmt::BinaryConditionalOperatorClass: case Stmt::TypeTraitExprClass: - case Stmt::CoroutineBodyStmtClass: case Stmt::CoawaitExprClass: case Stmt::DependentCoawaitExprClass: - case Stmt::CoreturnStmtClass: case Stmt::CoyieldExprClass: case Stmt::CXXBindTemporaryExprClass: case Stmt::CXXDefaultArgExprClass: @@ -325,6 +346,10 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, K = CXCursor_CharacterLiteral; break; + case Stmt::ConstantExprClass: + return MakeCXCursor(cast<ConstantExpr>(S)->getSubExpr(), + Parent, TU, RegionOfInterest); + case Stmt::ParenExprClass: K = CXCursor_ParenExpr; break; @@ -990,10 +1015,6 @@ const Attr *cxcursor::getCursorAttr(CXCursor Cursor) { return static_cast<const Attr *>(Cursor.data[1]); } -const Decl *cxcursor::getCursorParentDecl(CXCursor Cursor) { - return static_cast<const Decl *>(Cursor.data[0]); -} - ASTContext &cxcursor::getCursorContext(CXCursor Cursor) { return getCursorASTUnit(Cursor)->getASTContext(); } @@ -1146,6 +1167,9 @@ int clang_Cursor_getNumArguments(CXCursor C) { if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { return CE->getNumArgs(); } + if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E)) { + return CE->getNumArgs(); + } } return -1; @@ -1174,6 +1198,13 @@ CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i) { cxcursor::getCursorTU(C)); } } + if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E)) { + if (i < CE->getNumArgs()) { + return cxcursor::MakeCXCursor(CE->getArg(i), + getCursorDecl(C), + cxcursor::getCursorTU(C)); + } + } } return clang_getNullCursor(); @@ -1394,16 +1425,16 @@ CXCompletionString clang_getCursorCompletionString(CXCursor cursor) { } } else if (kind == CXCursor_MacroDefinition) { const MacroDefinitionRecord *definition = getCursorMacroDefinition(cursor); - const IdentifierInfo *MacroInfo = definition->getName(); + const IdentifierInfo *Macro = definition->getName(); ASTUnit *unit = getCursorASTUnit(cursor); - CodeCompletionResult Result(MacroInfo); - CodeCompletionString *String - = Result.CreateCodeCompletionString(unit->getASTContext(), - unit->getPreprocessor(), - CodeCompletionContext::CCC_Other, - unit->getCodeCompletionTUInfo().getAllocator(), - unit->getCodeCompletionTUInfo(), - false); + CodeCompletionResult Result( + Macro, + unit->getPreprocessor().getMacroDefinition(Macro).getMacroInfo()); + CodeCompletionString *String = Result.CreateCodeCompletionString( + unit->getASTContext(), unit->getPreprocessor(), + CodeCompletionContext::CCC_Other, + unit->getCodeCompletionTUInfo().getAllocator(), + unit->getCodeCompletionTUInfo(), false); return String; } return nullptr; diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h index a5d9fff2a55a..312fb3ff250b 100644 --- a/tools/libclang/CXCursor.h +++ b/tools/libclang/CXCursor.h @@ -43,11 +43,11 @@ class TemplateName; class TypeDecl; class VarDecl; class IdentifierInfo; - + namespace cxcursor { CXCursor getCursor(CXTranslationUnit, SourceLocation); - + CXCursor MakeCXCursor(const clang::Attr *A, const clang::Decl *Parent, CXTranslationUnit TU); CXCursor MakeCXCursor(const clang::Decl *D, CXTranslationUnit TU, @@ -125,7 +125,7 @@ std::pair<const VarDecl *, SourceLocation> getCursorVariableRef(CXCursor C); /// Create a reference to a field at the given location. CXCursor MakeCursorMemberRef(const FieldDecl *Field, SourceLocation Loc, CXTranslationUnit TU); - + /// Unpack a MemberRef cursor into the field it references and the /// location where the reference occurred. std::pair<const FieldDecl *, SourceLocation> getCursorMemberRef(CXCursor C); @@ -232,17 +232,16 @@ CXCursor MakeCursorOverloadedDeclRef(TemplateName Template, typedef llvm::PointerUnion3<const OverloadExpr *, const Decl *, OverloadedTemplateStorage *> OverloadedDeclRefStorage; - + /// Unpack an overloaded declaration reference into an expression, /// declaration, or template name along with the source location. std::pair<OverloadedDeclRefStorage, SourceLocation> getCursorOverloadedDeclRef(CXCursor C); - + const Decl *getCursorDecl(CXCursor Cursor); const Expr *getCursorExpr(CXCursor Cursor); const Stmt *getCursorStmt(CXCursor Cursor); const Attr *getCursorAttr(CXCursor Cursor); -const Decl *getCursorParentDecl(CXCursor Cursor); ASTContext &getCursorContext(CXCursor Cursor); ASTUnit *getCursorASTUnit(CXCursor Cursor); @@ -250,14 +249,14 @@ CXTranslationUnit getCursorTU(CXCursor Cursor); void getOverriddenCursors(CXCursor cursor, SmallVectorImpl<CXCursor> &overridden); - + /// Create an opaque pool used for fast generation of overridden /// CXCursor arrays. void *createOverridenCXCursorsPool(); /// Dispose of the overridden CXCursors pool. void disposeOverridenCXCursorsPool(void *pool); - + /// Returns a index/location pair for a selector identifier if the cursor /// points to one. std::pair<int, SourceLocation> getSelectorIdentifierIndexAndLoc(CXCursor); @@ -285,7 +284,7 @@ CXCursor getTypeRefCursor(CXCursor cursor); bool getDeclCursorUSR(const Decl *D, SmallVectorImpl<char> &Buf); bool operator==(CXCursor X, CXCursor Y); - + inline bool operator!=(CXCursor X, CXCursor Y) { return !(X == Y); } diff --git a/tools/libclang/CXIndexDataConsumer.cpp b/tools/libclang/CXIndexDataConsumer.cpp index 616a0797f52b..3dec36a5daeb 100644 --- a/tools/libclang/CXIndexDataConsumer.cpp +++ b/tools/libclang/CXIndexDataConsumer.cpp @@ -222,9 +222,11 @@ bool CXIndexDataConsumer::handleDeclOccurence( } bool CXIndexDataConsumer::handleModuleOccurence(const ImportDecl *ImportD, + const Module *Mod, SymbolRoleSet Roles, SourceLocation Loc) { - IndexingDeclVisitor(*this, SourceLocation(), nullptr).Visit(ImportD); + if (Roles & (SymbolRoleSet)SymbolRole::Declaration) + IndexingDeclVisitor(*this, SourceLocation(), nullptr).Visit(ImportD); return !shouldAbort(); } @@ -307,7 +309,7 @@ AttrListInfo::AttrListInfo(const Decl *D, CXIndexDataConsumer &IdxCtx) const IBOutletCollectionAttr * IBAttr = cast<IBOutletCollectionAttr>(IBInfo.A); SourceLocation InterfaceLocStart = - IBAttr->getInterfaceLoc()->getTypeLoc().getLocStart(); + IBAttr->getInterfaceLoc()->getTypeLoc().getBeginLoc(); IBInfo.IBCollInfo.attrInfo = &IBInfo; IBInfo.IBCollInfo.classLoc = IdxCtx.getIndexLoc(InterfaceLocStart); IBInfo.IBCollInfo.objcClass = nullptr; diff --git a/tools/libclang/CXIndexDataConsumer.h b/tools/libclang/CXIndexDataConsumer.h index 19e39b281ab0..5c1ce80b2f49 100644 --- a/tools/libclang/CXIndexDataConsumer.h +++ b/tools/libclang/CXIndexDataConsumer.h @@ -467,7 +467,7 @@ private: ArrayRef<index::SymbolRelation> Relations, SourceLocation Loc, ASTNodeInfo ASTNode) override; - bool handleModuleOccurence(const ImportDecl *ImportD, + bool handleModuleOccurence(const ImportDecl *ImportD, const Module *Mod, index::SymbolRoleSet Roles, SourceLocation Loc) override; diff --git a/tools/libclang/CXStoredDiagnostic.cpp b/tools/libclang/CXStoredDiagnostic.cpp index f2e9c1da28f6..6bd2f6746693 100644 --- a/tools/libclang/CXStoredDiagnostic.cpp +++ b/tools/libclang/CXStoredDiagnostic.cpp @@ -17,8 +17,8 @@ #include "CXSourceLocation.h" #include "CXString.h" +#include "clang/Basic/DiagnosticIDs.h" #include "clang/Frontend/ASTUnit.h" -#include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/ADT/Twine.h" using namespace clang; diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp index 7c0f307944a1..b8009ddc1c1a 100644 --- a/tools/libclang/CXType.cpp +++ b/tools/libclang/CXType.cpp @@ -70,6 +70,8 @@ static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) { #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) BTCASE(Id); #include "clang/Basic/OpenCLImageTypes.def" #undef IMAGE_TYPE +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) BTCASE(Id); +#include "clang/Basic/OpenCLExtensionTypes.def" BTCASE(OCLSampler); BTCASE(OCLEvent); BTCASE(OCLQueue); @@ -98,7 +100,9 @@ static CXTypeKind GetTypeKind(QualType T) { TKCASE(Enum); TKCASE(Typedef); TKCASE(ObjCInterface); + TKCASE(ObjCObject); TKCASE(ObjCObjectPointer); + TKCASE(ObjCTypeParam); TKCASE(FunctionNoProto); TKCASE(FunctionProto); TKCASE(ConstantArray); @@ -110,6 +114,7 @@ static CXTypeKind GetTypeKind(QualType T) { TKCASE(Auto); TKCASE(Elaborated); TKCASE(Pipe); + TKCASE(Attributed); default: return CXType_Unexposed; } @@ -123,7 +128,9 @@ CXType cxtype::MakeCXType(QualType T, CXTranslationUnit TU) { if (TU && !T.isNull()) { // Handle attributed types as the original type if (auto *ATT = T->getAs<AttributedType>()) { - return MakeCXType(ATT->getModifiedType(), TU); + if (!(TU->ParsingOptions & CXTranslationUnit_IncludeAttributedTypes)) { + return MakeCXType(ATT->getModifiedType(), TU); + } } // Handle paren types as the original type if (auto *PTT = T->getAs<ParenType>()) { @@ -131,7 +138,7 @@ CXType cxtype::MakeCXType(QualType T, CXTranslationUnit TU) { } ASTContext &Ctx = cxtu::getASTUnit(TU)->getASTContext(); - if (Ctx.getLangOpts().ObjC1) { + if (Ctx.getLangOpts().ObjC) { QualType UnqualT = T.getUnqualifiedType(); if (Ctx.isObjCIdType(UnqualT)) TK = CXType_ObjCId; @@ -437,6 +444,7 @@ CXType clang_getPointeeType(CXType CT) { if (!TP) return MakeCXType(QualType(), GetTU(CT)); +try_again: switch (TP->getTypeClass()) { case Type::Pointer: T = cast<PointerType>(TP)->getPointeeType(); @@ -454,6 +462,12 @@ CXType clang_getPointeeType(CXType CT) { case Type::MemberPointer: T = cast<MemberPointerType>(TP)->getPointeeType(); break; + case Type::Auto: + case Type::DeducedTemplateSpecialization: + TP = cast<DeducedType>(TP)->getDeducedType().getTypePtrOrNull(); + if (TP) + goto try_again; + break; default: T = QualType(); break; @@ -575,7 +589,9 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) { TKIND(Enum); TKIND(Typedef); TKIND(ObjCInterface); + TKIND(ObjCObject); TKIND(ObjCObjectPointer); + TKIND(ObjCTypeParam); TKIND(FunctionNoProto); TKIND(FunctionProto); TKIND(ConstantArray); @@ -587,9 +603,12 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) { TKIND(Auto); TKIND(Elaborated); TKIND(Pipe); + TKIND(Attributed); #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) TKIND(Id); #include "clang/Basic/OpenCLImageTypes.def" #undef IMAGE_TYPE +#define EXT_OPAQUE_TYPE(ExtTYpe, Id, Ext) TKIND(Id); +#include "clang/Basic/OpenCLExtensionTypes.def" TKIND(OCLSampler); TKIND(OCLEvent); TKIND(OCLQueue); @@ -632,6 +651,7 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) { TCALLINGCONV(X86Pascal); TCALLINGCONV(X86RegCall); TCALLINGCONV(X86VectorCall); + TCALLINGCONV(AArch64VectorCall); TCALLINGCONV(Win64); TCALLINGCONV(X86_64SysV); TCALLINGCONV(AAPCS); @@ -992,6 +1012,17 @@ long long clang_Type_getOffsetOf(CXType PT, const char *S) { return CXTypeLayoutError_InvalidFieldName; } +CXType clang_Type_getModifiedType(CXType CT) { + QualType T = GetQualType(CT); + if (T.isNull()) + return MakeCXType(QualType(), GetTU(CT)); + + if (auto *ATT = T->getAs<AttributedType>()) + return MakeCXType(ATT->getModifiedType(), GetTU(CT)); + + return MakeCXType(QualType(), GetTU(CT)); +} + long long clang_Cursor_getOffsetOfField(CXCursor C) { if (clang_isDeclaration(C.kind)) { // we need to validate the parent type @@ -1098,6 +1129,74 @@ CXType clang_Type_getTemplateArgumentAsType(CXType CT, unsigned index) { return MakeCXType(QT.getValueOr(QualType()), GetTU(CT)); } +CXType clang_Type_getObjCObjectBaseType(CXType CT) { + QualType T = GetQualType(CT); + if (T.isNull()) + return MakeCXType(QualType(), GetTU(CT)); + + const ObjCObjectType *OT = dyn_cast<ObjCObjectType>(T); + if (!OT) + return MakeCXType(QualType(), GetTU(CT)); + + return MakeCXType(OT->getBaseType(), GetTU(CT)); +} + +unsigned clang_Type_getNumObjCProtocolRefs(CXType CT) { + QualType T = GetQualType(CT); + if (T.isNull()) + return 0; + + const ObjCObjectType *OT = dyn_cast<ObjCObjectType>(T); + if (!OT) + return 0; + + return OT->getNumProtocols(); +} + +CXCursor clang_Type_getObjCProtocolDecl(CXType CT, unsigned i) { + QualType T = GetQualType(CT); + if (T.isNull()) + return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); + + const ObjCObjectType *OT = dyn_cast<ObjCObjectType>(T); + if (!OT) + return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); + + const ObjCProtocolDecl *PD = OT->getProtocol(i); + if (!PD) + return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); + + return cxcursor::MakeCXCursor(PD, GetTU(CT)); +} + +unsigned clang_Type_getNumObjCTypeArgs(CXType CT) { + QualType T = GetQualType(CT); + if (T.isNull()) + return 0; + + const ObjCObjectType *OT = dyn_cast<ObjCObjectType>(T); + if (!OT) + return 0; + + return OT->getTypeArgs().size(); +} + +CXType clang_Type_getObjCTypeArg(CXType CT, unsigned i) { + QualType T = GetQualType(CT); + if (T.isNull()) + return MakeCXType(QualType(), GetTU(CT)); + + const ObjCObjectType *OT = dyn_cast<ObjCObjectType>(T); + if (!OT) + return MakeCXType(QualType(), GetTU(CT)); + + const ArrayRef<QualType> TA = OT->getTypeArgs(); + if ((size_t)i >= TA.size()) + return MakeCXType(QualType(), GetTU(CT)); + + return MakeCXType(TA[i], GetTU(CT)); +} + unsigned clang_Type_visitFields(CXType PT, CXFieldVisitor visitor, CXClientData client_data){ @@ -1130,11 +1229,15 @@ unsigned clang_Cursor_isAnonymous(CXCursor C){ if (!clang_isDeclaration(C.kind)) return 0; const Decl *D = cxcursor::getCursorDecl(C); - if (const RecordDecl *FD = dyn_cast_or_null<RecordDecl>(D)) - return FD->isAnonymousStructOrUnion(); + if (const NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(D)) { + return ND->isAnonymousNamespace(); + } else if (const TagDecl *TD = dyn_cast_or_null<TagDecl>(D)) { + return TD->getTypedefNameForAnonDecl() == nullptr && + TD->getIdentifier() == nullptr; + } + return 0; } - CXType clang_Type_getNamedType(CXType CT){ QualType T = GetQualType(CT); const Type *TP = T.getTypePtrOrNull(); @@ -1153,3 +1256,22 @@ unsigned clang_Type_isTransparentTagTypedef(CXType TT){ } return false; } + +enum CXTypeNullabilityKind clang_Type_getNullability(CXType CT) { + QualType T = GetQualType(CT); + if (T.isNull()) + return CXTypeNullability_Invalid; + + ASTContext &Ctx = cxtu::getASTUnit(GetTU(CT))->getASTContext(); + if (auto nullability = T->getNullability(Ctx)) { + switch (*nullability) { + case NullabilityKind::NonNull: + return CXTypeNullability_NonNull; + case NullabilityKind::Nullable: + return CXTypeNullability_Nullable; + case NullabilityKind::Unspecified: + return CXTypeNullability_Unspecified; + } + } + return CXTypeNullability_Invalid; +} diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index 95a42712c4af..2c4b083a594a 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -31,6 +31,8 @@ clang_Cursor_getRawCommentText clang_Cursor_getNumArguments clang_Cursor_getObjCDeclQualifiers clang_Cursor_getObjCPropertyAttributes +clang_Cursor_getObjCPropertyGetterName +clang_Cursor_getObjCPropertySetterName clang_Cursor_getObjCSelectorIndex clang_Cursor_getOffsetOfField clang_Cursor_getSpellingNameRange @@ -98,6 +100,13 @@ clang_Type_getCXXRefQualifier clang_Type_visitFields clang_Type_getNamedType clang_Type_isTransparentTagTypedef +clang_Type_getObjCObjectBaseType +clang_Type_getNumObjCProtocolRefs +clang_Type_getObjCProtocolDecl +clang_Type_getNumObjCTypeArgs +clang_Type_getObjCTypeArg +clang_Type_getModifiedType +clang_Type_getNullability clang_VerbatimBlockLineComment_getText clang_VerbatimLineComment_getText clang_HTMLTagComment_getAsString diff --git a/tools/scan-build-py/README.md b/tools/scan-build-py/README.md index 720bde1cf3b1..01e3454bed44 100644 --- a/tools/scan-build-py/README.md +++ b/tools/scan-build-py/README.md @@ -53,7 +53,7 @@ with CTU analysis enabled, execute: $ analyze-build --ctu -For CTU analysis an additional (function-definition) collection-phase is required. +For CTU analysis an additional (external definition) collection-phase is required. For debugging purposes, it is possible to separately execute the collection and the analysis phase. By doing this, the intermediate files used for the analysis are kept on the disk in `./ctu-dir`. diff --git a/tools/scan-build-py/libscanbuild/__init__.py b/tools/scan-build-py/libscanbuild/__init__.py index e7b74879167e..903207c6be09 100644 --- a/tools/scan-build-py/libscanbuild/__init__.py +++ b/tools/scan-build-py/libscanbuild/__init__.py @@ -20,7 +20,7 @@ ENVIRONMENT_KEY = 'INTERCEPT_BUILD' Execution = collections.namedtuple('Execution', ['pid', 'cwd', 'cmd']) CtuConfig = collections.namedtuple('CtuConfig', ['collect', 'analyze', 'dir', - 'func_map_cmd']) + 'extdef_map_cmd']) def duplicate_check(method): diff --git a/tools/scan-build-py/libscanbuild/analyze.py b/tools/scan-build-py/libscanbuild/analyze.py index 5a7cc20a517e..ab8ea62f46fe 100644 --- a/tools/scan-build-py/libscanbuild/analyze.py +++ b/tools/scan-build-py/libscanbuild/analyze.py @@ -42,8 +42,8 @@ __all__ = ['scan_build', 'analyze_build', 'analyze_compiler_wrapper'] COMPILER_WRAPPER_CC = 'analyze-cc' COMPILER_WRAPPER_CXX = 'analyze-c++' -CTU_FUNCTION_MAP_FILENAME = 'externalFnMap.txt' -CTU_TEMP_FNMAP_FOLDER = 'tmpExternalFnMaps' +CTU_EXTDEF_MAP_FILENAME = 'externalDefMap.txt' +CTU_TEMP_DEFMAP_FOLDER = 'tmpExternalDefMaps' @command_entry_point @@ -117,9 +117,9 @@ def get_ctu_config_from_args(args): CtuConfig(collect=args.ctu_phases.collect, analyze=args.ctu_phases.analyze, dir=args.ctu_dir, - func_map_cmd=args.func_map_cmd) + extdef_map_cmd=args.extdef_map_cmd) if hasattr(args, 'ctu_phases') and hasattr(args.ctu_phases, 'dir') - else CtuConfig(collect=False, analyze=False, dir='', func_map_cmd='')) + else CtuConfig(collect=False, analyze=False, dir='', extdef_map_cmd='')) def get_ctu_config_from_json(ctu_conf_json): @@ -130,23 +130,24 @@ def get_ctu_config_from_json(ctu_conf_json): return CtuConfig(collect=ctu_config[0], analyze=ctu_config[1], dir=ctu_config[2], - func_map_cmd=ctu_config[3]) + extdef_map_cmd=ctu_config[3]) -def create_global_ctu_function_map(func_map_lines): - """ Takes iterator of individual function maps and creates a global map - keeping only unique names. We leave conflicting names out of CTU. +def create_global_ctu_extdef_map(extdef_map_lines): + """ Takes iterator of individual external definition maps and creates a + global map keeping only unique names. We leave conflicting names out of + CTU. - :param func_map_lines: Contains the id of a function (mangled name) and + :param extdef_map_lines: Contains the id of a definition (mangled name) and the originating source (the corresponding AST file) name. - :type func_map_lines: Iterator of str. + :type extdef_map_lines: Iterator of str. :returns: Mangled name - AST file pairs. :rtype: List of (str, str) tuples. """ mangled_to_asts = defaultdict(set) - for line in func_map_lines: + for line in extdef_map_lines: mangled_name, ast_file = line.strip().split(' ', 1) mangled_to_asts[mangled_name].add(ast_file) @@ -159,20 +160,20 @@ def create_global_ctu_function_map(func_map_lines): return mangled_ast_pairs -def merge_ctu_func_maps(ctudir): - """ Merge individual function maps into a global one. +def merge_ctu_extdef_maps(ctudir): + """ Merge individual external definition maps into a global one. As the collect phase runs parallel on multiple threads, all compilation - units are separately mapped into a temporary file in CTU_TEMP_FNMAP_FOLDER. - These function maps contain the mangled names of functions and the source - (AST generated from the source) which had them. + units are separately mapped into a temporary file in CTU_TEMP_DEFMAP_FOLDER. + These definition maps contain the mangled names and the source + (AST generated from the source) which had their definition. These files should be merged at the end into a global map file: - CTU_FUNCTION_MAP_FILENAME.""" + CTU_EXTDEF_MAP_FILENAME.""" - def generate_func_map_lines(fnmap_dir): + def generate_extdef_map_lines(extdefmap_dir): """ Iterate over all lines of input files in a determined order. """ - files = glob.glob(os.path.join(fnmap_dir, '*')) + files = glob.glob(os.path.join(extdefmap_dir, '*')) files.sort() for filename in files: with open(filename, 'r') as in_file: @@ -180,11 +181,11 @@ def merge_ctu_func_maps(ctudir): yield line def write_global_map(arch, mangled_ast_pairs): - """ Write (mangled function name, ast file) pairs into final file. """ + """ Write (mangled name, ast file) pairs into final file. """ - extern_fns_map_file = os.path.join(ctudir, arch, - CTU_FUNCTION_MAP_FILENAME) - with open(extern_fns_map_file, 'w') as out_file: + extern_defs_map_file = os.path.join(ctudir, arch, + CTU_EXTDEF_MAP_FILENAME) + with open(extern_defs_map_file, 'w') as out_file: for mangled_name, ast_file in mangled_ast_pairs: out_file.write('%s %s\n' % (mangled_name, ast_file)) @@ -192,15 +193,15 @@ def merge_ctu_func_maps(ctudir): for triple_path in triple_arches: if os.path.isdir(triple_path): triple_arch = os.path.basename(triple_path) - fnmap_dir = os.path.join(ctudir, triple_arch, - CTU_TEMP_FNMAP_FOLDER) + extdefmap_dir = os.path.join(ctudir, triple_arch, + CTU_TEMP_DEFMAP_FOLDER) - func_map_lines = generate_func_map_lines(fnmap_dir) - mangled_ast_pairs = create_global_ctu_function_map(func_map_lines) + extdef_map_lines = generate_extdef_map_lines(extdefmap_dir) + mangled_ast_pairs = create_global_ctu_extdef_map(extdef_map_lines) write_global_map(triple_arch, mangled_ast_pairs) # Remove all temporary files - shutil.rmtree(fnmap_dir, ignore_errors=True) + shutil.rmtree(extdefmap_dir, ignore_errors=True) def run_analyzer_parallel(args): @@ -251,21 +252,21 @@ def govern_analyzer_runs(args): # left so multiple analyze runs can use the same data gathered by a single # collection run. if ctu_config.collect and ctu_config.analyze: - # CTU strings are coming from args.ctu_dir and func_map_cmd, + # CTU strings are coming from args.ctu_dir and extdef_map_cmd, # so we can leave it empty args.ctu_phases = CtuConfig(collect=True, analyze=False, - dir='', func_map_cmd='') + dir='', extdef_map_cmd='') run_analyzer_parallel(args) - merge_ctu_func_maps(ctu_config.dir) + merge_ctu_extdef_maps(ctu_config.dir) args.ctu_phases = CtuConfig(collect=False, analyze=True, - dir='', func_map_cmd='') + dir='', extdef_map_cmd='') run_analyzer_parallel(args) shutil.rmtree(ctu_config.dir, ignore_errors=True) else: # Single runs (collect or analyze) are launched from here. run_analyzer_parallel(args) if ctu_config.collect: - merge_ctu_func_maps(ctu_config.dir) + merge_ctu_extdef_maps(ctu_config.dir) def setup_environment(args): @@ -395,8 +396,6 @@ def analyzer_params(args): if args.disable_checker: checkers = ','.join(args.disable_checker) result.extend(['-analyzer-disable-checker', checkers]) - if os.getenv('UBIVIZ'): - result.append('-analyzer-viz-egraph-ubigraph') return prefix_with('-Xclang', result) @@ -546,20 +545,20 @@ def run_analyzer(opts, continuation=report_failure): return result -def func_map_list_src_to_ast(func_src_list): - """ Turns textual function map list with source files into a - function map list with ast files. """ +def extdef_map_list_src_to_ast(extdef_src_list): + """ Turns textual external definition map list with source files into an + external definition map list with ast files. """ - func_ast_list = [] - for fn_src_txt in func_src_list: - mangled_name, path = fn_src_txt.split(" ", 1) + extdef_ast_list = [] + for extdef_src_txt in extdef_src_list: + mangled_name, path = extdef_src_txt.split(" ", 1) # Normalize path on windows as well path = os.path.splitdrive(path)[1] # Make relative path out of absolute path = path[1:] if path[0] == os.sep else path ast_path = os.path.join("ast", path + ".ast") - func_ast_list.append(mangled_name + " " + ast_path) - return func_ast_list + extdef_ast_list.append(mangled_name + " " + ast_path) + return extdef_ast_list @require(['clang', 'directory', 'flags', 'direct_args', 'file', 'ctu']) @@ -590,37 +589,38 @@ def ctu_collect_phase(opts): logging.debug("Generating AST using '%s'", ast_command) run_command(ast_command, cwd=opts['directory']) - def map_functions(triple_arch): - """ Generate function map file for the current source. """ + def map_extdefs(triple_arch): + """ Generate external definition map file for the current source. """ args = opts['direct_args'] + opts['flags'] - funcmap_command = [opts['ctu'].func_map_cmd] - funcmap_command.append(opts['file']) - funcmap_command.append('--') - funcmap_command.extend(args) - logging.debug("Generating function map using '%s'", funcmap_command) - func_src_list = run_command(funcmap_command, cwd=opts['directory']) - func_ast_list = func_map_list_src_to_ast(func_src_list) - extern_fns_map_folder = os.path.join(opts['ctu'].dir, triple_arch, - CTU_TEMP_FNMAP_FOLDER) - if not os.path.isdir(extern_fns_map_folder): + extdefmap_command = [opts['ctu'].extdef_map_cmd] + extdefmap_command.append(opts['file']) + extdefmap_command.append('--') + extdefmap_command.extend(args) + logging.debug("Generating external definition map using '%s'", + extdefmap_command) + extdef_src_list = run_command(extdefmap_command, cwd=opts['directory']) + extdef_ast_list = extdef_map_list_src_to_ast(extdef_src_list) + extern_defs_map_folder = os.path.join(opts['ctu'].dir, triple_arch, + CTU_TEMP_DEFMAP_FOLDER) + if not os.path.isdir(extern_defs_map_folder): try: - os.makedirs(extern_fns_map_folder) + os.makedirs(extern_defs_map_folder) except OSError: # In case an other process already created it. pass - if func_ast_list: + if extdef_ast_list: with tempfile.NamedTemporaryFile(mode='w', - dir=extern_fns_map_folder, + dir=extern_defs_map_folder, delete=False) as out_file: - out_file.write("\n".join(func_ast_list) + "\n") + out_file.write("\n".join(extdef_ast_list) + "\n") cwd = opts['directory'] cmd = [opts['clang'], '--analyze'] + opts['direct_args'] + opts['flags'] \ + [opts['file']] triple_arch = get_triple_arch(cmd, cwd) generate_ast(triple_arch) - map_functions(triple_arch) + map_extdefs(triple_arch) @require(['ctu']) diff --git a/tools/scan-build-py/libscanbuild/arguments.py b/tools/scan-build-py/libscanbuild/arguments.py index a5d0c6bda661..58c56d2b6d29 100644 --- a/tools/scan-build-py/libscanbuild/arguments.py +++ b/tools/scan-build-py/libscanbuild/arguments.py @@ -12,6 +12,7 @@ earlier.) It also implements basic validation methods, related to the command. Validations are mostly calling specific help methods, or mangling values. """ +from __future__ import absolute_import, division, print_function import os import sys @@ -134,10 +135,10 @@ def validate_args_for_analyze(parser, args, from_build_command): if args.ctu_phases.analyze and not args.ctu_phases.collect \ and not os.path.exists(args.ctu_dir): parser.error(message='missing CTU directory') - # Check CTU capability via checking clang-func-mapping - if not is_ctu_capable(args.func_map_cmd): + # Check CTU capability via checking clang-extdef-mapping + if not is_ctu_capable(args.extdef_map_cmd): parser.error(message="""This version of clang does not support CTU - functionality or clang-func-mapping command not found.""") + functionality or clang-extdef-mapping command not found.""") def create_intercept_parser(): @@ -365,7 +366,7 @@ def create_analyze_parser(from_build_command): '--ctu', action='store_const', const=CtuConfig(collect=True, analyze=True, - dir='', func_map_cmd=''), + dir='', extdef_map_cmd=''), dest='ctu_phases', help="""Perform cross translation unit (ctu) analysis (both collect and analyze phases) using default <ctu-dir> for temporary output. @@ -381,7 +382,7 @@ def create_analyze_parser(from_build_command): '--ctu-collect-only', action='store_const', const=CtuConfig(collect=True, analyze=False, - dir='', func_map_cmd=''), + dir='', extdef_map_cmd=''), dest='ctu_phases', help="""Perform only the collect phase of ctu. Keep <ctu-dir> for further use.""") @@ -389,20 +390,20 @@ def create_analyze_parser(from_build_command): '--ctu-analyze-only', action='store_const', const=CtuConfig(collect=False, analyze=True, - dir='', func_map_cmd=''), + dir='', extdef_map_cmd=''), dest='ctu_phases', help="""Perform only the analyze phase of ctu. <ctu-dir> should be present and will not be removed after analysis.""") ctu.add_argument( - '--use-func-map-cmd', + '--use-extdef-map-cmd', metavar='<path>', - dest='func_map_cmd', - default='clang-func-mapping', - help="""'%(prog)s' uses the 'clang-func-mapping' executable - relative to itself for generating function maps for static - analysis. One can override this behavior with this option by using - the 'clang-func-mapping' packaged with Xcode (on OS X) or from the - PATH.""") + dest='extdef_map_cmd', + default='clang-extdef-mapping', + help="""'%(prog)s' uses the 'clang-extdef-mapping' executable + relative to itself for generating external definition maps for + static analysis. One can override this behavior with this option + by using the 'clang-extdef-mapping' packaged with Xcode (on OS X) + or from the PATH.""") return parser diff --git a/tools/scan-build-py/libscanbuild/clang.py b/tools/scan-build-py/libscanbuild/clang.py index ab422066cab1..0cbfdb648f6a 100644 --- a/tools/scan-build-py/libscanbuild/clang.py +++ b/tools/scan-build-py/libscanbuild/clang.py @@ -156,12 +156,12 @@ def get_checkers(clang, plugins): return checkers -def is_ctu_capable(func_map_cmd): - """ Detects if the current (or given) clang and function mapping +def is_ctu_capable(extdef_map_cmd): + """ Detects if the current (or given) clang and external definition mapping executables are CTU compatible. """ try: - run_command([func_map_cmd, '-version']) + run_command([extdef_map_cmd, '-version']) except (OSError, subprocess.CalledProcessError): return False return True diff --git a/tools/scan-build-py/tests/unit/test_analyze.py b/tools/scan-build-py/tests/unit/test_analyze.py index 9964a296b8dd..768a3b691090 100644 --- a/tools/scan-build-py/tests/unit/test_analyze.py +++ b/tools/scan-build-py/tests/unit/test_analyze.py @@ -349,14 +349,14 @@ class PrefixWithTest(unittest.TestCase): class MergeCtuMapTest(unittest.TestCase): def test_no_map_gives_empty(self): - pairs = sut.create_global_ctu_function_map([]) + pairs = sut.create_global_ctu_extdef_map([]) self.assertFalse(pairs) def test_multiple_maps_merged(self): concat_map = ['c:@F@fun1#I# ast/fun1.c.ast', 'c:@F@fun2#I# ast/fun2.c.ast', 'c:@F@fun3#I# ast/fun3.c.ast'] - pairs = sut.create_global_ctu_function_map(concat_map) + pairs = sut.create_global_ctu_extdef_map(concat_map) self.assertTrue(('c:@F@fun1#I#', 'ast/fun1.c.ast') in pairs) self.assertTrue(('c:@F@fun2#I#', 'ast/fun2.c.ast') in pairs) self.assertTrue(('c:@F@fun3#I#', 'ast/fun3.c.ast') in pairs) @@ -366,7 +366,7 @@ class MergeCtuMapTest(unittest.TestCase): concat_map = ['c:@F@fun1#I# ast/fun1.c.ast', 'c:@F@fun2#I# ast/fun2.c.ast', 'c:@F@fun1#I# ast/fun7.c.ast'] - pairs = sut.create_global_ctu_function_map(concat_map) + pairs = sut.create_global_ctu_extdef_map(concat_map) self.assertFalse(('c:@F@fun1#I#', 'ast/fun1.c.ast') in pairs) self.assertFalse(('c:@F@fun1#I#', 'ast/fun7.c.ast') in pairs) self.assertTrue(('c:@F@fun2#I#', 'ast/fun2.c.ast') in pairs) @@ -376,28 +376,28 @@ class MergeCtuMapTest(unittest.TestCase): concat_map = ['c:@F@fun1#I# ast/fun1.c.ast', 'c:@F@fun2#I# ast/fun2.c.ast', 'c:@F@fun1#I# ast/fun1.c.ast'] - pairs = sut.create_global_ctu_function_map(concat_map) + pairs = sut.create_global_ctu_extdef_map(concat_map) self.assertTrue(('c:@F@fun1#I#', 'ast/fun1.c.ast') in pairs) self.assertTrue(('c:@F@fun2#I#', 'ast/fun2.c.ast') in pairs) self.assertEqual(2, len(pairs)) def test_space_handled_in_source(self): concat_map = ['c:@F@fun1#I# ast/f un.c.ast'] - pairs = sut.create_global_ctu_function_map(concat_map) + pairs = sut.create_global_ctu_extdef_map(concat_map) self.assertTrue(('c:@F@fun1#I#', 'ast/f un.c.ast') in pairs) self.assertEqual(1, len(pairs)) -class FuncMapSrcToAstTest(unittest.TestCase): +class ExtdefMapSrcToAstTest(unittest.TestCase): def test_empty_gives_empty(self): - fun_ast_lst = sut.func_map_list_src_to_ast([]) + fun_ast_lst = sut.extdef_map_list_src_to_ast([]) self.assertFalse(fun_ast_lst) def test_sources_to_asts(self): fun_src_lst = ['c:@F@f1#I# ' + os.path.join(os.sep + 'path', 'f1.c'), 'c:@F@f2#I# ' + os.path.join(os.sep + 'path', 'f2.c')] - fun_ast_lst = sut.func_map_list_src_to_ast(fun_src_lst) + fun_ast_lst = sut.extdef_map_list_src_to_ast(fun_src_lst) self.assertTrue('c:@F@f1#I# ' + os.path.join('ast', 'path', 'f1.c.ast') in fun_ast_lst) @@ -408,7 +408,7 @@ class FuncMapSrcToAstTest(unittest.TestCase): def test_spaces_handled(self): fun_src_lst = ['c:@F@f1#I# ' + os.path.join(os.sep + 'path', 'f 1.c')] - fun_ast_lst = sut.func_map_list_src_to_ast(fun_src_lst) + fun_ast_lst = sut.extdef_map_list_src_to_ast(fun_src_lst) self.assertTrue('c:@F@f1#I# ' + os.path.join('ast', 'path', 'f 1.c.ast') in fun_ast_lst) diff --git a/tools/scan-build-py/tests/unit/test_clang.py b/tools/scan-build-py/tests/unit/test_clang.py index 07ac4d9fb806..7d625c6c5bc4 100644 --- a/tools/scan-build-py/tests/unit/test_clang.py +++ b/tools/scan-build-py/tests/unit/test_clang.py @@ -96,7 +96,7 @@ class ClangGetCheckersTest(unittest.TestCase): class ClangIsCtuCapableTest(unittest.TestCase): def test_ctu_not_found(self): - is_ctu = sut.is_ctu_capable('not-found-clang-func-mapping') + is_ctu = sut.is_ctu_capable('not-found-clang-extdef-mapping') self.assertFalse(is_ctu) diff --git a/tools/scan-build/bin/scan-build b/tools/scan-build/bin/scan-build index c50f900cc45e..fd0dd66b2d6d 100755 --- a/tools/scan-build/bin/scan-build +++ b/tools/scan-build/bin/scan-build @@ -58,6 +58,7 @@ my %Options = ( KeepEmpty => 0, # Don't remove output directory even with 0 results. EnableCheckers => {}, DisableCheckers => {}, + Excludes => [], UseCC => undef, # C compiler to use for compilation. UseCXX => undef, # C++ compiler to use for compilation. AnalyzerTarget => undef, @@ -420,6 +421,20 @@ sub ScanFile { # The file no longer exists: use the original path. $BugFile = $1; } + + # Get just the path + my $p = dirname($BugFile); + # Check if the path is found in the list of exclude + if (grep { $p =~ m/$_/ } @{$Options{Excludes}}) { + if ($Options{Verbose}) { + Diag("File '$BugFile' deleted: part of an ignored directory.\n"); + } + + # File in an ignored directory. Remove it + unlink("$Dir/$FName"); + return; + } + UpdatePrefix($BugFile); } elsif (/<!-- BUGPATHLENGTH (.*) -->$/) { @@ -1079,7 +1094,7 @@ sub RunBuildCommand { if ($Cmd =~ /(.*\/?gcc[^\/]*$)/ or $Cmd =~ /(.*\/?cc[^\/]*$)/ or $Cmd =~ /(.*\/?llvm-gcc[^\/]*$)/ or - $Cmd =~ /(.*\/?clang$)/ or + $Cmd =~ /(.*\/?clang[^\/]*$)/ or $Cmd =~ /(.*\/?ccc-analyzer[^\/]*$)/) { if (!($Cmd =~ /ccc-analyzer/) and !defined $ENV{"CCC_CC"}) { @@ -1178,6 +1193,11 @@ OPTIONS: Display the description of defects in the list + -sarif + + By default the output of scan-build is a set of HTML files. This option + outputs the results in SARIF format. + -plist By default the output of scan-build is a set of HTML files. This option @@ -1192,7 +1212,13 @@ OPTIONS: By default, the exit status of scan-build is the same as the executed build command. Specifying this option causes the exit status of scan-build to be 1 - if it found potential bugs and 0 otherwise. + if it found potential bugs and the exit status of the build itself otherwise. + + --exclude <path> + + Do not run static analyzer against files found in this + directory (You can specify this option multiple times). + Could be useful when project contains 3rd party libraries. --use-cc [compiler path] --use-cc=[compiler path] @@ -1644,6 +1670,12 @@ sub ProcessArgs { next; } + if ($arg eq "-sarif") { + shift @$Args; + $Options{OutputFormat} = "sarif"; + next; + } + if ($arg eq "-plist") { shift @$Args; $Options{OutputFormat} = "plist"; @@ -1698,6 +1730,15 @@ sub ProcessArgs { next; } + if ($arg eq "--exclude") { + shift @$Args; + my $arg = shift @$Args; + # Remove the trailing slash if any + $arg =~ s|/$||; + push @{$Options{Excludes}}, $arg; + next; + } + if ($arg eq "-load-plugin") { shift @$Args; push @{$Options{PluginsToLoad}}, shift @$Args; @@ -1813,13 +1854,13 @@ Diag("Using '$Clang' for static analysis\n"); SetHtmlEnv(\@ARGV, $Options{OutputDir}); my @AnalysesToRun; -foreach (sort { $Options{EnableCheckers}{$a} <=> $Options{EnableCheckers}{$b} } - keys %{$Options{EnableCheckers}}) { +foreach (sort { $Options{EnableCheckers}{$a} <=> $Options{EnableCheckers}{$b} } + keys %{$Options{EnableCheckers}}) { # Push checkers in order they were enabled. push @AnalysesToRun, "-analyzer-checker", $_; } -foreach (sort { $Options{DisableCheckers}{$a} <=> $Options{DisableCheckers}{$b} } - keys %{$Options{DisableCheckers}}) { +foreach (sort { $Options{DisableCheckers}{$a} <=> $Options{DisableCheckers}{$b} } + keys %{$Options{DisableCheckers}}) { # Push checkers in order they were disabled. push @AnalysesToRun, "-analyzer-disable-checker", $_; } @@ -1858,9 +1899,12 @@ my $ExitStatus = RunBuildCommand(\@ARGV, $Options{IgnoreErrors}, $Options{KeepCC $Cmd, $CmdCXX, \%EnvVars); if (defined $Options{OutputFormat}) { - if ($Options{OutputFormat} =~ /plist/) { + if ($Options{OutputFormat} =~ /plist/ || + $Options{OutputFormat} =~ /sarif/) { Diag "Analysis run complete.\n"; - Diag "Analysis results (plist files) deposited in '$Options{OutputDir}'\n"; + Diag "Analysis results (" . + ($Options{OutputFormat} =~ /plist/ ? "plist" : "sarif") . + " files) deposited in '$Options{OutputDir}'\n"; } if ($Options{OutputFormat} =~ /html/) { # Postprocess the HTML directory. @@ -1878,7 +1922,7 @@ if (defined $Options{OutputFormat}) { if ($Options{ExitStatusFoundBugs}) { exit 1 if ($NumBugs > 0); - exit 0; + exit $ExitStatus; } } } diff --git a/tools/scan-build/libexec/ccc-analyzer b/tools/scan-build/libexec/ccc-analyzer index 73cd2ff3d915..70afb5bcbbd5 100755 --- a/tools/scan-build/libexec/ccc-analyzer +++ b/tools/scan-build/libexec/ccc-analyzer @@ -243,11 +243,6 @@ sub Analyze { push @Args, "-Xclang", $arg; } - # Display Ubiviz graph? - if (defined $ENV{'CCC_UBI'}) { - push @Args, "-Xclang", "-analyzer-viz-egraph-ubigraph"; - } - if (defined $AnalyzerTarget) { push @Args, "-target", $AnalyzerTarget; } @@ -751,9 +746,10 @@ if ($Action eq 'compile' or $Action eq 'link') { if (defined $OutputFormat) { push @AnalyzeArgs, "-analyzer-output=" . $OutputFormat; - if ($OutputFormat =~ /plist/) { + if ($OutputFormat =~ /plist/ || $OutputFormat =~ /sarif/) { # Change "Output" to be a file. - my ($h, $f) = tempfile("report-XXXXXX", SUFFIX => ".plist", + my $Suffix = $OutputFormat =~ /plist/ ? ".plist" : ".sarif"; + my ($h, $f) = tempfile("report-XXXXXX", SUFFIX => $Suffix, DIR => $HtmlDir); $ResultFile = $f; # If the HtmlDir is not set, we should clean up the plist files. diff --git a/tools/scan-view/bin/scan-view b/tools/scan-view/bin/scan-view index 1b6e8ba90dfa..6165432e7af8 100755 --- a/tools/scan-view/bin/scan-view +++ b/tools/scan-view/bin/scan-view @@ -1,5 +1,7 @@ #!/usr/bin/env python +from __future__ import print_function + """The clang static analyzer results viewer. """ @@ -7,9 +9,12 @@ import sys import imp import os import posixpath -import thread +import threading import time -import urllib +try: + from urllib.request import urlopen +except ImportError: + from urllib2 import urlopen import webbrowser # How long to wait for server to start. @@ -27,7 +32,7 @@ kMaxPortsToTry = 100 def url_is_up(url): try: - o = urllib.urlopen(url) + o = urlopen(url) except IOError: return False o.close() @@ -35,7 +40,6 @@ def url_is_up(url): def start_browser(port, options): - import urllib import webbrowser url = 'http://%s:%d' % (options.host, port) @@ -52,10 +56,10 @@ def start_browser(port, options): sys.stderr.flush() time.sleep(kSleepTimeout) else: - print >> sys.stderr, 'WARNING: Unable to detect that server started.' + print('WARNING: Unable to detect that server started.', file=sys.stderr) if options.debug: - print >> sys.stderr, '%s: Starting webbrowser...' % sys.argv[0] + print('%s: Starting webbrowser...' % sys.argv[0], file=sys.stderr) webbrowser.open(url) @@ -69,9 +73,9 @@ def run(port, options, root): import ScanView try: - print 'Starting scan-view at: http://%s:%d' % (options.host, - port) - print ' Use Ctrl-C to exit.' + print('Starting scan-view at: http://%s:%d' % (options.host, + port)) + print(' Use Ctrl-C to exit.') httpd = ScanView.create_server((options.host, port), options, root) httpd.serve_forever() @@ -80,9 +84,12 @@ def run(port, options, root): def port_is_open(port): - import SocketServer try: - t = SocketServer.TCPServer((kDefaultHost, port), None) + import socketserver + except ImportError: + import SocketServer as socketserver + try: + t = socketserver.TCPServer((kDefaultHost, port), None) except: return False t.server_close() @@ -135,7 +142,7 @@ def main(): # Kick off thread to wait for server and start web browser, if # requested. if args.startBrowser: - t = thread.start_new_thread(start_browser, (port, args)) + threading.Thread(target=start_browser, args=(port, args)).start() run(port, args, args.root) diff --git a/tools/scan-view/share/Reporter.py b/tools/scan-view/share/Reporter.py index 800af03b1a2c..b1ff16142e27 100644 --- a/tools/scan-view/share/Reporter.py +++ b/tools/scan-view/share/Reporter.py @@ -16,7 +16,7 @@ class ReportFailure(Exception): # Collect information about a bug. -class BugReport: +class BugReport(object): def __init__(self, title, description, files): self.title = title self.description = description @@ -37,7 +37,7 @@ from email.mime.text import MIMEText # ReporterParameter #===------------------------------------------------------------------------===# -class ReporterParameter: +class ReporterParameter(object): def __init__(self, n): self.name = n def getName(self): @@ -75,12 +75,12 @@ class SelectionParameter (ReporterParameter): # Reporters #===------------------------------------------------------------------------===# -class EmailReporter: +class EmailReporter(object): def getName(self): return 'Email' def getParameters(self): - return map(lambda x:TextParameter(x),['To', 'From', 'SMTP Server', 'SMTP Port']) + return [TextParameter(x) for x in ['To', 'From', 'SMTP Server', 'SMTP Port']] # Lifted from python email module examples. def attachFile(self, outer, path): @@ -143,12 +143,12 @@ Description: %s return "Message sent!" -class BugzillaReporter: +class BugzillaReporter(object): def getName(self): return 'Bugzilla' def getParameters(self): - return map(lambda x:TextParameter(x),['URL','Product']) + return [TextParameter(x) for x in ['URL','Product']] def fileReport(self, report, parameters): raise NotImplementedError @@ -174,7 +174,7 @@ class RadarClassificationParameter(SelectionParameter): else: return '7' -class RadarReporter: +class RadarReporter(object): @staticmethod def isAvailable(): # FIXME: Find this .scpt better @@ -211,7 +211,7 @@ class RadarReporter: script = os.path.join(os.path.dirname(__file__),'../share/scan-view/FileRadar.scpt') args = ['osascript', script, component, componentVersion, classification, personID, report.title, - report.description, diagnosis, config] + map(os.path.abspath, report.files) + report.description, diagnosis, config] + [os.path.abspath(f) for f in report.files] # print >>sys.stderr, args try: p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) diff --git a/tools/scan-view/share/ScanView.py b/tools/scan-view/share/ScanView.py index 7dc0351ebe7f..c40366b2e849 100644 --- a/tools/scan-view/share/ScanView.py +++ b/tools/scan-view/share/ScanView.py @@ -1,10 +1,24 @@ -import BaseHTTPServer -import SimpleHTTPServer +from __future__ import print_function +try: + from http.server import HTTPServer, SimpleHTTPRequestHandler +except ImportError: + from BaseHTTPServer import HTTPServer + from SimpleHTTPServer import SimpleHTTPRequestHandler import os import sys -import urllib, urlparse +try: + from urlparse import urlparse + from urllib import unquote +except ImportError: + from urllib.parse import urlparse, unquote + import posixpath -import StringIO + +if sys.version_info.major >= 3: + from io import StringIO, BytesIO +else: + from io import BytesIO, BytesIO as StringIO + import re import shutil import threading @@ -13,7 +27,10 @@ import socket import itertools import Reporter -import ConfigParser +try: + import configparser +except ImportError: + import ConfigParser as configparser ### # Various patterns matched or replaced by server. @@ -96,25 +113,25 @@ class ReporterThread(threading.Thread): result = None try: if self.server.options.debug: - print >>sys.stderr, "%s: SERVER: submitting bug."%(sys.argv[0],) + print("%s: SERVER: submitting bug."%(sys.argv[0],), file=sys.stderr) self.status = self.reporter.fileReport(self.report, self.parameters) self.success = True time.sleep(3) if self.server.options.debug: - print >>sys.stderr, "%s: SERVER: submission complete."%(sys.argv[0],) - except Reporter.ReportFailure,e: + print("%s: SERVER: submission complete."%(sys.argv[0],), file=sys.stderr) + except Reporter.ReportFailure as e: self.status = e.value - except Exception,e: - s = StringIO.StringIO() + except Exception as e: + s = StringIO() import traceback - print >>s,'<b>Unhandled Exception</b><br><pre>' - traceback.print_exc(e,file=s) - print >>s,'</pre>' + print('<b>Unhandled Exception</b><br><pre>', file=s) + traceback.print_exc(file=s) + print('</pre>', file=s) self.status = s.getvalue() -class ScanViewServer(BaseHTTPServer.HTTPServer): +class ScanViewServer(HTTPServer): def __init__(self, address, handler, root, reporters, options): - BaseHTTPServer.HTTPServer.__init__(self, address, handler) + HTTPServer.__init__(self, address, handler) self.root = root self.reporters = reporters self.options = options @@ -123,7 +140,7 @@ class ScanViewServer(BaseHTTPServer.HTTPServer): self.load_config() def load_config(self): - self.config = ConfigParser.RawConfigParser() + self.config = configparser.RawConfigParser() # Add defaults self.config.add_section('ScanView') @@ -155,44 +172,44 @@ class ScanViewServer(BaseHTTPServer.HTTPServer): def halt(self): self.halted = True if self.options.debug: - print >>sys.stderr, "%s: SERVER: halting." % (sys.argv[0],) + print("%s: SERVER: halting." % (sys.argv[0],), file=sys.stderr) def serve_forever(self): while not self.halted: if self.options.debug > 1: - print >>sys.stderr, "%s: SERVER: waiting..." % (sys.argv[0],) + print("%s: SERVER: waiting..." % (sys.argv[0],), file=sys.stderr) try: self.handle_request() - except OSError,e: - print 'OSError',e.errno + except OSError as e: + print('OSError',e.errno) def finish_request(self, request, client_address): if self.options.autoReload: import ScanView self.RequestHandlerClass = reload(ScanView).ScanViewRequestHandler - BaseHTTPServer.HTTPServer.finish_request(self, request, client_address) + HTTPServer.finish_request(self, request, client_address) def handle_error(self, request, client_address): # Ignore socket errors info = sys.exc_info() if info and isinstance(info[1], socket.error): if self.options.debug > 1: - print >>sys.stderr, "%s: SERVER: ignored socket error." % (sys.argv[0],) + print("%s: SERVER: ignored socket error." % (sys.argv[0],), file=sys.stderr) return - BaseHTTPServer.HTTPServer.handle_error(self, request, client_address) + HTTPServer.handle_error(self, request, client_address) # Borrowed from Quixote, with simplifications. def parse_query(qs, fields=None): if fields is None: fields = {} - for chunk in filter(None, qs.split('&')): + for chunk in (_f for _f in qs.split('&') if _f): if '=' not in chunk: name = chunk value = '' else: name, value = chunk.split('=', 1) - name = urllib.unquote(name.replace('+', ' ')) - value = urllib.unquote(value.replace('+', ' ')) + name = unquote(name.replace('+', ' ')) + value = unquote(value.replace('+', ' ')) item = fields.get(name) if item is None: fields[name] = [value] @@ -200,20 +217,20 @@ def parse_query(qs, fields=None): item.append(value) return fields -class ScanViewRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): +class ScanViewRequestHandler(SimpleHTTPRequestHandler): server_version = "ScanViewServer/" + __version__ dynamic_mtime = time.time() def do_HEAD(self): try: - SimpleHTTPServer.SimpleHTTPRequestHandler.do_HEAD(self) - except Exception,e: + SimpleHTTPRequestHandler.do_HEAD(self) + except Exception as e: self.handle_exception(e) def do_GET(self): try: - SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) - except Exception,e: + SimpleHTTPRequestHandler.do_GET(self) + except Exception as e: self.handle_exception(e) def do_POST(self): @@ -230,7 +247,7 @@ class ScanViewRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): if f: self.copyfile(f, self.wfile) f.close() - except Exception,e: + except Exception as e: self.handle_exception(e) def log_message(self, format, *args): @@ -263,9 +280,9 @@ class ScanViewRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): def handle_exception(self, exc): import traceback - s = StringIO.StringIO() - print >>s, "INTERNAL ERROR\n" - traceback.print_exc(exc, s) + s = StringIO() + print("INTERNAL ERROR\n", file=s) + traceback.print_exc(file=s) f = self.send_string(s.getvalue(), 'text/plain') if f: self.copyfile(f, self.wfile) @@ -410,8 +427,8 @@ Submit</h3> import startfile if self.server.options.debug: - print >>sys.stderr, '%s: SERVER: opening "%s"'%(sys.argv[0], - file) + print('%s: SERVER: opening "%s"'%(sys.argv[0], + file), file=sys.stderr) status = startfile.open(file) if status: @@ -422,13 +439,13 @@ Submit</h3> return self.send_string(res, 'text/plain') def get_report_context(self, report): - class Context: + class Context(object): pass if report is None or report == 'None': data = self.load_crashes() # Don't allow empty reports. if not data: - raise ValueError, 'No crashes detected!' + raise ValueError('No crashes detected!') c = Context() c.title = 'clang static analyzer failures' @@ -472,7 +489,7 @@ STDERR Summary # Check that this is a valid report. path = posixpath.join(self.server.root, 'report-%s.html' % report) if not posixpath.exists(path): - raise ValueError, 'Invalid report ID' + raise ValueError('Invalid report ID') keys = self.load_report(report) c = Context() c.title = keys.get('DESC','clang error (unrecognized') @@ -501,7 +518,7 @@ Line: %s # report is None is used for crashes try: c = self.get_report_context(report) - except ValueError, e: + except ValueError as e: return self.send_error(400, e.message) title = c.title @@ -544,7 +561,7 @@ Line: %s """%(r.getName(),display,r.getName(),options)) reporterSelections = '\n'.join(reporterSelections) reporterOptionsDivs = '\n'.join(reporterOptions) - reportersArray = '[%s]'%(','.join([`r.getName()` for r in self.server.reporters])) + reportersArray = '[%s]'%(','.join([repr(r.getName()) for r in self.server.reporters])) if c.files: fieldSize = min(5, len(c.files)) @@ -647,9 +664,9 @@ File Bug</h3> fields = {} self.fields = fields - o = urlparse.urlparse(self.path) + o = urlparse(self.path) self.fields = parse_query(o.query, fields) - path = posixpath.normpath(urllib.unquote(o.path)) + path = posixpath.normpath(unquote(o.path)) # Split the components and strip the root prefix. components = path.split('/')[1:] @@ -690,8 +707,8 @@ File Bug</h3> path = posixpath.join(self.server.root, relpath) if self.server.options.debug > 1: - print >>sys.stderr, '%s: SERVER: sending path "%s"'%(sys.argv[0], - path) + print('%s: SERVER: sending path "%s"'%(sys.argv[0], + path), file=sys.stderr) return self.send_path(path) def send_404(self): @@ -727,15 +744,16 @@ File Bug</h3> return f def send_string(self, s, ctype='text/html', headers=True, mtime=None): + encoded_s = s.encode() if headers: self.send_response(200) self.send_header("Content-type", ctype) - self.send_header("Content-Length", str(len(s))) + self.send_header("Content-Length", str(len(encoded_s))) if mtime is None: mtime = self.dynamic_mtime self.send_header("Last-Modified", self.date_time_string(mtime)) self.end_headers() - return StringIO.StringIO(s) + return BytesIO(encoded_s) def send_patched_file(self, path, ctype): # Allow a very limited set of variables. This is pretty gross. diff --git a/tools/scan-view/share/startfile.py b/tools/scan-view/share/startfile.py index f58dbeeaf817..9eb548bc4329 100644 --- a/tools/scan-view/share/startfile.py +++ b/tools/scan-view/share/startfile.py @@ -110,7 +110,10 @@ elif sys.platform == 'darwin': # Platform support for Unix else: - import commands + try: + from commands import getoutput + except ImportError: + from subprocess import getoutput # @WARNING: use the private API of the webbrowser module from webbrowser import _iscommand @@ -125,7 +128,7 @@ else: def detect_kde_version(self): kde_version = None try: - info = commands.getoutput('kde-config --version') + info = getoutput('kde-config --version') for line in info.splitlines(): if line.startswith('KDE'): @@ -158,7 +161,7 @@ else: desktop_environment = 'gnome' else: try: - info = commands.getoutput('xprop -root _DT_SAVE_MODE') + info = getoutput('xprop -root _DT_SAVE_MODE') if ' = "xfce4"' in info: desktop_environment = 'xfce' except (OSError, RuntimeError): @@ -189,7 +192,7 @@ else: return _controllers[controller_name].open except KeyError: - if _controllers.has_key('xdg-open'): + if 'xdg-open' in _controllers: return _controllers['xdg-open'].open else: return webbrowser.open |
