From ecb7e5c8afe929ee38155db94de6b084ec32a645 Mon Sep 17 00:00:00 2001 From: Roman Divacky Date: Tue, 16 Feb 2010 09:31:36 +0000 Subject: Update clang to r96341. --- include/clang-c/Index.h | 827 ++++++++++++----- include/clang/AST/ASTContext.h | 46 +- include/clang/AST/ASTDiagnostic.h | 22 +- include/clang/AST/ASTImporter.h | 234 +++++ include/clang/AST/Attr.h | 78 +- include/clang/AST/CXXInheritance.h | 11 +- include/clang/AST/Decl.h | 377 ++++---- include/clang/AST/DeclBase.h | 86 +- include/clang/AST/DeclCXX.h | 512 ++++++----- include/clang/AST/DeclObjC.h | 70 +- include/clang/AST/DeclTemplate.h | 53 +- include/clang/AST/DeclarationName.h | 12 +- include/clang/AST/Expr.h | 19 +- include/clang/AST/ExprCXX.h | 418 ++++++--- include/clang/AST/ExprObjC.h | 10 +- include/clang/AST/Stmt.h | 93 +- include/clang/AST/StmtCXX.h | 27 +- include/clang/AST/StmtNodes.def | 9 +- include/clang/AST/StmtVisitor.h | 1 + include/clang/AST/Type.h | 170 +++- include/clang/AST/TypeNodes.def | 5 + include/clang/AST/UnresolvedSet.h | 116 ++- .../clang/Analysis/Analyses/PrintfFormatString.h | 279 ++++++ .../clang/Analysis/Analyses/UninitializedValues.h | 3 + include/clang/Analysis/AnalysisContext.h | 260 ++++++ include/clang/Analysis/LocalCheckers.h | 63 -- include/clang/Analysis/ManagerRegistry.h | 53 -- include/clang/Analysis/PathDiagnostic.h | 494 ----------- .../clang/Analysis/PathSensitive/AnalysisContext.h | 277 ------ .../clang/Analysis/PathSensitive/AnalysisManager.h | 149 ---- .../Analysis/PathSensitive/BasicValueFactory.h | 198 ----- include/clang/Analysis/PathSensitive/BugReporter.h | 473 ---------- include/clang/Analysis/PathSensitive/BugType.h | 76 -- include/clang/Analysis/PathSensitive/Checker.h | 281 ------ .../Analysis/PathSensitive/CheckerVisitor.def | 38 - .../clang/Analysis/PathSensitive/CheckerVisitor.h | 101 --- .../PathSensitive/Checkers/DereferenceChecker.h | 31 - .../Analysis/PathSensitive/ConstraintManager.h | 75 -- include/clang/Analysis/PathSensitive/Environment.h | 103 --- .../clang/Analysis/PathSensitive/ExplodedGraph.h | 432 --------- include/clang/Analysis/PathSensitive/GRAuditor.h | 35 - .../clang/Analysis/PathSensitive/GRBlockCounter.h | 50 -- .../clang/Analysis/PathSensitive/GRCoreEngine.h | 443 ---------- .../clang/Analysis/PathSensitive/GRExprEngine.h | 433 --------- .../Analysis/PathSensitive/GRExprEngineBuilders.h | 76 -- .../Analysis/PathSensitive/GRSimpleAPICheck.h | 40 - include/clang/Analysis/PathSensitive/GRState.h | 751 ---------------- .../clang/Analysis/PathSensitive/GRStateTrait.h | 148 ---- include/clang/Analysis/PathSensitive/GRSubEngine.h | 75 -- .../clang/Analysis/PathSensitive/GRTransferFuncs.h | 85 -- include/clang/Analysis/PathSensitive/GRWorkList.h | 79 -- include/clang/Analysis/PathSensitive/MemRegion.h | 971 -------------------- include/clang/Analysis/PathSensitive/SVals.h | 499 ----------- include/clang/Analysis/PathSensitive/SValuator.h | 91 -- include/clang/Analysis/PathSensitive/Store.h | 220 ----- .../clang/Analysis/PathSensitive/SymbolManager.h | 385 -------- .../clang/Analysis/PathSensitive/ValueManager.h | 208 ----- include/clang/Analysis/Support/Optional.h | 12 +- include/clang/Basic/Builtins.def | 39 +- include/clang/Basic/Diagnostic.h | 27 +- include/clang/Basic/DiagnosticASTKinds.td | 29 + include/clang/Basic/DiagnosticCommonKinds.td | 3 + include/clang/Basic/DiagnosticDriverKinds.td | 4 + include/clang/Basic/DiagnosticFrontendKinds.td | 11 + include/clang/Basic/DiagnosticGroups.td | 6 +- include/clang/Basic/DiagnosticParseKinds.td | 15 +- include/clang/Basic/DiagnosticSemaKinds.td | 152 +++- include/clang/Basic/LangOptions.h | 14 +- include/clang/Basic/Linkage.h | 57 ++ include/clang/Basic/PartialDiagnostic.h | 2 +- include/clang/Basic/SourceManager.h | 8 + include/clang/Basic/Specifiers.h | 3 +- include/clang/Basic/TargetInfo.h | 19 +- include/clang/Basic/TokenKinds.def | 10 +- include/clang/Basic/Version.h | 6 +- include/clang/Checker/BugReporter/BugReporter.h | 477 ++++++++++ include/clang/Checker/BugReporter/BugType.h | 75 ++ include/clang/Checker/BugReporter/PathDiagnostic.h | 494 +++++++++++ .../clang/Checker/Checkers/DereferenceChecker.h | 31 + include/clang/Checker/Checkers/LocalCheckers.h | 61 ++ .../Checker/DomainSpecific/CocoaConventions.h | 40 + include/clang/Checker/ManagerRegistry.h | 53 ++ .../clang/Checker/PathSensitive/AnalysisManager.h | 149 ++++ .../Checker/PathSensitive/BasicValueFactory.h | 198 +++++ include/clang/Checker/PathSensitive/Checker.h | 281 ++++++ .../clang/Checker/PathSensitive/CheckerVisitor.def | 37 + .../clang/Checker/PathSensitive/CheckerVisitor.h | 102 +++ .../Checker/PathSensitive/ConstraintManager.h | 75 ++ include/clang/Checker/PathSensitive/Environment.h | 103 +++ .../clang/Checker/PathSensitive/ExplodedGraph.h | 432 +++++++++ include/clang/Checker/PathSensitive/GRAuditor.h | 35 + .../clang/Checker/PathSensitive/GRBlockCounter.h | 50 ++ include/clang/Checker/PathSensitive/GRCoreEngine.h | 443 ++++++++++ include/clang/Checker/PathSensitive/GRExprEngine.h | 422 +++++++++ .../Checker/PathSensitive/GRExprEngineBuilders.h | 76 ++ .../clang/Checker/PathSensitive/GRSimpleAPICheck.h | 40 + include/clang/Checker/PathSensitive/GRState.h | 756 ++++++++++++++++ include/clang/Checker/PathSensitive/GRStateTrait.h | 148 ++++ include/clang/Checker/PathSensitive/GRSubEngine.h | 75 ++ .../clang/Checker/PathSensitive/GRTransferFuncs.h | 85 ++ include/clang/Checker/PathSensitive/GRWorkList.h | 79 ++ include/clang/Checker/PathSensitive/MemRegion.h | 974 +++++++++++++++++++++ include/clang/Checker/PathSensitive/SVals.h | 499 +++++++++++ include/clang/Checker/PathSensitive/SValuator.h | 66 ++ include/clang/Checker/PathSensitive/Store.h | 230 +++++ .../clang/Checker/PathSensitive/SummaryManager.h | 57 ++ .../clang/Checker/PathSensitive/SymbolManager.h | 385 ++++++++ include/clang/Checker/PathSensitive/ValueManager.h | 208 +++++ include/clang/CodeGen/CodeGenOptions.h | 5 +- include/clang/Driver/CC1Options.td | 32 +- include/clang/Driver/Driver.h | 28 +- include/clang/Driver/Options.td | 17 +- include/clang/Driver/Tool.h | 1 + include/clang/Driver/ToolChain.h | 18 +- include/clang/Driver/Types.def | 1 + include/clang/Frontend/ASTConsumers.h | 7 +- include/clang/Frontend/ASTUnit.h | 10 +- include/clang/Frontend/Analyses.def | 17 +- include/clang/Frontend/CompilerInstance.h | 74 +- include/clang/Frontend/DiagnosticOptions.h | 6 +- include/clang/Frontend/FrontendAction.h | 8 +- include/clang/Frontend/FrontendActions.h | 44 + include/clang/Frontend/FrontendOptions.h | 4 + include/clang/Frontend/PCHBitCodes.h | 12 +- include/clang/Frontend/PCHReader.h | 4 + include/clang/Lex/Lexer.h | 3 + include/clang/Lex/Token.h | 4 + include/clang/Parse/Action.h | 17 +- include/clang/Parse/DeclSpec.h | 13 +- include/clang/Parse/Parser.h | 92 +- 130 files changed, 10581 insertions(+), 8660 deletions(-) create mode 100644 include/clang/AST/ASTImporter.h create mode 100644 include/clang/Analysis/Analyses/PrintfFormatString.h create mode 100644 include/clang/Analysis/AnalysisContext.h delete mode 100644 include/clang/Analysis/LocalCheckers.h delete mode 100644 include/clang/Analysis/ManagerRegistry.h delete mode 100644 include/clang/Analysis/PathDiagnostic.h delete mode 100644 include/clang/Analysis/PathSensitive/AnalysisContext.h delete mode 100644 include/clang/Analysis/PathSensitive/AnalysisManager.h delete mode 100644 include/clang/Analysis/PathSensitive/BasicValueFactory.h delete mode 100644 include/clang/Analysis/PathSensitive/BugReporter.h delete mode 100644 include/clang/Analysis/PathSensitive/BugType.h delete mode 100644 include/clang/Analysis/PathSensitive/Checker.h delete mode 100644 include/clang/Analysis/PathSensitive/CheckerVisitor.def delete mode 100644 include/clang/Analysis/PathSensitive/CheckerVisitor.h delete mode 100644 include/clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h delete mode 100644 include/clang/Analysis/PathSensitive/ConstraintManager.h delete mode 100644 include/clang/Analysis/PathSensitive/Environment.h delete mode 100644 include/clang/Analysis/PathSensitive/ExplodedGraph.h delete mode 100644 include/clang/Analysis/PathSensitive/GRAuditor.h delete mode 100644 include/clang/Analysis/PathSensitive/GRBlockCounter.h delete mode 100644 include/clang/Analysis/PathSensitive/GRCoreEngine.h delete mode 100644 include/clang/Analysis/PathSensitive/GRExprEngine.h delete mode 100644 include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h delete mode 100644 include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h delete mode 100644 include/clang/Analysis/PathSensitive/GRState.h delete mode 100644 include/clang/Analysis/PathSensitive/GRStateTrait.h delete mode 100644 include/clang/Analysis/PathSensitive/GRSubEngine.h delete mode 100644 include/clang/Analysis/PathSensitive/GRTransferFuncs.h delete mode 100644 include/clang/Analysis/PathSensitive/GRWorkList.h delete mode 100644 include/clang/Analysis/PathSensitive/MemRegion.h delete mode 100644 include/clang/Analysis/PathSensitive/SVals.h delete mode 100644 include/clang/Analysis/PathSensitive/SValuator.h delete mode 100644 include/clang/Analysis/PathSensitive/Store.h delete mode 100644 include/clang/Analysis/PathSensitive/SymbolManager.h delete mode 100644 include/clang/Analysis/PathSensitive/ValueManager.h create mode 100644 include/clang/Basic/Linkage.h create mode 100644 include/clang/Checker/BugReporter/BugReporter.h create mode 100644 include/clang/Checker/BugReporter/BugType.h create mode 100644 include/clang/Checker/BugReporter/PathDiagnostic.h create mode 100644 include/clang/Checker/Checkers/DereferenceChecker.h create mode 100644 include/clang/Checker/Checkers/LocalCheckers.h create mode 100644 include/clang/Checker/DomainSpecific/CocoaConventions.h create mode 100644 include/clang/Checker/ManagerRegistry.h create mode 100644 include/clang/Checker/PathSensitive/AnalysisManager.h create mode 100644 include/clang/Checker/PathSensitive/BasicValueFactory.h create mode 100644 include/clang/Checker/PathSensitive/Checker.h create mode 100644 include/clang/Checker/PathSensitive/CheckerVisitor.def create mode 100644 include/clang/Checker/PathSensitive/CheckerVisitor.h create mode 100644 include/clang/Checker/PathSensitive/ConstraintManager.h create mode 100644 include/clang/Checker/PathSensitive/Environment.h create mode 100644 include/clang/Checker/PathSensitive/ExplodedGraph.h create mode 100644 include/clang/Checker/PathSensitive/GRAuditor.h create mode 100644 include/clang/Checker/PathSensitive/GRBlockCounter.h create mode 100644 include/clang/Checker/PathSensitive/GRCoreEngine.h create mode 100644 include/clang/Checker/PathSensitive/GRExprEngine.h create mode 100644 include/clang/Checker/PathSensitive/GRExprEngineBuilders.h create mode 100644 include/clang/Checker/PathSensitive/GRSimpleAPICheck.h create mode 100644 include/clang/Checker/PathSensitive/GRState.h create mode 100644 include/clang/Checker/PathSensitive/GRStateTrait.h create mode 100644 include/clang/Checker/PathSensitive/GRSubEngine.h create mode 100644 include/clang/Checker/PathSensitive/GRTransferFuncs.h create mode 100644 include/clang/Checker/PathSensitive/GRWorkList.h create mode 100644 include/clang/Checker/PathSensitive/MemRegion.h create mode 100644 include/clang/Checker/PathSensitive/SVals.h create mode 100644 include/clang/Checker/PathSensitive/SValuator.h create mode 100644 include/clang/Checker/PathSensitive/Store.h create mode 100644 include/clang/Checker/PathSensitive/SummaryManager.h create mode 100644 include/clang/Checker/PathSensitive/SymbolManager.h create mode 100644 include/clang/Checker/PathSensitive/ValueManager.h (limited to 'include') diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index ef17ed1ca8be..84ec4724e0db 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -36,23 +36,23 @@ extern "C" { /** \defgroup CINDEX C Interface to Clang * - * The C Interface to Clang provides a relatively small API that exposes + * The C Interface to Clang provides a relatively small API that exposes * facilities for parsing source code into an abstract syntax tree (AST), * loading already-parsed ASTs, traversing the AST, associating * physical source locations with elements within the AST, and other * facilities that support Clang-based development tools. * - * This C interface to Clang will never provide all of the information + * This C interface to Clang will never provide all of the information * representation stored in Clang's C++ AST, nor should it: the intent is to * maintain an API that is relatively stable from one release to the next, * providing only the basic functionality needed to support development tools. - * - * To avoid namespace pollution, data types are prefixed with "CX" and + * + * To avoid namespace pollution, data types are prefixed with "CX" and * functions are prefixed with "clang_". * * @{ */ - + /** * \brief An "index" that consists of a set of translation units that would * typically be linked together into an executable or library. @@ -69,7 +69,7 @@ typedef void *CXTranslationUnit; /* A translation unit instance. */ * to various callbacks and visitors. */ typedef void *CXClientData; - + /** * \brief Provides the contents of a file that has not yet been saved to disk. * @@ -78,14 +78,14 @@ typedef void *CXClientData; * yet been saved to disk. */ struct CXUnsavedFile { - /** - * \brief The file whose contents have not yet been saved. + /** + * \brief The file whose contents have not yet been saved. * * This file must already exist in the file system. */ const char *Filename; - /** + /** * \brief A null-terminated buffer containing the unsaved contents * of this file. */ @@ -103,7 +103,7 @@ struct CXUnsavedFile { * * @{ */ - + /** * \brief A character string. * @@ -132,38 +132,36 @@ CINDEX_LINKAGE void clang_disposeString(CXString string); /** * @} */ - -/** + +/** * \brief clang_createIndex() provides a shared context for creating * translation units. It provides two options: * * - excludeDeclarationsFromPCH: When non-zero, allows enumeration of "local" * declarations (when loading any new translation units). A "local" declaration - * is one that belongs in the translation unit itself and not in a precompiled + * is one that belongs in the translation unit itself and not in a precompiled * header that was used by the translation unit. If zero, all declarations * will be enumerated. * - * - displayDiagnostics: when non-zero, diagnostics will be output. If zero, - * diagnostics will be ignored. - * * Here is an example: * - * // excludeDeclsFromPCH = 1, displayDiagnostics = 1 - * Idx = clang_createIndex(1, 1); + * // excludeDeclsFromPCH = 1 + * Idx = clang_createIndex(1); * * // IndexTest.pch was produced with the following command: * // "clang -x c IndexTest.h -emit-ast -o IndexTest.pch" * TU = clang_createTranslationUnit(Idx, "IndexTest.pch"); * * // This will load all the symbols from 'IndexTest.pch' - * clang_visitChildren(clang_getTranslationUnitCursor(TU), + * clang_visitChildren(clang_getTranslationUnitCursor(TU), * TranslationUnitVisitor, 0); * clang_disposeTranslationUnit(TU); * * // This will load all the symbols from 'IndexTest.c', excluding symbols * // from 'IndexTest.pch'. - * char *args[] = { "-Xclang", "-include-pch=IndexTest.pch", 0 }; - * TU = clang_createTranslationUnitFromSourceFile(Idx, "IndexTest.c", 2, args); + * char *args[] = { "-Xclang", "-include-pch=IndexTest.pch" }; + * TU = clang_createTranslationUnitFromSourceFile(Idx, "IndexTest.c", 2, args, + * 0, 0); * clang_visitChildren(clang_getTranslationUnitCursor(TU), * TranslationUnitVisitor, 0); * clang_disposeTranslationUnit(TU); @@ -172,14 +170,18 @@ CINDEX_LINKAGE void clang_disposeString(CXString string); * -include-pch) allows 'excludeDeclsFromPCH' to remove redundant callbacks * (which gives the indexer the same performance benefit as the compiler). */ -CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH, - int displayDiagnostics); +CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH); + +/** + * \brief Destroy the given index. + * + * The index must not be destroyed until all of the translation units created + * within that index have been destroyed. + */ CINDEX_LINKAGE void clang_disposeIndex(CXIndex index); -CINDEX_LINKAGE CXString -clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit); /** - * \brief Request that AST's be generated external for API calls which parse + * \brief Request that AST's be generated externally for API calls which parse * source code on the fly, e.g. \see createTranslationUnitFromSourceFile. * * Note: This is for debugging purposes only, and may be removed at a later @@ -190,71 +192,23 @@ clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit); */ CINDEX_LINKAGE void clang_setUseExternalASTGeneration(CXIndex index, int value); - -/** - * \brief Create a translation unit from an AST file (-emit-ast). - */ -CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit( - CXIndex, const char *ast_filename -); - -/** - * \brief Destroy the specified CXTranslationUnit object. - */ -CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit); - -/** - * \brief Return the CXTranslationUnit for a given source file and the provided - * command line arguments one would pass to the compiler. - * - * Note: The 'source_filename' argument is optional. If the caller provides a - * NULL pointer, the name of the source file is expected to reside in the - * specified command line arguments. - * - * Note: When encountered in 'clang_command_line_args', the following options - * are ignored: - * - * '-c' - * '-emit-ast' - * '-fsyntax-only' - * '-o ' (both '-o' and '' are ignored) - * - * - * \param source_filename - The name of the source file to load, or NULL if the - * source file is included in clang_command_line_args. - * - * \param num_unsaved_files the number of unsaved file entries in \p - * unsaved_files. - * - * \param unsaved_files the files that have not yet been saved to disk - * but may be required for code completion, including the contents of - * those files. - */ -CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile( - CXIndex CIdx, - const char *source_filename, - int num_clang_command_line_args, - const char **clang_command_line_args, - unsigned num_unsaved_files, - struct CXUnsavedFile *unsaved_files); - /** * \defgroup CINDEX_FILES File manipulation routines * * @{ */ - + /** * \brief A particular source file that is part of a translation unit. */ typedef void *CXFile; - + /** * \brief Retrieve the complete file and path name of the given file. */ CINDEX_LINKAGE const char *clang_getFileName(CXFile SFile); - + /** * \brief Retrieve the last modification time of the given file. */ @@ -264,15 +218,15 @@ CINDEX_LINKAGE time_t clang_getFileTime(CXFile SFile); * \brief Retrieve a file handle within the given translation unit. * * \param tu the translation unit - * + * * \param file_name the name of the file. * * \returns the file handle for the named file in the translation unit \p tu, * or a NULL file handle if the file was not a part of this translation unit. */ -CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu, +CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu, const char *file_name); - + /** * @} */ @@ -289,7 +243,7 @@ CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu, * * @{ */ - + /** * \brief Identifies a specific source location within a translation * unit. @@ -298,18 +252,18 @@ CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu, * particular file, line, and column. */ typedef struct { - void *ptr_data; + void *ptr_data[2]; unsigned int_data; } CXSourceLocation; /** - * \brief Identifies a range of source locations in the source code. + * \brief Identifies a half-open character range in the source code. * * Use clang_getRangeStart() and clang_getRangeEnd() to retrieve the * starting and end locations from a source range, respectively. */ typedef struct { - void *ptr_data; + void *ptr_data[2]; unsigned begin_int_data; unsigned end_int_data; } CXSourceRange; @@ -318,10 +272,10 @@ typedef struct { * \brief Retrieve a NULL (invalid) source location. */ CINDEX_LINKAGE CXSourceLocation clang_getNullLocation(); - + /** * \determine Determine whether two source locations, which must refer into - * the same translation unit, refer to exactly the same point in the source + * the same translation unit, refer to exactly the same point in the source * code. * * \returns non-zero if the source locations refer to the same location, zero @@ -329,15 +283,20 @@ CINDEX_LINKAGE CXSourceLocation clang_getNullLocation(); */ CINDEX_LINKAGE unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2); - + /** - * \brief Retrieves the source location associated with a given - * file/line/column in a particular translation unit. + * \brief Retrieves the source location associated with a given file/line/column + * in a particular translation unit. */ CINDEX_LINKAGE CXSourceLocation clang_getLocation(CXTranslationUnit tu, CXFile file, unsigned line, unsigned column); + +/** + * \brief Retrieve a NULL (invalid) source range. + */ +CINDEX_LINKAGE CXSourceRange clang_getNullRange(); /** * \brief Retrieve a source range given the beginning and ending source @@ -345,37 +304,41 @@ CINDEX_LINKAGE CXSourceLocation clang_getLocation(CXTranslationUnit tu, */ CINDEX_LINKAGE CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end); - + /** - * \brief Retrieve the file, line, and column represented by the - * given source location. + * \brief Retrieve the file, line, column, and offset represented by + * the given source location. + * + * \param location the location within a source file that will be decomposed + * into its parts. * - * \param location the location within a source file that will be - * decomposed into its parts. + * \param file [out] if non-NULL, will be set to the file to which the given + * source location points. * - * \param file if non-NULL, will be set to the file to which the given + * \param line [out] if non-NULL, will be set to the line to which the given * source location points. * - * \param line if non-NULL, will be set to the line to which the given + * \param column [out] if non-NULL, will be set to the column to which the given * source location points. * - * \param column if non-NULL, will be set to the column to which the - * given source location points. + * \param offset [out] if non-NULL, will be set to the offset into the + * buffer to which the given source location points. */ CINDEX_LINKAGE void clang_getInstantiationLocation(CXSourceLocation location, CXFile *file, unsigned *line, - unsigned *column); + unsigned *column, + unsigned *offset); /** - * \brief Retrieve a source location representing the first - * character within a source range. + * \brief Retrieve a source location representing the first character within a + * source range. */ CINDEX_LINKAGE CXSourceLocation clang_getRangeStart(CXSourceRange range); /** - * \brief Retrieve a source location representing the last - * character within a source range. + * \brief Retrieve a source location representing the last character within a + * source range. */ CINDEX_LINKAGE CXSourceLocation clang_getRangeEnd(CXSourceRange range); @@ -383,15 +346,290 @@ CINDEX_LINKAGE CXSourceLocation clang_getRangeEnd(CXSourceRange range); * @} */ +/** + * \defgroup CINDEX_DIAG Diagnostic reporting + * + * @{ + */ + +/** + * \brief Describes the severity of a particular diagnostic. + */ +enum CXDiagnosticSeverity { + /** + * \brief A diagnostic that has been suppressed, e.g., by a command-line + * option. + */ + CXDiagnostic_Ignored = 0, + + /** + * \brief This diagnostic is a note that should be attached to the + * previous (non-note) diagnostic. + */ + CXDiagnostic_Note = 1, + + /** + * \brief This diagnostic indicates suspicious code that may not be + * wrong. + */ + CXDiagnostic_Warning = 2, + + /** + * \brief This diagnostic indicates that the code is ill-formed. + */ + CXDiagnostic_Error = 3, + + /** + * \brief This diagnostic indicates that the code is ill-formed such + * that future parser recovery is unlikely to produce useful + * results. + */ + CXDiagnostic_Fatal = 4 +}; + +/** + * \brief Describes the kind of fix-it hint expressed within a + * diagnostic. + */ +enum CXFixItKind { + /** + * \brief A fix-it hint that inserts code at a particular position. + */ + CXFixIt_Insertion = 0, + + /** + * \brief A fix-it hint that removes code within a range. + */ + CXFixIt_Removal = 1, + + /** + * \brief A fix-it hint that replaces the code within a range with another + * string. + */ + CXFixIt_Replacement = 2 +}; + +/** + * \brief A single diagnostic, containing the diagnostic's severity, + * location, text, source ranges, and fix-it hints. + */ +typedef void *CXDiagnostic; + +/** + * \brief Callback function invoked for each diagnostic emitted during + * translation. + * + * \param Diagnostic the diagnostic emitted during translation. This + * diagnostic pointer is only valid during the execution of the + * callback. + * + * \param ClientData the callback client data. + */ +typedef void (*CXDiagnosticCallback)(CXDiagnostic Diagnostic, + CXClientData ClientData); + +/** + * \brief Determine the severity of the given diagnostic. + */ +CINDEX_LINKAGE enum CXDiagnosticSeverity +clang_getDiagnosticSeverity(CXDiagnostic); + +/** + * \brief Retrieve the source location of the given diagnostic. + * + * This location is where Clang would print the caret ('^') when + * displaying the diagnostic on the command line. + */ +CINDEX_LINKAGE CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic); + +/** + * \brief Retrieve the text of the given diagnostic. + */ +CINDEX_LINKAGE CXString clang_getDiagnosticSpelling(CXDiagnostic); + +/** + * \brief Determine the number of source ranges associated with the given + * diagnostic. + */ +CINDEX_LINKAGE unsigned clang_getDiagnosticNumRanges(CXDiagnostic); + +/** + * \brief Retrieve a source range associated with the diagnostic. + * + * A diagnostic's source ranges highlight important elements in the source + * code. On the command line, Clang displays source ranges by + * underlining them with '~' characters. + * + * \param Diagnostic the diagnostic whose range is being extracted. + * + * \param Range the zero-based index specifying which range to + * + * \returns the requested source range. + */ +CINDEX_LINKAGE CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diagnostic, + unsigned Range); + +/** + * \brief Determine the number of fix-it hints associated with the + * given diagnostic. + */ +CINDEX_LINKAGE unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diagnostic); + +/** + * \brief Retrieve the kind of the given fix-it. + * + * \param Diagnostic the diagnostic whose fix-its are being queried. + * + * \param FixIt the zero-based index of the fix-it to query. + */ +CINDEX_LINKAGE enum CXFixItKind +clang_getDiagnosticFixItKind(CXDiagnostic Diagnostic, unsigned FixIt); + +/** + * \brief Retrieve the insertion information for an insertion fix-it. + * + * For a fix-it that describes an insertion into a text buffer, + * retrieve the source location where the text should be inserted and + * the text to be inserted. + * + * \param Diagnostic the diagnostic whose fix-its are being queried. + * + * \param FixIt the zero-based index of the insertion fix-it. + * + * \param Location will be set to the location where text should be + * inserted. + * + * \returns the text string to insert at the given location. + */ +CINDEX_LINKAGE CXString +clang_getDiagnosticFixItInsertion(CXDiagnostic Diagnostic, unsigned FixIt, + CXSourceLocation *Location); + +/** + * \brief Retrieve the removal information for a removal fix-it. + * + * For a fix-it that describes a removal from a text buffer, retrieve + * the source range that should be removed. + * + * \param Diagnostic the diagnostic whose fix-its are being queried. + * + * \param FixIt the zero-based index of the removal fix-it. + * + * \returns a source range describing the text that should be removed + * from the buffer. + */ +CINDEX_LINKAGE CXSourceRange +clang_getDiagnosticFixItRemoval(CXDiagnostic Diagnostic, unsigned FixIt); + +/** + * \brief Retrieve the replacement information for an replacement fix-it. + * + * For a fix-it that describes replacement of text in the text buffer + * with alternative text. + * + * \param Diagnostic the diagnostic whose fix-its are being queried. + * + * \param FixIt the zero-based index of the replacement fix-it. + * + * \param Range will be set to the source range whose text should be + * replaced with the returned text. + * + * \returns the text string to use as replacement text. + */ +CINDEX_LINKAGE CXString +clang_getDiagnosticFixItReplacement(CXDiagnostic Diagnostic, unsigned FixIt, + CXSourceRange *Range); + +/** + * @} + */ + +/** + * \defgroup CINDEX_TRANSLATION_UNIT Translation unit manipulation + * + * The routines in this group provide the ability to create and destroy + * translation units from files, either by parsing the contents of the files or + * by reading in a serialized representation of a translation unit. + * + * @{ + */ + +/** + * \brief Get the original translation unit source file name. + */ +CINDEX_LINKAGE CXString +clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit); + +/** + * \brief Return the CXTranslationUnit for a given source file and the provided + * command line arguments one would pass to the compiler. + * + * Note: The 'source_filename' argument is optional. If the caller provides a + * NULL pointer, the name of the source file is expected to reside in the + * specified command line arguments. + * + * Note: When encountered in 'clang_command_line_args', the following options + * are ignored: + * + * '-c' + * '-emit-ast' + * '-fsyntax-only' + * '-o ' (both '-o' and '' are ignored) + * + * + * \param source_filename - The name of the source file to load, or NULL if the + * source file is included in clang_command_line_args. + * + * \param num_unsaved_files the number of unsaved file entries in \p + * unsaved_files. + * + * \param unsaved_files the files that have not yet been saved to disk + * but may be required for code completion, including the contents of + * those files. + * + * \param diag_callback callback function that will receive any diagnostics + * emitted while processing this source file. If NULL, diagnostics will be + * suppressed. + * + * \param diag_client_data client data that will be passed to the diagnostic + * callback function. + */ +CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile( + CXIndex CIdx, + const char *source_filename, + int num_clang_command_line_args, + const char **clang_command_line_args, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + CXDiagnosticCallback diag_callback, + CXClientData diag_client_data); + +/** + * \brief Create a translation unit from an AST file (-emit-ast). + */ +CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit(CXIndex, + const char *ast_filename, + CXDiagnosticCallback diag_callback, + CXClientData diag_client_data); + +/** + * \brief Destroy the specified CXTranslationUnit object. + */ +CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit); + +/** + * @} + */ + /** * \brief Describes the kind of entity that a cursor refers to. */ enum CXCursorKind { /* Declarations */ CXCursor_FirstDecl = 1, - /** + /** * \brief A declaration whose specific kind is not exposed via this - * interface. + * interface. * * Unexposed declarations have the same operations as any other kind * of declaration; one can extract their location information, @@ -400,14 +638,14 @@ enum CXCursorKind { */ CXCursor_UnexposedDecl = 1, /** \brief A C or C++ struct. */ - CXCursor_StructDecl = 2, + CXCursor_StructDecl = 2, /** \brief A C or C++ union. */ CXCursor_UnionDecl = 3, /** \brief A C++ class. */ CXCursor_ClassDecl = 4, /** \brief An enumeration. */ CXCursor_EnumDecl = 5, - /** + /** * \brief A field (in C) or non-static data member (in C++) in a * struct, union, or C++ class. */ @@ -441,10 +679,10 @@ enum CXCursorKind { /** \brief A typedef */ CXCursor_TypedefDecl = 20, CXCursor_LastDecl = 20, - + /* References */ CXCursor_FirstRef = 40, /* Decl references */ - CXCursor_ObjCSuperClassRef = 40, + CXCursor_ObjCSuperClassRef = 40, CXCursor_ObjCProtocolRef = 41, CXCursor_ObjCClassRef = 42, /** @@ -464,20 +702,20 @@ enum CXCursorKind { */ CXCursor_TypeRef = 43, CXCursor_LastRef = 43, - + /* Error conditions */ CXCursor_FirstInvalid = 70, CXCursor_InvalidFile = 70, CXCursor_NoDeclFound = 71, CXCursor_NotImplemented = 72, CXCursor_LastInvalid = 72, - + /* Expressions */ CXCursor_FirstExpr = 100, - + /** * \brief An expression whose specific kind is not exposed via this - * interface. + * interface. * * Unexposed expressions have the same operations as any other kind * of expression; one can extract their location information, @@ -485,27 +723,27 @@ enum CXCursorKind { * expression is not reported. */ CXCursor_UnexposedExpr = 100, - + /** * \brief An expression that refers to some value declaration, such * as a function, varible, or enumerator. */ CXCursor_DeclRefExpr = 101, - + /** * \brief An expression that refers to a member of a struct, union, * class, Objective-C class, etc. */ CXCursor_MemberRefExpr = 102, - + /** \brief An expression that calls a function. */ CXCursor_CallExpr = 103, - + /** \brief An expression that sends a message to an Objective-C object or class. */ CXCursor_ObjCMessageExpr = 104, CXCursor_LastExpr = 104, - + /* Statements */ CXCursor_FirstStmt = 200, /** @@ -519,7 +757,7 @@ enum CXCursorKind { */ CXCursor_UnexposedStmt = 200, CXCursor_LastStmt = 200, - + /** * \brief Cursor that represents the translation unit itself. * @@ -533,7 +771,7 @@ enum CXCursorKind { * \brief A cursor representing some element in the abstract syntax tree for * a translation unit. * - * The cursor abstraction unifies the different kinds of entities in a + * The cursor abstraction unifies the different kinds of entities in a * program--declaration, statements, expressions, references to declarations, * etc.--under a single "cursor" abstraction with a common set of operations. * Common operation for a cursor include: getting the physical location in @@ -550,19 +788,19 @@ enum CXCursorKind { typedef struct { enum CXCursorKind kind; void *data[3]; -} CXCursor; +} CXCursor; /** * \defgroup CINDEX_CURSOR_MANIP Cursor manipulations * * @{ */ - + /** * \brief Retrieve the NULL cursor, which represents no entity. */ CINDEX_LINKAGE CXCursor clang_getNullCursor(void); - + /** * \brief Retrieve the cursor that represents the given translation unit. * @@ -575,7 +813,7 @@ CINDEX_LINKAGE CXCursor clang_getTranslationUnitCursor(CXTranslationUnit); * \brief Determine whether two cursors are equivalent. */ CINDEX_LINKAGE unsigned clang_equalCursors(CXCursor, CXCursor); - + /** * \brief Retrieve the kind of the given cursor. */ @@ -607,21 +845,21 @@ CINDEX_LINKAGE unsigned clang_isExpression(enum CXCursorKind); CINDEX_LINKAGE unsigned clang_isStatement(enum CXCursorKind); /** - * \brief Determine whether the given cursor kind represents an invalid + * \brief Determine whether the given cursor kind represents an invalid * cursor. - */ + */ CINDEX_LINKAGE unsigned clang_isInvalid(enum CXCursorKind); /** - * \brief Determine whether the given cursor kind represents a translation - * unit. + * \brief Determine whether the given cursor kind represents a translation + * unit. */ CINDEX_LINKAGE unsigned clang_isTranslationUnit(enum CXCursorKind); - + /** * @} */ - + /** * \defgroup CINDEX_CURSOR_SOURCE Mapping between cursors and source code * @@ -632,16 +870,16 @@ CINDEX_LINKAGE unsigned clang_isTranslationUnit(enum CXCursorKind); * * @{ */ - + /** * \brief Map a source location to the cursor that describes the entity at that * location in the source code. * * clang_getCursor() maps an arbitrary source location within a translation * unit down to the most specific cursor that describes the entity at that - * location. For example, given an expression \c x + y, invoking + * location. For example, given an expression \c x + y, invoking * clang_getCursor() with a source location pointing to "x" will return the - * cursor for "x"; similarly for "y". If the cursor points anywhere between + * cursor for "x"; similarly for "y". If the cursor points anywhere between * "x" or "y" (e.g., on the + or the whitespace around it), clang_getCursor() * will return a cursor referring to the "+" expression. * @@ -649,15 +887,15 @@ CINDEX_LINKAGE unsigned clang_isTranslationUnit(enum CXCursorKind); * a NULL cursor if no such entity can be found. */ CINDEX_LINKAGE CXCursor clang_getCursor(CXTranslationUnit, CXSourceLocation); - + /** * \brief Retrieve the physical location of the source constructor referenced * by the given cursor. * * The location of a declaration is typically the location of the name of that - * declaration, where the name of that declaration would occur if it is - * unnamed, or some keyword that introduces that particular declaration. - * The location of a reference is where that reference occurs within the + * declaration, where the name of that declaration would occur if it is + * unnamed, or some keyword that introduces that particular declaration. + * The location of a reference is where that reference occurs within the * source code. */ CINDEX_LINKAGE CXSourceLocation clang_getCursorLocation(CXCursor); @@ -668,7 +906,7 @@ CINDEX_LINKAGE CXSourceLocation clang_getCursorLocation(CXCursor); * * The extent of a cursor starts with the file/line/column pointing at the * first character within the source construct that the cursor refers to and - * ends with the last character withinin that source construct. For a + * ends with the last character withinin that source construct. For a * declaration, the extent covers the declaration itself. For a reference, * the extent covers the location of the reference (e.g., where the referenced * entity was actually used). @@ -678,7 +916,7 @@ CINDEX_LINKAGE CXSourceRange clang_getCursorExtent(CXCursor); /** * @} */ - + /** * \defgroup CINDEX_CURSOR_TRAVERSAL Traversing the AST with cursors * @@ -687,7 +925,7 @@ CINDEX_LINKAGE CXSourceRange clang_getCursorExtent(CXCursor); * * @{ */ - + /** * \brief Describes how the traversal of the children of a particular * cursor should proceed after visiting a particular child cursor. @@ -697,10 +935,10 @@ CINDEX_LINKAGE CXSourceRange clang_getCursorExtent(CXCursor); */ enum CXChildVisitResult { /** - * \brief Terminates the cursor traversal. + * \brief Terminates the cursor traversal. */ CXChildVisit_Break, - /** + /** * \brief Continues the cursor traversal with the next sibling of * the cursor just visited, without visiting its children. */ @@ -724,8 +962,8 @@ enum CXChildVisitResult { * The visitor should return one of the \c CXChildVisitResult values * to direct clang_visitCursorChildren(). */ -typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor, - CXCursor parent, +typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor, + CXCursor parent, CXClientData client_data); /** @@ -737,10 +975,8 @@ typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor, * \c CXChildVisit_Recurse. The traversal may also be ended prematurely, if * the visitor returns \c CXChildVisit_Break. * - * \param tu the translation unit into which the cursor refers. - * * \param parent the cursor whose child may be visited. All kinds of - * cursors can be visited, including invalid visitors (which, by + * cursors can be visited, including invalid cursors (which, by * definition, have no children). * * \param visitor the visitor function that will be invoked for each @@ -752,25 +988,25 @@ typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor, * \returns a non-zero value if the traversal was terminated * prematurely by the visitor returning \c CXChildVisit_Break. */ -CINDEX_LINKAGE unsigned clang_visitChildren(CXCursor parent, +CINDEX_LINKAGE unsigned clang_visitChildren(CXCursor parent, CXCursorVisitor visitor, CXClientData client_data); - + /** * @} */ - + /** * \defgroup CINDEX_CURSOR_XREF Cross-referencing in the AST * - * These routines provide the ability to determine references within and + * These routines provide the ability to determine references within and * across translation units, by providing the names of the entities referenced * by cursors, follow reference cursors to the declarations they reference, * and associate declarations with their definitions. * * @{ */ - + /** * \brief Retrieve a Unified Symbol Resolution (USR) for the entity referenced * by the given cursor. @@ -792,14 +1028,14 @@ CINDEX_LINKAGE CXString clang_getCursorSpelling(CXCursor); * * Reference cursors refer to other entities in the AST. For example, an * Objective-C superclass reference cursor refers to an Objective-C class. - * This function produces the cursor for the Objective-C class from the + * This function produces the cursor for the Objective-C class from the * cursor for the superclass reference. If the input cursor is a declaration or * definition, it returns that declaration or definition unchanged. - * Othewise, returns the NULL cursor. + * Otherwise, returns the NULL cursor. */ CINDEX_LINKAGE CXCursor clang_getCursorReferenced(CXCursor); -/** +/** * \brief For a cursor that is either a reference to or a declaration * of some entity, retrieve a cursor that describes the definition of * that entity. @@ -829,12 +1065,148 @@ CINDEX_LINKAGE CXCursor clang_getCursorReferenced(CXCursor); */ CINDEX_LINKAGE CXCursor clang_getCursorDefinition(CXCursor); -/** +/** * \brief Determine whether the declaration pointed to by this cursor * is also a definition of that entity. */ CINDEX_LINKAGE unsigned clang_isCursorDefinition(CXCursor); +/** + * @} + */ + +/** + * \defgroup CINDEX_LEX Token extraction and manipulation + * + * The routines in this group provide access to the tokens within a + * translation unit, along with a semantic mapping of those tokens to + * their corresponding cursors. + * + * @{ + */ + +/** + * \brief Describes a kind of token. + */ +typedef enum CXTokenKind { + /** + * \brief A token that contains some kind of punctuation. + */ + CXToken_Punctuation, + + /** + * \brief A language keyword. + */ + CXToken_Keyword, + + /** + * \brief An identifier (that is not a keyword). + */ + CXToken_Identifier, + + /** + * \brief A numeric, string, or character literal. + */ + CXToken_Literal, + + /** + * \brief A comment. + */ + CXToken_Comment +} CXTokenKind; + +/** + * \brief Describes a single preprocessing token. + */ +typedef struct { + unsigned int_data[4]; + void *ptr_data; +} CXToken; + +/** + * \brief Determine the kind of the given token. + */ +CINDEX_LINKAGE CXTokenKind clang_getTokenKind(CXToken); + +/** + * \brief Determine the spelling of the given token. + * + * The spelling of a token is the textual representation of that token, e.g., + * the text of an identifier or keyword. + */ +CINDEX_LINKAGE CXString clang_getTokenSpelling(CXTranslationUnit, CXToken); + +/** + * \brief Retrieve the source location of the given token. + */ +CINDEX_LINKAGE CXSourceLocation clang_getTokenLocation(CXTranslationUnit, + CXToken); + +/** + * \brief Retrieve a source range that covers the given token. + */ +CINDEX_LINKAGE CXSourceRange clang_getTokenExtent(CXTranslationUnit, CXToken); + +/** + * \brief Tokenize the source code described by the given range into raw + * lexical tokens. + * + * \param TU the translation unit whose text is being tokenized. + * + * \param Range the source range in which text should be tokenized. All of the + * tokens produced by tokenization will fall within this source range, + * + * \param Tokens this pointer will be set to point to the array of tokens + * that occur within the given source range. The returned pointer must be + * freed with clang_disposeTokens() before the translation unit is destroyed. + * + * \param NumTokens will be set to the number of tokens in the \c *Tokens + * array. + * + */ +CINDEX_LINKAGE void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, + CXToken **Tokens, unsigned *NumTokens); + +/** + * \brief Annotate the given set of tokens by providing cursors for each token + * that can be mapped to a specific entity within the abstract syntax tree. + * + * This token-annotation routine is equivalent to invoking + * clang_getCursor() for the source locations of each of the + * tokens. The cursors provided are filtered, so that only those + * cursors that have a direct correspondence to the token are + * accepted. For example, given a function call \c f(x), + * clang_getCursor() would provide the following cursors: + * + * * when the cursor is over the 'f', a DeclRefExpr cursor referring to 'f'. + * * when the cursor is over the '(' or the ')', a CallExpr referring to 'f'. + * * when the cursor is over the 'x', a DeclRefExpr cursor referring to 'x'. + * + * Only the first and last of these cursors will occur within the + * annotate, since the tokens "f" and "x' directly refer to a function + * and a variable, respectively, but the parentheses are just a small + * part of the full syntax of the function call expression, which is + * not provided as an annotation. + * + * \param TU the translation unit that owns the given tokens. + * + * \param Tokens the set of tokens to annotate. + * + * \param NumTokens the number of tokens in \p Tokens. + * + * \param Cursors an array of \p NumTokens cursors, whose contents will be + * replaced with the cursors corresponding to each token. + */ +CINDEX_LINKAGE void clang_annotateTokens(CXTranslationUnit TU, + CXToken *Tokens, unsigned NumTokens, + CXCursor *Cursors); + +/** + * \brief Free the given set of tokens. + */ +CINDEX_LINKAGE void clang_disposeTokens(CXTranslationUnit TU, + CXToken *Tokens, unsigned NumTokens); + /** * @} */ @@ -847,11 +1219,11 @@ CINDEX_LINKAGE unsigned clang_isCursorDefinition(CXCursor); * * @{ */ - + /* for debug/testing */ -CINDEX_LINKAGE const char *clang_getCursorKindSpelling(enum CXCursorKind Kind); -CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor, - const char **startBuf, +CINDEX_LINKAGE const char *clang_getCursorKindSpelling(enum CXCursorKind Kind); +CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor, + const char **startBuf, const char **endBuf, unsigned *startLine, unsigned *startColumn, @@ -861,7 +1233,7 @@ CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor, /** * @} */ - + /** * \defgroup CINDEX_CODE_COMPLET Code completion * @@ -873,7 +1245,7 @@ CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor, * * @{ */ - + /** * \brief A semantic string that describes a code-completion result. * @@ -885,18 +1257,18 @@ CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor, * the name of the entity being referenced, whether the text chunk is part of * the template, or whether it is a "placeholder" that the user should replace * with actual code,of a specific kind. See \c CXCompletionChunkKind for a - * description of the different kinds of chunks. + * description of the different kinds of chunks. */ typedef void *CXCompletionString; - + /** * \brief A single result of code completion. */ typedef struct { /** - * \brief The kind of entity that this completion refers to. + * \brief The kind of entity that this completion refers to. * - * The cursor kind will be a macro, keyword, or a declaration (one of the + * The cursor kind will be a macro, keyword, or a declaration (one of the * *Decl cursor kinds), describing the entity that the completion is * referring to. * @@ -904,8 +1276,8 @@ typedef struct { * the client to extract additional information from declaration. */ enum CXCursorKind CursorKind; - - /** + + /** * \brief The code-completion string that describes how to insert this * code-completion result into the editing buffer. */ @@ -915,8 +1287,8 @@ typedef struct { /** * \brief Describes a single piece of text within a code-completion string. * - * Each "chunk" within a code-completion string (\c CXCompletionString) is - * either a piece of text with a specific "kind" that describes how that text + * Each "chunk" within a code-completion string (\c CXCompletionString) is + * either a piece of text with a specific "kind" that describes how that text * should be interpreted by the client or is another completion string. */ enum CXCompletionChunkKind { @@ -925,7 +1297,7 @@ enum CXCompletionChunkKind { * could be a part of the template (but is not required). * * The Optional chunk is the only kind of chunk that has a code-completion - * string for its representation, which is accessible via + * string for its representation, which is accessible via * \c clang_getCompletionChunkCompletionString(). The code-completion string * describes an additional part of the template that is completely optional. * For example, optional chunks can be used to describe the placeholders for @@ -956,10 +1328,10 @@ enum CXCompletionChunkKind { CXCompletionChunk_Optional, /** * \brief Text that a user would be expected to type to get this - * code-completion result. + * code-completion result. * - * There will be exactly one "typed text" chunk in a semantic string, which - * will typically provide the spelling of a keyword or the name of a + * There will be exactly one "typed text" chunk in a semantic string, which + * will typically provide the spelling of a keyword or the name of a * declaration that could be used at the current code point. Clients are * expected to filter the code-completion results based on the text in this * chunk. @@ -987,7 +1359,7 @@ enum CXCompletionChunkKind { /** * \brief Informative text that should be displayed but never inserted as * part of the template. - * + * * An "informative" chunk contains annotations that can be displayed to * help the user decide whether a particular code-completion result is the * right option, but which is not part of the actual template to be inserted @@ -1010,7 +1382,7 @@ enum CXCompletionChunkKind { * "(", the code-completion string will contain a "current parameter" chunk * for "int x", indicating that the current argument will initialize that * parameter. After typing further, to \c add(17, (where the code-completion - * point is after the ","), the code-completion string will contain a + * point is after the ","), the code-completion string will contain a * "current paremeter" chunk to "int y". */ CXCompletionChunk_CurrentParameter, @@ -1053,10 +1425,10 @@ enum CXCompletionChunkKind { */ CXCompletionChunk_Comma, /** - * \brief Text that specifies the result type of a given result. + * \brief Text that specifies the result type of a given result. * * This special kind of informative chunk is not meant to be inserted into - * the text buffer. Rather, it is meant to illustrate the type that an + * the text buffer. Rather, it is meant to illustrate the type that an * expression using the given completion string would have. */ CXCompletionChunk_ResultType, @@ -1082,7 +1454,7 @@ enum CXCompletionChunkKind { */ CXCompletionChunk_VerticalSpace }; - + /** * \brief Determine the kind of a particular chunk within a completion string. * @@ -1092,12 +1464,12 @@ enum CXCompletionChunkKind { * * \returns the kind of the chunk at the index \c chunk_number. */ -CINDEX_LINKAGE enum CXCompletionChunkKind +CINDEX_LINKAGE enum CXCompletionChunkKind clang_getCompletionChunkKind(CXCompletionString completion_string, unsigned chunk_number); - + /** - * \brief Retrieve the text associated with a particular chunk within a + * \brief Retrieve the text associated with a particular chunk within a * completion string. * * \param completion_string the completion string to query. @@ -1111,7 +1483,7 @@ clang_getCompletionChunkText(CXCompletionString completion_string, unsigned chunk_number); /** - * \brief Retrieve the completion string associated with a particular chunk + * \brief Retrieve the completion string associated with a particular chunk * within a completion string. * * \param completion_string the completion string to query. @@ -1125,7 +1497,7 @@ clang_getCompletionChunkText(CXCompletionString completion_string, CINDEX_LINKAGE CXCompletionString clang_getCompletionChunkCompletionString(CXCompletionString completion_string, unsigned chunk_number); - + /** * \brief Retrieve the number of chunks in the given code-completion string. */ @@ -1136,7 +1508,7 @@ clang_getNumCompletionChunks(CXCompletionString completion_string); * \brief Contains the results of code-completion. * * This data structure contains the results of code completion, as - * produced by \c clang_codeComplete. Its contents must be freed by + * produced by \c clang_codeComplete. Its contents must be freed by * \c clang_disposeCodeCompleteResults. */ typedef struct { @@ -1162,12 +1534,12 @@ typedef struct { * performing syntax checking up to the location where code-completion has * been requested. At that point, a special code-completion token is passed * to the parser, which recognizes this token and determines, based on the - * current location in the C/Objective-C/C++ grammar and the state of + * current location in the C/Objective-C/C++ grammar and the state of * semantic analysis, what completions to provide. These completions are * returned via a new \c CXCodeCompleteResults structure. * * Code completion itself is meant to be triggered by the client when the - * user types punctuation characters or whitespace, at which point the + * user types punctuation characters or whitespace, at which point the * code-completion location will coincide with the cursor. For example, if \c p * is a pointer, code-completion might be triggered after the "-" and then * after the ">" in \c p->. When the code-completion location is afer the ">", @@ -1196,9 +1568,9 @@ typedef struct { * \p command_line_args. * * \param command_line_args the command-line arguments to pass to the Clang - * compiler to build the given source file. This should include all of the + * compiler to build the given source file. This should include all of the * necessary include paths, language-dialect switches, precompiled header - * includes, etc., but should not include any information specific to + * includes, etc., but should not include any information specific to * code completion. * * \param num_unsaved_files the number of unsaved file entries in \p @@ -1210,59 +1582,104 @@ typedef struct { * * \param complete_filename the name of the source file where code completion * should be performed. In many cases, this name will be the same as the - * source filename. However, the completion filename may also be a file - * included by the source file, which is required when producing + * source filename. However, the completion filename may also be a file + * included by the source file, which is required when producing * code-completion results for a header. * * \param complete_line the line at which code-completion should occur. * - * \param complete_column the column at which code-completion should occur. + * \param complete_column the column at which code-completion should occur. * Note that the column should point just after the syntactic construct that * initiated code completion, and not in the middle of a lexical token. * + * \param diag_callback callback function that will receive any diagnostics + * emitted while processing this source file. If NULL, diagnostics will be + * suppressed. + * + * \param diag_client_data client data that will be passed to the diagnostic + * callback function. + * * \returns if successful, a new CXCodeCompleteResults structure * containing code-completion results, which should eventually be * freed with \c clang_disposeCodeCompleteResults(). If code * completion fails, returns NULL. */ -CINDEX_LINKAGE -CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, +CINDEX_LINKAGE +CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, const char *source_filename, - int num_command_line_args, + int num_command_line_args, const char **command_line_args, unsigned num_unsaved_files, struct CXUnsavedFile *unsaved_files, const char *complete_filename, unsigned complete_line, - unsigned complete_column); - + unsigned complete_column, + CXDiagnosticCallback diag_callback, + CXClientData diag_client_data); + /** * \brief Free the given set of code-completion results. */ -CINDEX_LINKAGE +CINDEX_LINKAGE void clang_disposeCodeCompleteResults(CXCodeCompleteResults *Results); - + /** * @} */ - - + + /** * \defgroup CINDEX_MISC Miscellaneous utility functions * * @{ */ - -CINDEX_LINKAGE const char *clang_getClangVersion(); + +/** + * \brief Return a version string, suitable for showing to a user, but not + * intended to be parsed (the format is not guaranteed to be stable). + */ +CINDEX_LINKAGE CXString clang_getClangVersion(); + +/** + * \brief Return a version string, suitable for showing to a user, but not + * intended to be parsed (the format is not guaranteed to be stable). + */ + + + /** + * \brief Visitor invoked for each file in a translation unit + * (used with clang_getInclusions()). + * + * This visitor function will be invoked by clang_getInclusions() for each + * file included (either at the top-level or by #include directives) within + * a translation unit. The first argument is the file being included, and + * the second and third arguments provide the inclusion stack. The + * array is sorted in order of immediate inclusion. For example, + * the first element refers to the location that included 'included_file'. + */ +typedef void (*CXInclusionVisitor)(CXFile included_file, + CXSourceLocation* inclusion_stack, + unsigned include_len, + CXClientData client_data); + +/** + * \brief Visit the set of preprocessor inclusions in a translation unit. + * The visitor function is called with the provided data for every included + * file. This does not include headers included by the PCH file (unless one + * is inspecting the inclusions in the PCH file itself). + */ +CINDEX_LINKAGE void clang_getInclusions(CXTranslationUnit tu, + CXInclusionVisitor visitor, + CXClientData client_data); /** * @} */ - + /** * @} */ - + #ifdef __cplusplus } #endif diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index e5429bec143c..2ed9fd708018 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -27,6 +27,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/Allocator.h" #include @@ -46,6 +47,7 @@ namespace clang { class SourceManager; class TargetInfo; // Decls + class DeclContext; class CXXMethodDecl; class CXXRecordDecl; class Decl; @@ -502,7 +504,8 @@ public: /// getVectorType - Return the unique reference to a vector type of /// the specified element type and size. VectorType must be a built-in type. - QualType getVectorType(QualType VectorType, unsigned NumElts); + QualType getVectorType(QualType VectorType, unsigned NumElts, + bool AltiVec, bool IsPixel); /// getExtVectorType - Return the unique reference to an extended vector type /// of the specified element type and size. VectorType must be a built-in @@ -534,11 +537,11 @@ public: /// getTypeDeclType - Return the unique reference to the type for /// the specified type declaration. - QualType getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl=0); + QualType getTypeDeclType(const TypeDecl *Decl, const TypeDecl* PrevDecl=0); /// getTypedefType - Return the unique reference to the type for the /// specified typename decl. - QualType getTypedefType(TypedefDecl *Decl); + QualType getTypedefType(const TypedefDecl *Decl); QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced, QualType Replacement); @@ -835,13 +838,23 @@ public: return getTypeInfo(T).second; } + /// getTypeAlignInChars - Return the ABI-specified alignment of a type, in + /// characters. This method does not work on incomplete types. + CharUnits getTypeAlignInChars(QualType T); + CharUnits getTypeAlignInChars(const Type *T); + /// getPreferredTypeAlign - Return the "preferred" alignment of the specified /// type for the current target in bits. This can be different than the ABI /// alignment in cases where it is beneficial for performance to overalign /// a data type. unsigned getPreferredTypeAlign(const Type *T); - unsigned getDeclAlignInBytes(const Decl *D, bool RefAsPointee = false); + /// getDeclAlign - Return a conservative estimate of the alignment of + /// the specified decl. Note that bitfields do not have a valid alignment, so + /// this method will assert on them. + /// If @p RefAsPointee, references are treated like their underlying type + /// (for alignof), else they're treated like pointers (for CodeGen). + CharUnits getDeclAlign(const Decl *D, bool RefAsPointee = false); /// getASTRecordLayout - Get or compute information about the layout of the /// specified record (struct/union/class), which indicates its size and field @@ -878,7 +891,7 @@ public: unsigned CountSynthesizedIvars(const ObjCInterfaceDecl *OI); unsigned CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD); void CollectInheritedProtocols(const Decl *CDecl, - llvm::SmallVectorImpl &Protocols); + llvm::SmallPtrSet &Protocols); //===--------------------------------------------------------------------===// // Type Operators @@ -960,6 +973,20 @@ public: NestedNameSpecifier * getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS); + /// \brief Retrieves the canonical representation of the given + /// calling convention. + CallingConv getCanonicalCallConv(CallingConv CC) { + if (CC == CC_C) + return CC_Default; + return CC; + } + + /// \brief Determines whether two calling conventions name the same + /// calling convention. + bool isSameCallConv(CallingConv lcc, CallingConv rcc) { + return (getCanonicalCallConv(lcc) == getCanonicalCallConv(rcc)); + } + /// \brief Retrieves the "canonical" template name that refers to a /// given template. /// @@ -1187,6 +1214,15 @@ private: const ASTRecordLayout &getObjCLayout(const ObjCInterfaceDecl *D, const ObjCImplementationDecl *Impl); + +private: + // FIXME: This currently contains the set of StoredDeclMaps used + // by DeclContext objects. This probably should not be in ASTContext, + // but we include it here so that ASTContext can quickly deallocate them. + std::vector SDMs; + friend class DeclContext; + void *CreateStoredDeclsMap(); + void ReleaseDeclContextMaps(); }; /// @brief Utility function for constructing a nullary selector. diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h index abd36f7e5f0f..2d314913469e 100644 --- a/include/clang/AST/ASTDiagnostic.h +++ b/include/clang/AST/ASTDiagnostic.h @@ -1,4 +1,4 @@ -//===--- DiagnosticAST.h - Diagnostics for the AST library ------*- C++ -*-===// +//===--- ASTDiagnostic.h - Diagnostics for the AST library ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -22,6 +22,26 @@ namespace clang { NUM_BUILTIN_AST_DIAGNOSTICS }; } // end namespace diag + + /// \brief Diagnostic argument formatting function for diagnostics that + /// involve AST nodes. + /// + /// This function formats diagnostic arguments for various AST nodes, + /// including types, declaration names, nested name specifiers, and + /// declaration contexts, into strings that can be printed as part of + /// diagnostics. It is meant to be used as the argument to + /// \c Diagnostic::SetArgToStringFn(), where the cookie is an \c ASTContext + /// pointer. + void FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind, + intptr_t Val, + const char *Modifier, + unsigned ModLen, + const char *Argument, + unsigned ArgLen, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs, + llvm::SmallVectorImpl &Output, + void *Cookie); } // end namespace clang #endif diff --git a/include/clang/AST/ASTImporter.h b/include/clang/AST/ASTImporter.h new file mode 100644 index 000000000000..f5f11ca83662 --- /dev/null +++ b/include/clang/AST/ASTImporter.h @@ -0,0 +1,234 @@ +//===--- ASTImporter.h - Importing ASTs from other Contexts -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTImporter class which imports AST nodes from one +// context into another context. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_ASTIMPORTER_H +#define LLVM_CLANG_AST_ASTIMPORTER_H + +#include "clang/AST/Type.h" +#include "clang/AST/DeclarationName.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class ASTContext; + class Decl; + class DeclContext; + class Diagnostic; + class Expr; + class FileManager; + class IdentifierInfo; + class NestedNameSpecifier; + class Stmt; + class TypeSourceInfo; + + /// \brief Imports selected nodes from one AST context into another context, + /// merging AST nodes where appropriate. + class ASTImporter { + public: + typedef llvm::DenseSet > NonEquivalentDeclSet; + + private: + /// \brief The contexts we're importing to and from. + ASTContext &ToContext, &FromContext; + + /// \brief The file managers we're importing to and from. + FileManager &ToFileManager, &FromFileManager; + + /// \brief The diagnostics object that we should use to emit diagnostics. + Diagnostic &Diags; + + /// \brief Mapping from the already-imported types in the "from" context + /// to the corresponding types in the "to" context. + llvm::DenseMap ImportedTypes; + + /// \brief Mapping from the already-imported declarations in the "from" + /// context to the corresponding declarations in the "to" context. + llvm::DenseMap ImportedDecls; + + /// \brief Mapping from the already-imported statements in the "from" + /// context to the corresponding statements in the "to" context. + llvm::DenseMap ImportedStmts; + + /// \brief Mapping from the already-imported FileIDs in the "from" source + /// manager to the corresponding FileIDs in the "to" source manager. + llvm::DenseMap ImportedFileIDs; + + /// \brief Imported, anonymous tag declarations that are missing their + /// corresponding typedefs. + llvm::SmallVector AnonTagsWithPendingTypedefs; + + /// \brief Declaration (from, to) pairs that are known not to be equivalent + /// (which we have already complained about). + NonEquivalentDeclSet NonEquivalentDecls; + + public: + ASTImporter(Diagnostic &Diags, + ASTContext &ToContext, FileManager &ToFileManager, + ASTContext &FromContext, FileManager &FromFileManager); + + virtual ~ASTImporter(); + + /// \brief Import the given type from the "from" context into the "to" + /// context. + /// + /// \returns the equivalent type in the "to" context, or a NULL type if + /// an error occurred. + QualType Import(QualType FromT); + + /// \brief Import the given type source information from the + /// "from" context into the "to" context. + /// + /// \returns the equivalent type source information in the "to" + /// context, or NULL if an error occurred. + TypeSourceInfo *Import(TypeSourceInfo *FromTSI); + + /// \brief Import the given declaration from the "from" context into the + /// "to" context. + /// + /// \returns the equivalent declaration in the "to" context, or a NULL type + /// if an error occurred. + Decl *Import(Decl *FromD); + + /// \brief Import the given declaration context from the "from" + /// AST context into the "to" AST context. + /// + /// \returns the equivalent declaration context in the "to" + /// context, or a NULL type if an error occurred. + DeclContext *ImportContext(DeclContext *FromDC); + + /// \brief Import the given expression from the "from" context into the + /// "to" context. + /// + /// \returns the equivalent expression in the "to" context, or NULL if + /// an error occurred. + Expr *Import(Expr *FromE); + + /// \brief Import the given statement from the "from" context into the + /// "to" context. + /// + /// \returns the equivalent statement in the "to" context, or NULL if + /// an error occurred. + Stmt *Import(Stmt *FromS); + + /// \brief Import the given nested-name-specifier from the "from" + /// context into the "to" context. + /// + /// \returns the equivalent nested-name-specifier in the "to" + /// context, or NULL if an error occurred. + NestedNameSpecifier *Import(NestedNameSpecifier *FromNNS); + + /// \brief Import the given source location from the "from" context into + /// the "to" context. + /// + /// \returns the equivalent source location in the "to" context, or an + /// invalid source location if an error occurred. + SourceLocation Import(SourceLocation FromLoc); + + /// \brief Import the given source range from the "from" context into + /// the "to" context. + /// + /// \returns the equivalent source range in the "to" context, or an + /// invalid source location if an error occurred. + SourceRange Import(SourceRange FromRange); + + /// \brief Import the given declaration name from the "from" + /// context into the "to" context. + /// + /// \returns the equivalent declaration name in the "to" context, + /// or an empty declaration name if an error occurred. + DeclarationName Import(DeclarationName FromName); + + /// \brief Import the given identifier from the "from" context + /// into the "to" context. + /// + /// \returns the equivalent identifier in the "to" context. + IdentifierInfo *Import(IdentifierInfo *FromId); + + /// \brief Import the given file ID from the "from" context into the + /// "to" context. + /// + /// \returns the equivalent file ID in the source manager of the "to" + /// context. + FileID Import(FileID); + + /// \brief Cope with a name conflict when importing a declaration into the + /// given context. + /// + /// This routine is invoked whenever there is a name conflict while + /// importing a declaration. The returned name will become the name of the + /// imported declaration. By default, the returned name is the same as the + /// original name, leaving the conflict unresolve such that name lookup + /// for this name is likely to find an ambiguity later. + /// + /// Subclasses may override this routine to resolve the conflict, e.g., by + /// renaming the declaration being imported. + /// + /// \param Name the name of the declaration being imported, which conflicts + /// with other declarations. + /// + /// \param DC the declaration context (in the "to" AST context) in which + /// the name is being imported. + /// + /// \param IDNS the identifier namespace in which the name will be found. + /// + /// \param Decls the set of declarations with the same name as the + /// declaration being imported. + /// + /// \param NumDecls the number of conflicting declarations in \p Decls. + /// + /// \returns the name that the newly-imported declaration should have. + virtual DeclarationName HandleNameConflict(DeclarationName Name, + DeclContext *DC, + unsigned IDNS, + NamedDecl **Decls, + unsigned NumDecls); + + /// \brief Retrieve the context that AST nodes are being imported into. + ASTContext &getToContext() const { return ToContext; } + + /// \brief Retrieve the context that AST nodes are being imported from. + ASTContext &getFromContext() const { return FromContext; } + + /// \brief Retrieve the file manager that AST nodes are being imported into. + FileManager &getToFileManager() const { return ToFileManager; } + + /// \brief Retrieve the file manager that AST nodes are being imported from. + FileManager &getFromFileManager() const { return FromFileManager; } + + /// \brief Retrieve the diagnostic formatter. + Diagnostic &getDiags() const { return Diags; } + + /// \brief Report a diagnostic in the "to" context. + DiagnosticBuilder ToDiag(SourceLocation Loc, unsigned DiagID); + + /// \brief Report a diagnostic in the "from" context. + DiagnosticBuilder FromDiag(SourceLocation Loc, unsigned DiagID); + + /// \brief Return the set of declarations that we know are not equivalent. + NonEquivalentDeclSet &getNonEquivalentDecls() { return NonEquivalentDecls; } + + /// \brief Note that we have imported the "from" declaration by mapping it + /// to the (potentially-newly-created) "to" declaration. + /// + /// \returns \p To + Decl *Imported(Decl *From, Decl *To); + + /// \brief Determine whether the given types are structurally + /// equivalent. + bool IsStructurallyEquivalent(QualType From, QualType To); + }; +} + +#endif // LLVM_CLANG_AST_ASTIMPORTER_H diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 03ab0f07020b..37225907c6de 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -18,7 +18,6 @@ #include "llvm/ADT/StringRef.h" #include #include -#include #include using llvm::dyn_cast; @@ -96,7 +95,8 @@ public: FIRST_TARGET_ATTRIBUTE, DLLExport, DLLImport, - MSP430Interrupt + MSP430Interrupt, + X86ForceAlignArgPointer }; private: @@ -119,8 +119,7 @@ protected: assert(Next == 0 && "Destroy didn't work"); } public: - - void Destroy(ASTContext &C); + virtual void Destroy(ASTContext &C); /// \brief Whether this attribute should be merged to new /// declarations. @@ -156,6 +155,18 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Attr *) { return true; } }; + +class AttrWithString : public Attr { +private: + const char *Str; + unsigned StrLen; +protected: + AttrWithString(Attr::Kind AK, ASTContext &C, llvm::StringRef s); + llvm::StringRef getString() const { return llvm::StringRef(Str, StrLen); } + void ReplaceString(ASTContext &C, llvm::StringRef newS); +public: + virtual void Destroy(ASTContext &C); +}; #define DEF_SIMPLE_ATTR(ATTR) \ class ATTR##Attr : public Attr { \ @@ -213,12 +224,12 @@ public: static bool classof(const AlignedAttr *A) { return true; } }; -class AnnotateAttr : public Attr { - std::string Annotation; +class AnnotateAttr : public AttrWithString { public: - AnnotateAttr(llvm::StringRef ann) : Attr(Annotate), Annotation(ann) {} + AnnotateAttr(ASTContext &C, llvm::StringRef ann) + : AttrWithString(Annotate, C, ann) {} - const std::string& getAnnotation() const { return Annotation; } + llvm::StringRef getAnnotation() const { return getString(); } virtual Attr* clone(ASTContext &C) const; @@ -229,12 +240,12 @@ public: static bool classof(const AnnotateAttr *A) { return true; } }; -class AsmLabelAttr : public Attr { - std::string Label; +class AsmLabelAttr : public AttrWithString { public: - AsmLabelAttr(llvm::StringRef L) : Attr(AsmLabel), Label(L) {} + AsmLabelAttr(ASTContext &C, llvm::StringRef L) + : AttrWithString(AsmLabel, C, L) {} - const std::string& getLabel() const { return Label; } + llvm::StringRef getLabel() const { return getString(); } virtual Attr* clone(ASTContext &C) const; @@ -247,12 +258,12 @@ public: DEF_SIMPLE_ATTR(AlwaysInline); -class AliasAttr : public Attr { - std::string Aliasee; +class AliasAttr : public AttrWithString { public: - AliasAttr(llvm::StringRef aliasee) : Attr(Alias), Aliasee(aliasee) {} + AliasAttr(ASTContext &C, llvm::StringRef aliasee) + : AttrWithString(Alias, C, aliasee) {} - const std::string& getAliasee() const { return Aliasee; } + llvm::StringRef getAliasee() const { return getString(); } virtual Attr *clone(ASTContext &C) const; @@ -321,12 +332,12 @@ DEF_SIMPLE_ATTR(AnalyzerNoReturn); DEF_SIMPLE_ATTR(Deprecated); DEF_SIMPLE_ATTR(Final); -class SectionAttr : public Attr { - std::string Name; +class SectionAttr : public AttrWithString { public: - SectionAttr(llvm::StringRef N) : Attr(Section), Name(N) {} + SectionAttr(ASTContext &C, llvm::StringRef N) + : AttrWithString(Section, C, N) {} - const std::string& getName() const { return Name; } + llvm::StringRef getName() const { return getString(); } virtual Attr *clone(ASTContext &C) const; @@ -350,19 +361,9 @@ class NonNullAttr : public Attr { unsigned* ArgNums; unsigned Size; public: - NonNullAttr(unsigned* arg_nums = 0, unsigned size = 0) : Attr(NonNull), - ArgNums(0), Size(0) { - - if (size == 0) return; - assert(arg_nums); - ArgNums = new unsigned[size]; - Size = size; - memcpy(ArgNums, arg_nums, sizeof(*ArgNums)*size); - } + NonNullAttr(ASTContext &C, unsigned* arg_nums = 0, unsigned size = 0); - virtual ~NonNullAttr() { - delete [] ArgNums; - } + virtual void Destroy(ASTContext &C); typedef const unsigned *iterator; iterator begin() const { return ArgNums; } @@ -379,15 +380,14 @@ public: static bool classof(const NonNullAttr *A) { return true; } }; -class FormatAttr : public Attr { - std::string Type; +class FormatAttr : public AttrWithString { int formatIdx, firstArg; public: - FormatAttr(llvm::StringRef type, int idx, int first) : Attr(Format), - Type(type), formatIdx(idx), firstArg(first) {} + FormatAttr(ASTContext &C, llvm::StringRef type, int idx, int first) + : AttrWithString(Format, C, type), formatIdx(idx), firstArg(first) {} - const std::string& getType() const { return Type; } - void setType(llvm::StringRef type) { Type = type; } + llvm::StringRef getType() const { return getString(); } + void setType(ASTContext &C, llvm::StringRef type); int getFormatIdx() const { return formatIdx; } int getFirstArg() const { return firstArg; } @@ -570,6 +570,8 @@ public: static bool classof(const MSP430InterruptAttr *A) { return true; } }; +DEF_SIMPLE_ATTR(X86ForceAlignArgPointer); + #undef DEF_SIMPLE_ATTR } // end namespace clang diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h index 1491b1edbbac..79a3022ee014 100644 --- a/include/clang/AST/CXXInheritance.h +++ b/include/clang/AST/CXXInheritance.h @@ -161,7 +161,8 @@ class CXXBasePaths { void ComputeDeclsFound(); public: - typedef std::list::const_iterator paths_iterator; + typedef std::list::iterator paths_iterator; + typedef std::list::const_iterator const_paths_iterator; typedef NamedDecl **decl_iterator; /// BasePaths - Construct a new BasePaths structure to record the @@ -175,8 +176,10 @@ public: ~CXXBasePaths() { delete [] DeclsFound; } - paths_iterator begin() const { return Paths.begin(); } - paths_iterator end() const { return Paths.end(); } + paths_iterator begin() { return Paths.begin(); } + paths_iterator end() { return Paths.end(); } + const_paths_iterator begin() const { return Paths.begin(); } + const_paths_iterator end() const { return Paths.end(); } CXXBasePath& front() { return Paths.front(); } const CXXBasePath& front() const { return Paths.front(); } @@ -206,7 +209,7 @@ public: const RecordType* getDetectedVirtual() const { return DetectedVirtual; } - + /// \brief Retrieve the type from which this base-paths search /// began CXXRecordDecl *getOrigin() const { return Origin; } diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 6d52b2b2bc91..07442896dc4b 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -19,6 +19,7 @@ #include "clang/AST/Redeclarable.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/ExternalASTSource.h" +#include "clang/Basic/Linkage.h" namespace clang { class CXXTemporary; @@ -75,8 +76,9 @@ public: static TranslationUnitDecl *Create(ASTContext &C); // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { return D->getKind() == TranslationUnit; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const TranslationUnitDecl *D) { return true; } + static bool classofKind(Kind K) { return K == TranslationUnit; } static DeclContext *castToDeclContext(const TranslationUnitDecl *D) { return static_cast(const_cast(D)); } @@ -194,23 +196,6 @@ public: return DC->isRecord(); } - /// \brief Describes the different kinds of linkage - /// (C++ [basic.link], C99 6.2.2) that an entity may have. - enum Linkage { - /// \brief No linkage, which means that the entity is unique and - /// can only be referred to from within its scope. - NoLinkage = 0, - - /// \brief Internal linkage, which indicates that the entity can - /// be referred to from within the translation unit (but not other - /// translation units). - InternalLinkage, - - /// \brief External linkage, which indicates that the entity can - /// be referred to from other translation units. - ExternalLinkage - }; - /// \brief Determine what kind of linkage this entity has. Linkage getLinkage() const; @@ -221,10 +206,9 @@ public: return const_cast(this)->getUnderlyingDecl(); } - static bool classof(const Decl *D) { - return D->getKind() >= NamedFirst && D->getKind() <= NamedLast; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const NamedDecl *D) { return true; } + static bool classofKind(Kind K) { return K >= NamedFirst && K <= NamedLast; } }; /// NamespaceDecl - Represent a C++ namespace. @@ -301,8 +285,9 @@ public: void setRBracLoc(SourceLocation RBrace) { RBracLoc = RBrace; } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { return D->getKind() == Namespace; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const NamespaceDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Namespace; } static DeclContext *castToDeclContext(const NamespaceDecl *D) { return static_cast(const_cast(D)); } @@ -326,10 +311,9 @@ public: void setType(QualType newType) { DeclType = newType; } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() >= ValueFirst && D->getKind() <= ValueLast; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ValueDecl *D) { return true; } + static bool classofKind(Kind K) { return K >= ValueFirst && K <= ValueLast; } }; /// \brief Represents a ValueDecl that came out of a declarator. @@ -349,10 +333,11 @@ public: SourceLocation getTypeSpecStartLoc() const; // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() >= DeclaratorFirst && D->getKind() <= DeclaratorLast; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const DeclaratorDecl *D) { return true; } + static bool classofKind(Kind K) { + return K >= DeclaratorFirst && K <= DeclaratorLast; + } }; /// \brief Structure used to store a statement, the constant value to @@ -474,14 +459,142 @@ public: SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S); - virtual ~VarDecl(); virtual void Destroy(ASTContext& C); + virtual ~VarDecl(); + + virtual SourceRange getSourceRange() const; StorageClass getStorageClass() const { return (StorageClass)SClass; } void setStorageClass(StorageClass SC) { SClass = SC; } - virtual SourceRange getSourceRange() const; + void setThreadSpecified(bool T) { ThreadSpecified = T; } + bool isThreadSpecified() const { + return ThreadSpecified; + } + + /// hasLocalStorage - Returns true if a variable with function scope + /// is a non-static local variable. + bool hasLocalStorage() const { + if (getStorageClass() == None) + return !isFileVarDecl(); + + // Return true for: Auto, Register. + // Return false for: Extern, Static, PrivateExtern. + + return getStorageClass() <= Register; + } + + /// hasExternStorage - Returns true if a variable has extern or + /// __private_extern__ storage. + bool hasExternalStorage() const { + return getStorageClass() == Extern || getStorageClass() == PrivateExtern; + } + + /// hasGlobalStorage - Returns true for all variables that do not + /// have local storage. This includs all global variables as well + /// as static variables declared within a function. + bool hasGlobalStorage() const { return !hasLocalStorage(); } + + /// \brief Determines whether this variable is a variable with + /// external, C linkage. + bool isExternC() const; + + /// isBlockVarDecl - Returns true for local variable declarations. Note that + /// this includes static variables inside of functions. + /// + /// void foo() { int x; static int y; extern int z; } + /// + bool isBlockVarDecl() const { + if (getKind() != Decl::Var) + return false; + if (const DeclContext *DC = getDeclContext()) + return DC->getLookupContext()->isFunctionOrMethod(); + return false; + } + + /// \brief Determines whether this is a static data member. + /// + /// This will only be true in C++, and applies to, e.g., the + /// variable 'x' in: + /// \code + /// struct S { + /// static int x; + /// }; + /// \endcode + bool isStaticDataMember() const { + // If it wasn't static, it would be a FieldDecl. + return getDeclContext()->isRecord(); + } + + virtual VarDecl *getCanonicalDecl(); + const VarDecl *getCanonicalDecl() const { + return const_cast(this)->getCanonicalDecl(); + } + + enum DefinitionKind { + DeclarationOnly, ///< This declaration is only a declaration. + TentativeDefinition, ///< This declaration is a tentative definition. + Definition ///< This declaration is definitely a definition. + }; + + /// \brief Check whether this declaration is a definition. If this could be + /// a tentative definition (in C), don't check whether there's an overriding + /// definition. + DefinitionKind isThisDeclarationADefinition() const; + + /// \brief Get the tentative definition that acts as the real definition in + /// a TU. Returns null if there is a proper definition available. + VarDecl *getActingDefinition(); + const VarDecl *getActingDefinition() const { + return const_cast(this)->getActingDefinition(); + } + + /// \brief Determine whether this is a tentative definition of a + /// variable in C. + bool isTentativeDefinitionNow() const; + + /// \brief Get the real (not just tentative) definition for this declaration. + VarDecl *getDefinition(); + const VarDecl *getDefinition() const { + return const_cast(this)->getDefinition(); + } + + /// \brief Determine whether this is or was instantiated from an out-of-line + /// definition of a static data member. + bool isOutOfLine() const; + + /// \brief If this is a static data member, find its out-of-line definition. + VarDecl *getOutOfLineDefinition(); + + /// isFileVarDecl - Returns true for file scoped variable declaration. + bool isFileVarDecl() const { + if (getKind() != Decl::Var) + return false; + if (const DeclContext *Ctx = getDeclContext()) { + Ctx = Ctx->getLookupContext(); + if (isa(Ctx) || isa(Ctx) ) + return true; + } + if (isStaticDataMember()) + return true; + + return false; + } + + /// getAnyInitializer - Get the initializer for this variable, no matter which + /// declaration it is attached to. + const Expr *getAnyInitializer() const { + const VarDecl *D; + return getAnyInitializer(D); + } + /// getAnyInitializer - Get the initializer for this variable, no matter which + /// declaration it is attached to. Also get that declaration. + const Expr *getAnyInitializer(const VarDecl *&D) const; + + bool hasInit() const { + return !Init.isNull(); + } const Expr *getInit() const { if (Init.isNull()) return 0; @@ -521,7 +634,7 @@ public: return StmtPtr; } - void setInit(ASTContext &C, Expr *I); + void setInit(Expr *I); EvaluatedStmt *EnsureEvaluatedStmt() const { EvaluatedStmt *Eval = Init.dyn_cast(); @@ -614,17 +727,6 @@ public: Eval->IsICE = IsICE; } - /// \brief Retrieve the definition of this variable, which may come - /// from a previous declaration. Def will be set to the VarDecl that - /// contains the initializer, and the result will be that - /// initializer. - const Expr *getDefinition(const VarDecl *&Def) const; - - void setThreadSpecified(bool T) { ThreadSpecified = T; } - bool isThreadSpecified() const { - return ThreadSpecified; - } - void setCXXDirectInitializer(bool T) { HasCXXDirectInit = T; } /// hasCXXDirectInitializer - If true, the initializer was a direct @@ -648,67 +750,6 @@ public: void setDeclaredInCondition(bool InCondition) { DeclaredInCondition = InCondition; } - - virtual VarDecl *getCanonicalDecl(); - const VarDecl *getCanonicalDecl() const { - return const_cast(this)->getCanonicalDecl(); - } - - /// hasLocalStorage - Returns true if a variable with function scope - /// is a non-static local variable. - bool hasLocalStorage() const { - if (getStorageClass() == None) - return !isFileVarDecl(); - - // Return true for: Auto, Register. - // Return false for: Extern, Static, PrivateExtern. - - return getStorageClass() <= Register; - } - - /// hasExternStorage - Returns true if a variable has extern or - /// __private_extern__ storage. - bool hasExternalStorage() const { - return getStorageClass() == Extern || getStorageClass() == PrivateExtern; - } - - /// hasGlobalStorage - Returns true for all variables that do not - /// have local storage. This includs all global variables as well - /// as static variables declared within a function. - bool hasGlobalStorage() const { return !hasLocalStorage(); } - - /// isBlockVarDecl - Returns true for local variable declarations. Note that - /// this includes static variables inside of functions. - /// - /// void foo() { int x; static int y; extern int z; } - /// - bool isBlockVarDecl() const { - if (getKind() != Decl::Var) - return false; - if (const DeclContext *DC = getDeclContext()) - return DC->getLookupContext()->isFunctionOrMethod(); - return false; - } - - /// \brief Determines whether this is a static data member. - /// - /// This will only be true in C++, and applies to, e.g., the - /// variable 'x' in: - /// \code - /// struct S { - /// static int x; - /// }; - /// \endcode - bool isStaticDataMember() const { - return getDeclContext()->isRecord(); - } - - /// \brief Determine whether this is or was instantiated from an out-of-line - /// definition of a static data member. - bool isOutOfLine() const; - - /// \brief If this is a static data member, find its out-of-line definition. - VarDecl *getOutOfLineDefinition(); /// \brief If this variable is an instantiated static data member of a /// class template specialization, returns the templated static data member @@ -728,35 +769,11 @@ public: /// data member of a class template, set the template specialiation kind. void setTemplateSpecializationKind(TemplateSpecializationKind TSK, SourceLocation PointOfInstantiation = SourceLocation()); - - /// isFileVarDecl - Returns true for file scoped variable declaration. - bool isFileVarDecl() const { - if (getKind() != Decl::Var) - return false; - if (const DeclContext *Ctx = getDeclContext()) { - Ctx = Ctx->getLookupContext(); - if (isa(Ctx) || isa(Ctx) ) - return true; - } - if (isStaticDataMember()) - return true; - - return false; - } - - /// \brief Determine whether this is a tentative definition of a - /// variable in C. - bool isTentativeDefinition(ASTContext &Context) const; - - /// \brief Determines whether this variable is a variable with - /// external, C linkage. - bool isExternC() const; // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() >= VarFirst && D->getKind() <= VarLast; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const VarDecl *D) { return true; } + static bool classofKind(Kind K) { return K >= VarFirst && K <= VarLast; } }; class ImplicitParamDecl : public VarDecl { @@ -770,7 +787,8 @@ public: QualType T); // Implement isa/cast/dyncast/etc. static bool classof(const ImplicitParamDecl *D) { return true; } - static bool classof(const Decl *D) { return D->getKind() == ImplicitParam; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ImplicitParam; } }; /// ParmVarDecl - Represent a parameter to a function. @@ -876,10 +894,9 @@ public: void setOwningFunction(DeclContext *FD) { setDeclContext(FD); } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return (D->getKind() == ParmVar); - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ParmVarDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ParmVar; } }; /// FunctionDecl - An instance of this class is created to represent a @@ -1096,8 +1113,6 @@ public: unsigned getBuiltinID() const; - unsigned getNumParmVarDeclsFromType() const; - // Iterator access to formal parameters. unsigned param_size() const { return getNumParams(); } typedef ParmVarDecl **param_iterator; @@ -1110,7 +1125,7 @@ public: param_const_iterator param_end() const { return ParamInfo+param_size(); } /// getNumParams - Return the number of parameters this function must have - /// based on its functiontype. This is the length of the PararmInfo array + /// based on its FunctionType. This is the length of the ParamInfo array /// after it has been created. unsigned getNumParams() const; @@ -1122,7 +1137,7 @@ public: assert(i < getNumParams() && "Illegal param #"); return ParamInfo[i]; } - void setParams(ASTContext& C, ParmVarDecl **NewParamInfo, unsigned NumParams); + void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams); /// getMinRequiredArguments - Returns the minimum number of arguments /// needed to call this function. This may be fewer than the number of @@ -1267,8 +1282,7 @@ public: /// be inserted. /// /// \param TSK the kind of template specialization this is. - void setFunctionTemplateSpecialization(ASTContext &Context, - FunctionTemplateDecl *Template, + void setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, const TemplateArgumentList *TemplateArgs, void *InsertPos, TemplateSpecializationKind TSK = TSK_ImplicitInstantiation); @@ -1295,10 +1309,11 @@ public: bool isOutOfLine() const; // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const FunctionDecl *D) { return true; } + static bool classofKind(Kind K) { + return K >= FunctionFirst && K <= FunctionLast; + } static DeclContext *castToDeclContext(const FunctionDecl *D) { return static_cast(const_cast(D)); } @@ -1347,11 +1362,20 @@ public: Expr *getBitWidth() const { return BitWidth; } void setBitWidth(Expr *BW) { BitWidth = BW; } - // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() >= FieldFirst && D->getKind() <= FieldLast; + /// getParent - Returns the parent of this field declaration, which + /// is the struct in which this method is defined. + const RecordDecl *getParent() const { + return cast(getDeclContext()); } + + RecordDecl *getParent() { + return cast(getDeclContext()); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const FieldDecl *D) { return true; } + static bool classofKind(Kind K) { return K >= FieldFirst && K <= FieldLast; } }; /// EnumConstantDecl - An instance of this object exists for each enum constant @@ -1385,8 +1409,9 @@ public: void setInitVal(const llvm::APSInt &V) { Val = V; } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { return D->getKind() == EnumConstant; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const EnumConstantDecl *D) { return true; } + static bool classofKind(Kind K) { return K == EnumConstant; } friend class StmtIteratorBase; }; @@ -1418,10 +1443,9 @@ public: void setTypeForDecl(Type *TD) { TypeForDecl = TD; } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() >= TypeFirst && D->getKind() <= TypeLast; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const TypeDecl *D) { return true; } + static bool classofKind(Kind K) { return K >= TypeFirst && K <= TypeLast; } }; @@ -1460,8 +1484,9 @@ public: } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { return D->getKind() == Typedef; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const TypedefDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Typedef; } }; class TypedefDecl; @@ -1486,6 +1511,11 @@ private: /// it is a declaration ("struct foo;"). bool IsDefinition : 1; + /// IsEmbeddedInDeclarator - True if this tag declaration is + /// "embedded" (i.e., defined or declared for the very first time) + /// in the syntax of a declarator, + bool IsEmbeddedInDeclarator : 1; + /// TypedefForAnonDecl - If a TagDecl is anonymous and part of a typedef, /// this points to the TypedefDecl. Used for mangling. TypedefDecl *TypedefForAnonDecl; @@ -1502,6 +1532,7 @@ protected: assert((DK != Enum || TK == TK_enum) &&"EnumDecl not matched with TK_enum"); TagDeclKind = TK; IsDefinition = false; + IsEmbeddedInDeclarator = false; setPreviousDeclaration(PrevDecl); } @@ -1535,6 +1566,13 @@ public: return IsDefinition; } + bool isEmbeddedInDeclarator() const { + return IsEmbeddedInDeclarator; + } + void setEmbeddedInDeclarator(bool isInDeclarator) { + IsEmbeddedInDeclarator = isInDeclarator; + } + /// \brief Whether this declaration declares a type that is /// dependent, i.e., a type that somehow depends on template /// parameters. @@ -1557,7 +1595,9 @@ public: /// specific TagDecl is defining declaration, not whether or not the /// struct/union/class/enum type is defined. This method returns NULL if /// there is no TagDecl that defines the struct/union/class/enum. - TagDecl* getDefinition(ASTContext& C) const; + TagDecl* getDefinition() const; + + void setDefinition(bool V) { IsDefinition = V; } const char *getKindName() const { return ElaboratedType::getNameForTagKind(getTagKind()); @@ -1583,10 +1623,9 @@ public: void setTypedefForAnonDecl(TypedefDecl *TDD) { TypedefForAnonDecl = TDD; } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() >= TagFirst && D->getKind() <= TagLast; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const TagDecl *D) { return true; } + static bool classofKind(Kind K) { return K >= TagFirst && K <= TagLast; } static DeclContext *castToDeclContext(const TagDecl *D) { return static_cast(const_cast(D)); @@ -1594,8 +1633,6 @@ public: static TagDecl *castFromDeclContext(const DeclContext *DC) { return static_cast(const_cast(DC)); } - - void setDefinition(bool V) { IsDefinition = V; } }; /// EnumDecl - Represents an enum. As an extension, we allow forward-declared @@ -1641,7 +1678,7 @@ public: /// declaration as being defined; it's enumerators have already been /// added (via DeclContext::addDecl). NewType is the new underlying /// type of the enumeration type. - void completeDefinition(ASTContext &C, QualType NewType, + void completeDefinition(QualType NewType, QualType PromotionType); // enumerator_iterator - Iterates through the enumerators of this @@ -1679,8 +1716,9 @@ public: void setInstantiationOfMemberEnum(EnumDecl *IF) { InstantiatedFrom = IF; } - static bool classof(const Decl *D) { return D->getKind() == Enum; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const EnumDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Enum; } }; @@ -1763,8 +1801,8 @@ public: /// RecordDecl is defining declaration, not whether or not the record /// type is defined. This method returns NULL if there is no RecordDecl /// that defines the struct/union/tag. - RecordDecl* getDefinition(ASTContext& C) const { - return cast_or_null(TagDecl::getDefinition(C)); + RecordDecl* getDefinition() const { + return cast_or_null(TagDecl::getDefinition()); } // Iterator access to field members. The field iterator only visits @@ -1787,12 +1825,13 @@ public: /// completeDefinition - Notes that the definition of this type is /// now complete. - void completeDefinition(ASTContext& C); + void completeDefinition(); - static bool classof(const Decl *D) { - return D->getKind() >= RecordFirst && D->getKind() <= RecordLast; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const RecordDecl *D) { return true; } + static bool classofKind(Kind K) { + return K >= RecordFirst && K <= RecordLast; + } }; class FileScopeAsmDecl : public Decl { @@ -1807,10 +1846,9 @@ public: StringLiteral *getAsmString() { return AsmString; } void setAsmString(StringLiteral *Asm) { AsmString = Asm; } - static bool classof(const Decl *D) { - return D->getKind() == FileScopeAsm; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const FileScopeAsmDecl *D) { return true; } + static bool classofKind(Kind K) { return K == FileScopeAsm; } }; /// BlockDecl - This represents a block literal declaration, which is like an @@ -1869,11 +1907,12 @@ public: assert(i < getNumParams() && "Illegal param #"); return ParamInfo[i]; } - void setParams(ASTContext& C, ParmVarDecl **NewParamInfo, unsigned NumParams); + void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams); // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { return D->getKind() == Block; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const BlockDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Block; } static DeclContext *castToDeclContext(const BlockDecl *D) { return static_cast(const_cast(D)); } diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 775bce2a15fc..a407a1627747 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -480,6 +480,7 @@ public: // Implement isa/cast/dyncast/etc. static bool classof(const Decl *) { return true; } + static bool classofKind(Kind K) { return true; } static DeclContext *castToDeclContext(const Decl *); static Decl *castFromDeclContext(const DeclContext *); @@ -1020,17 +1021,43 @@ inline bool Decl::isTemplateParameter() const { getKind() == TemplateTemplateParm; } + +// Specialization selected when ToTy is not a known subclass of DeclContext. +template ::value> +struct cast_convert_decl_context { + static const ToTy *doit(const DeclContext *Val) { + return static_cast(Decl::castFromDeclContext(Val)); + } + + static ToTy *doit(DeclContext *Val) { + return static_cast(Decl::castFromDeclContext(Val)); + } +}; + +// Specialization selected when ToTy is a known subclass of DeclContext. +template +struct cast_convert_decl_context { + static const ToTy *doit(const DeclContext *Val) { + return static_cast(Val); + } + + static ToTy *doit(DeclContext *Val) { + return static_cast(Val); + } +}; + + } // end clang. namespace llvm { -/// Implement a isa_impl_wrap specialization to check whether a DeclContext is -/// a specific Decl. +/// isa(DeclContext*) template struct isa_impl_wrap { static bool doit(const ::clang::DeclContext &Val) { - return ToTy::classof(::clang::Decl::castFromDeclContext(&Val)); + return ToTy::classofKind(Val.getDeclKind()); } }; template @@ -1038,6 +1065,34 @@ struct isa_impl_wrap : public isa_impl_wrap {}; +/// cast(DeclContext*) +template +struct cast_convert_val { + static const ToTy &doit(const ::clang::DeclContext &Val) { + return *::clang::cast_convert_decl_context::doit(&Val); + } +}; +template +struct cast_convert_val { + static ToTy &doit(::clang::DeclContext &Val) { + return *::clang::cast_convert_decl_context::doit(&Val); + } +}; +template +struct cast_convert_val { + static const ToTy *doit(const ::clang::DeclContext *Val) { + return ::clang::cast_convert_decl_context::doit(Val); + } +}; +template +struct cast_convert_val { + static ToTy *doit(::clang::DeclContext *Val) { + return ::clang::cast_convert_decl_context::doit(Val); + } +}; + /// Implement cast_convert_val for Decl -> DeclContext conversions. template struct cast_convert_val< ::clang::DeclContext, FromTy, FromTy> { @@ -1067,31 +1122,6 @@ struct cast_convert_val< const ::clang::DeclContext, FromTy*, FromTy*> { } }; -/// Implement cast_convert_val for DeclContext -> Decl conversions. -template -struct cast_convert_val { - static ToTy &doit(const ::clang::DeclContext &Val) { - return *reinterpret_cast(ToTy::castFromDeclContext(&Val)); - } -}; -template -struct cast_convert_val - : public cast_convert_val {}; - -template -struct cast_convert_val { - static ToTy *doit(const ::clang::DeclContext *Val) { - return reinterpret_cast(ToTy::castFromDeclContext(Val)); - } -}; -template -struct cast_convert_val - : public cast_convert_val {}; - } // end namespace llvm #endif diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 73ebf52d383b..0978c6da9d66 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -145,6 +145,10 @@ public: /// class (or not). bool isVirtual() const { return Virtual; } + /// \brief Determine whether this base class if a base of a class declared + /// with the 'class' keyword (vs. one declared with the 'struct' keyword). + bool isBaseOfClass() const { return BaseOfClass; } + /// getAccessSpecifier - Returns the access specifier for this base /// specifier. This is the actual base specifier as used for /// semantic analysis, so the result can never be AS_none. To @@ -174,115 +178,137 @@ public: /// FIXME: This class will disappear once we've properly taught RecordDecl /// to deal with C++-specific things. class CXXRecordDecl : public RecordDecl { - /// UserDeclaredConstructor - True when this class has a - /// user-declared constructor. - bool UserDeclaredConstructor : 1; - /// UserDeclaredCopyConstructor - True when this class has a - /// user-declared copy constructor. - bool UserDeclaredCopyConstructor : 1; + friend void TagDecl::startDefinition(); + + struct DefinitionData { + DefinitionData(CXXRecordDecl *D); + + /// UserDeclaredConstructor - True when this class has a + /// user-declared constructor. + bool UserDeclaredConstructor : 1; + + /// UserDeclaredCopyConstructor - True when this class has a + /// user-declared copy constructor. + bool UserDeclaredCopyConstructor : 1; + + /// UserDeclaredCopyAssignment - True when this class has a + /// user-declared copy assignment operator. + bool UserDeclaredCopyAssignment : 1; + + /// UserDeclaredDestructor - True when this class has a + /// user-declared destructor. + bool UserDeclaredDestructor : 1; + + /// Aggregate - True when this class is an aggregate. + bool Aggregate : 1; + + /// PlainOldData - True when this class is a POD-type. + bool PlainOldData : 1; + + /// Empty - true when this class is empty for traits purposes, + /// i.e. has no data members other than 0-width bit-fields, has no + /// virtual function/base, and doesn't inherit from a non-empty + /// class. Doesn't take union-ness into account. + bool Empty : 1; + + /// Polymorphic - True when this class is polymorphic, i.e. has at + /// least one virtual member or derives from a polymorphic class. + bool Polymorphic : 1; + + /// Abstract - True when this class is abstract, i.e. has at least + /// one pure virtual function, (that can come from a base class). + bool Abstract : 1; + + /// HasTrivialConstructor - True when this class has a trivial constructor. + /// + /// C++ [class.ctor]p5. A constructor is trivial if it is an + /// implicitly-declared default constructor and if: + /// * its class has no virtual functions and no virtual base classes, and + /// * all the direct base classes of its class have trivial constructors, and + /// * for all the nonstatic data members of its class that are of class type + /// (or array thereof), each such class has a trivial constructor. + bool HasTrivialConstructor : 1; + + /// HasTrivialCopyConstructor - True when this class has a trivial copy + /// constructor. + /// + /// C++ [class.copy]p6. A copy constructor for class X is trivial + /// if it is implicitly declared and if + /// * class X has no virtual functions and no virtual base classes, and + /// * each direct base class of X has a trivial copy constructor, and + /// * for all the nonstatic data members of X that are of class type (or + /// array thereof), each such class type has a trivial copy constructor; + /// otherwise the copy constructor is non-trivial. + bool HasTrivialCopyConstructor : 1; + + /// HasTrivialCopyAssignment - True when this class has a trivial copy + /// assignment operator. + /// + /// C++ [class.copy]p11. A copy assignment operator for class X is + /// trivial if it is implicitly declared and if + /// * class X has no virtual functions and no virtual base classes, and + /// * each direct base class of X has a trivial copy assignment operator, and + /// * for all the nonstatic data members of X that are of class type (or + /// array thereof), each such class type has a trivial copy assignment + /// operator; + /// otherwise the copy assignment operator is non-trivial. + bool HasTrivialCopyAssignment : 1; + + /// HasTrivialDestructor - True when this class has a trivial destructor. + /// + /// C++ [class.dtor]p3. A destructor is trivial if it is an + /// implicitly-declared destructor and if: + /// * all of the direct base classes of its class have trivial destructors + /// and + /// * for all of the non-static data members of its class that are of class + /// type (or array thereof), each such class has a trivial destructor. + bool HasTrivialDestructor : 1; + + /// ComputedVisibleConversions - True when visible conversion functions are + /// already computed and are available. + bool ComputedVisibleConversions : 1; + + /// Bases - Base classes of this class. + /// FIXME: This is wasted space for a union. + CXXBaseSpecifier *Bases; - /// UserDeclaredCopyAssignment - True when this class has a - /// user-declared copy assignment operator. - bool UserDeclaredCopyAssignment : 1; + /// NumBases - The number of base class specifiers in Bases. + unsigned NumBases; - /// UserDeclaredDestructor - True when this class has a - /// user-declared destructor. - bool UserDeclaredDestructor : 1; + /// VBases - direct and indirect virtual base classes of this class. + CXXBaseSpecifier *VBases; - /// Aggregate - True when this class is an aggregate. - bool Aggregate : 1; + /// NumVBases - The number of virtual base class specifiers in VBases. + unsigned NumVBases; - /// PlainOldData - True when this class is a POD-type. - bool PlainOldData : 1; + /// Conversions - Overload set containing the conversion functions + /// of this C++ class (but not its inherited conversion + /// functions). Each of the entries in this overload set is a + /// CXXConversionDecl. + UnresolvedSet<4> Conversions; - /// Empty - true when this class is empty for traits purposes, i.e. has no - /// data members other than 0-width bit-fields, has no virtual function/base, - /// and doesn't inherit from a non-empty class. Doesn't take union-ness into - /// account. - bool Empty : 1; + /// VisibleConversions - Overload set containing the conversion + /// functions of this C++ class and all those inherited conversion + /// functions that are visible in this class. Each of the entries + /// in this overload set is a CXXConversionDecl or a + /// FunctionTemplateDecl. + UnresolvedSet<4> VisibleConversions; - /// Polymorphic - True when this class is polymorphic, i.e. has at least one - /// virtual member or derives from a polymorphic class. - bool Polymorphic : 1; + /// Definition - The declaration which defines this record. + CXXRecordDecl *Definition; - /// Abstract - True when this class is abstract, i.e. has at least one - /// pure virtual function, (that can come from a base class). - bool Abstract : 1; + } *DefinitionData; - /// HasTrivialConstructor - True when this class has a trivial constructor. - /// - /// C++ [class.ctor]p5. A constructor is trivial if it is an - /// implicitly-declared default constructor and if: - /// * its class has no virtual functions and no virtual base classes, and - /// * all the direct base classes of its class have trivial constructors, and - /// * for all the nonstatic data members of its class that are of class type - /// (or array thereof), each such class has a trivial constructor. - bool HasTrivialConstructor : 1; - - /// HasTrivialCopyConstructor - True when this class has a trivial copy - /// constructor. - /// - /// C++ [class.copy]p6. A copy constructor for class X is trivial - /// if it is implicitly declared and if - /// * class X has no virtual functions and no virtual base classes, and - /// * each direct base class of X has a trivial copy constructor, and - /// * for all the nonstatic data members of X that are of class type (or - /// array thereof), each such class type has a trivial copy constructor; - /// otherwise the copy constructor is non-trivial. - bool HasTrivialCopyConstructor : 1; - - /// HasTrivialCopyAssignment - True when this class has a trivial copy - /// assignment operator. - /// - /// C++ [class.copy]p11. A copy assignment operator for class X is - /// trivial if it is implicitly declared and if - /// * class X has no virtual functions and no virtual base classes, and - /// * each direct base class of X has a trivial copy assignment operator, and - /// * for all the nonstatic data members of X that are of class type (or - /// array thereof), each such class type has a trivial copy assignment - /// operator; - /// otherwise the copy assignment operator is non-trivial. - bool HasTrivialCopyAssignment : 1; - - /// HasTrivialDestructor - True when this class has a trivial destructor. - /// - /// C++ [class.dtor]p3. A destructor is trivial if it is an - /// implicitly-declared destructor and if: - /// * all of the direct base classes of its class have trivial destructors - /// and - /// * for all of the non-static data members of its class that are of class - /// type (or array thereof), each such class has a trivial destructor. - bool HasTrivialDestructor : 1; - - /// ComputedVisibleConversions - True when visible conversion functions are - /// already computed and are available. - bool ComputedVisibleConversions : 1; - - /// Bases - Base classes of this class. - /// FIXME: This is wasted space for a union. - CXXBaseSpecifier *Bases; - - /// NumBases - The number of base class specifiers in Bases. - unsigned NumBases; - - /// VBases - direct and indirect virtual base classes of this class. - CXXBaseSpecifier *VBases; - - /// NumVBases - The number of virtual base class specifiers in VBases. - unsigned NumVBases; - - /// Conversions - Overload set containing the conversion functions - /// of this C++ class (but not its inherited conversion - /// functions). Each of the entries in this overload set is a - /// CXXConversionDecl. - UnresolvedSet<4> Conversions; - - /// VisibleConversions - Overload set containing the conversion functions - /// of this C++ class and all those inherited conversion functions that - /// are visible in this class. Each of the entries in this overload set is - /// a CXXConversionDecl or a FunctionTemplateDecl. - UnresolvedSet<4> VisibleConversions; + struct DefinitionData &data() { + assert(DefinitionData && "queried property of class with no definition"); + return *DefinitionData; + } + + const struct DefinitionData &data() const { + assert(DefinitionData && "queried property of class with no definition"); + return *DefinitionData; + } /// \brief The template or declaration that this declaration /// describes or was instantiated from, respectively. @@ -336,6 +362,13 @@ public: return cast(RecordDecl::getCanonicalDecl()); } + CXXRecordDecl *getDefinition() const { + if (!DefinitionData) return 0; + return data().Definition; + } + + bool hasDefinition() const { return DefinitionData != 0; } + static CXXRecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, SourceLocation TKL = SourceLocation(), @@ -345,21 +378,22 @@ public: virtual void Destroy(ASTContext& C); bool isDynamicClass() const { - return Polymorphic || NumVBases != 0; + return data().Polymorphic || data().NumVBases != 0; } /// setBases - Sets the base classes of this struct or class. - void setBases(ASTContext &C, - CXXBaseSpecifier const * const *Bases, unsigned NumBases); + void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases); /// getNumBases - Retrieves the number of base classes of this /// class. - unsigned getNumBases() const { return NumBases; } + unsigned getNumBases() const { return data().NumBases; } - base_class_iterator bases_begin() { return Bases; } - base_class_const_iterator bases_begin() const { return Bases; } - base_class_iterator bases_end() { return Bases + NumBases; } - base_class_const_iterator bases_end() const { return Bases + NumBases; } + base_class_iterator bases_begin() { return data().Bases; } + base_class_const_iterator bases_begin() const { return data().Bases; } + base_class_iterator bases_end() { return bases_begin() + data().NumBases; } + base_class_const_iterator bases_end() const { + return bases_begin() + data().NumBases; + } reverse_base_class_iterator bases_rbegin() { return reverse_base_class_iterator(bases_end()); } @@ -375,12 +409,14 @@ public: /// getNumVBases - Retrieves the number of virtual base classes of this /// class. - unsigned getNumVBases() const { return NumVBases; } + unsigned getNumVBases() const { return data().NumVBases; } - base_class_iterator vbases_begin() { return VBases; } - base_class_const_iterator vbases_begin() const { return VBases; } - base_class_iterator vbases_end() { return VBases + NumVBases; } - base_class_const_iterator vbases_end() const { return VBases + NumVBases; } + base_class_iterator vbases_begin() { return data().VBases; } + base_class_const_iterator vbases_begin() const { return data().VBases; } + base_class_iterator vbases_end() { return vbases_begin() + data().NumVBases; } + base_class_const_iterator vbases_end() const { + return vbases_begin() + data().NumVBases; + } reverse_base_class_iterator vbases_rbegin() { return reverse_base_class_iterator(vbases_end()); } @@ -445,17 +481,14 @@ public: /// user-declared constructors. When true, a default constructor /// will not be implicitly declared. bool hasUserDeclaredConstructor() const { - assert((isDefinition() || - cast(getTypeForDecl())->isBeingDefined()) && - "Incomplete record decl!"); - return UserDeclaredConstructor; + return data().UserDeclaredConstructor; } /// hasUserDeclaredCopyConstructor - Whether this class has a /// user-declared copy constructor. When false, a copy constructor /// will be implicitly declared. bool hasUserDeclaredCopyConstructor() const { - return UserDeclaredCopyConstructor; + return data().UserDeclaredCopyConstructor; } /// addedAssignmentOperator - Notify the class that another assignment @@ -467,45 +500,45 @@ public: /// user-declared copy assignment operator. When false, a copy /// assigment operator will be implicitly declared. bool hasUserDeclaredCopyAssignment() const { - return UserDeclaredCopyAssignment; + return data().UserDeclaredCopyAssignment; } /// hasUserDeclaredDestructor - Whether this class has a /// user-declared destructor. When false, a destructor will be /// implicitly declared. - bool hasUserDeclaredDestructor() const { return UserDeclaredDestructor; } + bool hasUserDeclaredDestructor() const { + return data().UserDeclaredDestructor; + } /// setUserDeclaredDestructor - Set whether this class has a /// user-declared destructor. If not set by the time the class is /// fully defined, a destructor will be implicitly declared. void setUserDeclaredDestructor(bool UCD) { - UserDeclaredDestructor = UCD; + data().UserDeclaredDestructor = UCD; } /// getConversions - Retrieve the overload set containing all of the /// conversion functions in this class. UnresolvedSetImpl *getConversionFunctions() { - assert((this->isDefinition() || - cast(getTypeForDecl())->isBeingDefined()) && - "getConversionFunctions() called on incomplete type"); - return &Conversions; + return &data().Conversions; } const UnresolvedSetImpl *getConversionFunctions() const { - assert((this->isDefinition() || - cast(getTypeForDecl())->isBeingDefined()) && - "getConversionFunctions() called on incomplete type"); - return &Conversions; + return &data().Conversions; } typedef UnresolvedSetImpl::iterator conversion_iterator; - conversion_iterator conversion_begin() const { return Conversions.begin(); } - conversion_iterator conversion_end() const { return Conversions.end(); } + conversion_iterator conversion_begin() const { + return getConversionFunctions()->begin(); + } + conversion_iterator conversion_end() const { + return getConversionFunctions()->end(); + } /// Replaces a conversion function with a new declaration. /// /// Returns true if the old conversion was found. bool replaceConversion(const NamedDecl* Old, NamedDecl *New) { - return Conversions.replace(Old, New); + return getConversionFunctions()->replace(Old, New); } /// getVisibleConversionFunctions - get all conversion functions visible @@ -532,11 +565,11 @@ public: /// [dcl.init.aggr]), which is a class with no user-declared /// constructors, no private or protected non-static data members, /// no base classes, and no virtual functions (C++ [dcl.init.aggr]p1). - bool isAggregate() const { return Aggregate; } + bool isAggregate() const { return data().Aggregate; } /// setAggregate - Set whether this class is an aggregate (C++ /// [dcl.init.aggr]). - void setAggregate(bool Agg) { Aggregate = Agg; } + void setAggregate(bool Agg) { data().Aggregate = Agg; } /// setMethodAsVirtual - Make input method virtual and set the necesssary /// special function bits and other bits accordingly. @@ -546,66 +579,74 @@ public: /// that is an aggregate that has no non-static non-POD data members, no /// reference data members, no user-defined copy assignment operator and no /// user-defined destructor. - bool isPOD() const { return PlainOldData; } + bool isPOD() const { return data().PlainOldData; } /// setPOD - Set whether this class is a POD-type (C++ [class]p4). - void setPOD(bool POD) { PlainOldData = POD; } + void setPOD(bool POD) { data().PlainOldData = POD; } /// isEmpty - Whether this class is empty (C++0x [meta.unary.prop]), which /// means it has a virtual function, virtual base, data member (other than /// 0-width bit-field) or inherits from a non-empty class. Does NOT include /// a check for union-ness. - bool isEmpty() const { return Empty; } + bool isEmpty() const { return data().Empty; } /// Set whether this class is empty (C++0x [meta.unary.prop]) - void setEmpty(bool Emp) { Empty = Emp; } + void setEmpty(bool Emp) { data().Empty = Emp; } /// isPolymorphic - Whether this class is polymorphic (C++ [class.virtual]), /// which means that the class contains or inherits a virtual function. - bool isPolymorphic() const { return Polymorphic; } + bool isPolymorphic() const { return data().Polymorphic; } /// setPolymorphic - Set whether this class is polymorphic (C++ /// [class.virtual]). - void setPolymorphic(bool Poly) { Polymorphic = Poly; } + void setPolymorphic(bool Poly) { data().Polymorphic = Poly; } /// isAbstract - Whether this class is abstract (C++ [class.abstract]), /// which means that the class contains or inherits a pure virtual function. - bool isAbstract() const { return Abstract; } + bool isAbstract() const { return data().Abstract; } /// setAbstract - Set whether this class is abstract (C++ [class.abstract]) - void setAbstract(bool Abs) { Abstract = Abs; } + void setAbstract(bool Abs) { data().Abstract = Abs; } // hasTrivialConstructor - Whether this class has a trivial constructor // (C++ [class.ctor]p5) - bool hasTrivialConstructor() const { return HasTrivialConstructor; } + bool hasTrivialConstructor() const { return data().HasTrivialConstructor; } // setHasTrivialConstructor - Set whether this class has a trivial constructor // (C++ [class.ctor]p5) - void setHasTrivialConstructor(bool TC) { HasTrivialConstructor = TC; } + void setHasTrivialConstructor(bool TC) { data().HasTrivialConstructor = TC; } // hasTrivialCopyConstructor - Whether this class has a trivial copy // constructor (C++ [class.copy]p6) - bool hasTrivialCopyConstructor() const { return HasTrivialCopyConstructor; } + bool hasTrivialCopyConstructor() const { + return data().HasTrivialCopyConstructor; + } // setHasTrivialCopyConstructor - Set whether this class has a trivial // copy constructor (C++ [class.copy]p6) - void setHasTrivialCopyConstructor(bool TC) { HasTrivialCopyConstructor = TC; } + void setHasTrivialCopyConstructor(bool TC) { + data().HasTrivialCopyConstructor = TC; + } // hasTrivialCopyAssignment - Whether this class has a trivial copy // assignment operator (C++ [class.copy]p11) - bool hasTrivialCopyAssignment() const { return HasTrivialCopyAssignment; } + bool hasTrivialCopyAssignment() const { + return data().HasTrivialCopyAssignment; + } // setHasTrivialCopyAssignment - Set whether this class has a // trivial copy assignment operator (C++ [class.copy]p11) - void setHasTrivialCopyAssignment(bool TC) { HasTrivialCopyAssignment = TC; } + void setHasTrivialCopyAssignment(bool TC) { + data().HasTrivialCopyAssignment = TC; + } // hasTrivialDestructor - Whether this class has a trivial destructor // (C++ [class.dtor]p3) - bool hasTrivialDestructor() const { return HasTrivialDestructor; } + bool hasTrivialDestructor() const { return data().HasTrivialDestructor; } // setHasTrivialDestructor - Set whether this class has a trivial destructor // (C++ [class.dtor]p3) - void setHasTrivialDestructor(bool TC) { HasTrivialDestructor = TC; } + void setHasTrivialDestructor(bool TC) { data().HasTrivialDestructor = TC; } /// \brief If this record is an instantiation of a member class, /// retrieves the member class from which it was instantiated. @@ -826,10 +867,11 @@ public: return (PathAccess > DeclAccess ? PathAccess : DeclAccess); } - static bool classof(const Decl *D) { - return D->getKind() == CXXRecord || - D->getKind() == ClassTemplateSpecialization || - D->getKind() == ClassTemplatePartialSpecialization; + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K == CXXRecord || + K == ClassTemplateSpecialization || + K == ClassTemplatePartialSpecialization; } static bool classof(const CXXRecordDecl *D) { return true; } static bool classof(const ClassTemplateSpecializationDecl *D) { @@ -911,10 +953,11 @@ public: bool hasInlineBody() const; // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() >= CXXMethod && D->getKind() <= CXXConversion; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const CXXMethodDecl *D) { return true; } + static bool classofKind(Kind K) { + return K >= CXXMethod && K <= CXXConversion; + } }; /// CXXBaseOrMemberInitializer - Represents a C++ base or member @@ -939,9 +982,9 @@ class CXXBaseOrMemberInitializer { /// \brief The source location for the field name. SourceLocation MemberLocation; - /// Args - The arguments used to initialize the base or member. - Stmt **Args; - unsigned NumArgs; + /// \brief The argument used to initialize the base or member, which may + /// end up constructing an object (when multiple arguments are involved). + Stmt *Init; /// \brief Stores either the constructor to call to initialize this base or /// member (a CXXConstructorDecl pointer), or stores the anonymous union of @@ -961,7 +1004,7 @@ class CXXBaseOrMemberInitializer { /// @endcode /// In above example, BaseOrMember holds the field decl. for anonymous union /// and AnonUnionMember holds field decl for au_i1. - llvm::PointerUnion CtorOrAnonUnion; + FieldDecl *AnonUnionMember; /// LParenLoc - Location of the left paren of the ctor-initializer. SourceLocation LParenLoc; @@ -973,30 +1016,22 @@ public: /// CXXBaseOrMemberInitializer - Creates a new base-class initializer. explicit CXXBaseOrMemberInitializer(ASTContext &Context, - TypeSourceInfo *TInfo, CXXConstructorDecl *C, + TypeSourceInfo *TInfo, SourceLocation L, - Expr **Args, unsigned NumArgs, + Expr *Init, SourceLocation R); /// CXXBaseOrMemberInitializer - Creates a new member initializer. explicit CXXBaseOrMemberInitializer(ASTContext &Context, FieldDecl *Member, SourceLocation MemberLoc, - CXXConstructorDecl *C, SourceLocation L, - Expr **Args, unsigned NumArgs, + SourceLocation L, + Expr *Init, SourceLocation R); /// \brief Destroy the base or member initializer. void Destroy(ASTContext &Context); - /// arg_iterator - Iterates through the member initialization - /// arguments. - typedef ExprIterator arg_iterator; - - /// arg_const_iterator - Iterates through the member initialization - /// arguments. - typedef ConstExprIterator const_arg_iterator; - /// isBaseInitializer - Returns true when this initializer is /// initializing a base class. bool isBaseInitializer() const { return BaseOrMember.is(); } @@ -1046,32 +1081,16 @@ public: SourceRange getSourceRange() const; FieldDecl *getAnonUnionMember() const { - return CtorOrAnonUnion.dyn_cast(); + return AnonUnionMember; } void setAnonUnionMember(FieldDecl *anonMember) { - CtorOrAnonUnion = anonMember; - } - - const CXXConstructorDecl *getConstructor() const { - return CtorOrAnonUnion.dyn_cast(); + AnonUnionMember = anonMember; } SourceLocation getLParenLoc() const { return LParenLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } - /// arg_begin() - Retrieve an iterator to the first initializer argument. - arg_iterator arg_begin() { return Args; } - /// arg_begin() - Retrieve an iterator to the first initializer argument. - const_arg_iterator const_arg_begin() const { return Args; } - - /// arg_end() - Retrieve an iterator past the last initializer argument. - arg_iterator arg_end() { return Args + NumArgs; } - /// arg_end() - Retrieve an iterator past the last initializer argument. - const_arg_iterator const_arg_end() const { return Args + NumArgs; } - - /// getNumArgs - Determine the number of arguments used to - /// initialize the member or base. - unsigned getNumArgs() const { return NumArgs; } + Expr *getInit() { return static_cast(Init); } }; /// CXXConstructorDecl - Represents a C++ constructor within a @@ -1084,8 +1103,9 @@ public: /// }; /// @endcode class CXXConstructorDecl : public CXXMethodDecl { - /// Explicit - Whether this constructor is explicit. - bool Explicit : 1; + /// IsExplicitSpecified - Whether this constructor declaration has the + /// 'explicit' keyword specified. + bool IsExplicitSpecified : 1; /// ImplicitlyDefined - Whether this constructor was implicitly /// defined by the compiler. When false, the constructor was defined @@ -1103,9 +1123,10 @@ class CXXConstructorDecl : public CXXMethodDecl { CXXConstructorDecl(CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, - bool isExplicit, bool isInline, bool isImplicitlyDeclared) + bool isExplicitSpecified, bool isInline, + bool isImplicitlyDeclared) : CXXMethodDecl(CXXConstructor, RD, L, N, T, TInfo, false, isInline), - Explicit(isExplicit), ImplicitlyDefined(false), + IsExplicitSpecified(isExplicitSpecified), ImplicitlyDefined(false), BaseOrMemberInitializers(0), NumBaseOrMemberInitializers(0) { setImplicit(isImplicitlyDeclared); } @@ -1118,8 +1139,15 @@ public: bool isExplicit, bool isInline, bool isImplicitlyDeclared); + /// isExplicitSpecified - Whether this constructor declaration has the + /// 'explicit' keyword specified. + bool isExplicitSpecified() const { return IsExplicitSpecified; } + /// isExplicit - Whether this constructor was marked "explicit" or not. - bool isExplicit() const { return Explicit; } + bool isExplicit() const { + return cast(getFirstDeclaration()) + ->isExplicitSpecified(); + } /// isImplicitlyDefined - Whether this constructor was implicitly /// defined. If false, then this constructor was defined by the @@ -1212,10 +1240,9 @@ public: bool isCopyConstructorLikeSpecialization() const; // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() == CXXConstructor; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const CXXConstructorDecl *D) { return true; } + static bool classofKind(Kind K) { return K == CXXConstructor; } }; /// CXXDestructorDecl - Represents a C++ destructor within a @@ -1274,10 +1301,9 @@ public: const FunctionDecl *getOperatorDelete() const { return OperatorDelete; } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() == CXXDestructor; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const CXXDestructorDecl *D) { return true; } + static bool classofKind(Kind K) { return K == CXXDestructor; } }; /// CXXConversionDecl - Represents a C++ conversion function within a @@ -1290,16 +1316,16 @@ public: /// }; /// @endcode class CXXConversionDecl : public CXXMethodDecl { - /// Explicit - Whether this conversion function is marked - /// "explicit", meaning that it can only be applied when the user + /// IsExplicitSpecified - Whether this conversion function declaration is + /// marked "explicit", meaning that it can only be applied when the user /// explicitly wrote a cast. This is a C++0x feature. - bool Explicit : 1; + bool IsExplicitSpecified : 1; CXXConversionDecl(CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, - bool isInline, bool isExplicit) + bool isInline, bool isExplicitSpecified) : CXXMethodDecl(CXXConversion, RD, L, N, T, TInfo, false, isInline), - Explicit(isExplicit) { } + IsExplicitSpecified(isExplicitSpecified) { } public: static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD, @@ -1307,10 +1333,18 @@ public: QualType T, TypeSourceInfo *TInfo, bool isInline, bool isExplicit); + /// IsExplicitSpecified - Whether this conversion function declaration is + /// marked "explicit", meaning that it can only be applied when the user + /// explicitly wrote a cast. This is a C++0x feature. + bool isExplicitSpecified() const { return IsExplicitSpecified; } + /// isExplicit - Whether this is an explicit conversion operator /// (C++0x only). Explicit conversion operators are only considered /// when the user has explicitly written a cast. - bool isExplicit() const { return Explicit; } + bool isExplicit() const { + return cast(getFirstDeclaration()) + ->isExplicitSpecified(); + } /// getConversionType - Returns the type that this conversion /// function is converting to. @@ -1319,10 +1353,9 @@ public: } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() == CXXConversion; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const CXXConversionDecl *D) { return true; } + static bool classofKind(Kind K) { return K == CXXConversion; } }; /// FriendDecl - Represents the declaration of a friend entity, @@ -1391,10 +1424,9 @@ public: void setSpecialization(bool WS) { WasSpecialization = WS; } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() == Decl::Friend; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const FriendDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Decl::Friend; } }; /// LinkageSpecDecl - This represents a linkage specification. For example: @@ -1432,10 +1464,9 @@ public: /// braces in its syntactic form. bool hasBraces() const { return HadBraces; } - static bool classof(const Decl *D) { - return D->getKind() == LinkageSpec; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const LinkageSpecDecl *D) { return true; } + static bool classofKind(Kind K) { return K == LinkageSpec; } static DeclContext *castToDeclContext(const LinkageSpecDecl *D) { return static_cast(const_cast(D)); } @@ -1537,10 +1568,9 @@ public: NamedDecl *Nominated, DeclContext *CommonAncestor); - static bool classof(const Decl *D) { - return D->getKind() == Decl::UsingDirective; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const UsingDirectiveDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Decl::UsingDirective; } // Friend for getUsingDirectiveName. friend class DeclContext; @@ -1598,6 +1628,16 @@ public: return const_cast(this)->getNamespace(); } + /// Returns the location of the alias name, i.e. 'foo' in + /// "namespace foo = ns::bar;". + SourceLocation getAliasLoc() const { return AliasLoc; } + + /// Returns the location of the 'namespace' keyword. + SourceLocation getNamespaceLoc() const { return getLocation(); } + + /// Returns the location of the identifier in the named namespace. + SourceLocation getTargetNameLoc() const { return IdentLoc; } + /// \brief Retrieve the namespace that this alias refers to, which /// may either be a NamespaceDecl or a NamespaceAliasDecl. NamedDecl *getAliasedNamespace() const { return Namespace; } @@ -1610,10 +1650,9 @@ public: SourceLocation IdentLoc, NamedDecl *Namespace); - static bool classof(const Decl *D) { - return D->getKind() == Decl::NamespaceAlias; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const NamespaceAliasDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Decl::NamespaceAlias; } }; /// UsingShadowDecl - Represents a shadow declaration introduced into @@ -1660,10 +1699,9 @@ public: return Using; } - static bool classof(const Decl *D) { - return D->getKind() == Decl::UsingShadow; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const UsingShadowDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Decl::UsingShadow; } }; /// UsingDecl - Represents a C++ using-declaration. For example: @@ -1732,10 +1770,9 @@ public: SourceLocation IdentL, SourceRange NNR, SourceLocation UsingL, NestedNameSpecifier* TargetNNS, DeclarationName Name, bool IsTypeNameArg); - static bool classof(const Decl *D) { - return D->getKind() == Decl::Using; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const UsingDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Decl::Using; } }; /// UnresolvedUsingValueDecl - Represents a dependent using @@ -1784,10 +1821,9 @@ public: SourceRange TargetNNR, NestedNameSpecifier *TargetNNS, SourceLocation TargetNameLoc, DeclarationName TargetName); - static bool classof(const Decl *D) { - return D->getKind() == Decl::UnresolvedUsingValue; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const UnresolvedUsingValueDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Decl::UnresolvedUsingValue; } }; /// UnresolvedUsingTypenameDecl - Represents a dependent using @@ -1843,10 +1879,9 @@ public: SourceRange TargetNNR, NestedNameSpecifier *TargetNNS, SourceLocation TargetNameLoc, DeclarationName TargetName); - static bool classof(const Decl *D) { - return D->getKind() == Decl::UnresolvedUsingTypename; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const UnresolvedUsingTypenameDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Decl::UnresolvedUsingTypename; } }; /// StaticAssertDecl - Represents a C++0x static_assert declaration. @@ -1872,10 +1907,9 @@ public: virtual ~StaticAssertDecl(); virtual void Destroy(ASTContext& C); - static bool classof(const Decl *D) { - return D->getKind() == Decl::StaticAssert; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(StaticAssertDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Decl::StaticAssert; } }; /// Insertion operator for diagnostics. This allows sending AccessSpecifier's diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 0fb0db13bb57..e562d352e070 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -193,6 +193,9 @@ public: ImplementationControl impControl = None); virtual ObjCMethodDecl *getCanonicalDecl(); + const ObjCMethodDecl *getCanonicalDecl() const { + return const_cast(this)->getCanonicalDecl(); + } ObjCDeclQualifier getObjCDeclQualifier() const { return ObjCDeclQualifier(objcDeclQualifier); @@ -277,8 +280,9 @@ public: bool isThisDeclarationADefinition() const { return Body; } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { return D->getKind() == ObjCMethod; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCMethodDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCMethod; } static DeclContext *castToDeclContext(const ObjCMethodDecl *D) { return static_cast(const_cast(D)); } @@ -383,11 +387,12 @@ public: } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() >= ObjCContainerFirst && - D->getKind() <= ObjCContainerLast; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCContainerDecl *D) { return true; } + static bool classofKind(Kind K) { + return K >= ObjCContainerFirst && + K <= ObjCContainerLast; + } static DeclContext *castToDeclContext(const ObjCContainerDecl *D) { return static_cast(const_cast(D)); @@ -584,8 +589,9 @@ public: Type *getTypeForDecl() const { return TypeForDecl; } void setTypeForDecl(Type *TD) const { TypeForDecl = TD; } - static bool classof(const Decl *D) { return D->getKind() == ObjCInterface; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCInterfaceDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCInterface; } }; /// ObjCIvarDecl - Represents an ObjC instance variable. In general, ObjC @@ -630,8 +636,9 @@ public: } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { return D->getKind() == ObjCIvar; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCIvarDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCIvar; } private: // NOTE: VC++ treats enums as signed, avoid using the AccessControl enum unsigned DeclAccess : 3; @@ -657,8 +664,9 @@ public: virtual void Destroy(ASTContext& C); // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { return D->getKind() == ObjCAtDefsField; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCAtDefsFieldDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCAtDefsField; } }; /// ObjCProtocolDecl - Represents a protocol declaration. ObjC protocols @@ -749,8 +757,9 @@ public: SourceLocation getLocEnd() const { return EndLoc; } void setLocEnd(SourceLocation LE) { EndLoc = LE; } - static bool classof(const Decl *D) { return D->getKind() == ObjCProtocol; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCProtocolDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCProtocol; } }; /// ObjCClassDecl - Specifies a list of forward class declarations. For example: @@ -796,8 +805,9 @@ public: void setClassList(ASTContext &C, ObjCInterfaceDecl*const*List, const SourceLocation *Locs, unsigned Num); - static bool classof(const Decl *D) { return D->getKind() == ObjCClass; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCClassDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCClass; } }; /// ObjCForwardProtocolDecl - Specifies a list of forward protocol declarations. @@ -846,10 +856,9 @@ public: const SourceLocation *Locs, ASTContext &C) { ReferencedProtocols.set(List, Num, Locs, C); } - static bool classof(const Decl *D) { - return D->getKind() == ObjCForwardProtocol; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCForwardProtocolDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCForwardProtocol; } }; /// ObjCCategoryDecl - Represents a category declaration. A category allows @@ -940,6 +949,8 @@ public: ClassInterface->setCategoryList(this); } + bool IsClassExtension() const { return getIdentifier() == 0; } + SourceLocation getAtLoc() const { return AtLoc; } void setAtLoc(SourceLocation At) { AtLoc = At; } @@ -950,8 +961,9 @@ public: return SourceRange(AtLoc, getAtEndRange().getEnd()); } - static bool classof(const Decl *D) { return D->getKind() == ObjCCategory; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCCategoryDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCCategory; } }; class ObjCImplDecl : public ObjCContainerDecl { @@ -997,10 +1009,11 @@ public: return propimpl_iterator(decls_end()); } - static bool classof(const Decl *D) { - return D->getKind() >= ObjCImplFirst && D->getKind() <= ObjCImplLast; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCImplDecl *D) { return true; } + static bool classofKind(Kind K) { + return K >= ObjCImplFirst && K <= ObjCImplLast; + } }; /// ObjCCategoryImplDecl - An object of this class encapsulates a category @@ -1068,8 +1081,9 @@ public: return getName(); } - static bool classof(const Decl *D) { return D->getKind() == ObjCCategoryImpl;} + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCCategoryImplDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCCategoryImpl;} }; /// ObjCImplementationDecl - Represents a class definition - this is where @@ -1152,10 +1166,9 @@ public: return ivar_begin() == ivar_end(); } - static bool classof(const Decl *D) { - return D->getKind() == ObjCImplementation; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCImplementationDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCImplementation; } }; /// ObjCCompatibleAliasDecl - Represents alias of a class. This alias is @@ -1176,10 +1189,9 @@ public: ObjCInterfaceDecl *getClassInterface() { return AliasedClass; } void setClassInterface(ObjCInterfaceDecl *D) { AliasedClass = D; } - static bool classof(const Decl *D) { - return D->getKind() == ObjCCompatibleAlias; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCCompatibleAliasDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCCompatibleAlias; } }; @@ -1294,10 +1306,9 @@ public: return PropertyIvarDecl; } - static bool classof(const Decl *D) { - return D->getKind() == ObjCProperty; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCPropertyDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCProperty; } }; /// ObjCPropertyImplDecl - Represents implementation declaration of a property @@ -1354,10 +1365,9 @@ public: } void setPropertyIvarDecl(ObjCIvarDecl *Ivar) { PropertyIvarDecl = Ivar; } - static bool classof(const Decl *D) { - return D->getKind() == ObjCPropertyImpl; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCPropertyImplDecl *D) { return true; } + static bool classofKind(Decl::Kind K) { return K == ObjCPropertyImpl; } }; } // end namespace clang diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index d8b004a049ce..ced174716c7a 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -247,13 +247,14 @@ public: NamedDecl *getTemplatedDecl() const { return TemplatedDecl; } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() >= TemplateFirst && D->getKind() <= TemplateLast; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const TemplateDecl *D) { return true; } static bool classof(const FunctionTemplateDecl *D) { return true; } static bool classof(const ClassTemplateDecl *D) { return true; } static bool classof(const TemplateTemplateParmDecl *D) { return true; } + static bool classofKind(Kind K) { + return K >= TemplateFirst && K <= TemplateLast; + } protected: NamedDecl *TemplatedDecl; @@ -510,10 +511,9 @@ public: NamedDecl *Decl); // Implement isa/cast/dyncast support - static bool classof(const Decl *D) - { return D->getKind() == FunctionTemplate; } - static bool classof(const FunctionTemplateDecl *D) - { return true; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const FunctionTemplateDecl *D) { return true; } + static bool classofKind(Kind K) { return K == FunctionTemplate; } }; //===----------------------------------------------------------------------===// @@ -634,10 +634,9 @@ public: bool isParameterPack() const { return ParameterPack; } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() == TemplateTypeParm; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const TemplateTypeParmDecl *D) { return true; } + static bool classofKind(Kind K) { return K == TemplateTypeParm; } }; /// NonTypeTemplateParmDecl - Declares a non-type template parameter, @@ -682,10 +681,9 @@ public: } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() == NonTypeTemplateParm; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const NonTypeTemplateParmDecl *D) { return true; } + static bool classofKind(Kind K) { return K == NonTypeTemplateParm; } }; /// TemplateTemplateParmDecl - Declares a template template parameter, @@ -735,10 +733,9 @@ public: } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() == TemplateTemplateParm; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const TemplateTemplateParmDecl *D) { return true; } + static bool classofKind(Kind K) { return K == TemplateTemplateParm; } }; /// \brief Represents a class template specialization, which refers to @@ -903,9 +900,10 @@ public: TemplateArgs[Arg].Profile(ID, Context); } - static bool classof(const Decl *D) { - return D->getKind() == ClassTemplateSpecialization || - D->getKind() == ClassTemplatePartialSpecialization; + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K == ClassTemplateSpecialization || + K == ClassTemplatePartialSpecialization; } static bool classof(const ClassTemplateSpecializationDecl *) { @@ -1039,8 +1037,9 @@ public: // FIXME: Add Profile support! - static bool classof(const Decl *D) { - return D->getKind() == ClassTemplatePartialSpecialization; + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K == ClassTemplatePartialSpecialization; } static bool classof(const ClassTemplatePartialSpecializationDecl *) { @@ -1212,10 +1211,9 @@ public: } // Implement isa/cast/dyncast support - static bool classof(const Decl *D) - { return D->getKind() == ClassTemplate; } - static bool classof(const ClassTemplateDecl *D) - { return true; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ClassTemplateDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ClassTemplate; } virtual void Destroy(ASTContext& C); }; @@ -1293,9 +1291,8 @@ public: } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() == Decl::FriendTemplate; - } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Decl::FriendTemplate; } static bool classof(const FriendTemplateDecl *D) { return true; } }; diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h index 59d7e439e570..2254724410d0 100644 --- a/include/clang/AST/DeclarationName.h +++ b/include/clang/AST/DeclarationName.h @@ -274,30 +274,34 @@ public: static DeclarationName getTombstoneMarker() { return DeclarationName(uintptr_t(-2)); } + + static int compare(DeclarationName LHS, DeclarationName RHS); void dump() const; }; /// Ordering on two declaration names. If both names are identifiers, /// this provides a lexicographical ordering. -bool operator<(DeclarationName LHS, DeclarationName RHS); +inline bool operator<(DeclarationName LHS, DeclarationName RHS) { + return DeclarationName::compare(LHS, RHS) < 0; +} /// Ordering on two declaration names. If both names are identifiers, /// this provides a lexicographical ordering. inline bool operator>(DeclarationName LHS, DeclarationName RHS) { - return RHS < LHS; + return DeclarationName::compare(LHS, RHS) > 0; } /// Ordering on two declaration names. If both names are identifiers, /// this provides a lexicographical ordering. inline bool operator<=(DeclarationName LHS, DeclarationName RHS) { - return !(RHS < LHS); + return DeclarationName::compare(LHS, RHS) <= 0; } /// Ordering on two declaration names. If both names are identifiers, /// this provides a lexicographical ordering. inline bool operator>=(DeclarationName LHS, DeclarationName RHS) { - return !(LHS < RHS); + return DeclarationName::compare(LHS, RHS) >= 0; } /// DeclarationNameTable - Used to store and retrieve DeclarationName diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 252781767169..114a19800f50 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -149,7 +149,8 @@ public: LV_DuplicateVectorComponents, LV_InvalidExpression, LV_MemberFunction, - LV_SubObjCPropertySetting + LV_SubObjCPropertySetting, + LV_SubObjCPropertyGetterSetting }; isLvalueResult isLvalue(ASTContext &Ctx) const; @@ -179,7 +180,8 @@ public: MLV_ReadonlyProperty, MLV_NoSetterProperty, MLV_MemberFunction, - MLV_SubObjCPropertySetting + MLV_SubObjCPropertySetting, + MLV_SubObjCPropertyGetterSetting }; isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc = 0) const; @@ -192,6 +194,9 @@ public: return const_cast(this)->getBitField(); } + /// \brief Returns whether this expression refers to a vector element. + bool refersToVectorElement() const; + /// isIntegerConstantExpr - Return true if this expression is a valid integer /// constant expression, and, if so, return its value in Result. If not a /// valid i-c-e, return false and fill in Loc (if specified) with the location @@ -563,7 +568,10 @@ public: enum IdentType { Func, Function, - PrettyFunction + PrettyFunction, + /// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the + /// 'virtual' keyword is omitted for virtual member functions. + PrettyFunctionNoVirtual }; private: @@ -584,8 +592,7 @@ public: SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } - static std::string ComputeName(ASTContext &Context, IdentType IT, - const Decl *CurrentDecl); + static std::string ComputeName(IdentType IT, const Decl *CurrentDecl); virtual SourceRange getSourceRange() const { return SourceRange(Loc); } @@ -1745,7 +1752,7 @@ public: static bool classof(const Stmt *T) { StmtClass SC = T->getStmtClass(); - if (SC >= ExplicitCastExprClass && SC <= CStyleCastExprClass) + if (SC >= CStyleCastExprClass && SC <= CStyleCastExprClass) return true; if (SC >= CXXNamedCastExprClass && SC <= CXXFunctionalCastExprClass) return true; diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 6ce95ac5227f..e4bc4b746439 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -241,10 +241,17 @@ public: CXXBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) : Expr(CXXBoolLiteralExprClass, Ty, false, false), Value(val), Loc(l) {} + explicit CXXBoolLiteralExpr(EmptyShell Empty) + : Expr(CXXBoolLiteralExprClass, Empty) { } + bool getValue() const { return Value; } + void setValue(bool V) { Value = V; } virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXBoolLiteralExprClass; } @@ -262,8 +269,14 @@ public: CXXNullPtrLiteralExpr(QualType Ty, SourceLocation l) : Expr(CXXNullPtrLiteralExprClass, Ty, false, false), Loc(l) {} + explicit CXXNullPtrLiteralExpr(EmptyShell Empty) + : Expr(CXXNullPtrLiteralExprClass, Empty) { } + virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXNullPtrLiteralExprClass; } @@ -544,6 +557,68 @@ public: virtual child_iterator child_end(); }; +/// CXXBindReferenceExpr - Represents binding an expression to a reference. +/// In the example: +/// +/// const int &i = 10; +/// +/// a bind reference expression is inserted to indicate that 10 is bound to +/// a reference. (Ans also that a temporary needs to be created to hold the +/// value). +class CXXBindReferenceExpr : public Expr { + // SubExpr - The expression being bound. + Stmt *SubExpr; + + // ExtendsLifetime - Whether binding this reference extends the lifetime of + // the expression being bound. FIXME: Add C++ reference. + bool ExtendsLifetime; + + /// RequiresTemporaryCopy - Whether binding the subexpression requires a + /// temporary copy. + bool RequiresTemporaryCopy; + + CXXBindReferenceExpr(Expr *subexpr, bool ExtendsLifetime, + bool RequiresTemporaryCopy) + : Expr(CXXBindReferenceExprClass, subexpr->getType(), false, false), + SubExpr(subexpr), ExtendsLifetime(ExtendsLifetime), + RequiresTemporaryCopy(RequiresTemporaryCopy) { } + ~CXXBindReferenceExpr() { } + +protected: + virtual void DoDestroy(ASTContext &C); + +public: + static CXXBindReferenceExpr *Create(ASTContext &C, Expr *SubExpr, + bool ExtendsLifetime, + bool RequiresTemporaryCopy); + + const Expr *getSubExpr() const { return cast(SubExpr); } + Expr *getSubExpr() { return cast(SubExpr); } + void setSubExpr(Expr *E) { SubExpr = E; } + + virtual SourceRange getSourceRange() const { + return SubExpr->getSourceRange(); + } + + /// requiresTemporaryCopy - Whether binding the subexpression requires a + /// temporary copy. + bool requiresTemporaryCopy() const { return RequiresTemporaryCopy; } + + // extendsLifetime - Whether binding this reference extends the lifetime of + // the expression being bound. FIXME: Add C++ reference. + bool extendsLifetime() { return ExtendsLifetime; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXBindReferenceExprClass; + } + static bool classof(const CXXBindReferenceExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + /// CXXConstructExpr - Represents a call to a C++ constructor. class CXXConstructExpr : public Expr { CXXConstructorDecl *Constructor; @@ -551,6 +626,7 @@ class CXXConstructExpr : public Expr { SourceLocation Loc; bool Elidable : 1; bool ZeroInitialization : 1; + bool BaseInitialization : 1; Stmt **Args; unsigned NumArgs; @@ -559,7 +635,8 @@ protected: SourceLocation Loc, CXXConstructorDecl *d, bool elidable, Expr **args, unsigned numargs, - bool ZeroInitialization = false); + bool ZeroInitialization = false, + bool BaseInitialization = false); ~CXXConstructExpr() { } virtual void DoDestroy(ASTContext &C); @@ -573,7 +650,8 @@ public: SourceLocation Loc, CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs, - bool ZeroInitialization = false); + bool ZeroInitialization = false, + bool BaseInitialization = false); CXXConstructorDecl* getConstructor() const { return Constructor; } @@ -593,6 +671,11 @@ public: ZeroInitialization = ZeroInit; } + /// \brief Determines whether this constructor is actually constructing + /// a base class (rather than a complete object). + bool isBaseInitialization() const { return BaseInitialization; } + void setBaseInitialization(bool BI) { BaseInitialization = BI; } + typedef ExprIterator arg_iterator; typedef ConstExprIterator const_arg_iterator; @@ -779,15 +862,14 @@ class CXXNewExpr : public Expr { SourceLocation EndLoc; public: - CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, Expr **placementArgs, - unsigned numPlaceArgs, bool ParenTypeId, Expr *arraySize, - CXXConstructorDecl *constructor, bool initializer, + CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, + Expr **placementArgs, unsigned numPlaceArgs, bool ParenTypeId, + Expr *arraySize, CXXConstructorDecl *constructor, bool initializer, Expr **constructorArgs, unsigned numConsArgs, FunctionDecl *operatorDelete, QualType ty, SourceLocation startLoc, SourceLocation endLoc); - ~CXXNewExpr() { - delete[] SubExprs; - } + + virtual void DoDestroy(ASTContext &C); QualType getAllocatedType() const { assert(getType()->isPointerType()); @@ -1059,33 +1141,123 @@ public: virtual child_iterator child_end(); }; -/// \brief A reference to a name which we were able to look up during -/// parsing but could not resolve to a specific declaration. This -/// arises in several ways: -/// * we might be waiting for argument-dependent lookup -/// * the name might resolve to an overloaded function -/// and eventually: -/// * the lookup might have included a function template -/// These never include UnresolvedUsingValueDecls, which are always -/// class members and therefore appear only in -/// UnresolvedMemberLookupExprs. -class UnresolvedLookupExpr : public Expr { +/// \brief A reference to an overloaded function set, either an +/// \t UnresolvedLookupExpr or an \t UnresolvedMemberExpr. +class OverloadExpr : public Expr { /// The results. These are undesugared, which is to say, they may - /// include UsingShadowDecls. + /// include UsingShadowDecls. Access is relative to the naming + /// class. UnresolvedSet<4> Results; - /// The name declared. + /// The common name of these declarations. DeclarationName Name; - /// The qualifier given, if any. + /// The scope specifier, if any. NestedNameSpecifier *Qualifier; - - /// The source range of the nested name specifier. + + /// The source range of the scope specifier. SourceRange QualifierRange; /// The location of the name. SourceLocation NameLoc; + /// True if the name was a template-id. + bool HasExplicitTemplateArgs; + +protected: + OverloadExpr(StmtClass K, QualType T, bool Dependent, + NestedNameSpecifier *Qualifier, SourceRange QRange, + DeclarationName Name, SourceLocation NameLoc, + bool HasTemplateArgs) + : Expr(K, T, Dependent, Dependent), + Name(Name), Qualifier(Qualifier), QualifierRange(QRange), + NameLoc(NameLoc), HasExplicitTemplateArgs(HasTemplateArgs) + {} + +public: + /// Computes whether an unresolved lookup on the given declarations + /// and optional template arguments is type- and value-dependent. + static bool ComputeDependence(UnresolvedSetIterator Begin, + UnresolvedSetIterator End, + const TemplateArgumentListInfo *Args); + + /// Finds the overloaded expression in the given expression of + /// OverloadTy. + /// + /// \return the expression (which must be there) and true if it is + /// within an address-of operator. + static llvm::PointerIntPair find(Expr *E) { + assert(E->getType()->isSpecificBuiltinType(BuiltinType::Overload)); + + bool op = false; + E = E->IgnoreParens(); + if (isa(E)) + op = true, E = cast(E)->getSubExpr()->IgnoreParens(); + return llvm::PointerIntPair(cast(E), op); + } + + void addDecls(UnresolvedSetIterator Begin, UnresolvedSetIterator End) { + Results.append(Begin, End); + } + + typedef UnresolvedSetImpl::iterator decls_iterator; + decls_iterator decls_begin() const { return Results.begin(); } + decls_iterator decls_end() const { return Results.end(); } + + /// Gets the decls as an unresolved set. + const UnresolvedSetImpl &getDecls() { return Results; } + + /// Gets the number of declarations in the unresolved set. + unsigned getNumDecls() const { return Results.size(); } + + /// Gets the name looked up. + DeclarationName getName() const { return Name; } + void setName(DeclarationName N) { Name = N; } + + /// Gets the location of the name. + SourceLocation getNameLoc() const { return NameLoc; } + void setNameLoc(SourceLocation Loc) { NameLoc = Loc; } + + /// Fetches the nested-name qualifier, if one was given. + NestedNameSpecifier *getQualifier() const { return Qualifier; } + + /// Fetches the range of the nested-name qualifier. + SourceRange getQualifierRange() const { return QualifierRange; } + + /// \brief Determines whether this expression had an explicit + /// template argument list, e.g. f. + bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; } + + ExplicitTemplateArgumentList &getExplicitTemplateArgs(); // defined far below + + const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const { + return const_cast(this)->getExplicitTemplateArgs(); + } + + ExplicitTemplateArgumentList *getOptionalExplicitTemplateArgs() { + if (hasExplicitTemplateArgs()) + return &getExplicitTemplateArgs(); + return 0; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnresolvedLookupExprClass || + T->getStmtClass() == UnresolvedMemberExprClass; + } + static bool classof(const OverloadExpr *) { return true; } +}; + +/// \brief A reference to a name which we were able to look up during +/// parsing but could not resolve to a specific declaration. This +/// arises in several ways: +/// * we might be waiting for argument-dependent lookup +/// * the name might resolve to an overloaded function +/// and eventually: +/// * the lookup might have included a function template +/// These never include UnresolvedUsingValueDecls, which are always +/// class members and therefore appear only in +/// UnresolvedMemberLookupExprs. +class UnresolvedLookupExpr : public OverloadExpr { /// True if these lookup results should be extended by /// argument-dependent lookup if this is the operand of a function /// call. @@ -1095,35 +1267,40 @@ class UnresolvedLookupExpr : public Expr { /// trivially rederivable if we urgently need to kill this field. bool Overloaded; - /// True if the name looked up had explicit template arguments. - /// This requires all the results to be function templates. - bool HasExplicitTemplateArgs; + /// The naming class (C++ [class.access.base]p5) of the lookup, if + /// any. This can generally be recalculated from the context chain, + /// but that can be fairly expensive for unqualified lookups. If we + /// want to improve memory use here, this could go in a union + /// against the qualified-lookup bits. + CXXRecordDecl *NamingClass; - UnresolvedLookupExpr(QualType T, bool Dependent, + UnresolvedLookupExpr(QualType T, bool Dependent, CXXRecordDecl *NamingClass, NestedNameSpecifier *Qualifier, SourceRange QRange, DeclarationName Name, SourceLocation NameLoc, bool RequiresADL, bool Overloaded, bool HasTemplateArgs) - : Expr(UnresolvedLookupExprClass, T, Dependent, Dependent), - Name(Name), Qualifier(Qualifier), QualifierRange(QRange), - NameLoc(NameLoc), RequiresADL(RequiresADL), Overloaded(Overloaded), - HasExplicitTemplateArgs(HasTemplateArgs) + : OverloadExpr(UnresolvedLookupExprClass, T, Dependent, Qualifier, QRange, + Name, NameLoc, HasTemplateArgs), + RequiresADL(RequiresADL), Overloaded(Overloaded), NamingClass(NamingClass) {} public: static UnresolvedLookupExpr *Create(ASTContext &C, bool Dependent, + CXXRecordDecl *NamingClass, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, DeclarationName Name, SourceLocation NameLoc, bool ADL, bool Overloaded) { return new(C) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy, - Dependent, Qualifier, QualifierRange, + Dependent, NamingClass, + Qualifier, QualifierRange, Name, NameLoc, ADL, Overloaded, false); } static UnresolvedLookupExpr *Create(ASTContext &C, bool Dependent, + CXXRecordDecl *NamingClass, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, DeclarationName Name, @@ -1131,20 +1308,6 @@ public: bool ADL, const TemplateArgumentListInfo &Args); - /// Computes whether an unresolved lookup on the given declarations - /// and optional template arguments is type- and value-dependent. - static bool ComputeDependence(UnresolvedSetImpl::const_iterator Begin, - UnresolvedSetImpl::const_iterator End, - const TemplateArgumentListInfo *Args); - - void addDecl(NamedDecl *Decl) { - Results.addDecl(Decl); - } - - typedef UnresolvedSetImpl::iterator decls_iterator; - decls_iterator decls_begin() const { return Results.begin(); } - decls_iterator decls_end() const { return Results.end(); } - /// True if this declaration should be extended by /// argument-dependent lookup. bool requiresADL() const { return RequiresADL; } @@ -1152,25 +1315,20 @@ public: /// True if this lookup is overloaded. bool isOverloaded() const { return Overloaded; } - /// Fetches the name looked up. - DeclarationName getName() const { return Name; } - - /// Gets the location of the name. - SourceLocation getNameLoc() const { return NameLoc; } - - /// Fetches the nested-name qualifier, if one was given. - NestedNameSpecifier *getQualifier() const { return Qualifier; } - - /// Fetches the range of the nested-name qualifier. - SourceRange getQualifierRange() const { return QualifierRange; } - - /// Determines whether this lookup had explicit template arguments. - bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; } + /// Gets the 'naming class' (in the sense of C++0x + /// [class.access.base]p5) of the lookup. This is the scope + /// that was looked in to find these results. + CXXRecordDecl *getNamingClass() const { return NamingClass; } // Note that, inconsistently with the explicit-template-argument AST // nodes, users are *forbidden* from calling these methods on objects // without explicit template arguments. + ExplicitTemplateArgumentList &getExplicitTemplateArgs() { + assert(hasExplicitTemplateArgs()); + return *reinterpret_cast(this + 1); + } + /// Gets a reference to the explicit template argument list. const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const { assert(hasExplicitTemplateArgs()); @@ -1200,8 +1358,8 @@ public: } virtual SourceRange getSourceRange() const { - SourceRange Range(NameLoc); - if (Qualifier) Range.setBegin(QualifierRange.getBegin()); + SourceRange Range(getNameLoc()); + if (getQualifier()) Range.setBegin(getQualifierRange().getBegin()); if (hasExplicitTemplateArgs()) Range.setEnd(getRAngleLoc()); return Range; } @@ -1456,11 +1614,24 @@ public: arg_iterator arg_begin() { return reinterpret_cast(this + 1); } arg_iterator arg_end() { return arg_begin() + NumArgs; } + typedef const Expr* const * const_arg_iterator; + const_arg_iterator arg_begin() const { + return reinterpret_cast(this + 1); + } + const_arg_iterator arg_end() const { + return arg_begin() + NumArgs; + } + Expr *getArg(unsigned I) { assert(I < NumArgs && "Argument index out-of-range"); return *(arg_begin() + I); } + const Expr *getArg(unsigned I) const { + assert(I < NumArgs && "Argument index out-of-range"); + return *(arg_begin() + I); + } + virtual SourceRange getSourceRange() const { return SourceRange(TyBeginLoc, RParenLoc); } @@ -1713,19 +1884,7 @@ public: /// In the final AST, an explicit access always becomes a MemberExpr. /// An implicit access may become either a MemberExpr or a /// DeclRefExpr, depending on whether the member is static. -class UnresolvedMemberExpr : public Expr { - /// The results. These are undesugared, which is to say, they may - /// include UsingShadowDecls. - UnresolvedSet<4> Results; - - /// \brief The expression for the base pointer or class reference, - /// e.g., the \c x in x.f. This can be null if this is an 'unbased' - /// member expression - Stmt *Base; - - /// \brief The type of the base expression; never null. - QualType BaseType; - +class UnresolvedMemberExpr : public OverloadExpr { /// \brief Whether this member expression used the '->' operator or /// the '.' operator. bool IsArrow : 1; @@ -1734,39 +1893,17 @@ class UnresolvedMemberExpr : public Expr { /// declaration. bool HasUnresolvedUsing : 1; - /// \brief Whether this member expression has explicitly-specified template - /// arguments. - bool HasExplicitTemplateArgs : 1; + /// \brief The expression for the base pointer or class reference, + /// e.g., the \c x in x.f. This can be null if this is an 'unbased' + /// member expression + Stmt *Base; + + /// \brief The type of the base expression; never null. + QualType BaseType; /// \brief The location of the '->' or '.' operator. SourceLocation OperatorLoc; - /// \brief The nested-name-specifier that precedes the member name, if any. - NestedNameSpecifier *Qualifier; - - /// \brief The source range covering the nested name specifier. - SourceRange QualifierRange; - - /// \brief The member to which this member expression refers, which - /// can be a name or an overloaded operator. - DeclarationName MemberName; - - /// \brief The location of the member name. - SourceLocation MemberLoc; - - /// \brief Retrieve the explicit template argument list that followed the - /// member template name. - ExplicitTemplateArgumentList *getExplicitTemplateArgs() { - assert(HasExplicitTemplateArgs); - return reinterpret_cast(this + 1); - } - - /// \brief Retrieve the explicit template argument list that followed the - /// member template name, if any. - const ExplicitTemplateArgumentList *getExplicitTemplateArgs() const { - return const_cast(this)->getExplicitTemplateArgs(); - } - UnresolvedMemberExpr(QualType T, bool Dependent, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, @@ -1788,19 +1925,6 @@ public: SourceLocation MemberLoc, const TemplateArgumentListInfo *TemplateArgs); - /// Adds a declaration to the unresolved set. By assumption, all of - /// these happen at initialization time and properties like - /// 'Dependent' and 'HasUnresolvedUsing' take them into account. - void addDecl(NamedDecl *Decl) { - Results.addDecl(Decl); - } - - typedef UnresolvedSetImpl::iterator decls_iterator; - decls_iterator decls_begin() const { return Results.begin(); } - decls_iterator decls_end() const { return Results.end(); } - - unsigned getNumDecls() const { return Results.size(); } - /// \brief True if this is an implicit access, i.e. one in which the /// member being accessed was not written in the source. The source /// location of the operator is invalid in this case. @@ -1812,6 +1936,10 @@ public: assert(!isImplicitAccess()); return cast(Base); } + const Expr *getBase() const { + assert(!isImplicitAccess()); + return cast(Base); + } void setBase(Expr *E) { Base = E; } QualType getBaseType() const { return BaseType; } @@ -1825,57 +1953,60 @@ public: SourceLocation getOperatorLoc() const { return OperatorLoc; } void setOperatorLoc(SourceLocation L) { OperatorLoc = L; } - /// \brief Retrieve the nested-name-specifier that qualifies the member - /// name. - NestedNameSpecifier *getQualifier() const { return Qualifier; } - - /// \brief Retrieve the source range covering the nested-name-specifier - /// that qualifies the member name. - SourceRange getQualifierRange() const { return QualifierRange; } + /// \brief Retrieves the naming class of this lookup. + CXXRecordDecl *getNamingClass() const; /// \brief Retrieve the name of the member that this expression /// refers to. - DeclarationName getMemberName() const { return MemberName; } - void setMemberName(DeclarationName N) { MemberName = N; } + DeclarationName getMemberName() const { return getName(); } + void setMemberName(DeclarationName N) { setName(N); } // \brief Retrieve the location of the name of the member that this // expression refers to. - SourceLocation getMemberLoc() const { return MemberLoc; } - void setMemberLoc(SourceLocation L) { MemberLoc = L; } + SourceLocation getMemberLoc() const { return getNameLoc(); } + void setMemberLoc(SourceLocation L) { setNameLoc(L); } - /// \brief Determines whether this member expression actually had a C++ - /// template argument list explicitly specified, e.g., x.f. - bool hasExplicitTemplateArgs() const { - return HasExplicitTemplateArgs; + /// \brief Retrieve the explicit template argument list that followed the + /// member template name. + ExplicitTemplateArgumentList &getExplicitTemplateArgs() { + assert(hasExplicitTemplateArgs()); + return *reinterpret_cast(this + 1); + } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const { + assert(hasExplicitTemplateArgs()); + return *reinterpret_cast(this + 1); } /// \brief Copies the template arguments into the given structure. void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { - getExplicitTemplateArgs()->copyInto(List); + getExplicitTemplateArgs().copyInto(List); } /// \brief Retrieve the location of the left angle bracket following /// the member name ('<'). SourceLocation getLAngleLoc() const { - return getExplicitTemplateArgs()->LAngleLoc; + return getExplicitTemplateArgs().LAngleLoc; } /// \brief Retrieve the template arguments provided as part of this /// template-id. const TemplateArgumentLoc *getTemplateArgs() const { - return getExplicitTemplateArgs()->getTemplateArgs(); + return getExplicitTemplateArgs().getTemplateArgs(); } /// \brief Retrieve the number of template arguments provided as /// part of this template-id. unsigned getNumTemplateArgs() const { - return getExplicitTemplateArgs()->NumTemplateArgs; + return getExplicitTemplateArgs().NumTemplateArgs; } /// \brief Retrieve the location of the right angle bracket /// following the template arguments ('>'). SourceLocation getRAngleLoc() const { - return getExplicitTemplateArgs()->RAngleLoc; + return getExplicitTemplateArgs().RAngleLoc; } virtual SourceRange getSourceRange() const { @@ -1885,12 +2016,12 @@ public: else if (getQualifier()) Range.setBegin(getQualifierRange().getBegin()); else - Range.setBegin(MemberLoc); + Range.setBegin(getMemberLoc()); if (hasExplicitTemplateArgs()) Range.setEnd(getRAngleLoc()); else - Range.setEnd(MemberLoc); + Range.setEnd(getMemberLoc()); return Range; } @@ -1904,6 +2035,13 @@ public: virtual child_iterator child_end(); }; +inline ExplicitTemplateArgumentList &OverloadExpr::getExplicitTemplateArgs() { + if (isa(this)) + return cast(this)->getExplicitTemplateArgs(); + else + return cast(this)->getExplicitTemplateArgs(); +} + } // end namespace clang #endif diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index 0b0cd64ad721..df39b535eb3e 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -367,7 +367,7 @@ class ObjCMessageExpr : public Expr { public: /// This constructor is used to represent class messages where the /// ObjCInterfaceDecl* of the receiver is not known. - ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, + ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName, Selector selInfo, QualType retType, ObjCMethodDecl *methDecl, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned NumArgs); @@ -375,13 +375,13 @@ public: /// This constructor is used to represent class messages where the /// ObjCInterfaceDecl* of the receiver is known. // FIXME: clsName should be typed to ObjCInterfaceType - ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo, + ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls, Selector selInfo, QualType retType, ObjCMethodDecl *methDecl, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned NumArgs); // constructor for instance messages. - ObjCMessageExpr(Expr *receiver, Selector selInfo, + ObjCMessageExpr(ASTContext &C, Expr *receiver, Selector selInfo, QualType retType, ObjCMethodDecl *methDecl, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned NumArgs); @@ -389,9 +389,7 @@ public: explicit ObjCMessageExpr(EmptyShell Empty) : Expr(ObjCMessageExprClass, Empty), SubExprs(0), NumArgs(0) {} - ~ObjCMessageExpr() { - delete [] SubExprs; - } + virtual void DoDestroy(ASTContext &C); /// getReceiver - Returns the receiver of the message expression. /// This can be NULL if the message is for class methods. For diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index d058f838a008..94caa6faad66 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -102,6 +102,7 @@ public: #define LAST_STMT(CLASS) lastStmtConstant = CLASS##Class, #define FIRST_EXPR(CLASS) firstExprConstant = CLASS##Class, #define LAST_EXPR(CLASS) lastExprConstant = CLASS##Class +#define ABSTRACT_EXPR(CLASS, PARENT) #include "clang/AST/StmtNodes.def" }; private: @@ -1120,21 +1121,27 @@ class AsmStmt : public Stmt { unsigned NumOutputs; unsigned NumInputs; + unsigned NumClobbers; - llvm::SmallVector Names; - llvm::SmallVector Constraints; - llvm::SmallVector Exprs; + // FIXME: If we wanted to, we could allocate all of these in one big array. + IdentifierInfo **Names; + StringLiteral **Constraints; + Stmt **Exprs; + StringLiteral **Clobbers; - llvm::SmallVector Clobbers; +protected: + virtual void DoDestroy(ASTContext &Ctx); + public: - AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile, bool msasm, - unsigned numoutputs, unsigned numinputs, - std::string *names, StringLiteral **constraints, + AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, bool isvolatile, + bool msasm, unsigned numoutputs, unsigned numinputs, + IdentifierInfo **names, StringLiteral **constraints, Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, StringLiteral **clobbers, SourceLocation rparenloc); /// \brief Build an empty inline-assembly statement. - explicit AsmStmt(EmptyShell Empty) : Stmt(AsmStmtClass, Empty) { } + explicit AsmStmt(EmptyShell Empty) : Stmt(AsmStmtClass, Empty), + Names(0), Constraints(0), Exprs(0), Clobbers(0) { } SourceLocation getAsmLoc() const { return AsmLoc; } void setAsmLoc(SourceLocation L) { AsmLoc = L; } @@ -1208,14 +1215,21 @@ public: unsigned getNumOutputs() const { return NumOutputs; } - const std::string &getOutputName(unsigned i) const { + IdentifierInfo *getOutputIdentifier(unsigned i) const { return Names[i]; } + llvm::StringRef getOutputName(unsigned i) const { + if (IdentifierInfo *II = getOutputIdentifier(i)) + return II->getName(); + + return llvm::StringRef(); + } + /// getOutputConstraint - Return the constraint string for the specified /// output operand. All output constraints are known to be non-empty (either /// '=' or '+'). - std::string getOutputConstraint(unsigned i) const; + llvm::StringRef getOutputConstraint(unsigned i) const; const StringLiteral *getOutputConstraintLiteral(unsigned i) const { return Constraints[i]; @@ -1224,7 +1238,6 @@ public: return Constraints[i]; } - Expr *getOutputExpr(unsigned i); const Expr *getOutputExpr(unsigned i) const { @@ -1246,13 +1259,20 @@ public: unsigned getNumInputs() const { return NumInputs; } - const std::string &getInputName(unsigned i) const { + IdentifierInfo *getInputIdentifier(unsigned i) const { return Names[i + NumOutputs]; } + llvm::StringRef getInputName(unsigned i) const { + if (IdentifierInfo *II = getInputIdentifier(i)) + return II->getName(); + + return llvm::StringRef(); + } + /// getInputConstraint - Return the specified input constraint. Unlike output /// constraints, these can be empty. - std::string getInputConstraint(unsigned i) const; + llvm::StringRef getInputConstraint(unsigned i) const; const StringLiteral *getInputConstraintLiteral(unsigned i) const { return Constraints[i + NumOutputs]; @@ -1261,32 +1281,31 @@ public: return Constraints[i + NumOutputs]; } - Expr *getInputExpr(unsigned i); const Expr *getInputExpr(unsigned i) const { return const_cast(this)->getInputExpr(i); } - void setOutputsAndInputs(unsigned NumOutputs, - unsigned NumInputs, - const std::string *Names, - StringLiteral **Constraints, - Stmt **Exprs); + void setOutputsAndInputsAndClobbers(ASTContext &C, + IdentifierInfo **Names, + StringLiteral **Constraints, + Stmt **Exprs, + unsigned NumOutputs, + unsigned NumInputs, + StringLiteral **Clobbers, + unsigned NumClobbers); //===--- Other ---===// /// getNamedOperand - Given a symbolic operand reference like %[foo], /// translate this into a numeric value needed to reference the same operand. /// This returns -1 if the operand name is invalid. - int getNamedOperand(const std::string &SymbolicName) const; - + int getNamedOperand(llvm::StringRef SymbolicName) const; - - unsigned getNumClobbers() const { return Clobbers.size(); } + unsigned getNumClobbers() const { return NumClobbers; } StringLiteral *getClobber(unsigned i) { return Clobbers[i]; } const StringLiteral *getClobber(unsigned i) const { return Clobbers[i]; } - void setClobbers(StringLiteral **Clobbers, unsigned NumClobbers); virtual SourceRange getSourceRange() const { return SourceRange(AsmLoc, RParenLoc); @@ -1301,19 +1320,19 @@ public: typedef ConstExprIterator const_inputs_iterator; inputs_iterator begin_inputs() { - return Exprs.data() + NumOutputs; + return &Exprs[0] + NumOutputs; } inputs_iterator end_inputs() { - return Exprs.data() + NumOutputs + NumInputs; + return &Exprs[0] + NumOutputs + NumInputs; } const_inputs_iterator begin_inputs() const { - return Exprs.data() + NumOutputs; + return &Exprs[0] + NumOutputs; } const_inputs_iterator end_inputs() const { - return Exprs.data() + NumOutputs + NumInputs; + return &Exprs[0] + NumOutputs + NumInputs; } // Output expr iterators. @@ -1322,27 +1341,17 @@ public: typedef ConstExprIterator const_outputs_iterator; outputs_iterator begin_outputs() { - return Exprs.data(); + return &Exprs[0]; } outputs_iterator end_outputs() { - return Exprs.data() + NumOutputs; + return &Exprs[0] + NumOutputs; } const_outputs_iterator begin_outputs() const { - return Exprs.data(); + return &Exprs[0]; } const_outputs_iterator end_outputs() const { - return Exprs.data() + NumOutputs; - } - - // Input name iterator. - - const std::string *begin_output_names() const { - return &Names[0]; - } - - const std::string *end_output_names() const { - return &Names[0] + NumOutputs; + return &Exprs[0] + NumOutputs; } // Child iterators diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h index 09ea4ca2101b..4e87c2701c26 100644 --- a/include/clang/AST/StmtCXX.h +++ b/include/clang/AST/StmtCXX.h @@ -59,31 +59,42 @@ public: /// class CXXTryStmt : public Stmt { SourceLocation TryLoc; - // First place is the guarded CompoundStatement. Subsequent are the handlers. - // More than three handlers should be rare. - llvm::SmallVector Stmts; + unsigned NumHandlers; + + CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, Stmt **handlers, + unsigned numHandlers); public: - CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, - Stmt **handlers, unsigned numHandlers); + static CXXTryStmt *Create(ASTContext &C, SourceLocation tryLoc, + Stmt *tryBlock, Stmt **handlers, + unsigned numHandlers); virtual SourceRange getSourceRange() const { return SourceRange(getTryLoc(), getEndLoc()); } SourceLocation getTryLoc() const { return TryLoc; } - SourceLocation getEndLoc() const { return Stmts.back()->getLocEnd(); } + SourceLocation getEndLoc() const { + Stmt const * const*Stmts = reinterpret_cast(this + 1); + return Stmts[NumHandlers]->getLocEnd(); + } - CompoundStmt *getTryBlock() { return llvm::cast(Stmts[0]); } + CompoundStmt *getTryBlock() { + Stmt **Stmts = reinterpret_cast(this + 1); + return llvm::cast(Stmts[0]); + } const CompoundStmt *getTryBlock() const { + Stmt const * const*Stmts = reinterpret_cast(this + 1); return llvm::cast(Stmts[0]); } - unsigned getNumHandlers() const { return Stmts.size() - 1; } + unsigned getNumHandlers() const { return NumHandlers; } CXXCatchStmt *getHandler(unsigned i) { + Stmt **Stmts = reinterpret_cast(this + 1); return llvm::cast(Stmts[i + 1]); } const CXXCatchStmt *getHandler(unsigned i) const { + Stmt const * const*Stmts = reinterpret_cast(this + 1); return llvm::cast(Stmts[i + 1]); } diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index 7102336180cf..ec6149e55f11 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -68,8 +68,7 @@ STMT(CXXTryStmt , Stmt) LAST_STMT(CXXTryStmt) // Expressions. -ABSTRACT_EXPR(Expr , Stmt) -FIRST_EXPR(Expr) +ABSTRACT_EXPR(Expr , Stmt) EXPR(PredefinedExpr , Expr) EXPR(DeclRefExpr , Expr) EXPR(IntegerLiteral , Expr) @@ -83,12 +82,12 @@ EXPR(SizeOfAlignOfExpr , Expr) EXPR(ArraySubscriptExpr , Expr) EXPR(CallExpr , Expr) EXPR(MemberExpr , Expr) -EXPR(CastExpr , Expr) +ABSTRACT_EXPR(CastExpr , Expr) EXPR(BinaryOperator , Expr) EXPR(CompoundAssignOperator, BinaryOperator) EXPR(ConditionalOperator , Expr) EXPR(ImplicitCastExpr , CastExpr) -EXPR(ExplicitCastExpr , CastExpr) +ABSTRACT_EXPR(ExplicitCastExpr, CastExpr) EXPR(CStyleCastExpr , ExplicitCastExpr) EXPR(CompoundLiteralExpr , Expr) EXPR(ExtVectorElementExpr , Expr) @@ -129,6 +128,7 @@ EXPR(UnaryTypeTraitExpr , Expr) EXPR(DependentScopeDeclRefExpr , Expr) EXPR(CXXConstructExpr , Expr) EXPR(CXXBindTemporaryExpr , Expr) +EXPR(CXXBindReferenceExpr , Expr) EXPR(CXXExprWithTemporaries , Expr) EXPR(CXXTemporaryObjectExpr , CXXConstructExpr) EXPR(CXXUnresolvedConstructExpr, Expr) @@ -152,6 +152,7 @@ EXPR(ShuffleVectorExpr , Expr) EXPR(BlockExpr , Expr) EXPR(BlockDeclRefExpr , Expr) +FIRST_EXPR(PredefinedExpr) LAST_EXPR(BlockDeclRefExpr) #undef ABSTRACT_EXPR diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h index 3a525507dad3..4986f08ac124 100644 --- a/include/clang/AST/StmtVisitor.h +++ b/include/clang/AST/StmtVisitor.h @@ -105,6 +105,7 @@ public: // Top switch stmt: dispatch to VisitFooStmt for each FooStmt. switch (S->getStmtClass()) { default: assert(0 && "Unknown stmt kind!"); +#define ABSTRACT_EXPR(CLASS, PARENT) #define STMT(CLASS, PARENT) \ case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS); #include "clang/AST/StmtNodes.def" diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index b7b60df5acb4..40e50988e6d2 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -16,6 +16,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/Linkage.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateName.h" #include "llvm/Support/Casting.h" @@ -750,24 +751,22 @@ class Type { public: enum TypeClass { #define TYPE(Class, Base) Class, +#define LAST_TYPE(Class) TypeLast = Class, #define ABSTRACT_TYPE(Class, Base) #include "clang/AST/TypeNodes.def" TagFirst = Record, TagLast = Enum }; -protected: - enum { TypeClassBitSize = 6 }; - private: QualType CanonicalType; - /// Dependent - Whether this type is a dependent type (C++ [temp.dep.type]). - bool Dependent : 1; - /// TypeClass bitfield - Enum that specifies what subclass this belongs to. + unsigned TC : 8; + + /// Dependent - Whether this type is a dependent type (C++ [temp.dep.type]). /// Note that this should stay at the end of the ivars for Type so that /// subclasses can pack their bitfields into the same word. - unsigned TC : TypeClassBitSize; + bool Dependent : 1; Type(const Type&); // DO NOT IMPLEMENT. void operator=(const Type&); // DO NOT IMPLEMENT. @@ -776,7 +775,7 @@ protected: Type *this_() { return this; } Type(TypeClass tc, QualType Canonical, bool dependent) : CanonicalType(Canonical.isNull() ? QualType(this_(), 0) : Canonical), - Dependent(dependent), TC(tc) {} + TC(tc), Dependent(dependent) {} virtual ~Type() {} virtual void Destroy(ASTContext& C); friend class ASTContext; @@ -974,6 +973,9 @@ public: const char *getTypeClassName() const; + /// \brief Determine the linkage of this type. + virtual Linkage getLinkage() const; + QualType getCanonicalTypeInternal() const { return CanonicalType; } void dump() const; static bool classof(const Type *) { return true; } @@ -1062,6 +1064,8 @@ public: return TypeKind >= Float && TypeKind <= LongDouble; } + virtual Linkage getLinkage() const; + static bool classof(const Type *T) { return T->getTypeClass() == Builtin; } static bool classof(const BuiltinType *) { return true; } }; @@ -1089,6 +1093,8 @@ public: ID.AddPointer(Element.getAsOpaquePtr()); } + virtual Linkage getLinkage() const; + static bool classof(const Type *T) { return T->getTypeClass() == Complex; } static bool classof(const ComplexType *) { return true; } }; @@ -1116,6 +1122,8 @@ public: ID.AddPointer(Pointee.getAsOpaquePtr()); } + virtual Linkage getLinkage() const; + static bool classof(const Type *T) { return T->getTypeClass() == Pointer; } static bool classof(const PointerType *) { return true; } }; @@ -1146,6 +1154,8 @@ public: ID.AddPointer(Pointee.getAsOpaquePtr()); } + virtual Linkage getLinkage() const; + static bool classof(const Type *T) { return T->getTypeClass() == BlockPointer; } @@ -1183,7 +1193,8 @@ protected: } public: bool isSpelledAsLValue() const { return SpelledAsLValue; } - + bool isInnerRef() const { return InnerRef; } + QualType getPointeeTypeAsWritten() const { return PointeeType; } QualType getPointeeType() const { // FIXME: this might strip inner qualifiers; okay? @@ -1203,6 +1214,8 @@ public: ID.AddBoolean(SpelledAsLValue); } + virtual Linkage getLinkage() const; + static bool classof(const Type *T) { return T->getTypeClass() == LValueReference || T->getTypeClass() == RValueReference; @@ -1277,6 +1290,8 @@ public: ID.AddPointer(Class); } + virtual Linkage getLinkage() const; + static bool classof(const Type *T) { return T->getTypeClass() == MemberPointer; } @@ -1328,6 +1343,8 @@ public: } unsigned getIndexTypeCVRQualifiers() const { return IndexTypeQuals; } + virtual Linkage getLinkage() const; + static bool classof(const Type *T) { return T->getTypeClass() == ConstantArray || T->getTypeClass() == VariableArray || @@ -1576,7 +1593,8 @@ public: /// VectorType - GCC generic vector type. This type is created using /// __attribute__((vector_size(n)), where "n" specifies the vector size in -/// bytes. Since the constructor takes the number of vector elements, the +/// bytes; or from an Altivec __vector or vector declaration. +/// Since the constructor takes the number of vector elements, the /// client is responsible for converting the size into the number of elements. class VectorType : public Type, public llvm::FoldingSetNode { protected: @@ -1586,13 +1604,21 @@ protected: /// NumElements - The number of elements in the vector. unsigned NumElements; - VectorType(QualType vecType, unsigned nElements, QualType canonType) : + /// AltiVec - True if this is for an Altivec vector. + bool AltiVec; + + /// Pixel - True if this is for an Altivec vector pixel. + bool Pixel; + + VectorType(QualType vecType, unsigned nElements, QualType canonType, + bool isAltiVec, bool isPixel) : Type(Vector, canonType, vecType->isDependentType()), - ElementType(vecType), NumElements(nElements) {} + ElementType(vecType), NumElements(nElements), + AltiVec(isAltiVec), Pixel(isPixel) {} VectorType(TypeClass tc, QualType vecType, unsigned nElements, - QualType canonType) + QualType canonType, bool isAltiVec, bool isPixel) : Type(tc, canonType, vecType->isDependentType()), ElementType(vecType), - NumElements(nElements) {} + NumElements(nElements), AltiVec(isAltiVec), Pixel(isPixel) {} friend class ASTContext; // ASTContext creates these. public: @@ -1602,15 +1628,26 @@ public: bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } + bool isAltiVec() const { return AltiVec; } + + bool isPixel() const { return Pixel; } + void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getElementType(), getNumElements(), getTypeClass()); + Profile(ID, getElementType(), getNumElements(), getTypeClass(), + AltiVec, Pixel); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType, - unsigned NumElements, TypeClass TypeClass) { + unsigned NumElements, TypeClass TypeClass, + bool isAltiVec, bool isPixel) { ID.AddPointer(ElementType.getAsOpaquePtr()); ID.AddInteger(NumElements); ID.AddInteger(TypeClass); + ID.AddBoolean(isAltiVec); + ID.AddBoolean(isPixel); } + + virtual Linkage getLinkage() const; + static bool classof(const Type *T) { return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector; } @@ -1624,7 +1661,7 @@ public: /// points, colors, and textures (modeled after OpenGL Shading Language). class ExtVectorType : public VectorType { ExtVectorType(QualType vecType, unsigned nElements, QualType canonType) : - VectorType(ExtVector, vecType, nElements, canonType) {} + VectorType(ExtVector, vecType, nElements, canonType, false, false) {} friend class ASTContext; // ASTContext creates these. public: static int getPointAccessorIdx(char c) { @@ -1723,6 +1760,8 @@ public: bool getNoReturnAttr() const { return NoReturn; } CallingConv getCallConv() const { return (CallingConv)CallConv; } + static llvm::StringRef getNameForCallConv(CallingConv CC); + static bool classof(const Type *T) { return T->getTypeClass() == FunctionNoProto || T->getTypeClass() == FunctionProto; @@ -1745,14 +1784,17 @@ public: QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getResultType(), getNoReturnAttr()); + Profile(ID, getResultType(), getNoReturnAttr(), getCallConv()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType, - bool NoReturn) { + bool NoReturn, CallingConv CallConv) { + ID.AddInteger(CallConv); ID.AddInteger(NoReturn); ID.AddPointer(ResultType.getAsOpaquePtr()); } + virtual Linkage getLinkage() const; + static bool classof(const Type *T) { return T->getTypeClass() == FunctionNoProto; } @@ -1856,6 +1898,8 @@ public: bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } + virtual Linkage getLinkage() const; + static bool classof(const Type *T) { return T->getTypeClass() == FunctionProto; } @@ -1867,7 +1911,7 @@ public: bool isVariadic, unsigned TypeQuals, bool hasExceptionSpec, bool anyExceptionSpec, unsigned NumExceptions, exception_iterator Exs, - bool NoReturn); + bool NoReturn, CallingConv CallConv); }; @@ -1878,8 +1922,9 @@ public: class UnresolvedUsingType : public Type { UnresolvedUsingTypenameDecl *Decl; - UnresolvedUsingType(UnresolvedUsingTypenameDecl *D) - : Type(UnresolvedUsing, QualType(), true), Decl(D) {} + UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D) + : Type(UnresolvedUsing, QualType(), true), + Decl(const_cast(D)) {} friend class ASTContext; // ASTContext creates these. public: @@ -1906,8 +1951,9 @@ public: class TypedefType : public Type { TypedefDecl *Decl; protected: - TypedefType(TypeClass tc, TypedefDecl *D, QualType can) - : Type(tc, can, can->isDependentType()), Decl(D) { + TypedefType(TypeClass tc, const TypedefDecl *D, QualType can) + : Type(tc, can, can->isDependentType()), + Decl(const_cast(D)) { assert(!isa(can) && "Invalid canonical type"); } friend class ASTContext; // ASTContext creates these. @@ -1950,8 +1996,12 @@ public: static bool classof(const TypeOfExprType *) { return true; } }; -/// Subclass of TypeOfExprType that is used for canonical, dependent +/// \brief Internal representation of canonical, dependent /// typeof(expr) types. +/// +/// This class is used internally by the ASTContext to manage +/// canonical, dependent types, only. Clients will only see instances +/// of this class via TypeOfExprType nodes. class DependentTypeOfExprType : public TypeOfExprType, public llvm::FoldingSetNode { ASTContext &Context; @@ -2018,8 +2068,12 @@ public: static bool classof(const DecltypeType *) { return true; } }; -/// Subclass of DecltypeType that is used for canonical, dependent -/// C++0x decltype types. +/// \brief Internal representation of canonical, dependent +/// decltype(expr) types. +/// +/// This class is used internally by the ASTContext to manage +/// canonical, dependent types, only. Clients will only see instances +/// of this class via DecltypeType nodes. class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode { ASTContext &Context; @@ -2048,7 +2102,7 @@ class TagType : public Type { friend class TagDecl; protected: - TagType(TypeClass TC, TagDecl *D, QualType can); + TagType(TypeClass TC, const TagDecl *D, QualType can); public: TagDecl *getDecl() const { return decl.getPointer(); } @@ -2058,6 +2112,8 @@ public: bool isBeingDefined() const { return decl.getInt(); } void setBeingDefined(bool Def) const { decl.setInt(Def? 1 : 0); } + virtual Linkage getLinkage() const; + static bool classof(const Type *T) { return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast; } @@ -2070,10 +2126,10 @@ public: /// to detect TagType objects of structs/unions/classes. class RecordType : public TagType { protected: - explicit RecordType(RecordDecl *D) - : TagType(Record, reinterpret_cast(D), QualType()) { } + explicit RecordType(const RecordDecl *D) + : TagType(Record, reinterpret_cast(D), QualType()) { } explicit RecordType(TypeClass TC, RecordDecl *D) - : TagType(TC, reinterpret_cast(D), QualType()) { } + : TagType(TC, reinterpret_cast(D), QualType()) { } friend class ASTContext; // ASTContext creates these. public: @@ -2103,8 +2159,8 @@ public: /// EnumType - This is a helper class that allows the use of isa/cast/dyncast /// to detect TagType objects of enums. class EnumType : public TagType { - explicit EnumType(EnumDecl *D) - : TagType(Enum, reinterpret_cast(D), QualType()) { } + explicit EnumType(const EnumDecl *D) + : TagType(Enum, reinterpret_cast(D), QualType()) { } friend class ASTContext; // ASTContext creates these. public: @@ -2512,12 +2568,12 @@ public: class ObjCInterfaceType : public Type, public llvm::FoldingSetNode { ObjCInterfaceDecl *Decl; - // List of protocols for this protocol conforming object type - // List is sorted on protocol name. No protocol is enterred more than once. - ObjCProtocolDecl **Protocols; + /// \brief The number of protocols stored after the ObjCInterfaceType node. + /// The list of protocols is sorted on protocol name. No protocol is enterred + /// more than once. unsigned NumProtocols; - ObjCInterfaceType(ASTContext &Ctx, QualType Canonical, ObjCInterfaceDecl *D, + ObjCInterfaceType(QualType Canonical, ObjCInterfaceDecl *D, ObjCProtocolDecl **Protos, unsigned NumP); friend class ASTContext; // ASTContext creates these. public: @@ -2529,14 +2585,20 @@ public: /// interface type, or 0 if there are none. unsigned getNumProtocols() const { return NumProtocols; } + /// \brief Retrieve the Ith protocol. + ObjCProtocolDecl *getProtocol(unsigned I) const { + assert(I < getNumProtocols() && "Out-of-range protocol access"); + return qual_begin()[I]; + } + /// qual_iterator and friends: this provides access to the (potentially empty) /// list of protocols qualifying this interface. typedef ObjCProtocolDecl* const * qual_iterator; qual_iterator qual_begin() const { - return Protocols; + return reinterpret_cast(this + 1); } qual_iterator qual_end() const { - return Protocols ? Protocols + NumProtocols : 0; + return qual_begin() + NumProtocols; } bool qual_empty() const { return NumProtocols == 0; } @@ -2546,7 +2608,10 @@ public: void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, const ObjCInterfaceDecl *Decl, - ObjCProtocolDecl **protocols, unsigned NumProtocols); + ObjCProtocolDecl * const *protocols, + unsigned NumProtocols); + + virtual Linkage getLinkage() const; static bool classof(const Type *T) { return T->getTypeClass() == ObjCInterface; @@ -2562,12 +2627,14 @@ public: class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { QualType PointeeType; // A builtin or interface type. - // List of protocols for this protocol conforming object type - // List is sorted on protocol name. No protocol is entered more than once. - ObjCProtocolDecl **Protocols; + /// \brief The number of protocols stored after the ObjCObjectPointerType + /// node. + /// + /// The list of protocols is sorted on protocol name. No protocol is enterred + /// more than once. unsigned NumProtocols; - ObjCObjectPointerType(ASTContext &Ctx, QualType Canonical, QualType T, + ObjCObjectPointerType(QualType Canonical, QualType T, ObjCProtocolDecl **Protos, unsigned NumP); friend class ASTContext; // ASTContext creates these. @@ -2614,10 +2681,10 @@ public: typedef ObjCProtocolDecl* const * qual_iterator; qual_iterator qual_begin() const { - return Protocols; + return reinterpret_cast (this + 1); } qual_iterator qual_end() const { - return Protocols ? Protocols + NumProtocols : NULL; + return qual_begin() + NumProtocols; } bool qual_empty() const { return NumProtocols == 0; } @@ -2625,12 +2692,21 @@ public: /// interface type, or 0 if there are none. unsigned getNumProtocols() const { return NumProtocols; } + /// \brief Retrieve the Ith protocol. + ObjCProtocolDecl *getProtocol(unsigned I) const { + assert(I < getNumProtocols() && "Out-of-range protocol access"); + return qual_begin()[I]; + } + bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } + virtual Linkage getLinkage() const; + void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, QualType T, - ObjCProtocolDecl **protocols, unsigned NumProtocols); + ObjCProtocolDecl *const *protocols, + unsigned NumProtocols); static bool classof(const Type *T) { return T->getTypeClass() == ObjCObjectPointer; } diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 575011a8724c..9cf2cb7bd773 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -87,6 +87,11 @@ DEPENDENT_TYPE(Typename, Type) TYPE(ObjCInterface, Type) TYPE(ObjCObjectPointer, Type) +#ifdef LAST_TYPE +LAST_TYPE(ObjCObjectPointer) +#undef LAST_TYPE +#endif + // These types are always leaves in the type hierarchy. #ifdef LEAF_TYPE LEAF_TYPE(Enum) diff --git a/include/clang/AST/UnresolvedSet.h b/include/clang/AST/UnresolvedSet.h index 055d15264674..9c59229e3134 100644 --- a/include/clang/AST/UnresolvedSet.h +++ b/include/clang/AST/UnresolvedSet.h @@ -16,7 +16,6 @@ #define LLVM_CLANG_AST_UNRESOLVEDSET_H #include -#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" #include "clang/Basic/Specifiers.h" @@ -24,12 +23,58 @@ namespace clang { class NamedDecl; +/// A POD class for pairing a NamedDecl* with an access specifier. +/// Can be put into unions. +class DeclAccessPair { + NamedDecl *Ptr; // we'd use llvm::PointerUnion, but it isn't trivial + + enum { Mask = 0x3 }; + +public: + static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS) { + DeclAccessPair p; + p.set(D, AS); + return p; + } + + NamedDecl *getDecl() const { + return (NamedDecl*) (~Mask & (uintptr_t) Ptr); + } + AccessSpecifier getAccess() const { + return AccessSpecifier(Mask & (uintptr_t) Ptr); + } + + void setDecl(NamedDecl *D) { + set(D, getAccess()); + } + void setAccess(AccessSpecifier AS) { + set(getDecl(), AS); + } + void set(NamedDecl *D, AccessSpecifier AS) { + Ptr = reinterpret_cast(uintptr_t(AS) | + reinterpret_cast(D)); + } + + operator NamedDecl*() const { return getDecl(); } + NamedDecl *operator->() const { return getDecl(); } +}; +} + +// Take a moment to tell SmallVector that this is POD. +namespace llvm { +template struct isPodLike; +template<> struct isPodLike { + static const bool value = true; +}; +} + +namespace clang { + /// The iterator over UnresolvedSets. Serves as both the const and /// non-const iterator. class UnresolvedSetIterator { - - typedef llvm::PointerIntPair DeclEntry; - typedef llvm::SmallVectorImpl DeclsTy; +private: + typedef llvm::SmallVectorImpl DeclsTy; typedef DeclsTy::iterator IteratorTy; IteratorTy ir; @@ -47,8 +92,8 @@ public: typedef NamedDecl *reference; typedef std::iterator_traits::iterator_category iterator_category; - NamedDecl *getDecl() const { return ir->getPointer(); } - AccessSpecifier getAccess() const { return AccessSpecifier(ir->getInt()); } + NamedDecl *getDecl() const { return ir->getDecl(); } + AccessSpecifier getAccess() const { return ir->getAccess(); } NamedDecl *operator*() const { return getDecl(); } @@ -87,7 +132,6 @@ public: /// in a lot of places, but isn't really worth breaking into its own /// header right now. class UnresolvedSetImpl { - typedef UnresolvedSetIterator::DeclEntry DeclEntry; typedef UnresolvedSetIterator::DeclsTy DeclsTy; // Don't allow direct construction, and only permit subclassing by @@ -114,7 +158,7 @@ public: } void addDecl(NamedDecl *D, AccessSpecifier AS) { - decls().push_back(DeclEntry(D, AS)); + decls().push_back(DeclAccessPair::make(D, AS)); } /// Replaces the given declaration with the new one, once. @@ -122,19 +166,24 @@ public: /// \return true if the set changed bool replace(const NamedDecl* Old, NamedDecl *New) { for (DeclsTy::iterator I = decls().begin(), E = decls().end(); I != E; ++I) - if (I->getPointer() == Old) - return (I->setPointer(New), true); + if (I->getDecl() == Old) + return (I->setDecl(New), true); return false; } /// Replaces the declaration at the given iterator with the new one, /// preserving the original access bits. void replace(iterator I, NamedDecl *New) { - I.ir->setPointer(New); + I.ir->setDecl(New); } void replace(iterator I, NamedDecl *New, AccessSpecifier AS) { - *I.ir = DeclEntry(New, AS); + I.ir->set(New, AS); + } + + void erase(unsigned I) { + decls()[I] = decls().back(); + decls().pop_back(); } void erase(iterator I) { @@ -142,6 +191,10 @@ public: decls().pop_back(); } + void setAccess(iterator I, AccessSpecifier AS) { + I.ir->setAccess(AS); + } + void clear() { decls().clear(); } void set_size(unsigned N) { decls().set_size(N); } @@ -152,41 +205,8 @@ public: decls().append(I.ir, E.ir); } - /// A proxy reference for implementing operator[]. - class Proxy { - DeclEntry &Ref; - - friend class UnresolvedSetImpl; - Proxy(DeclEntry &Ref) : Ref(Ref) {} - - public: - NamedDecl *getDecl() const { return Ref.getPointer(); } - void setDecl(NamedDecl *D) { Ref.setPointer(D); } - - AccessSpecifier getAccess() const { return AccessSpecifier(Ref.getInt()); } - void setAccess(AccessSpecifier AS) const { Ref.setInt(AS); } - - NamedDecl* operator->() const { return getDecl(); } - operator NamedDecl*() const { return getDecl(); } - Proxy &operator=(const Proxy &D) { Ref = D.Ref; return *this; } - }; - Proxy operator[](unsigned I) { return Proxy(decls()[I]); } - - /// A proxy reference for implementing operator[] const. - class ConstProxy { - const DeclEntry &Ref; - - friend class UnresolvedSetImpl; - ConstProxy(const DeclEntry &Ref) : Ref(Ref) {} - - public: - NamedDecl *getDecl() const { return Ref.getPointer(); } - AccessSpecifier getAccess() const { return AccessSpecifier(Ref.getInt()); } - - NamedDecl *operator->() const { return getDecl(); } - operator NamedDecl*() const { return getDecl(); } - }; - ConstProxy operator[](unsigned I) const { return ConstProxy(decls()[I]); } + DeclAccessPair &operator[](unsigned I) { return decls()[I]; } + const DeclAccessPair &operator[](unsigned I) const { return decls()[I]; } private: // These work because the only permitted subclass is UnresolvedSetImpl @@ -202,7 +222,7 @@ private: /// A set of unresolved declarations template class UnresolvedSet : public UnresolvedSetImpl { - llvm::SmallVector Decls; + llvm::SmallVector Decls; }; diff --git a/include/clang/Analysis/Analyses/PrintfFormatString.h b/include/clang/Analysis/Analyses/PrintfFormatString.h new file mode 100644 index 000000000000..a4ad0b703708 --- /dev/null +++ b/include/clang/Analysis/Analyses/PrintfFormatString.h @@ -0,0 +1,279 @@ +//==- PrintfFormatStrings.h - Analysis of printf format strings --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Handling of format string in printf and friends. The structure of format +// strings for fprintf() are described in C99 7.19.6.1. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FPRINTF_FORMAT_H +#define LLVM_CLANG_FPRINTF_FORMAT_H + +#include "clang/AST/CanonicalType.h" + +namespace clang { + +class ASTContext; + +namespace analyze_printf { + +class ArgTypeResult { +public: + enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CStrTy, + WCStrTy }; +private: + const Kind K; + QualType T; + ArgTypeResult(bool) : K(InvalidTy) {} +public: + ArgTypeResult(Kind k = UnknownTy) : K(k) {} + ArgTypeResult(QualType t) : K(SpecificTy), T(t) {} + ArgTypeResult(CanQualType t) : K(SpecificTy), T(t) {} + + static ArgTypeResult Invalid() { return ArgTypeResult(true); } + + bool isValid() const { return K != InvalidTy; } + + const QualType *getSpecificType() const { + return K == SpecificTy ? &T : 0; + } + + bool matchesType(ASTContext &C, QualType argTy) const; + + bool matchesAnyObjCObjectRef() const { return K == ObjCPointerTy; } + + QualType getRepresentativeType(ASTContext &C) const; +}; + +class ConversionSpecifier { +public: + enum Kind { + InvalidSpecifier = 0, + // C99 conversion specifiers. + dArg, // 'd' + iArg, // 'i', + oArg, // 'o', + uArg, // 'u', + xArg, // 'x', + XArg, // 'X', + fArg, // 'f', + FArg, // 'F', + eArg, // 'e', + EArg, // 'E', + gArg, // 'g', + GArg, // 'G', + aArg, // 'a', + AArg, // 'A', + IntAsCharArg, // 'c' + CStrArg, // 's' + VoidPtrArg, // 'p' + OutIntPtrArg, // 'n' + PercentArg, // '%' + // Objective-C specific specifiers. + ObjCObjArg, // '@' + // GlibC specific specifiers. + PrintErrno, // 'm' + // Specifier ranges. + IntArgBeg = dArg, + IntArgEnd = iArg, + UIntArgBeg = oArg, + UIntArgEnd = XArg, + DoubleArgBeg = fArg, + DoubleArgEnd = AArg, + C99Beg = IntArgBeg, + C99End = DoubleArgEnd, + ObjCBeg = ObjCObjArg, + ObjCEnd = ObjCObjArg + }; + + ConversionSpecifier() + : Position(0), kind(InvalidSpecifier) {} + + ConversionSpecifier(const char *pos, Kind k) + : Position(pos), kind(k) {} + + const char *getStart() const { + return Position; + } + + llvm::StringRef getCharacters() const { + return llvm::StringRef(getStart(), getLength()); + } + + bool consumesDataArgument() const { + switch (kind) { + case PercentArg: + case PrintErrno: + return false; + default: + return true; + } + } + + bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; } + bool isIntArg() const { return kind >= dArg && kind <= iArg; } + bool isUIntArg() const { return kind >= oArg && kind <= XArg; } + bool isDoubleArg() const { return kind >= fArg && kind <= AArg; } + Kind getKind() const { return kind; } + unsigned getLength() const { + // Conversion specifiers currently only are represented by + // single characters, but we be flexible. + return 1; + } + +private: + const char *Position; + Kind kind; +}; + +enum LengthModifier { + None, + AsChar, // 'hh' + AsShort, // 'h' + AsLong, // 'l' + AsLongLong, // 'll', 'q' (BSD, deprecated) + AsIntMax, // 'j' + AsSizeT, // 'z' + AsPtrDiff, // 't' + AsLongDouble, // 'L' + AsWideChar = AsLong // for '%ls' +}; + +class OptionalAmount { +public: + enum HowSpecified { NotSpecified, Constant, Arg }; + + OptionalAmount(HowSpecified h, const char *st) + : start(st), hs(h), amt(0) {} + + OptionalAmount() + : start(0), hs(NotSpecified), amt(0) {} + + OptionalAmount(unsigned i, const char *st) + : start(st), hs(Constant), amt(i) {} + + HowSpecified getHowSpecified() const { return hs; } + bool hasDataArgument() const { return hs == Arg; } + + unsigned getConstantAmount() const { + assert(hs == Constant); + return amt; + } + + const char *getStart() const { + return start; + } + + ArgTypeResult getArgType(ASTContext &Ctx) const; + +private: + const char *start; + HowSpecified hs; + unsigned amt; +}; + +class FormatSpecifier { + LengthModifier LM; + unsigned IsLeftJustified : 1; + unsigned HasPlusPrefix : 1; + unsigned HasSpacePrefix : 1; + unsigned HasAlternativeForm : 1; + unsigned HasLeadingZeroes : 1; + unsigned flags : 5; + ConversionSpecifier CS; + OptionalAmount FieldWidth; + OptionalAmount Precision; +public: + FormatSpecifier() : LM(None), + IsLeftJustified(0), HasPlusPrefix(0), HasSpacePrefix(0), + HasAlternativeForm(0), HasLeadingZeroes(0) {} + + static FormatSpecifier Parse(const char *beg, const char *end); + + // Methods for incrementally constructing the FormatSpecifier. + void setConversionSpecifier(const ConversionSpecifier &cs) { + CS = cs; + } + void setLengthModifier(LengthModifier lm) { + LM = lm; + } + void setIsLeftJustified() { IsLeftJustified = 1; } + void setHasPlusPrefix() { HasPlusPrefix = 1; } + void setHasSpacePrefix() { HasSpacePrefix = 1; } + void setHasAlternativeForm() { HasAlternativeForm = 1; } + void setHasLeadingZeros() { HasLeadingZeroes = 1; } + + // Methods for querying the format specifier. + + const ConversionSpecifier &getConversionSpecifier() const { + return CS; + } + + LengthModifier getLengthModifier() const { + return LM; + } + + const OptionalAmount &getFieldWidth() const { + return FieldWidth; + } + + void setFieldWidth(const OptionalAmount &Amt) { + FieldWidth = Amt; + } + + void setPrecision(const OptionalAmount &Amt) { + Precision = Amt; + } + + const OptionalAmount &getPrecision() const { + return Precision; + } + + /// \brief Returns the builtin type that a data argument + /// paired with this format specifier should have. This method + /// will return null if the format specifier does not have + /// a matching data argument or the matching argument matches + /// more than one type. + ArgTypeResult getArgType(ASTContext &Ctx) const; + + bool isLeftJustified() const { return (bool) IsLeftJustified; } + bool hasPlusPrefix() const { return (bool) HasPlusPrefix; } + bool hasAlternativeForm() const { return (bool) HasAlternativeForm; } + bool hasLeadingZeros() const { return (bool) HasLeadingZeroes; } + bool hasSpacePrefix() const { return (bool) HasSpacePrefix; } +}; + +class FormatStringHandler { +public: + FormatStringHandler() {} + virtual ~FormatStringHandler(); + + virtual void HandleIncompleteFormatSpecifier(const char *startSpecifier, + unsigned specifierLen) {} + + virtual void HandleNullChar(const char *nullCharacter) {} + + virtual void + HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) {} + + virtual bool HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + return true; + } +}; + +bool ParseFormatString(FormatStringHandler &H, + const char *beg, const char *end); + +} // end printf namespace +} // end clang namespace +#endif diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h index 2b367b7e37f6..cd771acb06a5 100644 --- a/include/clang/Analysis/Analyses/UninitializedValues.h +++ b/include/clang/Analysis/Analyses/UninitializedValues.h @@ -70,5 +70,8 @@ public: void InitializeValues(const CFG& cfg); }; + +void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags, + bool FullUninitTaint=false); } // end namespace clang #endif diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h new file mode 100644 index 000000000000..ea4f5b20669c --- /dev/null +++ b/include/clang/Analysis/AnalysisContext.h @@ -0,0 +1,260 @@ +//=== AnalysisContext.h - Analysis context for Path Sens analysis --*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines AnalysisContext, a class that manages the analysis context +// data for path sensitive analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H +#define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H + +#include "clang/AST/Decl.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Allocator.h" + +namespace clang { + +class Decl; +class Stmt; +class CFG; +class CFGBlock; +class LiveVariables; +class ParentMap; +class ImplicitParamDecl; +class LocationContextManager; +class StackFrameContext; + +/// AnalysisContext contains the context data for the function or method under +/// analysis. +class AnalysisContext { + const Decl *D; + + // AnalysisContext owns the following data. + CFG *cfg; + LiveVariables *liveness; + ParentMap *PM; + llvm::DenseMap *ReferencedBlockVars; + llvm::BumpPtrAllocator A; + bool AddEHEdges; +public: + AnalysisContext(const Decl *d, bool addehedges = false) + : D(d), cfg(0), liveness(0), PM(0), ReferencedBlockVars(0), + AddEHEdges(addehedges) {} + + ~AnalysisContext(); + + ASTContext &getASTContext() { return D->getASTContext(); } + const Decl *getDecl() { return D; } + /// getAddEHEdges - Return true iff we are adding exceptional edges from + /// callExprs. If this is false, then try/catch statements and blocks + /// reachable from them can appear to be dead in the CFG, analysis passes must + /// cope with that. + bool getAddEHEdges() const { return AddEHEdges; } + Stmt *getBody(); + CFG *getCFG(); + ParentMap &getParentMap(); + LiveVariables *getLiveVariables(); + + typedef const VarDecl * const * referenced_decls_iterator; + + std::pair + getReferencedBlockVars(const BlockDecl *BD); + + /// Return the ImplicitParamDecl* associated with 'self' if this + /// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise. + const ImplicitParamDecl *getSelfDecl() const; +}; + +class AnalysisContextManager { + typedef llvm::DenseMap ContextMap; + ContextMap Contexts; +public: + ~AnalysisContextManager(); + + AnalysisContext *getContext(const Decl *D); + + // Discard all previously created AnalysisContexts. + void clear(); +}; + +class LocationContext : public llvm::FoldingSetNode { +public: + enum ContextKind { StackFrame, Scope, Block }; + +private: + ContextKind Kind; + AnalysisContext *Ctx; + const LocationContext *Parent; + +protected: + LocationContext(ContextKind k, AnalysisContext *ctx, + const LocationContext *parent) + : Kind(k), Ctx(ctx), Parent(parent) {} + +public: + virtual ~LocationContext(); + + ContextKind getKind() const { return Kind; } + + AnalysisContext *getAnalysisContext() const { return Ctx; } + + const LocationContext *getParent() const { return Parent; } + + const Decl *getDecl() const { return getAnalysisContext()->getDecl(); } + + CFG *getCFG() const { return getAnalysisContext()->getCFG(); } + + LiveVariables *getLiveVariables() const { + return getAnalysisContext()->getLiveVariables(); + } + + ParentMap &getParentMap() const { + return getAnalysisContext()->getParentMap(); + } + + const ImplicitParamDecl *getSelfDecl() const { + return Ctx->getSelfDecl(); + } + + const StackFrameContext *getCurrentStackFrame() const; + const StackFrameContext * + getStackFrameForDeclContext(const DeclContext *DC) const; + + virtual void Profile(llvm::FoldingSetNodeID &ID) = 0; + + static bool classof(const LocationContext*) { return true; } + +public: + static void ProfileCommon(llvm::FoldingSetNodeID &ID, + ContextKind ck, + AnalysisContext *ctx, + const LocationContext *parent, + const void* data); +}; + +class StackFrameContext : public LocationContext { + // The callsite where this stack frame is established. + const Stmt *CallSite; + + // The parent block of the callsite. + const CFGBlock *Block; + + // The index of the callsite in the CFGBlock. + unsigned Index; + + friend class LocationContextManager; + StackFrameContext(AnalysisContext *ctx, const LocationContext *parent, + const Stmt *s, const CFGBlock *blk, unsigned idx) + : LocationContext(StackFrame, ctx, parent), CallSite(s), Block(blk), + Index(idx) {} + +public: + ~StackFrameContext() {} + + const Stmt *getCallSite() const { return CallSite; } + + const CFGBlock *getCallSiteBlock() const { return Block; } + + unsigned getIndex() const { return Index; } + + void Profile(llvm::FoldingSetNodeID &ID); + + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, + const LocationContext *parent, const Stmt *s, + const CFGBlock *blk, unsigned idx) { + ProfileCommon(ID, StackFrame, ctx, parent, s); + ID.AddPointer(blk); + ID.AddInteger(idx); + } + + static bool classof(const LocationContext* Ctx) { + return Ctx->getKind() == StackFrame; + } +}; + +class ScopeContext : public LocationContext { + const Stmt *Enter; + + friend class LocationContextManager; + ScopeContext(AnalysisContext *ctx, const LocationContext *parent, + const Stmt *s) + : LocationContext(Scope, ctx, parent), Enter(s) {} + +public: + ~ScopeContext() {} + + void Profile(llvm::FoldingSetNodeID &ID); + + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, + const LocationContext *parent, const Stmt *s) { + ProfileCommon(ID, Scope, ctx, parent, s); + } + + static bool classof(const LocationContext* Ctx) { + return Ctx->getKind() == Scope; + } +}; + +class BlockInvocationContext : public LocationContext { + // FIXME: Add back context-sensivity (we don't want libAnalysis to know + // about MemRegion). + const BlockDecl *BD; + + friend class LocationContextManager; + + BlockInvocationContext(AnalysisContext *ctx, const LocationContext *parent, + const BlockDecl *bd) + : LocationContext(Block, ctx, parent), BD(bd) {} + +public: + ~BlockInvocationContext() {} + + const BlockDecl *getBlockDecl() const { return BD; } + + void Profile(llvm::FoldingSetNodeID &ID); + + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, + const LocationContext *parent, const BlockDecl *bd) { + ProfileCommon(ID, Block, ctx, parent, bd); + } + + static bool classof(const LocationContext* Ctx) { + return Ctx->getKind() == Block; + } +}; + +class LocationContextManager { + llvm::FoldingSet Contexts; +public: + ~LocationContextManager(); + + const StackFrameContext *getStackFrame(AnalysisContext *ctx, + const LocationContext *parent, + const Stmt *s, const CFGBlock *blk, + unsigned idx); + + const ScopeContext *getScope(AnalysisContext *ctx, + const LocationContext *parent, + const Stmt *s); + + /// Discard all previously created LocationContext objects. + void clear(); +private: + template + const LOC *getLocationContext(AnalysisContext *ctx, + const LocationContext *parent, + const DATA *d); +}; + +} // end clang namespace +#endif diff --git a/include/clang/Analysis/LocalCheckers.h b/include/clang/Analysis/LocalCheckers.h deleted file mode 100644 index 9c343e078641..000000000000 --- a/include/clang/Analysis/LocalCheckers.h +++ /dev/null @@ -1,63 +0,0 @@ -//==- LocalCheckers.h - Intra-Procedural+Flow-Sensitive Checkers -*- C++ -*-==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the interface to call a set of intra-procedural (local) -// checkers that use flow/path-sensitive analyses to find bugs. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_LOCALCHECKERS_H -#define LLVM_CLANG_ANALYSIS_LOCALCHECKERS_H - -namespace clang { - -class CFG; -class Decl; -class Diagnostic; -class ASTContext; -class PathDiagnosticClient; -class GRTransferFuncs; -class BugType; -class LangOptions; -class ParentMap; -class LiveVariables; -class BugReporter; -class ObjCImplementationDecl; -class LangOptions; -class GRExprEngine; - -void CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &map, - BugReporter& BR); - -void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags, - bool FullUninitTaint=false); - -GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, - const LangOptions& lopts); - -void CheckObjCDealloc(const ObjCImplementationDecl* D, const LangOptions& L, - BugReporter& BR); - -void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID, - BugReporter& BR); - -void CheckObjCUnusedIvar(const ObjCImplementationDecl *D, BugReporter& BR); - -void RegisterAppleChecks(GRExprEngine& Eng, const Decl &D); -void RegisterExperimentalChecks(GRExprEngine &Eng); -void RegisterExperimentalInternalChecks(GRExprEngine &Eng); - -void CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR); - -void CheckSizeofPointer(const Decl *D, BugReporter &BR); - -void RegisterCallInliner(GRExprEngine &Eng); -} // end namespace clang - -#endif diff --git a/include/clang/Analysis/ManagerRegistry.h b/include/clang/Analysis/ManagerRegistry.h deleted file mode 100644 index 972993855c28..000000000000 --- a/include/clang/Analysis/ManagerRegistry.h +++ /dev/null @@ -1,53 +0,0 @@ -//===-- ManagerRegistry.h - Pluggable analyzer module registry --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the ManagerRegistry and Register* classes. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_MANAGER_REGISTRY_H -#define LLVM_CLANG_ANALYSIS_MANAGER_REGISTRY_H - -#include "clang/Analysis/PathSensitive/GRState.h" - -namespace clang { - -/// ManagerRegistry - This class records manager creators registered at -/// runtime. The information is communicated to AnalysisManager through static -/// members. Better design is expected. - -class ManagerRegistry { -public: - static StoreManagerCreator StoreMgrCreator; - static ConstraintManagerCreator ConstraintMgrCreator; -}; - -/// RegisterConstraintManager - This class is used to setup the constraint -/// manager of the static analyzer. The constructor takes a creator function -/// pointer for creating the constraint manager. -/// -/// It is used like this: -/// -/// class MyConstraintManager {}; -/// ConstraintManager* CreateMyConstraintManager(GRStateManager& statemgr) { -/// return new MyConstraintManager(statemgr); -/// } -/// RegisterConstraintManager X(CreateMyConstraintManager); - -class RegisterConstraintManager { -public: - RegisterConstraintManager(ConstraintManagerCreator CMC) { - assert(ManagerRegistry::ConstraintMgrCreator == 0 - && "ConstraintMgrCreator already set!"); - ManagerRegistry::ConstraintMgrCreator = CMC; - } -}; - -} -#endif diff --git a/include/clang/Analysis/PathDiagnostic.h b/include/clang/Analysis/PathDiagnostic.h deleted file mode 100644 index d380c45480cb..000000000000 --- a/include/clang/Analysis/PathDiagnostic.h +++ /dev/null @@ -1,494 +0,0 @@ -//===--- PathDiagnostic.h - Path-Specific Diagnostic Handling ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the PathDiagnostic-related interfaces. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H -#define LLVM_CLANG_PATH_DIAGNOSTIC_H - -#include "clang/Basic/Diagnostic.h" -#include "llvm/ADT/FoldingSet.h" -#include -#include -#include -#include - -namespace clang { - -class Decl; -class SourceManager; -class Stmt; - -//===----------------------------------------------------------------------===// -// High-level interface for handlers of path-sensitive diagnostics. -//===----------------------------------------------------------------------===// - -class PathDiagnostic; - -class PathDiagnosticClient : public DiagnosticClient { -public: - PathDiagnosticClient() {} - - virtual ~PathDiagnosticClient() {} - - virtual void - FlushDiagnostics(llvm::SmallVectorImpl *FilesMade = 0) = 0; - - void FlushDiagnostics(llvm::SmallVectorImpl &FilesMade) { - FlushDiagnostics(&FilesMade); - } - - virtual llvm::StringRef getName() const = 0; - - virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, - const DiagnosticInfo &Info); - virtual void HandlePathDiagnostic(const PathDiagnostic* D) = 0; - - enum PathGenerationScheme { Minimal, Extensive }; - virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } - virtual bool supportsLogicalOpControlFlow() const { return false; } - virtual bool supportsAllBlockEdges() const { return false; } - virtual bool useVerboseDescription() const { return true; } -}; - -//===----------------------------------------------------------------------===// -// Path-sensitive diagnostics. -//===----------------------------------------------------------------------===// - -class PathDiagnosticRange : public SourceRange { -public: - const bool isPoint; - - PathDiagnosticRange(const SourceRange &R, bool isP = false) - : SourceRange(R), isPoint(isP) {} -}; - -class PathDiagnosticLocation { -private: - enum Kind { RangeK, SingleLocK, StmtK, DeclK } K; - SourceRange R; - const Stmt *S; - const Decl *D; - const SourceManager *SM; -public: - PathDiagnosticLocation() - : K(SingleLocK), S(0), D(0), SM(0) {} - - PathDiagnosticLocation(FullSourceLoc L) - : K(SingleLocK), R(L, L), S(0), D(0), SM(&L.getManager()) {} - - PathDiagnosticLocation(const Stmt *s, const SourceManager &sm) - : K(StmtK), S(s), D(0), SM(&sm) {} - - PathDiagnosticLocation(SourceRange r, const SourceManager &sm) - : K(RangeK), R(r), S(0), D(0), SM(&sm) {} - - PathDiagnosticLocation(const Decl *d, const SourceManager &sm) - : K(DeclK), S(0), D(d), SM(&sm) {} - - bool operator==(const PathDiagnosticLocation &X) const { - return K == X.K && R == X.R && S == X.S && D == X.D; - } - - bool operator!=(const PathDiagnosticLocation &X) const { - return K != X.K || R != X.R || S != X.S || D != X.D;; - } - - PathDiagnosticLocation& operator=(const PathDiagnosticLocation &X) { - K = X.K; - R = X.R; - S = X.S; - D = X.D; - SM = X.SM; - return *this; - } - - bool isValid() const { - return SM != 0; - } - - const SourceManager& getSourceManager() const { assert(isValid());return *SM;} - - FullSourceLoc asLocation() const; - PathDiagnosticRange asRange() const; - const Stmt *asStmt() const { assert(isValid()); return S; } - const Decl *asDecl() const { assert(isValid()); return D; } - - bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; } - - void invalidate() { - *this = PathDiagnosticLocation(); - } - - void flatten(); - - const SourceManager& getManager() const { assert(isValid()); return *SM; } - - void Profile(llvm::FoldingSetNodeID &ID) const; -}; - -class PathDiagnosticLocationPair { -private: - PathDiagnosticLocation Start, End; -public: - PathDiagnosticLocationPair(const PathDiagnosticLocation &start, - const PathDiagnosticLocation &end) - : Start(start), End(end) {} - - const PathDiagnosticLocation &getStart() const { return Start; } - const PathDiagnosticLocation &getEnd() const { return End; } - - void flatten() { - Start.flatten(); - End.flatten(); - } - - void Profile(llvm::FoldingSetNodeID &ID) const { - Start.Profile(ID); - End.Profile(ID); - } -}; - -//===----------------------------------------------------------------------===// -// Path "pieces" for path-sensitive diagnostics. -//===----------------------------------------------------------------------===// - -class PathDiagnosticPiece { -public: - enum Kind { ControlFlow, Event, Macro }; - enum DisplayHint { Above, Below }; - -private: - const std::string str; - std::vector CodeModificationHints; - const Kind kind; - const DisplayHint Hint; - std::vector ranges; - - // Do not implement: - PathDiagnosticPiece(); - PathDiagnosticPiece(const PathDiagnosticPiece &P); - PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P); - -protected: - PathDiagnosticPiece(llvm::StringRef s, Kind k, DisplayHint hint = Below); - - PathDiagnosticPiece(Kind k, DisplayHint hint = Below); - -public: - virtual ~PathDiagnosticPiece(); - - const std::string& getString() const { return str; } - - /// getDisplayHint - Return a hint indicating where the diagnostic should - /// be displayed by the PathDiagnosticClient. - DisplayHint getDisplayHint() const { return Hint; } - - virtual PathDiagnosticLocation getLocation() const = 0; - virtual void flattenLocations() = 0; - - Kind getKind() const { return kind; } - - void addRange(SourceRange R) { ranges.push_back(R); } - - void addRange(SourceLocation B, SourceLocation E) { - ranges.push_back(SourceRange(B,E)); - } - - void addCodeModificationHint(const CodeModificationHint& Hint) { - CodeModificationHints.push_back(Hint); - } - - typedef const SourceRange* range_iterator; - - range_iterator ranges_begin() const { - return ranges.empty() ? NULL : &ranges[0]; - } - - range_iterator ranges_end() const { - return ranges_begin() + ranges.size(); - } - - typedef const CodeModificationHint *code_modifications_iterator; - - code_modifications_iterator code_modifications_begin() const { - return CodeModificationHints.empty()? 0 : &CodeModificationHints[0]; - } - - code_modifications_iterator code_modifications_end() const { - return CodeModificationHints.empty()? 0 - : &CodeModificationHints[0] + CodeModificationHints.size(); - } - - static inline bool classof(const PathDiagnosticPiece* P) { - return true; - } - - virtual void Profile(llvm::FoldingSetNodeID &ID) const; -}; - -class PathDiagnosticSpotPiece : public PathDiagnosticPiece { -private: - PathDiagnosticLocation Pos; -public: - PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos, - llvm::StringRef s, - PathDiagnosticPiece::Kind k, - bool addPosRange = true) - : PathDiagnosticPiece(s, k), Pos(pos) { - assert(Pos.asLocation().isValid() && - "PathDiagnosticSpotPiece's must have a valid location."); - if (addPosRange && Pos.hasRange()) addRange(Pos.asRange()); - } - - PathDiagnosticLocation getLocation() const { return Pos; } - virtual void flattenLocations() { Pos.flatten(); } - - virtual void Profile(llvm::FoldingSetNodeID &ID) const; -}; - -class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { - -public: - PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, - llvm::StringRef s, bool addPosRange = true) - : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {} - - ~PathDiagnosticEventPiece(); - - static inline bool classof(const PathDiagnosticPiece* P) { - return P->getKind() == Event; - } -}; - -class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece { - std::vector LPairs; -public: - PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, - const PathDiagnosticLocation &endPos, - llvm::StringRef s) - : PathDiagnosticPiece(s, ControlFlow) { - LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); - } - - PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, - const PathDiagnosticLocation &endPos) - : PathDiagnosticPiece(ControlFlow) { - LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); - } - - ~PathDiagnosticControlFlowPiece(); - - PathDiagnosticLocation getStartLocation() const { - assert(!LPairs.empty() && - "PathDiagnosticControlFlowPiece needs at least one location."); - return LPairs[0].getStart(); - } - - PathDiagnosticLocation getEndLocation() const { - assert(!LPairs.empty() && - "PathDiagnosticControlFlowPiece needs at least one location."); - return LPairs[0].getEnd(); - } - - void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); } - - virtual PathDiagnosticLocation getLocation() const { - return getStartLocation(); - } - - typedef std::vector::iterator iterator; - iterator begin() { return LPairs.begin(); } - iterator end() { return LPairs.end(); } - - virtual void flattenLocations() { - for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten(); - } - - typedef std::vector::const_iterator - const_iterator; - const_iterator begin() const { return LPairs.begin(); } - const_iterator end() const { return LPairs.end(); } - - static inline bool classof(const PathDiagnosticPiece* P) { - return P->getKind() == ControlFlow; - } - - virtual void Profile(llvm::FoldingSetNodeID &ID) const; -}; - -class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece { - std::vector SubPieces; -public: - PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos) - : PathDiagnosticSpotPiece(pos, "", Macro) {} - - ~PathDiagnosticMacroPiece(); - - bool containsEvent() const; - - void push_back(PathDiagnosticPiece* P) { SubPieces.push_back(P); } - - typedef std::vector::iterator iterator; - iterator begin() { return SubPieces.begin(); } - iterator end() { return SubPieces.end(); } - - virtual void flattenLocations() { - PathDiagnosticSpotPiece::flattenLocations(); - for (iterator I=begin(), E=end(); I!=E; ++I) (*I)->flattenLocations(); - } - - typedef std::vector::const_iterator const_iterator; - const_iterator begin() const { return SubPieces.begin(); } - const_iterator end() const { return SubPieces.end(); } - - static inline bool classof(const PathDiagnosticPiece* P) { - return P->getKind() == Macro; - } - - virtual void Profile(llvm::FoldingSetNodeID &ID) const; -}; - -/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive -/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces, -/// each which represent the pieces of the path. -class PathDiagnostic : public llvm::FoldingSetNode { - std::deque path; - unsigned Size; - std::string BugType; - std::string Desc; - std::string Category; - std::deque OtherDesc; - -public: - PathDiagnostic(); - - PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc, - llvm::StringRef category); - - ~PathDiagnostic(); - - llvm::StringRef getDescription() const { return Desc; } - llvm::StringRef getBugType() const { return BugType; } - llvm::StringRef getCategory() const { return Category; } - - typedef std::deque::const_iterator meta_iterator; - meta_iterator meta_begin() const { return OtherDesc.begin(); } - meta_iterator meta_end() const { return OtherDesc.end(); } - void addMeta(llvm::StringRef s) { OtherDesc.push_back(s); } - - PathDiagnosticLocation getLocation() const { - assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic."); - return rbegin()->getLocation(); - } - - void push_front(PathDiagnosticPiece* piece) { - assert(piece); - path.push_front(piece); - ++Size; - } - - void push_back(PathDiagnosticPiece* piece) { - assert(piece); - path.push_back(piece); - ++Size; - } - - PathDiagnosticPiece* back() { - return path.back(); - } - - const PathDiagnosticPiece* back() const { - return path.back(); - } - - unsigned size() const { return Size; } - bool empty() const { return Size == 0; } - - void resetPath(bool deletePieces = true); - - class iterator { - public: - typedef std::deque::iterator ImplTy; - - typedef PathDiagnosticPiece value_type; - typedef value_type& reference; - typedef value_type* pointer; - typedef ptrdiff_t difference_type; - typedef std::bidirectional_iterator_tag iterator_category; - - private: - ImplTy I; - - public: - iterator(const ImplTy& i) : I(i) {} - - bool operator==(const iterator& X) const { return I == X.I; } - bool operator!=(const iterator& X) const { return I != X.I; } - - PathDiagnosticPiece& operator*() const { return **I; } - PathDiagnosticPiece* operator->() const { return *I; } - - iterator& operator++() { ++I; return *this; } - iterator& operator--() { --I; return *this; } - }; - - class const_iterator { - public: - typedef std::deque::const_iterator ImplTy; - - typedef const PathDiagnosticPiece value_type; - typedef value_type& reference; - typedef value_type* pointer; - typedef ptrdiff_t difference_type; - typedef std::bidirectional_iterator_tag iterator_category; - - private: - ImplTy I; - - public: - const_iterator(const ImplTy& i) : I(i) {} - - bool operator==(const const_iterator& X) const { return I == X.I; } - bool operator!=(const const_iterator& X) const { return I != X.I; } - - reference operator*() const { return **I; } - pointer operator->() const { return *I; } - - const_iterator& operator++() { ++I; return *this; } - const_iterator& operator--() { --I; return *this; } - }; - - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; - - // forward iterator creation methods. - - iterator begin() { return path.begin(); } - iterator end() { return path.end(); } - - const_iterator begin() const { return path.begin(); } - const_iterator end() const { return path.end(); } - - // reverse iterator creation methods. - reverse_iterator rbegin() { return reverse_iterator(end()); } - const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } - reverse_iterator rend() { return reverse_iterator(begin()); } - const_reverse_iterator rend() const { return const_reverse_iterator(begin());} - - void flattenLocations() { - for (iterator I = begin(), E = end(); I != E; ++I) I->flattenLocations(); - } - - void Profile(llvm::FoldingSetNodeID &ID) const; -}; -} //end clang namespace -#endif diff --git a/include/clang/Analysis/PathSensitive/AnalysisContext.h b/include/clang/Analysis/PathSensitive/AnalysisContext.h deleted file mode 100644 index c82bb962fd18..000000000000 --- a/include/clang/Analysis/PathSensitive/AnalysisContext.h +++ /dev/null @@ -1,277 +0,0 @@ -//=== AnalysisContext.h - Analysis context for Path Sens analysis --*- C++ -*-// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines AnalysisContext, a class that manages the analysis context -// data for path sensitive analysis. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H -#define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H - -#include "clang/AST/Decl.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/PointerUnion.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/Support/Allocator.h" - -namespace clang { - -class Decl; -class Stmt; -class CFG; -class CFGBlock; -class LiveVariables; -class ParentMap; -class ImplicitParamDecl; -class LocationContextManager; -class BlockDataRegion; -class StackFrameContext; - -/// AnalysisContext contains the context data for the function or method under -/// analysis. -class AnalysisContext { - const Decl *D; - - // AnalysisContext owns the following data. - CFG *cfg; - LiveVariables *liveness; - ParentMap *PM; - llvm::DenseMap *ReferencedBlockVars; - llvm::BumpPtrAllocator A; - bool AddEHEdges; -public: - AnalysisContext(const Decl *d, bool addehedges = false) - : D(d), cfg(0), liveness(0), PM(0), ReferencedBlockVars(0), - AddEHEdges(addehedges) {} - - ~AnalysisContext(); - - ASTContext &getASTContext() { return D->getASTContext(); } - const Decl *getDecl() { return D; } - /// getAddEHEdges - Return true iff we are adding exceptional edges from - /// callExprs. If this is false, then try/catch statements and blocks - /// reachable from them can appear to be dead in the CFG, analysis passes must - /// cope with that. - bool getAddEHEdges() const { return AddEHEdges; } - Stmt *getBody(); - CFG *getCFG(); - ParentMap &getParentMap(); - LiveVariables *getLiveVariables(); - - typedef const VarDecl * const * referenced_decls_iterator; - - std::pair - getReferencedBlockVars(const BlockDecl *BD); - - /// Return the ImplicitParamDecl* associated with 'self' if this - /// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise. - const ImplicitParamDecl *getSelfDecl() const; -}; - -class AnalysisContextManager { - typedef llvm::DenseMap ContextMap; - ContextMap Contexts; -public: - ~AnalysisContextManager(); - - AnalysisContext *getContext(const Decl *D); - - // Discard all previously created AnalysisContexts. - void clear(); -}; - -class LocationContext : public llvm::FoldingSetNode { -public: - enum ContextKind { StackFrame, Scope, Block }; - -private: - ContextKind Kind; - AnalysisContext *Ctx; - const LocationContext *Parent; - -protected: - LocationContext(ContextKind k, AnalysisContext *ctx, - const LocationContext *parent) - : Kind(k), Ctx(ctx), Parent(parent) {} - -public: - virtual ~LocationContext(); - - ContextKind getKind() const { return Kind; } - - AnalysisContext *getAnalysisContext() const { return Ctx; } - - const LocationContext *getParent() const { return Parent; } - - const Decl *getDecl() const { return getAnalysisContext()->getDecl(); } - - CFG *getCFG() const { return getAnalysisContext()->getCFG(); } - - LiveVariables *getLiveVariables() const { - return getAnalysisContext()->getLiveVariables(); - } - - ParentMap &getParentMap() const { - return getAnalysisContext()->getParentMap(); - } - - const ImplicitParamDecl *getSelfDecl() const { - return Ctx->getSelfDecl(); - } - - const StackFrameContext *getCurrentStackFrame() const; - const StackFrameContext * - getStackFrameForDeclContext(const DeclContext *DC) const; - - virtual void Profile(llvm::FoldingSetNodeID &ID) = 0; - - static bool classof(const LocationContext*) { return true; } - -public: - static void ProfileCommon(llvm::FoldingSetNodeID &ID, - ContextKind ck, - AnalysisContext *ctx, - const LocationContext *parent, - const void* data); -}; - -class StackFrameContext : public LocationContext { - // The callsite where this stack frame is established. - const Stmt *CallSite; - - // The parent block of the callsite. - const CFGBlock *Block; - - // The index of the callsite in the CFGBlock. - unsigned Index; - - friend class LocationContextManager; - StackFrameContext(AnalysisContext *ctx, const LocationContext *parent, - const Stmt *s, const CFGBlock *blk, unsigned idx) - : LocationContext(StackFrame, ctx, parent), CallSite(s), Block(blk), - Index(idx) {} - -public: - ~StackFrameContext() {} - - const Stmt *getCallSite() const { return CallSite; } - - const CFGBlock *getCallSiteBlock() const { return Block; } - - unsigned getIndex() const { return Index; } - - void Profile(llvm::FoldingSetNodeID &ID); - - static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, - const LocationContext *parent, const Stmt *s, - const CFGBlock *blk, unsigned idx) { - ProfileCommon(ID, StackFrame, ctx, parent, s); - ID.AddPointer(blk); - ID.AddInteger(idx); - } - - static bool classof(const LocationContext* Ctx) { - return Ctx->getKind() == StackFrame; - } -}; - -class ScopeContext : public LocationContext { - const Stmt *Enter; - - friend class LocationContextManager; - ScopeContext(AnalysisContext *ctx, const LocationContext *parent, - const Stmt *s) - : LocationContext(Scope, ctx, parent), Enter(s) {} - -public: - ~ScopeContext() {} - - void Profile(llvm::FoldingSetNodeID &ID); - - static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, - const LocationContext *parent, const Stmt *s) { - ProfileCommon(ID, Scope, ctx, parent, s); - } - - static bool classof(const LocationContext* Ctx) { - return Ctx->getKind() == Scope; - } -}; - -class BlockInvocationContext : public LocationContext { - llvm::PointerUnion Data; - - friend class LocationContextManager; - - BlockInvocationContext(AnalysisContext *ctx, const LocationContext *parent, - const BlockDataRegion *br) - : LocationContext(Block, ctx, parent), Data(br) {} - - BlockInvocationContext(AnalysisContext *ctx, const LocationContext *parent, - const BlockDecl *bd) - : LocationContext(Block, ctx, parent), Data(bd) {} - -public: - ~BlockInvocationContext() {} - - const BlockDataRegion *getBlockRegion() const { - return Data.is() ? - Data.get() : 0; - } - - const BlockDecl *getBlockDecl() const; - - void Profile(llvm::FoldingSetNodeID &ID); - - static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, - const LocationContext *parent, const BlockDataRegion *br){ - ProfileCommon(ID, Block, ctx, parent, br); - } - - static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, - const LocationContext *parent, const BlockDecl *bd) { - ProfileCommon(ID, Block, ctx, parent, bd); - } - - static bool classof(const LocationContext* Ctx) { - return Ctx->getKind() == Block; - } -}; - -class LocationContextManager { - llvm::FoldingSet Contexts; -public: - ~LocationContextManager(); - - const StackFrameContext *getStackFrame(AnalysisContext *ctx, - const LocationContext *parent, - const Stmt *s, const CFGBlock *blk, - unsigned idx); - - const ScopeContext *getScope(AnalysisContext *ctx, - const LocationContext *parent, - const Stmt *s); - - const BlockInvocationContext * - getBlockInvocation(AnalysisContext *ctx, const LocationContext *parent, - const BlockDataRegion *BR); - - /// Discard all previously created LocationContext objects. - void clear(); -private: - template - const LOC *getLocationContext(AnalysisContext *ctx, - const LocationContext *parent, - const DATA *d); -}; - -} // end clang namespace -#endif diff --git a/include/clang/Analysis/PathSensitive/AnalysisManager.h b/include/clang/Analysis/PathSensitive/AnalysisManager.h deleted file mode 100644 index 8288864f2b61..000000000000 --- a/include/clang/Analysis/PathSensitive/AnalysisManager.h +++ /dev/null @@ -1,149 +0,0 @@ -//== AnalysisManager.h - Path sensitive analysis data manager ------*- C++ -*-// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the AnalysisManager class that manages the data and policy -// for path sensitive analysis. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_ANALYSISMANAGER_H -#define LLVM_CLANG_ANALYSIS_ANALYSISMANAGER_H - -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/PathSensitive/AnalysisContext.h" -#include "clang/Analysis/PathDiagnostic.h" - -namespace clang { - -class AnalysisManager : public BugReporterData { - AnalysisContextManager AnaCtxMgr; - LocationContextManager LocCtxMgr; - - ASTContext &Ctx; - Diagnostic &Diags; - const LangOptions &LangInfo; - - llvm::OwningPtr PD; - - // Configurable components creators. - StoreManagerCreator CreateStoreMgr; - ConstraintManagerCreator CreateConstraintMgr; - - enum AnalysisScope { ScopeTU, ScopeDecl } AScope; - - bool VisualizeEGDot; - bool VisualizeEGUbi; - bool PurgeDead; - - /// EargerlyAssume - A flag indicating how the engine should handle - // expressions such as: 'x = (y != 0)'. When this flag is true then - // the subexpression 'y != 0' will be eagerly assumed to be true or false, - // thus evaluating it to the integers 0 or 1 respectively. The upside - // is that this can increase analysis precision until we have a better way - // to lazily evaluate such logic. The downside is that it eagerly - // bifurcates paths. - bool EagerlyAssume; - bool TrimGraph; - -public: - AnalysisManager(ASTContext &ctx, Diagnostic &diags, - const LangOptions &lang, PathDiagnosticClient *pd, - StoreManagerCreator storemgr, - ConstraintManagerCreator constraintmgr, - bool vizdot, bool vizubi, bool purge, bool eager, bool trim) - - : Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd), - CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), - AScope(ScopeDecl), - VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge), - EagerlyAssume(eager), TrimGraph(trim) {} - - ~AnalysisManager() { FlushDiagnostics(); } - - void ClearContexts() { - LocCtxMgr.clear(); - AnaCtxMgr.clear(); - } - - StoreManagerCreator getStoreManagerCreator() { - return CreateStoreMgr; - } - - ConstraintManagerCreator getConstraintManagerCreator() { - return CreateConstraintMgr; - } - - virtual ASTContext &getASTContext() { - return Ctx; - } - - virtual SourceManager &getSourceManager() { - return getASTContext().getSourceManager(); - } - - virtual Diagnostic &getDiagnostic() { - return Diags; - } - - const LangOptions &getLangOptions() const { - return LangInfo; - } - - virtual PathDiagnosticClient *getPathDiagnosticClient() { - return PD.get(); - } - - void FlushDiagnostics() { - if (PD.get()) - PD->FlushDiagnostics(); - } - - bool shouldVisualizeGraphviz() const { return VisualizeEGDot; } - - bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; } - - bool shouldVisualize() const { - return VisualizeEGDot || VisualizeEGUbi; - } - - bool shouldTrimGraph() const { return TrimGraph; } - - bool shouldPurgeDead() const { return PurgeDead; } - - bool shouldEagerlyAssume() const { return EagerlyAssume; } - - CFG *getCFG(Decl const *D) { - return AnaCtxMgr.getContext(D)->getCFG(); - } - - LiveVariables *getLiveVariables(Decl const *D) { - return AnaCtxMgr.getContext(D)->getLiveVariables(); - } - - ParentMap &getParentMap(Decl const *D) { - return AnaCtxMgr.getContext(D)->getParentMap(); - } - - // Get the top level stack frame. - const StackFrameContext *getStackFrame(Decl const *D) { - return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), 0, 0, 0, 0); - } - - // Get a stack frame with parent. - StackFrameContext const *getStackFrame(Decl const *D, - LocationContext const *Parent, - Stmt const *S, const CFGBlock *Blk, - unsigned Idx) { - return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), Parent, S, Blk,Idx); - } -}; - -} - -#endif diff --git a/include/clang/Analysis/PathSensitive/BasicValueFactory.h b/include/clang/Analysis/PathSensitive/BasicValueFactory.h deleted file mode 100644 index 12f0ce2d50b7..000000000000 --- a/include/clang/Analysis/PathSensitive/BasicValueFactory.h +++ /dev/null @@ -1,198 +0,0 @@ -//=== BasicValueFactory.h - Basic values for Path Sens analysis --*- C++ -*---// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines BasicValueFactory, a class that manages the lifetime -// of APSInt objects and symbolic constraints used by GRExprEngine -// and related classes. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H -#define LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H - -#include "clang/Analysis/PathSensitive/SymbolManager.h" -#include "clang/Analysis/PathSensitive/SVals.h" -#include "clang/AST/ASTContext.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/APSInt.h" -#include "llvm/ADT/ImmutableList.h" - -namespace clang { - - class GRState; - -class CompoundValData : public llvm::FoldingSetNode { - QualType T; - llvm::ImmutableList L; - -public: - CompoundValData(QualType t, llvm::ImmutableList l) - : T(t), L(l) {} - - typedef llvm::ImmutableList::iterator iterator; - iterator begin() const { return L.begin(); } - iterator end() const { return L.end(); } - - static void Profile(llvm::FoldingSetNodeID& ID, QualType T, - llvm::ImmutableList L); - - void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, T, L); } -}; - -class LazyCompoundValData : public llvm::FoldingSetNode { - const GRState *state; - const TypedRegion *region; -public: - LazyCompoundValData(const GRState *st, const TypedRegion *r) - : state(st), region(r) {} - - const GRState *getState() const { return state; } - const TypedRegion *getRegion() const { return region; } - - static void Profile(llvm::FoldingSetNodeID& ID, const GRState *state, - const TypedRegion *region); - - void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, state, region); } -}; - -class BasicValueFactory { - typedef llvm::FoldingSet > - APSIntSetTy; - - ASTContext& Ctx; - llvm::BumpPtrAllocator& BPAlloc; - - APSIntSetTy APSIntSet; - void* PersistentSVals; - void* PersistentSValPairs; - - llvm::ImmutableList::Factory SValListFactory; - llvm::FoldingSet CompoundValDataSet; - llvm::FoldingSet LazyCompoundValDataSet; - -public: - BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc) - : Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0), - SValListFactory(Alloc) {} - - ~BasicValueFactory(); - - ASTContext& getContext() const { return Ctx; } - - const llvm::APSInt& getValue(const llvm::APSInt& X); - const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned); - const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned); - const llvm::APSInt& getValue(uint64_t X, QualType T); - - /// Convert - Create a new persistent APSInt with the same value as 'From' - /// but with the bitwidth and signedness of 'To'. - const llvm::APSInt &Convert(const llvm::APSInt& To, - const llvm::APSInt& From) { - - if (To.isUnsigned() == From.isUnsigned() && - To.getBitWidth() == From.getBitWidth()) - return From; - - return getValue(From.getSExtValue(), To.getBitWidth(), To.isUnsigned()); - } - - const llvm::APSInt &Convert(QualType T, const llvm::APSInt &From) { - assert(T->isIntegerType() || Loc::IsLocType(T)); - unsigned bitwidth = Ctx.getTypeSize(T); - bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T); - - if (isUnsigned == From.isUnsigned() && bitwidth == From.getBitWidth()) - return From; - - return getValue(From.getSExtValue(), bitwidth, isUnsigned); - } - - const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) { - QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy; - return getValue(X, T); - } - - inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) { - return getValue(llvm::APSInt::getMaxValue(v.getBitWidth(), v.isUnsigned())); - } - - inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) { - return getValue(llvm::APSInt::getMinValue(v.getBitWidth(), v.isUnsigned())); - } - - inline const llvm::APSInt& getMaxValue(QualType T) { - assert(T->isIntegerType() || Loc::IsLocType(T)); - bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T); - return getValue(llvm::APSInt::getMaxValue(Ctx.getTypeSize(T), isUnsigned)); - } - - inline const llvm::APSInt& getMinValue(QualType T) { - assert(T->isIntegerType() || Loc::IsLocType(T)); - bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T); - return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned)); - } - - inline const llvm::APSInt& Add1(const llvm::APSInt& V) { - llvm::APSInt X = V; - ++X; - return getValue(X); - } - - inline const llvm::APSInt& Sub1(const llvm::APSInt& V) { - llvm::APSInt X = V; - --X; - return getValue(X); - } - - inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) { - return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); - } - - inline const llvm::APSInt &getIntWithPtrWidth(uint64_t X, bool isUnsigned) { - return getValue(X, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); - } - - inline const llvm::APSInt& getTruthValue(bool b, QualType T) { - return getValue(b ? 1 : 0, Ctx.getTypeSize(T), false); - } - - inline const llvm::APSInt& getTruthValue(bool b) { - return getTruthValue(b, Ctx.IntTy); - } - - const CompoundValData *getCompoundValData(QualType T, - llvm::ImmutableList Vals); - - const LazyCompoundValData *getLazyCompoundValData(const GRState *state, - const TypedRegion *region); - - llvm::ImmutableList getEmptySValList() { - return SValListFactory.GetEmptyList(); - } - - llvm::ImmutableList consVals(SVal X, llvm::ImmutableList L) { - return SValListFactory.Add(X, L); - } - - const llvm::APSInt* EvaluateAPSInt(BinaryOperator::Opcode Op, - const llvm::APSInt& V1, - const llvm::APSInt& V2); - - const std::pair& - getPersistentSValWithData(const SVal& V, uintptr_t Data); - - const std::pair& - getPersistentSValPair(const SVal& V1, const SVal& V2); - - const SVal* getPersistentSVal(SVal X); -}; - -} // end clang namespace - -#endif diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h deleted file mode 100644 index 6f6681a3629b..000000000000 --- a/include/clang/Analysis/PathSensitive/BugReporter.h +++ /dev/null @@ -1,473 +0,0 @@ -//===--- BugReporter.h - Generate PathDiagnostics --------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines BugReporter, a utility class for generating -// PathDiagnostics for analyses based on GRState. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_BUGREPORTER -#define LLVM_CLANG_ANALYSIS_BUGREPORTER - -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/SourceLocation.h" -#include "clang/Analysis/PathSensitive/GRState.h" -#include "clang/Analysis/PathSensitive/ExplodedGraph.h" -#include "clang/Analysis/PathSensitive/BugType.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/ImmutableSet.h" -#include - -namespace clang { - -class PathDiagnostic; -class PathDiagnosticPiece; -class PathDiagnosticClient; -class ASTContext; -class Diagnostic; -class BugReporter; -class BugReporterContext; -class GRExprEngine; -class GRState; -class Stmt; -class BugType; -class ParentMap; - -//===----------------------------------------------------------------------===// -// Interface for individual bug reports. -//===----------------------------------------------------------------------===// - -class BugReporterVisitor { -public: - virtual ~BugReporterVisitor(); - virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N, - const ExplodedNode* PrevN, - BugReporterContext& BRC) = 0; - - virtual bool isOwnedByReporterContext() { return true; } -}; - -// FIXME: Combine this with RangedBugReport and remove RangedBugReport. -class BugReport : public BugReporterVisitor { -protected: - BugType& BT; - std::string ShortDescription; - std::string Description; - const ExplodedNode *EndNode; - SourceRange R; - -protected: - friend class BugReporter; - friend class BugReportEquivClass; - - virtual void Profile(llvm::FoldingSetNodeID& hash) const { - hash.AddInteger(getLocation().getRawEncoding()); - } - -public: - class NodeResolver { - public: - virtual ~NodeResolver() {} - virtual const ExplodedNode* - getOriginalNode(const ExplodedNode* N) = 0; - }; - - BugReport(BugType& bt, llvm::StringRef desc, const ExplodedNode *n) - : BT(bt), Description(desc), EndNode(n) {} - - BugReport(BugType& bt, llvm::StringRef shortDesc, llvm::StringRef desc, - const ExplodedNode *n) - : BT(bt), ShortDescription(shortDesc), Description(desc), EndNode(n) {} - - virtual ~BugReport(); - - virtual bool isOwnedByReporterContext() { return false; } - - const BugType& getBugType() const { return BT; } - BugType& getBugType() { return BT; } - - // FIXME: Perhaps this should be moved into a subclass? - const ExplodedNode* getEndNode() const { return EndNode; } - - // FIXME: Do we need this? Maybe getLocation() should return a ProgramPoint - // object. - // FIXME: If we do need it, we can probably just make it private to - // BugReporter. - const Stmt* getStmt() const; - - const llvm::StringRef getDescription() const { return Description; } - - const llvm::StringRef getShortDescription() const { - return ShortDescription.empty() ? Description : ShortDescription; - } - - // FIXME: Is this needed? - virtual std::pair getExtraDescriptiveText() { - return std::make_pair((const char**)0,(const char**)0); - } - - // FIXME: Perhaps move this into a subclass. - virtual PathDiagnosticPiece* getEndPath(BugReporterContext& BRC, - const ExplodedNode* N); - - /// getLocation - Return the "definitive" location of the reported bug. - /// While a bug can span an entire path, usually there is a specific - /// location that can be used to identify where the key issue occured. - /// This location is used by clients rendering diagnostics. - virtual SourceLocation getLocation() const; - - /// getRanges - Returns the source ranges associated with this bug. - virtual void getRanges(const SourceRange*& beg, const SourceRange*& end); - - virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N, - const ExplodedNode* PrevN, - BugReporterContext& BR); - - virtual void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N) {} -}; - -//===----------------------------------------------------------------------===// -// BugTypes (collections of related reports). -//===----------------------------------------------------------------------===// - -class BugReportEquivClass : public llvm::FoldingSetNode { - // List of *owned* BugReport objects. - std::list Reports; - - friend class BugReporter; - void AddReport(BugReport* R) { Reports.push_back(R); } -public: - BugReportEquivClass(BugReport* R) { Reports.push_back(R); } - ~BugReportEquivClass(); - - void Profile(llvm::FoldingSetNodeID& ID) const { - assert(!Reports.empty()); - (*Reports.begin())->Profile(ID); - } - - class iterator { - std::list::iterator impl; - public: - iterator(std::list::iterator i) : impl(i) {} - iterator& operator++() { ++impl; return *this; } - bool operator==(const iterator& I) const { return I.impl == impl; } - bool operator!=(const iterator& I) const { return I.impl != impl; } - BugReport* operator*() const { return *impl; } - BugReport* operator->() const { return *impl; } - }; - - class const_iterator { - std::list::const_iterator impl; - public: - const_iterator(std::list::const_iterator i) : impl(i) {} - const_iterator& operator++() { ++impl; return *this; } - bool operator==(const const_iterator& I) const { return I.impl == impl; } - bool operator!=(const const_iterator& I) const { return I.impl != impl; } - const BugReport* operator*() const { return *impl; } - const BugReport* operator->() const { return *impl; } - }; - - iterator begin() { return iterator(Reports.begin()); } - iterator end() { return iterator(Reports.end()); } - - const_iterator begin() const { return const_iterator(Reports.begin()); } - const_iterator end() const { return const_iterator(Reports.end()); } -}; - - -//===----------------------------------------------------------------------===// -// Specialized subclasses of BugReport. -//===----------------------------------------------------------------------===// - -// FIXME: Collapse this with the default BugReport class. -class RangedBugReport : public BugReport { - std::vector Ranges; -public: - RangedBugReport(BugType& D, llvm::StringRef description, ExplodedNode *n) - : BugReport(D, description, n) {} - - RangedBugReport(BugType& D, llvm::StringRef shortDescription, - llvm::StringRef description, ExplodedNode *n) - : BugReport(D, shortDescription, description, n) {} - - ~RangedBugReport(); - - // FIXME: Move this out of line. - void addRange(SourceRange R) { - assert(R.isValid()); - Ranges.push_back(R); - } - - // FIXME: Move this out of line. - void getRanges(const SourceRange*& beg, const SourceRange*& end) { - - if (Ranges.empty()) { - beg = NULL; - end = NULL; - } - else { - beg = &Ranges[0]; - end = beg + Ranges.size(); - } - } -}; - -class EnhancedBugReport : public RangedBugReport { -public: - typedef void (*VisitorCreator)(BugReporterContext &BRcC, const void *data, - const ExplodedNode *N); - -private: - typedef std::vector > Creators; - Creators creators; - -public: - EnhancedBugReport(BugType& D, llvm::StringRef description, ExplodedNode *n) - : RangedBugReport(D, description, n) {} - - EnhancedBugReport(BugType& D, llvm::StringRef shortDescription, - llvm::StringRef description, ExplodedNode *n) - : RangedBugReport(D, shortDescription, description, n) {} - - ~EnhancedBugReport() {} - - void registerInitialVisitors(BugReporterContext& BRC, const ExplodedNode* N) { - for (Creators::iterator I = creators.begin(), E = creators.end(); I!=E; ++I) - I->first(BRC, I->second, N); - } - - void addVisitorCreator(VisitorCreator creator, const void *data) { - creators.push_back(std::make_pair(creator, data)); - } -}; - -//===----------------------------------------------------------------------===// -// BugReporter and friends. -//===----------------------------------------------------------------------===// - -class BugReporterData { -public: - virtual ~BugReporterData(); - virtual Diagnostic& getDiagnostic() = 0; - virtual PathDiagnosticClient* getPathDiagnosticClient() = 0; - virtual ASTContext& getASTContext() = 0; - virtual SourceManager& getSourceManager() = 0; -}; - -class BugReporter { -public: - enum Kind { BaseBRKind, GRBugReporterKind }; - -private: - typedef llvm::ImmutableSet BugTypesTy; - BugTypesTy::Factory F; - BugTypesTy BugTypes; - - const Kind kind; - BugReporterData& D; - - void FlushReport(BugReportEquivClass& EQ); - -protected: - BugReporter(BugReporterData& d, Kind k) : BugTypes(F.GetEmptySet()), kind(k), D(d) {} - -public: - BugReporter(BugReporterData& d) : BugTypes(F.GetEmptySet()), kind(BaseBRKind), D(d) {} - virtual ~BugReporter(); - - void FlushReports(); - - Kind getKind() const { return kind; } - - Diagnostic& getDiagnostic() { - return D.getDiagnostic(); - } - - PathDiagnosticClient* getPathDiagnosticClient() { - return D.getPathDiagnosticClient(); - } - - typedef BugTypesTy::iterator iterator; - iterator begin() { return BugTypes.begin(); } - iterator end() { return BugTypes.end(); } - - ASTContext& getContext() { return D.getASTContext(); } - - SourceManager& getSourceManager() { return D.getSourceManager(); } - - virtual void GeneratePathDiagnostic(PathDiagnostic& PD, - BugReportEquivClass& EQ) {} - - void Register(BugType *BT); - - void EmitReport(BugReport *R); - - void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr, - SourceLocation Loc, - SourceRange* RangeBeg, unsigned NumRanges); - - void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory, - llvm::StringRef BugStr, SourceLocation Loc, - SourceRange* RangeBeg, unsigned NumRanges); - - - void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr, - SourceLocation Loc) { - EmitBasicReport(BugName, BugStr, Loc, 0, 0); - } - - void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory, - llvm::StringRef BugStr, SourceLocation Loc) { - EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0); - } - - void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr, - SourceLocation Loc, SourceRange R) { - EmitBasicReport(BugName, BugStr, Loc, &R, 1); - } - - void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef Category, - llvm::StringRef BugStr, SourceLocation Loc, - SourceRange R) { - EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1); - } - - static bool classof(const BugReporter* R) { return true; } -}; - -// FIXME: Get rid of GRBugReporter. It's the wrong abstraction. -class GRBugReporter : public BugReporter { - GRExprEngine& Eng; - llvm::SmallSet NotableSymbols; -public: - GRBugReporter(BugReporterData& d, GRExprEngine& eng) - : BugReporter(d, GRBugReporterKind), Eng(eng) {} - - virtual ~GRBugReporter(); - - /// getEngine - Return the analysis engine used to analyze a given - /// function or method. - GRExprEngine &getEngine() { return Eng; } - - /// getGraph - Get the exploded graph created by the analysis engine - /// for the analyzed method or function. - ExplodedGraph &getGraph(); - - /// getStateManager - Return the state manager used by the analysis - /// engine. - GRStateManager &getStateManager(); - - virtual void GeneratePathDiagnostic(PathDiagnostic& PD, - BugReportEquivClass& R); - - void addNotableSymbol(SymbolRef Sym) { - NotableSymbols.insert(Sym); - } - - bool isNotable(SymbolRef Sym) const { - return (bool) NotableSymbols.count(Sym); - } - - /// classof - Used by isa<>, cast<>, and dyn_cast<>. - static bool classof(const BugReporter* R) { - return R->getKind() == GRBugReporterKind; - } -}; - -class BugReporterContext { - GRBugReporter &BR; - std::vector Callbacks; -public: - BugReporterContext(GRBugReporter& br) : BR(br) {} - virtual ~BugReporterContext(); - - void addVisitor(BugReporterVisitor* visitor) { - if (visitor) Callbacks.push_back(visitor); - } - - typedef std::vector::iterator visitor_iterator; - visitor_iterator visitor_begin() { return Callbacks.begin(); } - visitor_iterator visitor_end() { return Callbacks.end(); } - - GRBugReporter& getBugReporter() { return BR; } - - ExplodedGraph &getGraph() { return BR.getGraph(); } - - void addNotableSymbol(SymbolRef Sym) { - // FIXME: For now forward to GRBugReporter. - BR.addNotableSymbol(Sym); - } - - bool isNotable(SymbolRef Sym) const { - // FIXME: For now forward to GRBugReporter. - return BR.isNotable(Sym); - } - - GRStateManager& getStateManager() { - return BR.getStateManager(); - } - - ValueManager& getValueManager() { - return getStateManager().getValueManager(); - } - - ASTContext& getASTContext() { - return BR.getContext(); - } - - SourceManager& getSourceManager() { - return BR.getSourceManager(); - } - - virtual BugReport::NodeResolver& getNodeResolver() = 0; -}; - -class DiagBugReport : public RangedBugReport { - std::list Strs; - FullSourceLoc L; -public: - DiagBugReport(BugType& D, llvm::StringRef desc, FullSourceLoc l) : - RangedBugReport(D, desc, 0), L(l) {} - - virtual ~DiagBugReport() {} - - // FIXME: Move out-of-line (virtual function). - SourceLocation getLocation() const { return L; } - - void addString(llvm::StringRef s) { Strs.push_back(s); } - - typedef std::list::const_iterator str_iterator; - str_iterator str_begin() const { return Strs.begin(); } - str_iterator str_end() const { return Strs.end(); } -}; - -//===----------------------------------------------------------------------===// -//===----------------------------------------------------------------------===// - -namespace bugreporter { - -const Stmt *GetDerefExpr(const ExplodedNode *N); -const Stmt *GetReceiverExpr(const ExplodedNode *N); -const Stmt *GetDenomExpr(const ExplodedNode *N); -const Stmt *GetCalleeExpr(const ExplodedNode *N); -const Stmt *GetRetValExpr(const ExplodedNode *N); - -void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt, - const ExplodedNode* N); - -} // end namespace clang::bugreporter - -//===----------------------------------------------------------------------===// - -} // end clang namespace - -#endif diff --git a/include/clang/Analysis/PathSensitive/BugType.h b/include/clang/Analysis/PathSensitive/BugType.h deleted file mode 100644 index b75a8189e54c..000000000000 --- a/include/clang/Analysis/PathSensitive/BugType.h +++ /dev/null @@ -1,76 +0,0 @@ -//===--- BugType.h - Bug Information Desciption ----------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines BugType, a class representing a bug type. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE -#define LLVM_CLANG_ANALYSIS_BUGTYPE - -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include -#include - -namespace clang { - -class BugReportEquivClass; -class BugReporter; -class BuiltinBugReport; -class BugReporterContext; -class ExplodedNode; -class GRExprEngine; - -class BugType { -private: - const std::string Name; - const std::string Category; - llvm::FoldingSet EQClasses; - friend class BugReporter; - bool SuppressonSink; -public: - BugType(llvm::StringRef name, llvm::StringRef cat) - : Name(name), Category(cat), SuppressonSink(false) {} - virtual ~BugType(); - - // FIXME: Should these be made strings as well? - llvm::StringRef getName() const { return Name; } - llvm::StringRef getCategory() const { return Category; } - - /// isSuppressOnSink - Returns true if bug reports associated with this bug - /// type should be suppressed if the end node of the report is post-dominated - /// by a sink node. - bool isSuppressOnSink() const { return SuppressonSink; } - void setSuppressOnSink(bool x) { SuppressonSink = x; } - - virtual void FlushReports(BugReporter& BR); - - typedef llvm::FoldingSet::iterator iterator; - iterator begin() { return EQClasses.begin(); } - iterator end() { return EQClasses.end(); } - - typedef llvm::FoldingSet::const_iterator const_iterator; - const_iterator begin() const { return EQClasses.begin(); } - const_iterator end() const { return EQClasses.end(); } -}; - -class BuiltinBug : public BugType { - const std::string desc; -public: - BuiltinBug(const char *name, const char *description) - : BugType(name, "Logic error"), desc(description) {} - - BuiltinBug(const char *name) - : BugType(name, "Logic error"), desc(name) {} - - llvm::StringRef getDescription() const { return desc; } -}; - -} // end clang namespace -#endif diff --git a/include/clang/Analysis/PathSensitive/Checker.h b/include/clang/Analysis/PathSensitive/Checker.h deleted file mode 100644 index 924a8b11b098..000000000000 --- a/include/clang/Analysis/PathSensitive/Checker.h +++ /dev/null @@ -1,281 +0,0 @@ -//== Checker.h - Abstract interface for checkers -----------------*- C++ -*--=// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines Checker and CheckerVisitor, classes used for creating -// domain-specific checks. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_CHECKER -#define LLVM_CLANG_ANALYSIS_CHECKER -#include "clang/Analysis/Support/SaveAndRestore.h" -#include "clang/Analysis/PathSensitive/GRCoreEngine.h" -#include "clang/Analysis/PathSensitive/GRState.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/AST/ExprCXX.h" -#include "clang/AST/ExprObjC.h" -#include "clang/AST/StmtCXX.h" -#include "clang/AST/StmtObjC.h" - -//===----------------------------------------------------------------------===// -// Checker interface. -//===----------------------------------------------------------------------===// - -namespace clang { - class GRExprEngine; - -class CheckerContext { - ExplodedNodeSet &Dst; - GRStmtNodeBuilder &B; - GRExprEngine &Eng; - ExplodedNode *Pred; - SaveAndRestore OldSink; - SaveAndRestore OldTag; - SaveAndRestore OldPointKind; - SaveOr OldHasGen; - const GRState *ST; - const Stmt *statement; - const unsigned size; - bool DoneEvaluating; // FIXME: This is not a permanent API change. -public: - CheckerContext(ExplodedNodeSet &dst, GRStmtNodeBuilder &builder, - GRExprEngine &eng, ExplodedNode *pred, - const void *tag, ProgramPoint::Kind K, - const Stmt *stmt = 0, const GRState *st = 0) - : Dst(dst), B(builder), Eng(eng), Pred(pred), - OldSink(B.BuildSinks), - OldTag(B.Tag, tag), - OldPointKind(B.PointKind, K), - OldHasGen(B.HasGeneratedNode), - ST(st), statement(stmt), size(Dst.size()) {} - - ~CheckerContext(); - - GRExprEngine &getEngine() { - return Eng; - } - - AnalysisManager &getAnalysisManager() { - return Eng.getAnalysisManager(); - } - - ConstraintManager &getConstraintManager() { - return Eng.getConstraintManager(); - } - - StoreManager &getStoreManager() { - return Eng.getStoreManager(); - } - - ExplodedNodeSet &getNodeSet() { return Dst; } - GRStmtNodeBuilder &getNodeBuilder() { return B; } - ExplodedNode *&getPredecessor() { return Pred; } - const GRState *getState() { return ST ? ST : B.GetState(Pred); } - - ASTContext &getASTContext() { - return Eng.getContext(); - } - - BugReporter &getBugReporter() { - return Eng.getBugReporter(); - } - - SourceManager &getSourceManager() { - return getBugReporter().getSourceManager(); - } - - ValueManager &getValueManager() { - return Eng.getValueManager(); - } - - SValuator &getSValuator() { - return Eng.getSValuator(); - } - - ExplodedNode *GenerateNode(bool autoTransition = true) { - assert(statement && "Only transitions with statements currently supported"); - ExplodedNode *N = GenerateNodeImpl(statement, getState(), false); - if (N && autoTransition) - Dst.Add(N); - return N; - } - - ExplodedNode *GenerateNode(const Stmt *stmt, const GRState *state, - bool autoTransition = true) { - assert(state); - ExplodedNode *N = GenerateNodeImpl(stmt, state, false); - if (N && autoTransition) - addTransition(N); - return N; - } - - ExplodedNode *GenerateNode(const GRState *state, ExplodedNode *pred, - bool autoTransition = true) { - assert(statement && "Only transitions with statements currently supported"); - ExplodedNode *N = GenerateNodeImpl(statement, state, pred, false); - if (N && autoTransition) - addTransition(N); - return N; - } - - ExplodedNode *GenerateNode(const GRState *state, bool autoTransition = true) { - assert(statement && "Only transitions with statements currently supported"); - ExplodedNode *N = GenerateNodeImpl(statement, state, false); - if (N && autoTransition) - addTransition(N); - return N; - } - - ExplodedNode *GenerateSink(const Stmt *stmt, const GRState *state = 0) { - return GenerateNodeImpl(stmt, state ? state : getState(), true); - } - - ExplodedNode *GenerateSink(const GRState *state = 0) { - assert(statement && "Only transitions with statements currently supported"); - return GenerateNodeImpl(statement, state ? state : getState(), true); - } - - void addTransition(ExplodedNode *node) { - Dst.Add(node); - } - - void addTransition(const GRState *state) { - assert(state); - if (state != getState() || (ST && ST != B.GetState(Pred))) - GenerateNode(state, true); - else - Dst.Add(Pred); - } - - void EmitReport(BugReport *R) { - Eng.getBugReporter().EmitReport(R); - } - -private: - ExplodedNode *GenerateNodeImpl(const Stmt* stmt, const GRState *state, - bool markAsSink) { - ExplodedNode *node = B.generateNode(stmt, state, Pred); - if (markAsSink && node) - node->markAsSink(); - return node; - } - - ExplodedNode *GenerateNodeImpl(const Stmt* stmt, const GRState *state, - ExplodedNode *pred, bool markAsSink) { - ExplodedNode *node = B.generateNode(stmt, state, pred); - if (markAsSink && node) - node->markAsSink(); - return node; - } -}; - -class Checker { -private: - friend class GRExprEngine; - - // FIXME: Remove the 'tag' option. - void GR_Visit(ExplodedNodeSet &Dst, - GRStmtNodeBuilder &Builder, - GRExprEngine &Eng, - const Stmt *S, - ExplodedNode *Pred, void *tag, bool isPrevisit) { - CheckerContext C(Dst, Builder, Eng, Pred, tag, - isPrevisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind, S); - if (isPrevisit) - _PreVisit(C, S); - else - _PostVisit(C, S); - } - - bool GR_EvalNilReceiver(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder, - GRExprEngine &Eng, const ObjCMessageExpr *ME, - ExplodedNode *Pred, const GRState *state, void *tag) { - CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind, - ME, state); - return EvalNilReceiver(C, ME); - } - - bool GR_EvalCallExpr(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder, - GRExprEngine &Eng, const CallExpr *CE, - ExplodedNode *Pred, void *tag) { - CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind, - CE); - return EvalCallExpr(C, CE); - } - - // FIXME: Remove the 'tag' option. - void GR_VisitBind(ExplodedNodeSet &Dst, - GRStmtNodeBuilder &Builder, GRExprEngine &Eng, - const Stmt *AssignE, - const Stmt *StoreE, ExplodedNode *Pred, void *tag, - SVal location, SVal val, - bool isPrevisit) { - CheckerContext C(Dst, Builder, Eng, Pred, tag, - isPrevisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind, StoreE); - assert(isPrevisit && "Only previsit supported for now."); - PreVisitBind(C, AssignE, StoreE, location, val); - } - - // FIXME: Remove the 'tag' option. - void GR_VisitLocation(ExplodedNodeSet &Dst, - GRStmtNodeBuilder &Builder, - GRExprEngine &Eng, - const Stmt *S, - ExplodedNode *Pred, const GRState *state, - SVal location, - void *tag, bool isLoad) { - CheckerContext C(Dst, Builder, Eng, Pred, tag, - isLoad ? ProgramPoint::PreLoadKind : - ProgramPoint::PreStoreKind, S, state); - VisitLocation(C, S, location); - } - - void GR_EvalDeadSymbols(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder, - GRExprEngine &Eng, const Stmt *S, ExplodedNode *Pred, - SymbolReaper &SymReaper, void *tag) { - CheckerContext C(Dst, Builder, Eng, Pred, tag, - ProgramPoint::PostPurgeDeadSymbolsKind, S); - EvalDeadSymbols(C, S, SymReaper); - } - -public: - virtual ~Checker(); - virtual void _PreVisit(CheckerContext &C, const Stmt *S) {} - virtual void _PostVisit(CheckerContext &C, const Stmt *S) {} - virtual void VisitLocation(CheckerContext &C, const Stmt *S, SVal location) {} - virtual void PreVisitBind(CheckerContext &C, const Stmt *AssignE, - const Stmt *StoreE, SVal location, SVal val) {} - virtual void EvalDeadSymbols(CheckerContext &C, const Stmt *S, - SymbolReaper &SymReaper) {} - virtual void EvalEndPath(GREndPathNodeBuilder &B, void *tag, - GRExprEngine &Eng) {} - - virtual void VisitBranchCondition(GRBranchNodeBuilder &Builder, - GRExprEngine &Eng, - Stmt *Condition, void *tag) {} - - virtual bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME) { - return false; - } - - virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE) { - return false; - } - - virtual const GRState *EvalAssume(const GRState *state, SVal Cond, - bool Assumption) { - return state; - } -}; -} // end clang namespace - -#endif - diff --git a/include/clang/Analysis/PathSensitive/CheckerVisitor.def b/include/clang/Analysis/PathSensitive/CheckerVisitor.def deleted file mode 100644 index 7ec27efe5199..000000000000 --- a/include/clang/Analysis/PathSensitive/CheckerVisitor.def +++ /dev/null @@ -1,38 +0,0 @@ -//===-- CheckerVisitor.def - Metadata for CheckerVisitor ----------------*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the AST nodes accepted by the CheckerVisitor class. -// -//===---------------------------------------------------------------------===// - -#ifndef PREVISIT -#define PREVISIT(NODE, FALLBACK) -#endif - -#ifndef POSTVISIT -#define POSTVISIT(NODE, FALLBACK) -#endif - -PREVISIT(ArraySubscriptExpr, Stmt) -PREVISIT(BinaryOperator, Stmt) -PREVISIT(CallExpr, Stmt) -PREVISIT(CastExpr, Stmt) -PREVISIT(CXXOperatorCallExpr, CallExpr) -PREVISIT(DeclStmt, Stmt) -PREVISIT(ObjCMessageExpr, Stmt) -PREVISIT(ReturnStmt, Stmt) - -POSTVISIT(BlockExpr, Stmt) -POSTVISIT(BinaryOperator, Stmt) -POSTVISIT(CallExpr, Stmt) -POSTVISIT(CXXOperatorCallExpr, CallExpr) -POSTVISIT(ObjCMessageExpr, Stmt) - -#undef PREVISIT -#undef POSTVISIT diff --git a/include/clang/Analysis/PathSensitive/CheckerVisitor.h b/include/clang/Analysis/PathSensitive/CheckerVisitor.h deleted file mode 100644 index 37ec8def50b3..000000000000 --- a/include/clang/Analysis/PathSensitive/CheckerVisitor.h +++ /dev/null @@ -1,101 +0,0 @@ -//== CheckerVisitor.h - Abstract visitor for checkers ------------*- C++ -*--=// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines CheckerVisitor. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_CHECKERVISITOR -#define LLVM_CLANG_ANALYSIS_CHECKERVISITOR -#include "clang/Analysis/PathSensitive/Checker.h" - -namespace clang { - -//===----------------------------------------------------------------------===// -// Checker visitor interface. Used by subclasses of Checker to specify their -// own checker visitor logic. -//===----------------------------------------------------------------------===// - -/// CheckerVisitor - This class implements a simple visitor for Stmt subclasses. -/// Since Expr derives from Stmt, this also includes support for visiting Exprs. -template -class CheckerVisitor : public Checker { -public: - virtual void _PreVisit(CheckerContext &C, const Stmt *S) { - PreVisit(C, S); - } - - virtual void _PostVisit(CheckerContext &C, const Stmt *S) { - PostVisit(C, S); - } - - void PreVisit(CheckerContext &C, const Stmt *S) { - switch (S->getStmtClass()) { - default: - assert(false && "Unsupport statement."); - return; - - case Stmt::ImplicitCastExprClass: - case Stmt::ExplicitCastExprClass: - case Stmt::CStyleCastExprClass: - static_cast(this)->PreVisitCastExpr(C, - static_cast(S)); - break; - - case Stmt::CompoundAssignOperatorClass: - static_cast(this)->PreVisitBinaryOperator(C, - static_cast(S)); - break; - -#define PREVISIT(NAME, FALLBACK) \ -case Stmt::NAME ## Class:\ -static_cast(this)->PreVisit ## NAME(C,static_cast(S));\ -break; -#include "clang/Analysis/PathSensitive/CheckerVisitor.def" - } - } - - void PostVisit(CheckerContext &C, const Stmt *S) { - switch (S->getStmtClass()) { - default: - assert(false && "Unsupport statement."); - return; - case Stmt::CompoundAssignOperatorClass: - static_cast(this)->PostVisitBinaryOperator(C, - static_cast(S)); - break; - -#define POSTVISIT(NAME, FALLBACK) \ -case Stmt::NAME ## Class:\ -static_cast(this)->\ -PostVisit ## NAME(C,static_cast(S));\ -break; -#include "clang/Analysis/PathSensitive/CheckerVisitor.def" - } - } - - void PreVisitStmt(CheckerContext &C, const Stmt *S) {} - void PostVisitStmt(CheckerContext &C, const Stmt *S) {} - -#define PREVISIT(NAME, FALLBACK) \ -void PreVisit ## NAME(CheckerContext &C, const NAME* S) {\ - PreVisit ## FALLBACK(C, S);\ -} -#include "clang/Analysis/PathSensitive/CheckerVisitor.def" - -#define POSTVISIT(NAME, FALLBACK) \ -void PostVisit ## NAME(CheckerContext &C, const NAME* S) {\ - PostVisit ## FALLBACK(C, S);\ -} -#include "clang/Analysis/PathSensitive/CheckerVisitor.def" -}; - -} // end clang namespace - -#endif diff --git a/include/clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h b/include/clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h deleted file mode 100644 index a84183e7f27f..000000000000 --- a/include/clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h +++ /dev/null @@ -1,31 +0,0 @@ -//== NullDerefChecker.h - Null dereference checker --------------*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This defines NullDerefChecker and UndefDerefChecker, two builtin checks -// in GRExprEngine that check for null and undefined pointers at loads -// and stores. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_DEREFCHECKER -#define LLVM_CLANG_DEREFCHECKER - -#include - -namespace clang { - -class GRExprEngine; -class ExplodedNode; - -std::pair -GetImplicitNullDereferences(GRExprEngine &Eng); - -} // end clang namespace - -#endif diff --git a/include/clang/Analysis/PathSensitive/ConstraintManager.h b/include/clang/Analysis/PathSensitive/ConstraintManager.h deleted file mode 100644 index c8292802ae9d..000000000000 --- a/include/clang/Analysis/PathSensitive/ConstraintManager.h +++ /dev/null @@ -1,75 +0,0 @@ -//== ConstraintManager.h - Constraints on symbolic values.-------*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defined the interface to manage constraints on symbolic values. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H -#define LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H - -// FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place. -#include "clang/Analysis/PathSensitive/Store.h" - -namespace llvm { -class APSInt; -} - -namespace clang { - -class GRState; -class GRStateManager; -class GRSubEngine; -class SVal; - -class ConstraintManager { -public: - virtual ~ConstraintManager(); - virtual const GRState *Assume(const GRState *state, DefinedSVal Cond, - bool Assumption) = 0; - - virtual const GRState *AssumeInBound(const GRState *state, DefinedSVal Idx, - DefinedSVal UpperBound, bool Assumption) = 0; - - std::pair AssumeDual(const GRState *state, - DefinedSVal Cond) { - return std::make_pair(Assume(state, Cond, true), - Assume(state, Cond, false)); - } - - virtual const llvm::APSInt* getSymVal(const GRState *state, - SymbolRef sym) const = 0; - - virtual bool isEqual(const GRState *state, SymbolRef sym, - const llvm::APSInt& V) const = 0; - - virtual const GRState *RemoveDeadBindings(const GRState *state, - SymbolReaper& SymReaper) = 0; - - virtual void print(const GRState *state, llvm::raw_ostream& Out, - const char* nl, const char *sep) = 0; - - virtual void EndPath(const GRState *state) {} - - /// canReasonAbout - Not all ConstraintManagers can accurately reason about - /// all SVal values. This method returns true if the ConstraintManager can - /// reasonably handle a given SVal value. This is typically queried by - /// GRExprEngine to determine if the value should be replaced with a - /// conjured symbolic value in order to recover some precision. - virtual bool canReasonAbout(SVal X) const = 0; -}; - -ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr, - GRSubEngine &subengine); -ConstraintManager* CreateRangeConstraintManager(GRStateManager& statemgr, - GRSubEngine &subengine); - -} // end clang namespace - -#endif diff --git a/include/clang/Analysis/PathSensitive/Environment.h b/include/clang/Analysis/PathSensitive/Environment.h deleted file mode 100644 index 6d5c5678e59b..000000000000 --- a/include/clang/Analysis/PathSensitive/Environment.h +++ /dev/null @@ -1,103 +0,0 @@ -//== Environment.h - Map from Stmt* to Locations/Values ---------*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defined the Environment and EnvironmentManager classes. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_ENVIRONMENT_H -#define LLVM_CLANG_ANALYSIS_ENVIRONMENT_H - -// For using typedefs in StoreManager. Should find a better place for these -// typedefs. -#include "clang/Analysis/PathSensitive/Store.h" - -#include "llvm/ADT/ImmutableMap.h" -#include "llvm/ADT/SmallVector.h" -#include "clang/Analysis/PathSensitive/SVals.h" -#include "llvm/Support/Allocator.h" -#include "llvm/ADT/FoldingSet.h" - -namespace clang { - -class AnalysisContext; -class EnvironmentManager; -class ValueManager; -class LiveVariables; - - -class Environment { -private: - friend class EnvironmentManager; - - // Type definitions. - typedef llvm::ImmutableMap BindingsTy; - - // Data. - BindingsTy ExprBindings; - AnalysisContext *ACtx; - - Environment(BindingsTy eb, AnalysisContext *aCtx) - : ExprBindings(eb), ACtx(aCtx) {} - -public: - typedef BindingsTy::iterator iterator; - iterator begin() const { return ExprBindings.begin(); } - iterator end() const { return ExprBindings.end(); } - - SVal LookupExpr(const Stmt* E) const { - const SVal* X = ExprBindings.lookup(E); - return X ? *X : UnknownVal(); - } - - SVal GetSVal(const Stmt* Ex, ValueManager& ValMgr) const; - - AnalysisContext &getAnalysisContext() const { return *ACtx; } - - /// Profile - Profile the contents of an Environment object for use - /// in a FoldingSet. - static void Profile(llvm::FoldingSetNodeID& ID, const Environment* E) { - E->ExprBindings.Profile(ID); - } - - /// Profile - Used to profile the contents of this object for inclusion - /// in a FoldingSet. - void Profile(llvm::FoldingSetNodeID& ID) const { - Profile(ID, this); - } - - bool operator==(const Environment& RHS) const { - return ExprBindings == RHS.ExprBindings; - } -}; - -class EnvironmentManager { -private: - typedef Environment::BindingsTy::Factory FactoryTy; - FactoryTy F; - -public: - EnvironmentManager(llvm::BumpPtrAllocator& Allocator) : F(Allocator) {} - ~EnvironmentManager() {} - - Environment getInitialEnvironment(AnalysisContext *ACtx) { - return Environment(F.GetEmptyMap(), ACtx); - } - - Environment BindExpr(Environment Env, const Stmt *S, SVal V, - bool Invalidate); - - Environment RemoveDeadBindings(Environment Env, const Stmt *S, - SymbolReaper &SymReaper, const GRState *ST, - llvm::SmallVectorImpl& RegionRoots); -}; - -} // end clang namespace - -#endif diff --git a/include/clang/Analysis/PathSensitive/ExplodedGraph.h b/include/clang/Analysis/PathSensitive/ExplodedGraph.h deleted file mode 100644 index fb5e1b8a415f..000000000000 --- a/include/clang/Analysis/PathSensitive/ExplodedGraph.h +++ /dev/null @@ -1,432 +0,0 @@ -//=-- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -*- C++ -*-------==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the template classes ExplodedNode and ExplodedGraph, -// which represent a path-sensitive, intra-procedural "exploded graph." -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH -#define LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH - -#include "clang/Analysis/ProgramPoint.h" -#include "clang/Analysis/PathSensitive/AnalysisContext.h" -#include "clang/AST/Decl.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/Support/Allocator.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/GraphTraits.h" -#include "llvm/ADT/DepthFirstIterator.h" -#include "llvm/Support/Casting.h" -#include "clang/Analysis/Support/BumpVector.h" - -namespace clang { - -class GRState; -class CFG; -class ASTContext; -class ExplodedGraph; - -//===----------------------------------------------------------------------===// -// ExplodedGraph "implementation" classes. These classes are not typed to -// contain a specific kind of state. Typed-specialized versions are defined -// on top of these classes. -//===----------------------------------------------------------------------===// - -class ExplodedNode : public llvm::FoldingSetNode { - friend class ExplodedGraph; - friend class GRCoreEngine; - friend class GRStmtNodeBuilder; - friend class GRBranchNodeBuilder; - friend class GRIndirectGotoNodeBuilder; - friend class GRSwitchNodeBuilder; - friend class GREndPathNodeBuilder; - - class NodeGroup { - enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 }; - uintptr_t P; - - unsigned getKind() const { - return P & 0x1; - } - - void* getPtr() const { - assert (!getFlag()); - return reinterpret_cast(P & ~Mask); - } - - ExplodedNode *getNode() const { - return reinterpret_cast(getPtr()); - } - - public: - NodeGroup() : P(0) {} - - ExplodedNode **begin() const; - - ExplodedNode **end() const; - - unsigned size() const; - - bool empty() const { return (P & ~Mask) == 0; } - - void addNode(ExplodedNode* N, ExplodedGraph &G); - - void setFlag() { - assert(P == 0); - P = AuxFlag; - } - - bool getFlag() const { - return P & AuxFlag ? true : false; - } - }; - - /// Location - The program location (within a function body) associated - /// with this node. - const ProgramPoint Location; - - /// State - The state associated with this node. - const GRState* State; - - /// Preds - The predecessors of this node. - NodeGroup Preds; - - /// Succs - The successors of this node. - NodeGroup Succs; - -public: - - explicit ExplodedNode(const ProgramPoint& loc, const GRState* state) - : Location(loc), State(state) {} - - /// getLocation - Returns the edge associated with the given node. - ProgramPoint getLocation() const { return Location; } - - const LocationContext *getLocationContext() const { - return getLocation().getLocationContext(); - } - - const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); } - - CFG &getCFG() const { return *getLocationContext()->getCFG(); } - - ParentMap &getParentMap() const {return getLocationContext()->getParentMap();} - - LiveVariables &getLiveVariables() const { - return *getLocationContext()->getLiveVariables(); - } - - const GRState* getState() const { return State; } - - template - const T* getLocationAs() const { return llvm::dyn_cast(&Location); } - - static void Profile(llvm::FoldingSetNodeID &ID, - const ProgramPoint& Loc, const GRState* state) { - ID.Add(Loc); - ID.AddPointer(state); - } - - void Profile(llvm::FoldingSetNodeID& ID) const { - Profile(ID, getLocation(), getState()); - } - - /// addPredeccessor - Adds a predecessor to the current node, and - /// in tandem add this node as a successor of the other node. - void addPredecessor(ExplodedNode* V, ExplodedGraph &G); - - unsigned succ_size() const { return Succs.size(); } - unsigned pred_size() const { return Preds.size(); } - bool succ_empty() const { return Succs.empty(); } - bool pred_empty() const { return Preds.empty(); } - - bool isSink() const { return Succs.getFlag(); } - void markAsSink() { Succs.setFlag(); } - - ExplodedNode* getFirstPred() { - return pred_empty() ? NULL : *(pred_begin()); - } - - const ExplodedNode* getFirstPred() const { - return const_cast(this)->getFirstPred(); - } - - // Iterators over successor and predecessor vertices. - typedef ExplodedNode** succ_iterator; - typedef const ExplodedNode* const * const_succ_iterator; - typedef ExplodedNode** pred_iterator; - typedef const ExplodedNode* const * const_pred_iterator; - - pred_iterator pred_begin() { return Preds.begin(); } - pred_iterator pred_end() { return Preds.end(); } - - const_pred_iterator pred_begin() const { - return const_cast(this)->pred_begin(); - } - const_pred_iterator pred_end() const { - return const_cast(this)->pred_end(); - } - - succ_iterator succ_begin() { return Succs.begin(); } - succ_iterator succ_end() { return Succs.end(); } - - const_succ_iterator succ_begin() const { - return const_cast(this)->succ_begin(); - } - const_succ_iterator succ_end() const { - return const_cast(this)->succ_end(); - } - - // For debugging. - -public: - - class Auditor { - public: - virtual ~Auditor(); - virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst) = 0; - }; - - static void SetAuditor(Auditor* A); -}; - -// FIXME: Is this class necessary? -class InterExplodedGraphMap { - llvm::DenseMap M; - friend class ExplodedGraph; - -public: - ExplodedNode* getMappedNode(const ExplodedNode* N) const; - - InterExplodedGraphMap() {} - virtual ~InterExplodedGraphMap() {} -}; - -class ExplodedGraph { -protected: - friend class GRCoreEngine; - - // Type definitions. - typedef llvm::SmallVector RootsTy; - typedef llvm::SmallVector EndNodesTy; - - /// Roots - The roots of the simulation graph. Usually there will be only - /// one, but clients are free to establish multiple subgraphs within a single - /// SimulGraph. Moreover, these subgraphs can often merge when paths from - /// different roots reach the same state at the same program location. - RootsTy Roots; - - /// EndNodes - The nodes in the simulation graph which have been - /// specially marked as the endpoint of an abstract simulation path. - EndNodesTy EndNodes; - - /// Nodes - The nodes in the graph. - llvm::FoldingSet Nodes; - - /// BVC - Allocator and context for allocating nodes and their predecessor - /// and successor groups. - BumpVectorContext BVC; - - /// Ctx - The ASTContext used to "interpret" CodeDecl. - ASTContext& Ctx; - - /// NumNodes - The number of nodes in the graph. - unsigned NumNodes; - -public: - /// getNode - Retrieve the node associated with a (Location,State) pair, - /// where the 'Location' is a ProgramPoint in the CFG. If no node for - /// this pair exists, it is created. IsNew is set to true if - /// the node was freshly created. - - ExplodedNode* getNode(const ProgramPoint& L, const GRState *State, - bool* IsNew = 0); - - ExplodedGraph* MakeEmptyGraph() const { - return new ExplodedGraph(Ctx); - } - - /// addRoot - Add an untyped node to the set of roots. - ExplodedNode* addRoot(ExplodedNode* V) { - Roots.push_back(V); - return V; - } - - /// addEndOfPath - Add an untyped node to the set of EOP nodes. - ExplodedNode* addEndOfPath(ExplodedNode* V) { - EndNodes.push_back(V); - return V; - } - - ExplodedGraph(ASTContext& ctx) : Ctx(ctx), NumNodes(0) {} - - ~ExplodedGraph() {} - - unsigned num_roots() const { return Roots.size(); } - unsigned num_eops() const { return EndNodes.size(); } - - bool empty() const { return NumNodes == 0; } - unsigned size() const { return NumNodes; } - - // Iterators. - typedef ExplodedNode NodeTy; - typedef llvm::FoldingSet AllNodesTy; - typedef NodeTy** roots_iterator; - typedef NodeTy* const * const_roots_iterator; - typedef NodeTy** eop_iterator; - typedef NodeTy* const * const_eop_iterator; - typedef AllNodesTy::iterator node_iterator; - typedef AllNodesTy::const_iterator const_node_iterator; - - node_iterator nodes_begin() { return Nodes.begin(); } - - node_iterator nodes_end() { return Nodes.end(); } - - const_node_iterator nodes_begin() const { return Nodes.begin(); } - - const_node_iterator nodes_end() const { return Nodes.end(); } - - roots_iterator roots_begin() { return Roots.begin(); } - - roots_iterator roots_end() { return Roots.end(); } - - const_roots_iterator roots_begin() const { return Roots.begin(); } - - const_roots_iterator roots_end() const { return Roots.end(); } - - eop_iterator eop_begin() { return EndNodes.begin(); } - - eop_iterator eop_end() { return EndNodes.end(); } - - const_eop_iterator eop_begin() const { return EndNodes.begin(); } - - const_eop_iterator eop_end() const { return EndNodes.end(); } - - llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); } - BumpVectorContext &getNodeAllocator() { return BVC; } - - ASTContext& getContext() { return Ctx; } - - typedef llvm::DenseMap NodeMap; - - std::pair - Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd, - llvm::DenseMap *InverseMap = 0) const; - - ExplodedGraph* TrimInternal(const ExplodedNode* const * NBeg, - const ExplodedNode* const * NEnd, - InterExplodedGraphMap *M, - llvm::DenseMap *InverseMap) const; -}; - -class ExplodedNodeSet { - typedef llvm::SmallPtrSet ImplTy; - ImplTy Impl; - -public: - ExplodedNodeSet(ExplodedNode* N) { - assert (N && !static_cast(N)->isSink()); - Impl.insert(N); - } - - ExplodedNodeSet() {} - - inline void Add(ExplodedNode* N) { - if (N && !static_cast(N)->isSink()) Impl.insert(N); - } - - ExplodedNodeSet& operator=(const ExplodedNodeSet &X) { - Impl = X.Impl; - return *this; - } - - typedef ImplTy::iterator iterator; - typedef ImplTy::const_iterator const_iterator; - - unsigned size() const { return Impl.size(); } - bool empty() const { return Impl.empty(); } - - void clear() { Impl.clear(); } - void insert(const ExplodedNodeSet &S) { - if (empty()) - Impl = S.Impl; - else - Impl.insert(S.begin(), S.end()); - } - - inline iterator begin() { return Impl.begin(); } - inline iterator end() { return Impl.end(); } - - inline const_iterator begin() const { return Impl.begin(); } - inline const_iterator end() const { return Impl.end(); } -}; - -} // end clang namespace - -// GraphTraits - -namespace llvm { - template<> struct GraphTraits { - typedef clang::ExplodedNode NodeType; - typedef NodeType::succ_iterator ChildIteratorType; - typedef llvm::df_iterator nodes_iterator; - - static inline NodeType* getEntryNode(NodeType* N) { - return N; - } - - static inline ChildIteratorType child_begin(NodeType* N) { - return N->succ_begin(); - } - - static inline ChildIteratorType child_end(NodeType* N) { - return N->succ_end(); - } - - static inline nodes_iterator nodes_begin(NodeType* N) { - return df_begin(N); - } - - static inline nodes_iterator nodes_end(NodeType* N) { - return df_end(N); - } - }; - - template<> struct GraphTraits { - typedef const clang::ExplodedNode NodeType; - typedef NodeType::const_succ_iterator ChildIteratorType; - typedef llvm::df_iterator nodes_iterator; - - static inline NodeType* getEntryNode(NodeType* N) { - return N; - } - - static inline ChildIteratorType child_begin(NodeType* N) { - return N->succ_begin(); - } - - static inline ChildIteratorType child_end(NodeType* N) { - return N->succ_end(); - } - - static inline nodes_iterator nodes_begin(NodeType* N) { - return df_begin(N); - } - - static inline nodes_iterator nodes_end(NodeType* N) { - return df_end(N); - } - }; - -} // end llvm namespace - -#endif diff --git a/include/clang/Analysis/PathSensitive/GRAuditor.h b/include/clang/Analysis/PathSensitive/GRAuditor.h deleted file mode 100644 index 015c82e80bb5..000000000000 --- a/include/clang/Analysis/PathSensitive/GRAuditor.h +++ /dev/null @@ -1,35 +0,0 @@ -//==- GRAuditor.h - Observers of the creation of ExplodedNodes------*- C++ -*-// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines GRAuditor and its primary subclasses, an interface -// to audit the creation of ExplodedNodes. This interface can be used -// to implement simple checkers that do not mutate analysis state but -// instead operate by perfoming simple logical checks at key monitoring -// locations (e.g., function calls). -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_GRAUDITOR -#define LLVM_CLANG_ANALYSIS_GRAUDITOR - -namespace clang { - -class ExplodedNode; -class GRStateManager; - -class GRAuditor { -public: - virtual ~GRAuditor() {} - virtual bool Audit(ExplodedNode* N, GRStateManager& M) = 0; -}; - - -} // end clang namespace - -#endif diff --git a/include/clang/Analysis/PathSensitive/GRBlockCounter.h b/include/clang/Analysis/PathSensitive/GRBlockCounter.h deleted file mode 100644 index 67ed9532db02..000000000000 --- a/include/clang/Analysis/PathSensitive/GRBlockCounter.h +++ /dev/null @@ -1,50 +0,0 @@ -//==- GRBlockCounter.h - ADT for counting block visits -------------*- C++ -*-// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines GRBlockCounter, an abstract data type used to count -// the number of times a given block has been visited along a path -// analyzed by GRCoreEngine. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER -#define LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER - -namespace llvm { - class BumpPtrAllocator; -} - -namespace clang { - -class GRBlockCounter { - void* Data; - - GRBlockCounter(void* D) : Data(D) {} - -public: - GRBlockCounter() : Data(0) {} - - unsigned getNumVisited(unsigned BlockID) const; - - class Factory { - void* F; - public: - Factory(llvm::BumpPtrAllocator& Alloc); - ~Factory(); - - GRBlockCounter GetEmptyCounter(); - GRBlockCounter IncrementCount(GRBlockCounter BC, unsigned BlockID); - }; - - friend class Factory; -}; - -} // end clang namespace - -#endif diff --git a/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/include/clang/Analysis/PathSensitive/GRCoreEngine.h deleted file mode 100644 index 74f7a147b841..000000000000 --- a/include/clang/Analysis/PathSensitive/GRCoreEngine.h +++ /dev/null @@ -1,443 +0,0 @@ -//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine --------------*- C++ -*-// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines a generic engine for intraprocedural, path-sensitive, -// dataflow analysis via graph reachability. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_GRENGINE -#define LLVM_CLANG_ANALYSIS_GRENGINE - -#include "clang/AST/Expr.h" -#include "clang/Analysis/PathSensitive/ExplodedGraph.h" -#include "clang/Analysis/PathSensitive/GRWorkList.h" -#include "clang/Analysis/PathSensitive/GRBlockCounter.h" -#include "clang/Analysis/PathSensitive/GRAuditor.h" -#include "clang/Analysis/PathSensitive/GRSubEngine.h" -#include "llvm/ADT/OwningPtr.h" - -namespace clang { - -//===----------------------------------------------------------------------===// -/// GRCoreEngine - Implements the core logic of the graph-reachability -/// analysis. It traverses the CFG and generates the ExplodedGraph. -/// Program "states" are treated as opaque void pointers. -/// The template class GRCoreEngine (which subclasses GRCoreEngine) -/// provides the matching component to the engine that knows the actual types -/// for states. Note that this engine only dispatches to transfer functions -/// at the statement and block-level. The analyses themselves must implement -/// any transfer function logic and the sub-expression level (if any). -class GRCoreEngine { - friend class GRStmtNodeBuilder; - friend class GRBranchNodeBuilder; - friend class GRIndirectGotoNodeBuilder; - friend class GRSwitchNodeBuilder; - friend class GREndPathNodeBuilder; - - GRSubEngine& SubEngine; - - /// G - The simulation graph. Each node is a (location,state) pair. - llvm::OwningPtr G; - - /// WList - A set of queued nodes that need to be processed by the - /// worklist algorithm. It is up to the implementation of WList to decide - /// the order that nodes are processed. - GRWorkList* WList; - - /// BCounterFactory - A factory object for created GRBlockCounter objects. - /// These are used to record for key nodes in the ExplodedGraph the - /// number of times different CFGBlocks have been visited along a path. - GRBlockCounter::Factory BCounterFactory; - - void GenerateNode(const ProgramPoint& Loc, const GRState* State, - ExplodedNode* Pred); - - void HandleBlockEdge(const BlockEdge& E, ExplodedNode* Pred); - void HandleBlockEntrance(const BlockEntrance& E, ExplodedNode* Pred); - void HandleBlockExit(CFGBlock* B, ExplodedNode* Pred); - void HandlePostStmt(const PostStmt& S, CFGBlock* B, - unsigned StmtIdx, ExplodedNode *Pred); - - void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B, - ExplodedNode* Pred); - - /// Get the initial state from the subengine. - const GRState* getInitialState(const LocationContext *InitLoc) { - return SubEngine.getInitialState(InitLoc); - } - - void ProcessEndPath(GREndPathNodeBuilder& Builder); - - void ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder); - - bool ProcessBlockEntrance(CFGBlock* Blk, const GRState* State, - GRBlockCounter BC); - - - void ProcessBranch(Stmt* Condition, Stmt* Terminator, - GRBranchNodeBuilder& Builder); - - - void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& Builder); - - - void ProcessSwitch(GRSwitchNodeBuilder& Builder); - -private: - GRCoreEngine(const GRCoreEngine&); // Do not implement. - GRCoreEngine& operator=(const GRCoreEngine&); - -public: - /// Construct a GRCoreEngine object to analyze the provided CFG using - /// a DFS exploration of the exploded graph. - GRCoreEngine(ASTContext& ctx, GRSubEngine& subengine) - : SubEngine(subengine), G(new ExplodedGraph(ctx)), - WList(GRWorkList::MakeBFS()), - BCounterFactory(G->getAllocator()) {} - - /// Construct a GRCoreEngine object to analyze the provided CFG and to - /// use the provided worklist object to execute the worklist algorithm. - /// The GRCoreEngine object assumes ownership of 'wlist'. - GRCoreEngine(ASTContext& ctx, GRWorkList* wlist, GRSubEngine& subengine) - : SubEngine(subengine), G(new ExplodedGraph(ctx)), WList(wlist), - BCounterFactory(G->getAllocator()) {} - - ~GRCoreEngine() { - delete WList; - } - - /// getGraph - Returns the exploded graph. - ExplodedGraph& getGraph() { return *G.get(); } - - /// takeGraph - Returns the exploded graph. Ownership of the graph is - /// transfered to the caller. - ExplodedGraph* takeGraph() { return G.take(); } - - /// ExecuteWorkList - Run the worklist algorithm for a maximum number of - /// steps. Returns true if there is still simulation state on the worklist. - bool ExecuteWorkList(const LocationContext *L, unsigned Steps); -}; - -class GRStmtNodeBuilder { - GRCoreEngine& Eng; - CFGBlock& B; - const unsigned Idx; - ExplodedNode* Pred; - ExplodedNode* LastNode; - GRStateManager& Mgr; - GRAuditor* Auditor; - -public: - bool PurgingDeadSymbols; - bool BuildSinks; - bool HasGeneratedNode; - ProgramPoint::Kind PointKind; - const void *Tag; - - const GRState* CleanedState; - - - typedef llvm::SmallPtrSet DeferredTy; - DeferredTy Deferred; - - void GenerateAutoTransition(ExplodedNode* N); - -public: - GRStmtNodeBuilder(CFGBlock* b, unsigned idx, ExplodedNode* N, - GRCoreEngine* e, GRStateManager &mgr); - - ~GRStmtNodeBuilder(); - - ExplodedNode* getBasePredecessor() const { return Pred; } - - ExplodedNode* getLastNode() const { - return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL; - } - - // FIXME: This should not be exposed. - GRWorkList *getWorkList() { return Eng.WList; } - - void SetCleanedState(const GRState* St) { - CleanedState = St; - } - - GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} - - unsigned getCurrentBlockCount() const { - return getBlockCounter().getNumVisited(B.getBlockID()); - } - - ExplodedNode* generateNode(PostStmt PP,const GRState* St,ExplodedNode* Pred) { - HasGeneratedNode = true; - return generateNodeInternal(PP, St, Pred); - } - - ExplodedNode* generateNode(const Stmt *S, const GRState *St, - ExplodedNode *Pred, ProgramPoint::Kind K) { - HasGeneratedNode = true; - - if (PurgingDeadSymbols) - K = ProgramPoint::PostPurgeDeadSymbolsKind; - - return generateNodeInternal(S, St, Pred, K, Tag); - } - - ExplodedNode* generateNode(const Stmt *S, const GRState *St, - ExplodedNode *Pred) { - return generateNode(S, St, Pred, PointKind); - } - - ExplodedNode* - generateNodeInternal(const ProgramPoint &PP, const GRState* State, - ExplodedNode* Pred); - - ExplodedNode* - generateNodeInternal(const Stmt* S, const GRState* State, ExplodedNode* Pred, - ProgramPoint::Kind K = ProgramPoint::PostStmtKind, - const void *tag = 0); - - /// getStmt - Return the current block-level expression associated with - /// this builder. - Stmt* getStmt() const { return B[Idx]; } - - /// getBlock - Return the CFGBlock associated with the block-level expression - /// of this builder. - CFGBlock* getBlock() const { return &B; } - - unsigned getIndex() const { return Idx; } - - void setAuditor(GRAuditor* A) { Auditor = A; } - - const GRState* GetState(ExplodedNode* Pred) const { - if (Pred == getBasePredecessor()) - return CleanedState; - else - return Pred->getState(); - } - - ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred, - const GRState* St) { - return MakeNode(Dst, S, Pred, St, PointKind); - } - - ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred, - const GRState* St, ProgramPoint::Kind K) { - - const GRState* PredState = GetState(Pred); - - // If the state hasn't changed, don't generate a new node. - if (!BuildSinks && St == PredState && Auditor == 0) { - Dst.Add(Pred); - return NULL; - } - - ExplodedNode* N = generateNode(S, St, Pred, K); - - if (N) { - if (BuildSinks) - N->markAsSink(); - else { - if (Auditor && Auditor->Audit(N, Mgr)) - N->markAsSink(); - - Dst.Add(N); - } - } - - return N; - } - - ExplodedNode* MakeSinkNode(ExplodedNodeSet& Dst, Stmt* S, - ExplodedNode* Pred, const GRState* St) { - bool Tmp = BuildSinks; - BuildSinks = true; - ExplodedNode* N = MakeNode(Dst, S, Pred, St); - BuildSinks = Tmp; - return N; - } - -}; - -class GRBranchNodeBuilder { - GRCoreEngine& Eng; - CFGBlock* Src; - CFGBlock* DstT; - CFGBlock* DstF; - ExplodedNode* Pred; - - typedef llvm::SmallVector DeferredTy; - DeferredTy Deferred; - - bool GeneratedTrue; - bool GeneratedFalse; - bool InFeasibleTrue; - bool InFeasibleFalse; - -public: - GRBranchNodeBuilder(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF, - ExplodedNode* pred, GRCoreEngine* e) - : Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred), - GeneratedTrue(false), GeneratedFalse(false), - InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {} - - ~GRBranchNodeBuilder(); - - ExplodedNode* getPredecessor() const { return Pred; } - - const ExplodedGraph& getGraph() const { return *Eng.G; } - - GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} - - ExplodedNode* generateNode(const GRState* State, bool branch); - - CFGBlock* getTargetBlock(bool branch) const { - return branch ? DstT : DstF; - } - - void markInfeasible(bool branch) { - if (branch) - InFeasibleTrue = GeneratedTrue = true; - else - InFeasibleFalse = GeneratedFalse = true; - } - - bool isFeasible(bool branch) { - return branch ? !InFeasibleTrue : !InFeasibleFalse; - } - - const GRState* getState() const { - return getPredecessor()->getState(); - } -}; - -class GRIndirectGotoNodeBuilder { - GRCoreEngine& Eng; - CFGBlock* Src; - CFGBlock& DispatchBlock; - Expr* E; - ExplodedNode* Pred; - -public: - GRIndirectGotoNodeBuilder(ExplodedNode* pred, CFGBlock* src, Expr* e, - CFGBlock* dispatch, GRCoreEngine* eng) - : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {} - - class iterator { - CFGBlock::succ_iterator I; - - friend class GRIndirectGotoNodeBuilder; - iterator(CFGBlock::succ_iterator i) : I(i) {} - public: - - iterator& operator++() { ++I; return *this; } - bool operator!=(const iterator& X) const { return I != X.I; } - - LabelStmt* getLabel() const { - return llvm::cast((*I)->getLabel()); - } - - CFGBlock* getBlock() const { - return *I; - } - }; - - iterator begin() { return iterator(DispatchBlock.succ_begin()); } - iterator end() { return iterator(DispatchBlock.succ_end()); } - - ExplodedNode* generateNode(const iterator& I, const GRState* State, - bool isSink = false); - - Expr* getTarget() const { return E; } - - const GRState* getState() const { return Pred->State; } -}; - -class GRSwitchNodeBuilder { - GRCoreEngine& Eng; - CFGBlock* Src; - Expr* Condition; - ExplodedNode* Pred; - -public: - GRSwitchNodeBuilder(ExplodedNode* pred, CFGBlock* src, - Expr* condition, GRCoreEngine* eng) - : Eng(*eng), Src(src), Condition(condition), Pred(pred) {} - - class iterator { - CFGBlock::succ_reverse_iterator I; - - friend class GRSwitchNodeBuilder; - iterator(CFGBlock::succ_reverse_iterator i) : I(i) {} - - public: - iterator& operator++() { ++I; return *this; } - bool operator!=(const iterator& X) const { return I != X.I; } - - CaseStmt* getCase() const { - return llvm::cast((*I)->getLabel()); - } - - CFGBlock* getBlock() const { - return *I; - } - }; - - iterator begin() { return iterator(Src->succ_rbegin()+1); } - iterator end() { return iterator(Src->succ_rend()); } - - ExplodedNode* generateCaseStmtNode(const iterator& I, const GRState* State); - - ExplodedNode* generateDefaultCaseNode(const GRState* State, - bool isSink = false); - - Expr* getCondition() const { return Condition; } - - const GRState* getState() const { return Pred->State; } -}; - -class GREndPathNodeBuilder { - GRCoreEngine &Eng; - CFGBlock& B; - ExplodedNode* Pred; - -public: - bool HasGeneratedNode; - -public: - GREndPathNodeBuilder(CFGBlock* b, ExplodedNode* N, GRCoreEngine* e) - : Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {} - - ~GREndPathNodeBuilder(); - - GRWorkList &getWorkList() { return *Eng.WList; } - - ExplodedNode* getPredecessor() const { return Pred; } - - GRBlockCounter getBlockCounter() const { - return Eng.WList->getBlockCounter(); - } - - unsigned getCurrentBlockCount() const { - return getBlockCounter().getNumVisited(B.getBlockID()); - } - - ExplodedNode* generateNode(const GRState* State, const void *tag = 0, - ExplodedNode *P = 0); - - CFGBlock* getBlock() const { return &B; } - - const GRState* getState() const { - return getPredecessor()->getState(); - } -}; - -} // end clang namespace - -#endif diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h deleted file mode 100644 index df90ad9f7f08..000000000000 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ /dev/null @@ -1,433 +0,0 @@ -//===-- GRExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- C++ -*-= -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines a meta-engine for path-sensitive dataflow analysis that -// is built on GRCoreEngine, but provides the boilerplate to execute transfer -// functions and build the ExplodedGraph at the expression level. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE -#define LLVM_CLANG_ANALYSIS_GREXPRENGINE - -#include "clang/Analysis/PathSensitive/AnalysisManager.h" -#include "clang/Analysis/PathSensitive/GRSubEngine.h" -#include "clang/Analysis/PathSensitive/GRCoreEngine.h" -#include "clang/Analysis/PathSensitive/GRState.h" -#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h" -#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/AST/Type.h" -#include "clang/AST/ExprObjC.h" -#include "clang/AST/ExprCXX.h" - -namespace clang { - - class PathDiagnosticClient; - class Diagnostic; - class ObjCForCollectionStmt; - class Checker; - -class GRExprEngine : public GRSubEngine { - AnalysisManager &AMgr; - - GRCoreEngine CoreEngine; - - /// G - the simulation graph. - ExplodedGraph& G; - - /// Builder - The current GRStmtNodeBuilder which is used when building the - /// nodes for a given statement. - GRStmtNodeBuilder* Builder; - - /// StateMgr - Object that manages the data for all created states. - GRStateManager StateMgr; - - /// SymMgr - Object that manages the symbol information. - SymbolManager& SymMgr; - - /// ValMgr - Object that manages/creates SVals. - ValueManager &ValMgr; - - /// SVator - SValuator object that creates SVals from expressions. - SValuator &SVator; - - /// EntryNode - The immediate predecessor node. - ExplodedNode* EntryNode; - - /// CleanedState - The state for EntryNode "cleaned" of all dead - /// variables and symbols (as determined by a liveness analysis). - const GRState* CleanedState; - - /// CurrentStmt - The current block-level statement. - Stmt* CurrentStmt; - - // Obj-C Class Identifiers. - IdentifierInfo* NSExceptionII; - - // Obj-C Selectors. - Selector* NSExceptionInstanceRaiseSelectors; - Selector RaiseSel; - - llvm::OwningPtr BatchAuditor; - - typedef llvm::DenseMap CheckerMap; - CheckerMap CheckerM; - - typedef std::vector > CheckersOrdered; - CheckersOrdered Checkers; - - /// BR - The BugReporter associated with this engine. It is important that - // this object be placed at the very end of member variables so that its - // destructor is called before the rest of the GRExprEngine is destroyed. - GRBugReporter BR; - - llvm::OwningPtr TF; - -public: - GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf); - - ~GRExprEngine(); - - void ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) { - CoreEngine.ExecuteWorkList(L, Steps); - } - - /// getContext - Return the ASTContext associated with this analysis. - ASTContext& getContext() const { return G.getContext(); } - - AnalysisManager &getAnalysisManager() const { return AMgr; } - - SValuator &getSValuator() { return SVator; } - - GRTransferFuncs& getTF() { return *TF; } - - BugReporter& getBugReporter() { return BR; } - - GRStmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; } - - // FIXME: Remove once GRTransferFuncs is no longer referenced. - void setTransferFunction(GRTransferFuncs* tf); - - /// ViewGraph - Visualize the ExplodedGraph created by executing the - /// simulation. - void ViewGraph(bool trim = false); - - void ViewGraph(ExplodedNode** Beg, ExplodedNode** End); - - /// getInitialState - Return the initial state used for the root vertex - /// in the ExplodedGraph. - const GRState* getInitialState(const LocationContext *InitLoc); - - ExplodedGraph& getGraph() { return G; } - const ExplodedGraph& getGraph() const { return G; } - - template - void registerCheck(CHECKER *check) { - unsigned entry = Checkers.size(); - void *tag = CHECKER::getTag(); - Checkers.push_back(std::make_pair(tag, check)); - CheckerM[tag] = entry; - } - - Checker *lookupChecker(void *tag) const; - - template - CHECKER *getChecker() const { - return static_cast(lookupChecker(CHECKER::getTag())); - } - - void AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C); - void AddCheck(GRSimpleAPICheck* A); - - /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor - /// nodes by processing the 'effects' of a block-level statement. - void ProcessStmt(CFGElement E, GRStmtNodeBuilder& builder); - - /// ProcessBlockEntrance - Called by GRCoreEngine when start processing - /// a CFGBlock. This method returns true if the analysis should continue - /// exploring the given path, and false otherwise. - bool ProcessBlockEntrance(CFGBlock* B, const GRState* St, - GRBlockCounter BC); - - /// ProcessBranch - Called by GRCoreEngine. Used to generate successor - /// nodes by processing the 'effects' of a branch condition. - void ProcessBranch(Stmt* Condition, Stmt* Term, GRBranchNodeBuilder& builder); - - /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor - /// nodes by processing the 'effects' of a computed goto jump. - void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder); - - /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor - /// nodes by processing the 'effects' of a switch statement. - void ProcessSwitch(GRSwitchNodeBuilder& builder); - - /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path - /// nodes when the control reaches the end of a function. - void ProcessEndPath(GREndPathNodeBuilder& builder); - - /// EvalAssume - Callback function invoked by the ConstraintManager when - /// making assumptions about state values. - const GRState *ProcessAssume(const GRState *state, SVal cond, bool assumption); - - GRStateManager& getStateManager() { return StateMgr; } - const GRStateManager& getStateManager() const { return StateMgr; } - - StoreManager& getStoreManager() { return StateMgr.getStoreManager(); } - - ConstraintManager& getConstraintManager() { - return StateMgr.getConstraintManager(); - } - - // FIXME: Remove when we migrate over to just using ValueManager. - BasicValueFactory& getBasicVals() { - return StateMgr.getBasicVals(); - } - const BasicValueFactory& getBasicVals() const { - return StateMgr.getBasicVals(); - } - - ValueManager &getValueManager() { return ValMgr; } - const ValueManager &getValueManager() const { return ValMgr; } - - // FIXME: Remove when we migrate over to just using ValueManager. - SymbolManager& getSymbolManager() { return SymMgr; } - const SymbolManager& getSymbolManager() const { return SymMgr; } - -protected: - const GRState* GetState(ExplodedNode* N) { - return N == EntryNode ? CleanedState : N->getState(); - } - -public: - ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred, - const GRState* St, - ProgramPoint::Kind K = ProgramPoint::PostStmtKind, - const void *tag = 0); -protected: - /// CheckerVisit - Dispatcher for performing checker-specific logic - /// at specific statements. - void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, - bool isPrevisit); - - bool CheckerEvalCall(const CallExpr *CE, - ExplodedNodeSet &Dst, - ExplodedNode *Pred); - - void CheckerEvalNilReceiver(const ObjCMessageExpr *ME, - ExplodedNodeSet &Dst, - const GRState *state, - ExplodedNode *Pred); - - void CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, - ExplodedNodeSet &Dst, ExplodedNodeSet &Src, - SVal location, SVal val, bool isPrevisit); - - - /// Visit - Transfer function logic for all statements. Dispatches to - /// other functions that handle specific kinds of statements. - void Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst); - - /// VisitLValue - Evaluate the lvalue of the expression. For example, if Ex is - /// a DeclRefExpr, it evaluates to the MemRegionVal which represents its - /// storage location. Note that not all kinds of expressions has lvalue. - void VisitLValue(Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst); - - /// VisitArraySubscriptExpr - Transfer function for array accesses. - void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); - - /// VisitAsmStmt - Transfer function logic for inline asm. - void VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst); - - void VisitAsmStmtHelperOutputs(AsmStmt* A, - AsmStmt::outputs_iterator I, - AsmStmt::outputs_iterator E, - ExplodedNode* Pred, ExplodedNodeSet& Dst); - - void VisitAsmStmtHelperInputs(AsmStmt* A, - AsmStmt::inputs_iterator I, - AsmStmt::inputs_iterator E, - ExplodedNode* Pred, ExplodedNodeSet& Dst); - - /// VisitBlockExpr - Transfer function logic for BlockExprs. - void VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred, ExplodedNodeSet &Dst); - - /// VisitBinaryOperator - Transfer function logic for binary operators. - void VisitBinaryOperator(BinaryOperator* B, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); - - - /// VisitCall - Transfer function for function calls. - void VisitCall(CallExpr* CE, ExplodedNode* Pred, - CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, - ExplodedNodeSet& Dst, bool asLValue); - - /// VisitCast - Transfer function logic for all casts (implicit and explicit). - void VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred, - ExplodedNodeSet &Dst, bool asLValue); - - /// VisitCompoundLiteralExpr - Transfer function logic for compound literals. - void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); - - /// VisitDeclRefExpr - Transfer function logic for DeclRefExprs. - void VisitDeclRefExpr(DeclRefExpr* DR, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); - - /// VisitBlockDeclRefExpr - Transfer function logic for BlockDeclRefExprs. - void VisitBlockDeclRefExpr(BlockDeclRefExpr* DR, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); - - void VisitCommonDeclRefExpr(Expr* DR, const NamedDecl *D,ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); - - /// VisitDeclStmt - Transfer function logic for DeclStmts. - void VisitDeclStmt(DeclStmt* DS, ExplodedNode* Pred, ExplodedNodeSet& Dst); - - /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose - void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, ExplodedNode* Pred, - ExplodedNodeSet& Dst); - - /// VisitCondInit - Transfer function for handling the initialization - /// of a condition variable in an IfStmt, SwitchStmt, etc. - void VisitCondInit(VarDecl *VD, Stmt *S, ExplodedNode *Pred, - ExplodedNodeSet& Dst); - - void VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, - ExplodedNodeSet& Dst); - - /// VisitLogicalExpr - Transfer function logic for '&&', '||' - void VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, - ExplodedNodeSet& Dst); - - /// VisitMemberExpr - Transfer function for member expressions. - void VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, ExplodedNodeSet& Dst, - bool asLValue); - - /// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs. - void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); - - /// VisitObjCForCollectionStmt - Transfer function logic for - /// ObjCForCollectionStmt. - void VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, ExplodedNode* Pred, - ExplodedNodeSet& Dst); - - void VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, - ExplodedNode* Pred, - ExplodedNodeSet& Dst, SVal ElementV); - - /// VisitObjCMessageExpr - Transfer function for ObjC message expressions. - void VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); - - void VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME, - ObjCMessageExpr::arg_iterator I, - ObjCMessageExpr::arg_iterator E, - ExplodedNode* Pred, ExplodedNodeSet& Dst, - bool asLValue); - - void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, - ExplodedNode* Pred, - ExplodedNodeSet& Dst, - bool asLValue); - - /// VisitReturnStmt - Transfer function logic for return statements. - void VisitReturnStmt(ReturnStmt* R, ExplodedNode* Pred, ExplodedNodeSet& Dst); - - /// VisitSizeOfAlignOfExpr - Transfer function for sizeof. - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, ExplodedNode* Pred, - ExplodedNodeSet& Dst); - - /// VisitUnaryOperator - Transfer function logic for unary operators. - void VisitUnaryOperator(UnaryOperator* B, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); - - void VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, - ExplodedNodeSet & Dst); - - /// Create a C++ temporary object for an rvalue. - void CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, - ExplodedNodeSet &Dst); - - /// EvalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic - /// expressions of the form 'x != 0' and generate new nodes (stored in Dst) - /// with those assumptions. - void EvalEagerlyAssume(ExplodedNodeSet& Dst, ExplodedNodeSet& Src, Expr *Ex); - - SVal EvalMinus(SVal X) { - return X.isValid() ? SVator.EvalMinus(cast(X)) : X; - } - - SVal EvalComplement(SVal X) { - return X.isValid() ? SVator.EvalComplement(cast(X)) : X; - } - -public: - - SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op, - NonLoc L, NonLoc R, QualType T) { - return SVator.EvalBinOpNN(state, op, L, R, T); - } - - SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op, - NonLoc L, SVal R, QualType T) { - return R.isValid() ? SVator.EvalBinOpNN(state,op,L, cast(R), T) : R; - } - - SVal EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op, - SVal LHS, SVal RHS, QualType T) { - return SVator.EvalBinOp(ST, Op, LHS, RHS, T); - } - -protected: - void EvalObjCMessageExpr(ExplodedNodeSet& Dst, ObjCMessageExpr* ME, - ExplodedNode* Pred, const GRState *state) { - assert (Builder && "GRStmtNodeBuilder must be defined."); - getTF().EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred, state); - } - - const GRState* MarkBranch(const GRState* St, Stmt* Terminator, - bool branchTaken); - - /// EvalBind - Handle the semantics of binding a value to a specific location. - /// This method is used by EvalStore, VisitDeclStmt, and others. - void EvalBind(ExplodedNodeSet& Dst, Stmt *AssignE, - Stmt* StoreE, ExplodedNode* Pred, - const GRState* St, SVal location, SVal Val, - bool atDeclInit = false); - -public: - // FIXME: 'tag' should be removed, and a LocationContext should be used - // instead. - void EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, - const GRState* St, SVal location, const void *tag = 0, - QualType LoadTy = QualType()); - - // FIXME: 'tag' should be removed, and a LocationContext should be used - // instead. - void EvalStore(ExplodedNodeSet& Dst, Expr* AssignE, Expr* StoreE, - ExplodedNode* Pred, const GRState* St, SVal TargetLV, SVal Val, - const void *tag = 0); -private: - void EvalLoadCommon(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, - const GRState* St, SVal location, const void *tag, - QualType LoadTy); - - // FIXME: 'tag' should be removed, and a LocationContext should be used - // instead. - void EvalLocation(ExplodedNodeSet &Dst, Stmt *S, ExplodedNode* Pred, - const GRState* St, SVal location, - const void *tag, bool isLoad); -}; - -} // end clang namespace - -#endif diff --git a/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h b/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h deleted file mode 100644 index 60db406cd13d..000000000000 --- a/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h +++ /dev/null @@ -1,76 +0,0 @@ -//===-- GRExprEngineBuilders.h - "Builder" classes for GRExprEngine -*- C++ -*-= -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines smart builder "references" which are used to marshal -// builders between GRExprEngine objects and their related components. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS -#define LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/Support/SaveAndRestore.h" - -namespace clang { - -class GRStmtNodeBuilderRef { - ExplodedNodeSet &Dst; - GRStmtNodeBuilder &B; - GRExprEngine& Eng; - ExplodedNode* Pred; - const GRState* state; - const Stmt* stmt; - const unsigned OldSize; - const bool AutoCreateNode; - SaveAndRestore OldSink; - SaveAndRestore OldTag; - SaveOr OldHasGen; - -private: - friend class GRExprEngine; - - GRStmtNodeBuilderRef(); // do not implement - void operator=(const GRStmtNodeBuilderRef&); // do not implement - - GRStmtNodeBuilderRef(ExplodedNodeSet &dst, - GRStmtNodeBuilder &builder, - GRExprEngine& eng, - ExplodedNode* pred, - const GRState *st, - const Stmt* s, bool auto_create_node) - : Dst(dst), B(builder), Eng(eng), Pred(pred), - state(st), stmt(s), OldSize(Dst.size()), AutoCreateNode(auto_create_node), - OldSink(B.BuildSinks), OldTag(B.Tag), OldHasGen(B.HasGeneratedNode) {} - -public: - - ~GRStmtNodeBuilderRef() { - // Handle the case where no nodes where generated. Auto-generate that - // contains the updated state if we aren't generating sinks. - if (!B.BuildSinks && Dst.size() == OldSize && !B.HasGeneratedNode) { - if (AutoCreateNode) - B.MakeNode(Dst, const_cast(stmt), Pred, state); - else - Dst.Add(Pred); - } - } - - const GRState *getState() { return state; } - - GRStateManager& getStateManager() { - return Eng.getStateManager(); - } - - ExplodedNode* MakeNode(const GRState* state) { - return B.MakeNode(Dst, const_cast(stmt), Pred, state); - } -}; - -} // end clang namespace -#endif diff --git a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h deleted file mode 100644 index 978ff0889e64..000000000000 --- a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h +++ /dev/null @@ -1,40 +0,0 @@ -// GRCheckAPI.h - Simple API checks based on GRAuditor ------------*- C++ -*--// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the interface for building simple, path-sensitive checks -// that are stateless and only emit warnings at errors that occur at -// CallExpr or ObjCMessageExpr. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_GRAPICHECKS -#define LLVM_CLANG_ANALYSIS_GRAPICHECKS - -#include "clang/Analysis/PathSensitive/GRAuditor.h" -#include "clang/Analysis/PathSensitive/GRState.h" - -namespace clang { - -class Diagnostic; -class BugReporter; -class ASTContext; -class GRExprEngine; -class PathDiagnosticClient; -class ExplodedGraph; - - -class GRSimpleAPICheck : public GRAuditor { -public: - GRSimpleAPICheck() {} - virtual ~GRSimpleAPICheck() {} -}; - -} // end namespace clang - -#endif diff --git a/include/clang/Analysis/PathSensitive/GRState.h b/include/clang/Analysis/PathSensitive/GRState.h deleted file mode 100644 index 11cdac0e96de..000000000000 --- a/include/clang/Analysis/PathSensitive/GRState.h +++ /dev/null @@ -1,751 +0,0 @@ -//== GRState*h - Path-Sens. "State" for tracking valuues -----*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines SymbolRef, ExprBindKey, and GRState* -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_VALUESTATE_H -#define LLVM_CLANG_ANALYSIS_VALUESTATE_H - -// FIXME: Reduce the number of includes. - -#include "clang/Analysis/PathSensitive/Environment.h" -#include "clang/Analysis/PathSensitive/Store.h" -#include "clang/Analysis/PathSensitive/ConstraintManager.h" -#include "clang/Analysis/PathSensitive/ValueManager.h" -#include "clang/Analysis/PathSensitive/GRCoreEngine.h" -#include "clang/AST/Expr.h" -#include "clang/AST/Decl.h" -#include "clang/AST/ASTContext.h" -#include "clang/Analysis/Analyses/LiveVariables.h" -#include "llvm/Support/Casting.h" -#include "llvm/System/DataTypes.h" -#include "llvm/ADT/APSInt.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/ImmutableMap.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/raw_ostream.h" - -#include - -namespace clang { - -class GRStateManager; -class Checker; - -typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&, - GRSubEngine&); -typedef StoreManager* (*StoreManagerCreator)(GRStateManager&); - -//===----------------------------------------------------------------------===// -// GRStateTrait - Traits used by the Generic Data Map of a GRState. -//===----------------------------------------------------------------------===// - -template struct GRStatePartialTrait; - -template struct GRStateTrait { - typedef typename T::data_type data_type; - static inline void* GDMIndex() { return &T::TagInt; } - static inline void* MakeVoidPtr(data_type D) { return (void*) D; } - static inline data_type MakeData(void* const* P) { - return P ? (data_type) *P : (data_type) 0; - } -}; - -//===----------------------------------------------------------------------===// -// GRState- An ImmutableMap type Stmt*/Decl*/Symbols to SVals. -//===----------------------------------------------------------------------===// - -class GRStateManager; - -/// GRState - This class encapsulates the actual data values for -/// for a "state" in our symbolic value tracking. It is intended to be -/// used as a functional object; that is once it is created and made -/// "persistent" in a FoldingSet its values will never change. -class GRState : public llvm::FoldingSetNode { -public: - typedef llvm::ImmutableSet IntSetTy; - typedef llvm::ImmutableMap GenericDataMap; - -private: - void operator=(const GRState& R) const; - - friend class GRStateManager; - - GRStateManager *StateMgr; - Environment Env; - Store St; - - // FIXME: Make these private. -public: - GenericDataMap GDM; - -public: - - /// This ctor is used when creating the first GRState object. - GRState(GRStateManager *mgr, const Environment& env, - Store st, GenericDataMap gdm) - : StateMgr(mgr), - Env(env), - St(st), - GDM(gdm) {} - - /// Copy ctor - We must explicitly define this or else the "Next" ptr - /// in FoldingSetNode will also get copied. - GRState(const GRState& RHS) - : llvm::FoldingSetNode(), - StateMgr(RHS.StateMgr), - Env(RHS.Env), - St(RHS.St), - GDM(RHS.GDM) {} - - /// getStateManager - Return the GRStateManager associated with this state. - GRStateManager &getStateManager() const { - return *StateMgr; - } - - /// getAnalysisContext - Return the AnalysisContext associated with this - /// state. - AnalysisContext &getAnalysisContext() const { - return Env.getAnalysisContext(); - } - - /// getEnvironment - Return the environment associated with this state. - /// The environment is the mapping from expressions to values. - const Environment& getEnvironment() const { return Env; } - - /// getStore - Return the store associated with this state. The store - /// is a mapping from locations to values. - Store getStore() const { return St; } - - void setStore(Store s) { St = s; } - - /// getGDM - Return the generic data map associated with this state. - GenericDataMap getGDM() const { return GDM; } - - void setGDM(GenericDataMap gdm) { GDM = gdm; } - - /// Profile - Profile the contents of a GRState object for use - /// in a FoldingSet. - static void Profile(llvm::FoldingSetNodeID& ID, const GRState* V) { - // FIXME: Do we need to include the AnalysisContext in the profile? - V->Env.Profile(ID); - ID.AddPointer(V->St); - V->GDM.Profile(ID); - } - - /// Profile - Used to profile the contents of this object for inclusion - /// in a FoldingSet. - void Profile(llvm::FoldingSetNodeID& ID) const { - Profile(ID, this); - } - - SVal LookupExpr(Expr* E) const { - return Env.LookupExpr(E); - } - - /// makeWithStore - Return a GRState with the same values as the current - /// state with the exception of using the specified Store. - const GRState *makeWithStore(Store store) const; - - BasicValueFactory &getBasicVals() const; - SymbolManager &getSymbolManager() const; - - //==---------------------------------------------------------------------==// - // Constraints on values. - //==---------------------------------------------------------------------==// - // - // Each GRState records constraints on symbolic values. These constraints - // are managed using the ConstraintManager associated with a GRStateManager. - // As constraints gradually accrue on symbolic values, added constraints - // may conflict and indicate that a state is infeasible (as no real values - // could satisfy all the constraints). This is the principal mechanism - // for modeling path-sensitivity in GRExprEngine/GRState. - // - // Various "Assume" methods form the interface for adding constraints to - // symbolic values. A call to "Assume" indicates an assumption being placed - // on one or symbolic values. Assume methods take the following inputs: - // - // (1) A GRState object representing the current state. - // - // (2) The assumed constraint (which is specific to a given "Assume" method). - // - // (3) A binary value "Assumption" that indicates whether the constraint is - // assumed to be true or false. - // - // The output of "Assume" are two values: - // - // (a) "isFeasible" is set to true or false to indicate whether or not - // the assumption is feasible. - // - // (b) A new GRState object with the added constraints. - // - // FIXME: (a) should probably disappear since it is redundant with (b). - // (i.e., (b) could just be set to NULL). - // - - const GRState *Assume(DefinedOrUnknownSVal cond, bool assumption) const; - - std::pair - Assume(DefinedOrUnknownSVal cond) const; - - const GRState *AssumeInBound(DefinedOrUnknownSVal idx, - DefinedOrUnknownSVal upperBound, - bool assumption) const; - - //==---------------------------------------------------------------------==// - // Utility methods for getting regions. - //==---------------------------------------------------------------------==// - - const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const; - - //==---------------------------------------------------------------------==// - // Binding and retrieving values to/from the environment and symbolic store. - //==---------------------------------------------------------------------==// - - /// BindCompoundLiteral - Return the state that has the bindings currently - /// in 'state' plus the bindings for the CompoundLiteral. 'R' is the region - /// for the compound literal and 'BegInit' and 'EndInit' represent an - /// array of initializer values. - const GRState* bindCompoundLiteral(const CompoundLiteralExpr* CL, - const LocationContext *LC, - SVal V) const; - - const GRState *BindExpr(const Stmt *S, SVal V, bool Invalidate = true) const; - - const GRState *bindDecl(const VarRegion *VR, SVal V) const; - - const GRState *bindDeclWithNoInit(const VarRegion *VR) const; - - const GRState *bindLoc(Loc location, SVal V) const; - - const GRState *bindLoc(SVal location, SVal V) const; - - const GRState *unbindLoc(Loc LV) const; - - /// Get the lvalue for a variable reference. - SVal getLValue(const VarDecl *D, const LocationContext *LC) const; - - /// Get the lvalue for a StringLiteral. - SVal getLValue(const StringLiteral *literal) const; - - SVal getLValue(const CompoundLiteralExpr *literal, - const LocationContext *LC) const; - - /// Get the lvalue for an ivar reference. - SVal getLValue(const ObjCIvarDecl *decl, SVal base) const; - - /// Get the lvalue for a field reference. - SVal getLValue(const FieldDecl *decl, SVal Base) const; - - /// Get the lvalue for an array index. - SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const; - - const llvm::APSInt *getSymVal(SymbolRef sym) const; - - SVal getSVal(const Stmt* Ex) const; - - SVal getSValAsScalarOrLoc(const Stmt *Ex) const; - - SVal getSVal(Loc LV, QualType T = QualType()) const; - - SVal getSVal(const MemRegion* R) const; - - SVal getSValAsScalarOrLoc(const MemRegion *R) const; - - const llvm::APSInt *getSymVal(SymbolRef sym); - - bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const; - - bool scanReachableSymbols(const SVal *I, const SVal *E, - SymbolVisitor &visitor) const; - - bool scanReachableSymbols(const MemRegion * const *I, - const MemRegion * const *E, - SymbolVisitor &visitor) const; - - template CB scanReachableSymbols(SVal val) const; - template CB scanReachableSymbols(const SVal *beg, - const SVal *end) const; - - template CB - scanReachableSymbols(const MemRegion * const *beg, - const MemRegion * const *end) const; - - //==---------------------------------------------------------------------==// - // Accessing the Generic Data Map (GDM). - //==---------------------------------------------------------------------==// - - void* const* FindGDM(void* K) const; - - template - const GRState *add(typename GRStateTrait::key_type K) const; - - template - typename GRStateTrait::data_type - get() const { - return GRStateTrait::MakeData(FindGDM(GRStateTrait::GDMIndex())); - } - - template - typename GRStateTrait::lookup_type - get(typename GRStateTrait::key_type key) const { - void* const* d = FindGDM(GRStateTrait::GDMIndex()); - return GRStateTrait::Lookup(GRStateTrait::MakeData(d), key); - } - - template - typename GRStateTrait::context_type get_context() const; - - - template - const GRState *remove(typename GRStateTrait::key_type K) const; - - template - const GRState *remove(typename GRStateTrait::key_type K, - typename GRStateTrait::context_type C) const; - - template - const GRState *set(typename GRStateTrait::data_type D) const; - - template - const GRState *set(typename GRStateTrait::key_type K, - typename GRStateTrait::value_type E) const; - - template - const GRState *set(typename GRStateTrait::key_type K, - typename GRStateTrait::value_type E, - typename GRStateTrait::context_type C) const; - - template - bool contains(typename GRStateTrait::key_type key) const { - void* const* d = FindGDM(GRStateTrait::GDMIndex()); - return GRStateTrait::Contains(GRStateTrait::MakeData(d), key); - } - - // State pretty-printing. - class Printer { - public: - virtual ~Printer() {} - virtual void Print(llvm::raw_ostream& Out, const GRState* state, - const char* nl, const char* sep) = 0; - }; - - // Pretty-printing. - void print(llvm::raw_ostream& Out, const char *nl = "\n", - const char *sep = "") const; - - void printStdErr() const; - - void printDOT(llvm::raw_ostream& Out) const; -}; - -class GRStateSet { - typedef llvm::SmallPtrSet ImplTy; - ImplTy Impl; -public: - GRStateSet() {} - - inline void Add(const GRState* St) { - Impl.insert(St); - } - - typedef ImplTy::const_iterator iterator; - - inline unsigned size() const { return Impl.size(); } - inline bool empty() const { return Impl.empty(); } - - inline iterator begin() const { return Impl.begin(); } - inline iterator end() const { return Impl.end(); } - - class AutoPopulate { - GRStateSet& S; - unsigned StartSize; - const GRState* St; - public: - AutoPopulate(GRStateSet& s, const GRState* st) - : S(s), StartSize(S.size()), St(st) {} - - ~AutoPopulate() { - if (StartSize == S.size()) - S.Add(St); - } - }; -}; - -//===----------------------------------------------------------------------===// -// GRStateManager - Factory object for GRStates. -//===----------------------------------------------------------------------===// - -class GRStateManager { - friend class GRState; - friend class GRExprEngine; // FIXME: Remove. -private: - EnvironmentManager EnvMgr; - llvm::OwningPtr StoreMgr; - llvm::OwningPtr ConstraintMgr; - - GRState::GenericDataMap::Factory GDMFactory; - - typedef llvm::DenseMap > GDMContextsTy; - GDMContextsTy GDMContexts; - - /// Printers - A set of printer objects used for pretty-printing a GRState. - /// GRStateManager owns these objects. - std::vector Printers; - - /// StateSet - FoldingSet containing all the states created for analyzing - /// a particular function. This is used to unique states. - llvm::FoldingSet StateSet; - - /// ValueMgr - Object that manages the data for all created SVals. - ValueManager ValueMgr; - - /// Alloc - A BumpPtrAllocator to allocate states. - llvm::BumpPtrAllocator &Alloc; - -public: - GRStateManager(ASTContext& Ctx, - StoreManagerCreator CreateStoreManager, - ConstraintManagerCreator CreateConstraintManager, - llvm::BumpPtrAllocator& alloc, - GRSubEngine &subeng) - : EnvMgr(alloc), - GDMFactory(alloc), - ValueMgr(alloc, Ctx, *this), - Alloc(alloc) { - StoreMgr.reset((*CreateStoreManager)(*this)); - ConstraintMgr.reset((*CreateConstraintManager)(*this, subeng)); - } - - ~GRStateManager(); - - const GRState *getInitialState(const LocationContext *InitLoc); - - ASTContext &getContext() { return ValueMgr.getContext(); } - const ASTContext &getContext() const { return ValueMgr.getContext(); } - - BasicValueFactory &getBasicVals() { - return ValueMgr.getBasicValueFactory(); - } - const BasicValueFactory& getBasicVals() const { - return ValueMgr.getBasicValueFactory(); - } - - SymbolManager &getSymbolManager() { - return ValueMgr.getSymbolManager(); - } - const SymbolManager &getSymbolManager() const { - return ValueMgr.getSymbolManager(); - } - - ValueManager &getValueManager() { return ValueMgr; } - const ValueManager &getValueManager() const { return ValueMgr; } - - llvm::BumpPtrAllocator& getAllocator() { return Alloc; } - - MemRegionManager& getRegionManager() { - return ValueMgr.getRegionManager(); - } - const MemRegionManager& getRegionManager() const { - return ValueMgr.getRegionManager(); - } - - StoreManager& getStoreManager() { return *StoreMgr; } - ConstraintManager& getConstraintManager() { return *ConstraintMgr; } - - const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc, - SymbolReaper& SymReaper); - -public: - - SVal ArrayToPointer(Loc Array) { - return StoreMgr->ArrayToPointer(Array); - } - - // Methods that manipulate the GDM. - const GRState* addGDM(const GRState* St, void* Key, void* Data); - - // Methods that query & manipulate the Store. - - void iterBindings(const GRState* state, StoreManager::BindingsHandler& F) { - StoreMgr->iterBindings(state->getStore(), F); - } - - const GRState* getPersistentState(GRState& Impl); - - bool isEqual(const GRState* state, const Expr* Ex, const llvm::APSInt& V); - bool isEqual(const GRState* state, const Expr* Ex, uint64_t); - - //==---------------------------------------------------------------------==// - // Generic Data Map methods. - //==---------------------------------------------------------------------==// - // - // GRStateManager and GRState support a "generic data map" that allows - // different clients of GRState objects to embed arbitrary data within a - // GRState object. The generic data map is essentially an immutable map - // from a "tag" (that acts as the "key" for a client) and opaque values. - // Tags/keys and values are simply void* values. The typical way that clients - // generate unique tags are by taking the address of a static variable. - // Clients are responsible for ensuring that data values referred to by a - // the data pointer are immutable (and thus are essentially purely functional - // data). - // - // The templated methods below use the GRStateTrait class - // to resolve keys into the GDM and to return data values to clients. - // - - // Trait based GDM dispatch. - template - const GRState* set(const GRState* st, typename GRStateTrait::data_type D) { - return addGDM(st, GRStateTrait::GDMIndex(), - GRStateTrait::MakeVoidPtr(D)); - } - - template - const GRState* set(const GRState* st, - typename GRStateTrait::key_type K, - typename GRStateTrait::value_type V, - typename GRStateTrait::context_type C) { - - return addGDM(st, GRStateTrait::GDMIndex(), - GRStateTrait::MakeVoidPtr(GRStateTrait::Set(st->get(), K, V, C))); - } - - template - const GRState* add(const GRState* st, - typename GRStateTrait::key_type K, - typename GRStateTrait::context_type C) { - return addGDM(st, GRStateTrait::GDMIndex(), - GRStateTrait::MakeVoidPtr(GRStateTrait::Add(st->get(), K, C))); - } - - template - const GRState* remove(const GRState* st, - typename GRStateTrait::key_type K, - typename GRStateTrait::context_type C) { - - return addGDM(st, GRStateTrait::GDMIndex(), - GRStateTrait::MakeVoidPtr(GRStateTrait::Remove(st->get(), K, C))); - } - - - void* FindGDMContext(void* index, - void* (*CreateContext)(llvm::BumpPtrAllocator&), - void (*DeleteContext)(void*)); - - template - typename GRStateTrait::context_type get_context() { - void* p = FindGDMContext(GRStateTrait::GDMIndex(), - GRStateTrait::CreateContext, - GRStateTrait::DeleteContext); - - return GRStateTrait::MakeContext(p); - } - - const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) { - return ConstraintMgr->getSymVal(St, sym); - } - - void EndPath(const GRState* St) { - ConstraintMgr->EndPath(St); - } -}; - - -//===----------------------------------------------------------------------===// -// Out-of-line method definitions for GRState. -//===----------------------------------------------------------------------===// - -inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) { - return getStateManager().getSymVal(this, sym); -} - -inline const VarRegion* GRState::getRegion(const VarDecl *D, - const LocationContext *LC) const { - return getStateManager().getRegionManager().getVarRegion(D, LC); -} - -inline const GRState *GRState::Assume(DefinedOrUnknownSVal Cond, - bool Assumption) const { - if (Cond.isUnknown()) - return this; - - return getStateManager().ConstraintMgr->Assume(this, cast(Cond), - Assumption); -} - -inline std::pair -GRState::Assume(DefinedOrUnknownSVal Cond) const { - if (Cond.isUnknown()) - return std::make_pair(this, this); - - return getStateManager().ConstraintMgr->AssumeDual(this, - cast(Cond)); -} - -inline const GRState *GRState::AssumeInBound(DefinedOrUnknownSVal Idx, - DefinedOrUnknownSVal UpperBound, - bool Assumption) const { - if (Idx.isUnknown() || UpperBound.isUnknown()) - return this; - - ConstraintManager &CM = *getStateManager().ConstraintMgr; - return CM.AssumeInBound(this, cast(Idx), - cast(UpperBound), Assumption); -} - -inline const GRState * -GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL, - const LocationContext *LC, SVal V) const { - return getStateManager().StoreMgr->BindCompoundLiteral(this, CL, LC, V); -} - -inline const GRState *GRState::bindDecl(const VarRegion* VR, SVal IVal) const { - return getStateManager().StoreMgr->BindDecl(this, VR, IVal); -} - -inline const GRState *GRState::bindDeclWithNoInit(const VarRegion* VR) const { - return getStateManager().StoreMgr->BindDeclWithNoInit(this, VR); -} - -inline const GRState *GRState::bindLoc(Loc LV, SVal V) const { - return getStateManager().StoreMgr->Bind(this, LV, V); -} - -inline const GRState *GRState::bindLoc(SVal LV, SVal V) const { - return !isa(LV) ? this : bindLoc(cast(LV), V); -} - -inline SVal GRState::getLValue(const VarDecl* VD, - const LocationContext *LC) const { - return getStateManager().StoreMgr->getLValueVar(VD, LC); -} - -inline SVal GRState::getLValue(const StringLiteral *literal) const { - return getStateManager().StoreMgr->getLValueString(literal); -} - -inline SVal GRState::getLValue(const CompoundLiteralExpr *literal, - const LocationContext *LC) const { - return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, LC); -} - -inline SVal GRState::getLValue(const ObjCIvarDecl *D, SVal Base) const { - return getStateManager().StoreMgr->getLValueIvar(D, Base); -} - -inline SVal GRState::getLValue(const FieldDecl* D, SVal Base) const { - return getStateManager().StoreMgr->getLValueField(D, Base); -} - -inline SVal GRState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{ - return getStateManager().StoreMgr->getLValueElement(ElementType, Idx, Base); -} - -inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) const { - return getStateManager().getSymVal(this, sym); -} - -inline SVal GRState::getSVal(const Stmt* Ex) const { - return Env.GetSVal(Ex, getStateManager().ValueMgr); -} - -inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const { - if (const Expr *Ex = dyn_cast(S)) { - QualType T = Ex->getType(); - if (Loc::IsLocType(T) || T->isIntegerType()) - return getSVal(S); - } - - return UnknownVal(); -} - -inline SVal GRState::getSVal(Loc LV, QualType T) const { - return getStateManager().StoreMgr->Retrieve(this, LV, T).getSVal(); -} - -inline SVal GRState::getSVal(const MemRegion* R) const { - return getStateManager().StoreMgr->Retrieve(this, loc::MemRegionVal(R)).getSVal(); -} - -inline BasicValueFactory &GRState::getBasicVals() const { - return getStateManager().getBasicVals(); -} - -inline SymbolManager &GRState::getSymbolManager() const { - return getStateManager().getSymbolManager(); -} - -template -const GRState *GRState::add(typename GRStateTrait::key_type K) const { - return getStateManager().add(this, K, get_context()); -} - -template -typename GRStateTrait::context_type GRState::get_context() const { - return getStateManager().get_context(); -} - -template -const GRState *GRState::remove(typename GRStateTrait::key_type K) const { - return getStateManager().remove(this, K, get_context()); -} - -template -const GRState *GRState::remove(typename GRStateTrait::key_type K, - typename GRStateTrait::context_type C) const { - return getStateManager().remove(this, K, C); -} - -template -const GRState *GRState::set(typename GRStateTrait::data_type D) const { - return getStateManager().set(this, D); -} - -template -const GRState *GRState::set(typename GRStateTrait::key_type K, - typename GRStateTrait::value_type E) const { - return getStateManager().set(this, K, E, get_context()); -} - -template -const GRState *GRState::set(typename GRStateTrait::key_type K, - typename GRStateTrait::value_type E, - typename GRStateTrait::context_type C) const { - return getStateManager().set(this, K, E, C); -} - -template -CB GRState::scanReachableSymbols(SVal val) const { - CB cb(this); - scanReachableSymbols(val, cb); - return cb; -} - -template -CB GRState::scanReachableSymbols(const SVal *beg, const SVal *end) const { - CB cb(this); - scanReachableSymbols(beg, end, cb); - return cb; -} - -template -CB GRState::scanReachableSymbols(const MemRegion * const *beg, - const MemRegion * const *end) const { - CB cb(this); - scanReachableSymbols(beg, end, cb); - return cb; -} -} // end clang namespace - -#endif diff --git a/include/clang/Analysis/PathSensitive/GRStateTrait.h b/include/clang/Analysis/PathSensitive/GRStateTrait.h deleted file mode 100644 index 5189a1f5aa7e..000000000000 --- a/include/clang/Analysis/PathSensitive/GRStateTrait.h +++ /dev/null @@ -1,148 +0,0 @@ -//==- GRStateTrait.h - Partial implementations of GRStateTrait -----*- C++ -*-// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines partial implementations of template specializations of -// the class GRStateTrait<>. GRStateTrait<> is used by GRState to implement -// set/get methods for mapulating a GRState's generic data map. -// -//===----------------------------------------------------------------------===// - - -#ifndef LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H -#define LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H - -namespace llvm { - class BumpPtrAllocator; - template class ImmutableMap; - template class ImmutableSet; - template class ImmutableList; - template class ImmutableListImpl; -} - -namespace clang { - template struct GRStatePartialTrait; - - // Partial-specialization for ImmutableMap. - - template - struct GRStatePartialTrait< llvm::ImmutableMap > { - typedef llvm::ImmutableMap data_type; - typedef typename data_type::Factory& context_type; - typedef Key key_type; - typedef Data value_type; - typedef const value_type* lookup_type; - - static inline data_type MakeData(void* const* p) { - return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0); - } - static inline void* MakeVoidPtr(data_type B) { - return B.getRoot(); - } - static lookup_type Lookup(data_type B, key_type K) { - return B.lookup(K); - } - static data_type Set(data_type B, key_type K, value_type E,context_type F){ - return F.Add(B, K, E); - } - - static data_type Remove(data_type B, key_type K, context_type F) { - return F.Remove(B, K); - } - - static inline context_type MakeContext(void* p) { - return *((typename data_type::Factory*) p); - } - - static void* CreateContext(llvm::BumpPtrAllocator& Alloc) { - return new typename data_type::Factory(Alloc); - } - - static void DeleteContext(void* Ctx) { - delete (typename data_type::Factory*) Ctx; - } - }; - - - // Partial-specialization for ImmutableSet. - - template - struct GRStatePartialTrait< llvm::ImmutableSet > { - typedef llvm::ImmutableSet data_type; - typedef typename data_type::Factory& context_type; - typedef Key key_type; - - static inline data_type MakeData(void* const* p) { - return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0); - } - - static inline void* MakeVoidPtr(data_type B) { - return B.getRoot(); - } - - static data_type Add(data_type B, key_type K, context_type F) { - return F.Add(B, K); - } - - static data_type Remove(data_type B, key_type K, context_type F) { - return F.Remove(B, K); - } - - static bool Contains(data_type B, key_type K) { - return B.contains(K); - } - - static inline context_type MakeContext(void* p) { - return *((typename data_type::Factory*) p); - } - - static void* CreateContext(llvm::BumpPtrAllocator& Alloc) { - return new typename data_type::Factory(Alloc); - } - - static void DeleteContext(void* Ctx) { - delete (typename data_type::Factory*) Ctx; - } - }; - - // Partial-specialization for ImmutableList. - - template - struct GRStatePartialTrait< llvm::ImmutableList > { - typedef llvm::ImmutableList data_type; - typedef T key_type; - typedef typename data_type::Factory& context_type; - - static data_type Add(data_type L, key_type K, context_type F) { - return F.Add(K, L); - } - - static inline data_type MakeData(void* const* p) { - return p ? data_type((const llvm::ImmutableListImpl*) *p) - : data_type(0); - } - - static inline void* MakeVoidPtr(data_type D) { - return (void*) D.getInternalPointer(); - } - - static inline context_type MakeContext(void* p) { - return *((typename data_type::Factory*) p); - } - - static void* CreateContext(llvm::BumpPtrAllocator& Alloc) { - return new typename data_type::Factory(Alloc); - } - - static void DeleteContext(void* Ctx) { - delete (typename data_type::Factory*) Ctx; - } - }; -} // end clang namespace - -#endif diff --git a/include/clang/Analysis/PathSensitive/GRSubEngine.h b/include/clang/Analysis/PathSensitive/GRSubEngine.h deleted file mode 100644 index 5b383fae9bd0..000000000000 --- a/include/clang/Analysis/PathSensitive/GRSubEngine.h +++ /dev/null @@ -1,75 +0,0 @@ -//== GRSubEngine.h - Interface of the subengine of GRCoreEngine ----*- C++ -*-// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the interface of a subengine of the GRCoreEngine. -// -//===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_GRSUBENGINE_H -#define LLVM_CLANG_ANALYSIS_GRSUBENGINE_H - -#include "clang/Analysis/PathSensitive/SVals.h" - -namespace clang { - -class Stmt; -class CFGBlock; -class CFGElement; -class GRState; -class GRStateManager; -class GRBlockCounter; -class GRStmtNodeBuilder; -class GRBranchNodeBuilder; -class GRIndirectGotoNodeBuilder; -class GRSwitchNodeBuilder; -class GREndPathNodeBuilder; -class LocationContext; - -class GRSubEngine { -public: - virtual ~GRSubEngine() {} - - virtual const GRState* getInitialState(const LocationContext *InitLoc) = 0; - - virtual GRStateManager& getStateManager() = 0; - - /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor - /// nodes by processing the 'effects' of a block-level statement. - virtual void ProcessStmt(CFGElement E, GRStmtNodeBuilder& builder) = 0; - - /// ProcessBlockEntrance - Called by GRCoreEngine when start processing - /// a CFGBlock. This method returns true if the analysis should continue - /// exploring the given path, and false otherwise. - virtual bool ProcessBlockEntrance(CFGBlock* B, const GRState* St, - GRBlockCounter BC) = 0; - - /// ProcessBranch - Called by GRCoreEngine. Used to generate successor - /// nodes by processing the 'effects' of a branch condition. - virtual void ProcessBranch(Stmt* Condition, Stmt* Term, - GRBranchNodeBuilder& builder) = 0; - - /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor - /// nodes by processing the 'effects' of a computed goto jump. - virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) = 0; - - /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor - /// nodes by processing the 'effects' of a switch statement. - virtual void ProcessSwitch(GRSwitchNodeBuilder& builder) = 0; - - /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path - /// nodes when the control reaches the end of a function. - virtual void ProcessEndPath(GREndPathNodeBuilder& builder) = 0; - - /// EvalAssume - Called by ConstraintManager. Used to call checker-specific - /// logic for handling assumptions on symbolic values. - virtual const GRState* ProcessAssume(const GRState *state, - SVal cond, bool assumption) = 0; -}; -} - -#endif diff --git a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h deleted file mode 100644 index b058460a4934..000000000000 --- a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h +++ /dev/null @@ -1,85 +0,0 @@ -//== GRTransferFuncs.h - Path-Sens. Transfer Functions Interface -*- C++ -*--=// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines GRTransferFuncs, which provides a base-class that -// defines an interface for transfer functions used by GRExprEngine. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_GRTF -#define LLVM_CLANG_ANALYSIS_GRTF - -#include "clang/Analysis/PathSensitive/SVals.h" -#include "clang/Analysis/PathSensitive/GRCoreEngine.h" -#include "clang/Analysis/PathSensitive/GRState.h" -#include - -namespace clang { - -class GRExprEngine; -class ObjCMessageExpr; -class GRStmtNodeBuilderRef; - -class GRTransferFuncs { -public: - GRTransferFuncs() {} - virtual ~GRTransferFuncs() {} - - virtual void RegisterPrinters(std::vector& Printers) {} - virtual void RegisterChecks(GRExprEngine& Eng) {} - - - // Calls. - - virtual void EvalCall(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - CallExpr* CE, SVal L, - ExplodedNode* Pred) {} - - virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - ObjCMessageExpr* ME, - ExplodedNode* Pred, - const GRState *state) {} - - // Stores. - - virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) {} - - // End-of-path and dead symbol notification. - - virtual void EvalEndPath(GRExprEngine& Engine, - GREndPathNodeBuilder& Builder) {} - - - virtual void EvalDeadSymbols(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - ExplodedNode* Pred, - Stmt* S, const GRState* state, - SymbolReaper& SymReaper) {} - - // Return statements. - virtual void EvalReturn(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - ReturnStmt* S, - ExplodedNode* Pred) {} - - // Assumptions. - virtual const GRState* EvalAssume(const GRState *state, - SVal Cond, bool Assumption) { - return state; - } -}; -} // end clang namespace - -#endif diff --git a/include/clang/Analysis/PathSensitive/GRWorkList.h b/include/clang/Analysis/PathSensitive/GRWorkList.h deleted file mode 100644 index 857fa316911f..000000000000 --- a/include/clang/Analysis/PathSensitive/GRWorkList.h +++ /dev/null @@ -1,79 +0,0 @@ -//==- GRWorkList.h - Worklist class used by GRCoreEngine -----------*- C++ -*-// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines GRWorkList, a pure virtual class that represents an opaque -// worklist used by GRCoreEngine to explore the reachability state space. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_GRWORKLIST -#define LLVM_CLANG_ANALYSIS_GRWORKLIST - -#include "clang/Analysis/PathSensitive/GRBlockCounter.h" -#include - -namespace clang { - -class CFGBlock; -class ExplodedNode; -class ExplodedNodeImpl; - -class GRWorkListUnit { - ExplodedNode* Node; - GRBlockCounter Counter; - CFGBlock* Block; - unsigned BlockIdx; // This is the index of the next statement. - -public: - GRWorkListUnit(ExplodedNode* N, GRBlockCounter C, - CFGBlock* B, unsigned idx) - : Node(N), - Counter(C), - Block(B), - BlockIdx(idx) {} - - explicit GRWorkListUnit(ExplodedNode* N, GRBlockCounter C) - : Node(N), - Counter(C), - Block(NULL), - BlockIdx(0) {} - - ExplodedNode* getNode() const { return Node; } - GRBlockCounter getBlockCounter() const { return Counter; } - CFGBlock* getBlock() const { return Block; } - unsigned getIndex() const { return BlockIdx; } -}; - -class GRWorkList { - GRBlockCounter CurrentCounter; -public: - virtual ~GRWorkList(); - virtual bool hasWork() const = 0; - - virtual void Enqueue(const GRWorkListUnit& U) = 0; - - void Enqueue(ExplodedNode* N, CFGBlock& B, unsigned idx) { - Enqueue(GRWorkListUnit(N, CurrentCounter, &B, idx)); - } - - void Enqueue(ExplodedNode* N) { - Enqueue(GRWorkListUnit(N, CurrentCounter)); - } - - virtual GRWorkListUnit Dequeue() = 0; - - void setBlockCounter(GRBlockCounter C) { CurrentCounter = C; } - GRBlockCounter getBlockCounter() const { return CurrentCounter; } - - static GRWorkList *MakeDFS(); - static GRWorkList *MakeBFS(); - static GRWorkList *MakeBFSBlockDFSContents(); -}; -} // end clang namespace -#endif diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h deleted file mode 100644 index 3bcedbefd65c..000000000000 --- a/include/clang/Analysis/PathSensitive/MemRegion.h +++ /dev/null @@ -1,971 +0,0 @@ -//== MemRegion.h - Abstract memory regions for static analysis --*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines MemRegion and its subclasses. MemRegion defines a -// partially-typed abstraction of memory useful for path-sensitive dataflow -// analyses. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_MEMREGION_H -#define LLVM_CLANG_ANALYSIS_MEMREGION_H - -#include "clang/AST/Decl.h" -#include "clang/AST/DeclObjC.h" -#include "clang/Analysis/PathSensitive/SymbolManager.h" -#include "clang/Analysis/PathSensitive/SVals.h" -#include "clang/AST/ASTContext.h" -#include "llvm/Support/Casting.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/ImmutableList.h" -#include "llvm/ADT/ImmutableMap.h" -#include "llvm/Support/Allocator.h" -#include - -namespace llvm { class raw_ostream; } - -namespace clang { - -class MemRegionManager; -class MemSpaceRegion; -class LocationContext; -class StackFrameContext; -class VarRegion; - -//===----------------------------------------------------------------------===// -// Base region classes. -//===----------------------------------------------------------------------===// - -/// MemRegion - The root abstract class for all memory regions. -class MemRegion : public llvm::FoldingSetNode { - friend class MemRegionManager; -public: - enum Kind { - // Memory spaces. - BEG_MEMSPACES, - GenericMemSpaceRegionKind = BEG_MEMSPACES, - StackLocalsSpaceRegionKind, - StackArgumentsSpaceRegionKind, - HeapSpaceRegionKind, - UnknownSpaceRegionKind, - GlobalsSpaceRegionKind, - END_MEMSPACES = GlobalsSpaceRegionKind, - // Untyped regions. - SymbolicRegionKind, - AllocaRegionKind, - // Typed regions. - BEG_TYPED_REGIONS, - FunctionTextRegionKind = BEG_TYPED_REGIONS, - BlockTextRegionKind, - BlockDataRegionKind, - CompoundLiteralRegionKind, - CXXThisRegionKind, - StringRegionKind, - ElementRegionKind, - // Decl Regions. - BEG_DECL_REGIONS, - VarRegionKind = BEG_DECL_REGIONS, - FieldRegionKind, - ObjCIvarRegionKind, - CXXObjectRegionKind, - END_DECL_REGIONS = CXXObjectRegionKind, - END_TYPED_REGIONS = END_DECL_REGIONS - }; - -private: - const Kind kind; - -protected: - MemRegion(Kind k) : kind(k) {} - virtual ~MemRegion(); - -public: - ASTContext &getContext() const; - - virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0; - - virtual MemRegionManager* getMemRegionManager() const = 0; - - std::string getString() const; - - const MemSpaceRegion *getMemorySpace() const; - - const MemRegion *getBaseRegion() const; - - const MemRegion *StripCasts() const; - - bool hasGlobalsOrParametersStorage() const; - - bool hasStackStorage() const; - - bool hasStackNonParametersStorage() const; - - bool hasStackParametersStorage() const; - - virtual void dumpToStream(llvm::raw_ostream& os) const; - - void dump() const; - - Kind getKind() const { return kind; } - - template const RegionTy* getAs() const; - - virtual bool isBoundable() const { return false; } - - static bool classof(const MemRegion*) { return true; } -}; - -/// MemSpaceRegion - A memory region that represents and "memory space"; -/// for example, the set of global variables, the stack frame, etc. -class MemSpaceRegion : public MemRegion { -protected: - friend class MemRegionManager; - - MemRegionManager *Mgr; - - MemSpaceRegion(MemRegionManager *mgr, Kind k = GenericMemSpaceRegionKind) - : MemRegion(k), Mgr(mgr) { - assert(classof(this)); - } - - MemRegionManager* getMemRegionManager() const { return Mgr; } - -public: - bool isBoundable() const { return false; } - - void Profile(llvm::FoldingSetNodeID &ID) const; - - static bool classof(const MemRegion *R) { - Kind k = R->getKind(); - return k >= BEG_MEMSPACES && k <= END_MEMSPACES; - } -}; - -class GlobalsSpaceRegion : public MemSpaceRegion { - friend class MemRegionManager; - - GlobalsSpaceRegion(MemRegionManager *mgr) - : MemSpaceRegion(mgr, GlobalsSpaceRegionKind) {} -public: - static bool classof(const MemRegion *R) { - return R->getKind() == GlobalsSpaceRegionKind; - } -}; - -class HeapSpaceRegion : public MemSpaceRegion { - friend class MemRegionManager; - - HeapSpaceRegion(MemRegionManager *mgr) - : MemSpaceRegion(mgr, HeapSpaceRegionKind) {} -public: - static bool classof(const MemRegion *R) { - return R->getKind() == HeapSpaceRegionKind; - } -}; - -class UnknownSpaceRegion : public MemSpaceRegion { - friend class MemRegionManager; - UnknownSpaceRegion(MemRegionManager *mgr) - : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {} -public: - static bool classof(const MemRegion *R) { - return R->getKind() == UnknownSpaceRegionKind; - } -}; - -class StackSpaceRegion : public MemSpaceRegion { -private: - const StackFrameContext *SFC; - -protected: - StackSpaceRegion(MemRegionManager *mgr, Kind k, const StackFrameContext *sfc) - : MemSpaceRegion(mgr, k), SFC(sfc) { - assert(classof(this)); - } - -public: - const StackFrameContext *getStackFrame() const { return SFC; } - - void Profile(llvm::FoldingSetNodeID &ID) const; - - static bool classof(const MemRegion *R) { - Kind k = R->getKind(); - return k >= StackLocalsSpaceRegionKind && - k <= StackArgumentsSpaceRegionKind; - } -}; - -class StackLocalsSpaceRegion : public StackSpaceRegion { -private: - friend class MemRegionManager; - StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) - : StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {} -public: - static bool classof(const MemRegion *R) { - return R->getKind() == StackLocalsSpaceRegionKind; - } -}; - -class StackArgumentsSpaceRegion : public StackSpaceRegion { -private: - friend class MemRegionManager; - StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) - : StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {} -public: - static bool classof(const MemRegion *R) { - return R->getKind() == StackArgumentsSpaceRegionKind; - } -}; - -/// SubRegion - A region that subsets another larger region. Most regions -/// are subclasses of SubRegion. -class SubRegion : public MemRegion { -protected: - const MemRegion* superRegion; - SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {} -public: - const MemRegion* getSuperRegion() const { - return superRegion; - } - - MemRegionManager* getMemRegionManager() const; - - bool isSubRegionOf(const MemRegion* R) const; - - static bool classof(const MemRegion* R) { - return R->getKind() > END_MEMSPACES; - } -}; - -//===----------------------------------------------------------------------===// -// Auxillary data classes for use with MemRegions. -//===----------------------------------------------------------------------===// - -class ElementRegion; - -class RegionRawOffset : public std::pair { -private: - friend class ElementRegion; - - RegionRawOffset(const MemRegion* reg, int64_t offset = 0) - : std::pair(reg, offset) {} - -public: - // FIXME: Eventually support symbolic offsets. - int64_t getByteOffset() const { return second; } - const MemRegion *getRegion() const { return first; } - - void dumpToStream(llvm::raw_ostream& os) const; - void dump() const; -}; - -//===----------------------------------------------------------------------===// -// MemRegion subclasses. -//===----------------------------------------------------------------------===// - -/// AllocaRegion - A region that represents an untyped blob of bytes created -/// by a call to 'alloca'. -class AllocaRegion : public SubRegion { - friend class MemRegionManager; -protected: - unsigned Cnt; // Block counter. Used to distinguish different pieces of - // memory allocated by alloca at the same call site. - const Expr* Ex; - - AllocaRegion(const Expr* ex, unsigned cnt, const MemRegion *superRegion) - : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {} - -public: - - const Expr* getExpr() const { return Ex; } - - bool isBoundable() const { return true; } - - void Profile(llvm::FoldingSetNodeID& ID) const; - - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr* Ex, - unsigned Cnt, const MemRegion *superRegion); - - void dumpToStream(llvm::raw_ostream& os) const; - - static bool classof(const MemRegion* R) { - return R->getKind() == AllocaRegionKind; - } -}; - -/// TypedRegion - An abstract class representing regions that are typed. -class TypedRegion : public SubRegion { -protected: - TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {} - -public: - virtual QualType getValueType(ASTContext &C) const = 0; - - virtual QualType getLocationType(ASTContext& C) const { - // FIXME: We can possibly optimize this later to cache this value. - return C.getPointerType(getValueType(C)); - } - - QualType getDesugaredValueType(ASTContext& C) const { - QualType T = getValueType(C); - return T.getTypePtr() ? T.getDesugaredType() : T; - } - - QualType getDesugaredLocationType(ASTContext& C) const { - return getLocationType(C).getDesugaredType(); - } - - bool isBoundable() const { - return !getValueType(getContext()).isNull(); - } - - static bool classof(const MemRegion* R) { - unsigned k = R->getKind(); - return k >= BEG_TYPED_REGIONS && k <= END_TYPED_REGIONS; - } -}; - - -class CodeTextRegion : public TypedRegion { -protected: - CodeTextRegion(const MemRegion *sreg, Kind k) : TypedRegion(sreg, k) {} -public: - QualType getValueType(ASTContext &C) const { - // Do not get the object type of a CodeTextRegion. - assert(0); - return QualType(); - } - - bool isBoundable() const { return false; } - - static bool classof(const MemRegion* R) { - Kind k = R->getKind(); - return k >= FunctionTextRegionKind && k <= BlockTextRegionKind; - } -}; - -/// FunctionTextRegion - A region that represents code texts of function. -class FunctionTextRegion : public CodeTextRegion { - const FunctionDecl *FD; -public: - FunctionTextRegion(const FunctionDecl* fd, const MemRegion* sreg) - : CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) {} - - QualType getLocationType(ASTContext &C) const { - return C.getPointerType(FD->getType()); - } - - const FunctionDecl *getDecl() const { - return FD; - } - - virtual void dumpToStream(llvm::raw_ostream& os) const; - - void Profile(llvm::FoldingSetNodeID& ID) const; - - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FunctionDecl *FD, - const MemRegion*); - - static bool classof(const MemRegion* R) { - return R->getKind() == FunctionTextRegionKind; - } -}; - - -/// BlockTextRegion - A region that represents code texts of blocks (closures). -/// Blocks are represented with two kinds of regions. BlockTextRegions -/// represent the "code", while BlockDataRegions represent instances of blocks, -/// which correspond to "code+data". The distinction is important, because -/// like a closure a block captures the values of externally referenced -/// variables. -class BlockTextRegion : public CodeTextRegion { - friend class MemRegionManager; - - const BlockDecl *BD; - AnalysisContext *AC; - CanQualType locTy; - - BlockTextRegion(const BlockDecl *bd, CanQualType lTy, - AnalysisContext *ac, const MemRegion* sreg) - : CodeTextRegion(sreg, BlockTextRegionKind), BD(bd), AC(ac), locTy(lTy) {} - -public: - QualType getLocationType(ASTContext &C) const { - return locTy; - } - - const BlockDecl *getDecl() const { - return BD; - } - - AnalysisContext *getAnalysisContext() const { return AC; } - - virtual void dumpToStream(llvm::raw_ostream& os) const; - - void Profile(llvm::FoldingSetNodeID& ID) const; - - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD, - CanQualType, const AnalysisContext*, - const MemRegion*); - - static bool classof(const MemRegion* R) { - return R->getKind() == BlockTextRegionKind; - } -}; - -/// BlockDataRegion - A region that represents a block instance. -/// Blocks are represented with two kinds of regions. BlockTextRegions -/// represent the "code", while BlockDataRegions represent instances of blocks, -/// which correspond to "code+data". The distinction is important, because -/// like a closure a block captures the values of externally referenced -/// variables. -/// BlockDataRegion - A region that represents code texts of blocks (closures). -class BlockDataRegion : public SubRegion { - friend class MemRegionManager; - const BlockTextRegion *BC; - const LocationContext *LC; // Can be null */ - void *ReferencedVars; - - BlockDataRegion(const BlockTextRegion *bc, const LocationContext *lc, - const MemRegion *sreg) - : SubRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), ReferencedVars(0) {} - -public: - const BlockTextRegion *getCodeRegion() const { return BC; } - - const BlockDecl *getDecl() const { return BC->getDecl(); } - - class referenced_vars_iterator { - const MemRegion * const *R; - public: - explicit referenced_vars_iterator(const MemRegion * const *r) : R(r) {} - - operator const MemRegion * const *() const { - return R; - } - - const VarRegion* operator*() const { - return cast(*R); - } - - bool operator==(const referenced_vars_iterator &I) const { - return I.R == R; - } - bool operator!=(const referenced_vars_iterator &I) const { - return I.R != R; - } - referenced_vars_iterator& operator++() { - ++R; - return *this; - } - }; - - referenced_vars_iterator referenced_vars_begin() const; - referenced_vars_iterator referenced_vars_end() const; - - virtual void dumpToStream(llvm::raw_ostream& os) const; - - void Profile(llvm::FoldingSetNodeID& ID) const; - - static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockTextRegion *, - const LocationContext *, const MemRegion *); - - static bool classof(const MemRegion* R) { - return R->getKind() == BlockDataRegionKind; - } -private: - void LazyInitializeReferencedVars(); -}; - -/// SymbolicRegion - A special, "non-concrete" region. Unlike other region -/// clases, SymbolicRegion represents a region that serves as an alias for -/// either a real region, a NULL pointer, etc. It essentially is used to -/// map the concept of symbolic values into the domain of regions. Symbolic -/// regions do not need to be typed. -class SymbolicRegion : public SubRegion { -protected: - const SymbolRef sym; - -public: - SymbolicRegion(const SymbolRef s, const MemRegion* sreg) - : SubRegion(sreg, SymbolicRegionKind), sym(s) {} - - SymbolRef getSymbol() const { - return sym; - } - - bool isBoundable() const { return true; } - - void Profile(llvm::FoldingSetNodeID& ID) const; - - static void ProfileRegion(llvm::FoldingSetNodeID& ID, - SymbolRef sym, - const MemRegion* superRegion); - - void dumpToStream(llvm::raw_ostream& os) const; - - static bool classof(const MemRegion* R) { - return R->getKind() == SymbolicRegionKind; - } -}; - -/// StringRegion - Region associated with a StringLiteral. -class StringRegion : public TypedRegion { - friend class MemRegionManager; - const StringLiteral* Str; -protected: - - StringRegion(const StringLiteral* str, const MemRegion* sreg) - : TypedRegion(sreg, StringRegionKind), Str(str) {} - - static void ProfileRegion(llvm::FoldingSetNodeID& ID, - const StringLiteral* Str, - const MemRegion* superRegion); - -public: - - const StringLiteral* getStringLiteral() const { return Str; } - - QualType getValueType(ASTContext& C) const { - return Str->getType(); - } - - bool isBoundable() const { return false; } - - void Profile(llvm::FoldingSetNodeID& ID) const { - ProfileRegion(ID, Str, superRegion); - } - - void dumpToStream(llvm::raw_ostream& os) const; - - static bool classof(const MemRegion* R) { - return R->getKind() == StringRegionKind; - } -}; - -/// CompoundLiteralRegion - A memory region representing a compound literal. -/// Compound literals are essentially temporaries that are stack allocated -/// or in the global constant pool. -class CompoundLiteralRegion : public TypedRegion { -private: - friend class MemRegionManager; - const CompoundLiteralExpr* CL; - - CompoundLiteralRegion(const CompoundLiteralExpr* cl, const MemRegion* sReg) - : TypedRegion(sReg, CompoundLiteralRegionKind), CL(cl) {} - - static void ProfileRegion(llvm::FoldingSetNodeID& ID, - const CompoundLiteralExpr* CL, - const MemRegion* superRegion); -public: - QualType getValueType(ASTContext& C) const { - return C.getCanonicalType(CL->getType()); - } - - bool isBoundable() const { return !CL->isFileScope(); } - - void Profile(llvm::FoldingSetNodeID& ID) const; - - void dumpToStream(llvm::raw_ostream& os) const; - - const CompoundLiteralExpr* getLiteralExpr() const { return CL; } - - static bool classof(const MemRegion* R) { - return R->getKind() == CompoundLiteralRegionKind; - } -}; - -class DeclRegion : public TypedRegion { -protected: - const Decl* D; - - DeclRegion(const Decl* d, const MemRegion* sReg, Kind k) - : TypedRegion(sReg, k), D(d) {} - - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D, - const MemRegion* superRegion, Kind k); - -public: - const Decl* getDecl() const { return D; } - void Profile(llvm::FoldingSetNodeID& ID) const; - - static bool classof(const MemRegion* R) { - unsigned k = R->getKind(); - return k >= BEG_DECL_REGIONS && k <= END_DECL_REGIONS; - } -}; - -class VarRegion : public DeclRegion { - friend class MemRegionManager; - - // Constructors and private methods. - VarRegion(const VarDecl* vd, const MemRegion* sReg) - : DeclRegion(vd, sReg, VarRegionKind) {} - - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl* VD, - const MemRegion *superRegion) { - DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind); - } - - void Profile(llvm::FoldingSetNodeID& ID) const; - -public: - const VarDecl *getDecl() const { return cast(D); } - - const StackFrameContext *getStackFrame() const; - - QualType getValueType(ASTContext& C) const { - // FIXME: We can cache this if needed. - return C.getCanonicalType(getDecl()->getType()); - } - - void dumpToStream(llvm::raw_ostream& os) const; - - static bool classof(const MemRegion* R) { - return R->getKind() == VarRegionKind; - } -}; - -/// CXXThisRegion - Represents the region for the implicit 'this' parameter -/// in a call to a C++ method. This region doesn't represent the object -/// referred to by 'this', but rather 'this' itself. -class CXXThisRegion : public TypedRegion { - friend class MemRegionManager; - CXXThisRegion(const PointerType *thisPointerTy, - const MemRegion *sReg) - : TypedRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {} - - static void ProfileRegion(llvm::FoldingSetNodeID &ID, - const PointerType *PT, - const MemRegion *sReg); - - void Profile(llvm::FoldingSetNodeID &ID) const; - -public: - QualType getValueType(ASTContext &C) const { - return QualType(ThisPointerTy, 0); - } - - void dumpToStream(llvm::raw_ostream& os) const; - - static bool classof(const MemRegion* R) { - return R->getKind() == CXXThisRegionKind; - } - -private: - const PointerType *ThisPointerTy; -}; - -class FieldRegion : public DeclRegion { - friend class MemRegionManager; - - FieldRegion(const FieldDecl* fd, const MemRegion* sReg) - : DeclRegion(fd, sReg, FieldRegionKind) {} - -public: - - void dumpToStream(llvm::raw_ostream& os) const; - - const FieldDecl* getDecl() const { return cast(D); } - - QualType getValueType(ASTContext& C) const { - // FIXME: We can cache this if needed. - return C.getCanonicalType(getDecl()->getType()); - } - - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl* FD, - const MemRegion* superRegion) { - DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind); - } - - static bool classof(const MemRegion* R) { - return R->getKind() == FieldRegionKind; - } -}; - -class ObjCIvarRegion : public DeclRegion { - - friend class MemRegionManager; - - ObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* sReg) - : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {} - - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl* ivd, - const MemRegion* superRegion) { - DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind); - } - -public: - const ObjCIvarDecl* getDecl() const { return cast(D); } - QualType getValueType(ASTContext&) const { return getDecl()->getType(); } - - void dumpToStream(llvm::raw_ostream& os) const; - - static bool classof(const MemRegion* R) { - return R->getKind() == ObjCIvarRegionKind; - } -}; - -class ElementRegion : public TypedRegion { - friend class MemRegionManager; - - QualType ElementType; - SVal Index; - - ElementRegion(QualType elementType, SVal Idx, const MemRegion* sReg) - : TypedRegion(sReg, ElementRegionKind), - ElementType(elementType), Index(Idx) { - assert((!isa(&Idx) || - cast(&Idx)->getValue().isSigned()) && - "The index must be signed"); - } - - static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType, - SVal Idx, const MemRegion* superRegion); - -public: - - SVal getIndex() const { return Index; } - - QualType getValueType(ASTContext&) const { - return ElementType; - } - - QualType getElementType() const { - return ElementType; - } - - RegionRawOffset getAsRawOffset() const; - - void dumpToStream(llvm::raw_ostream& os) const; - - void Profile(llvm::FoldingSetNodeID& ID) const; - - static bool classof(const MemRegion* R) { - return R->getKind() == ElementRegionKind; - } -}; - -// C++ temporary object associated with an expression. -class CXXObjectRegion : public TypedRegion { - friend class MemRegionManager; - - Expr const *Ex; - - CXXObjectRegion(Expr const *E, MemRegion const *sReg) - : TypedRegion(sReg, CXXObjectRegionKind), Ex(E) {} - - static void ProfileRegion(llvm::FoldingSetNodeID &ID, - Expr const *E, const MemRegion *sReg); - -public: - QualType getValueType(ASTContext& C) const { - return Ex->getType(); - } - - void Profile(llvm::FoldingSetNodeID &ID) const; - - static bool classof(const MemRegion* R) { - return R->getKind() == CXXObjectRegionKind; - } -}; - -template -const RegionTy* MemRegion::getAs() const { - if (const RegionTy* RT = dyn_cast(this)) - return RT; - - return NULL; -} - -//===----------------------------------------------------------------------===// -// MemRegionManager - Factory object for creating regions. -//===----------------------------------------------------------------------===// - -class MemRegionManager { - ASTContext &C; - llvm::BumpPtrAllocator& A; - llvm::FoldingSet Regions; - - GlobalsSpaceRegion *globals; - - const StackFrameContext *cachedStackLocalsFrame; - StackLocalsSpaceRegion *cachedStackLocalsRegion; - - const StackFrameContext *cachedStackArgumentsFrame; - StackArgumentsSpaceRegion *cachedStackArgumentsRegion; - - HeapSpaceRegion *heap; - UnknownSpaceRegion *unknown; - MemSpaceRegion *code; - -public: - MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator& a) - : C(c), A(a), globals(0), - cachedStackLocalsFrame(0), cachedStackLocalsRegion(0), - cachedStackArgumentsFrame(0), cachedStackArgumentsRegion(0), - heap(0), unknown(0), code(0) {} - - ~MemRegionManager(); - - ASTContext &getContext() { return C; } - - llvm::BumpPtrAllocator &getAllocator() { return A; } - - /// getStackLocalsRegion - Retrieve the memory region associated with the - /// specified stack frame. - const StackLocalsSpaceRegion * - getStackLocalsRegion(const StackFrameContext *STC); - - /// getStackArgumentsRegion - Retrieve the memory region associated with - /// function/method arguments of the specified stack frame. - const StackArgumentsSpaceRegion * - getStackArgumentsRegion(const StackFrameContext *STC); - - /// getGlobalsRegion - Retrieve the memory region associated with - /// all global variables. - const GlobalsSpaceRegion *getGlobalsRegion(); - - /// getHeapRegion - Retrieve the memory region associated with the - /// generic "heap". - const HeapSpaceRegion *getHeapRegion(); - - /// getUnknownRegion - Retrieve the memory region associated with unknown - /// memory space. - const MemSpaceRegion *getUnknownRegion(); - - const MemSpaceRegion *getCodeRegion(); - - /// getAllocaRegion - Retrieve a region associated with a call to alloca(). - const AllocaRegion *getAllocaRegion(const Expr* Ex, unsigned Cnt, - const LocationContext *LC); - - /// getCompoundLiteralRegion - Retrieve the region associated with a - /// given CompoundLiteral. - const CompoundLiteralRegion* - getCompoundLiteralRegion(const CompoundLiteralExpr* CL, - const LocationContext *LC); - - /// getCXXThisRegion - Retrieve the [artifical] region associated with the - /// parameter 'this'. - const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy, - const LocationContext *LC); - - /// getSymbolicRegion - Retrieve or create a "symbolic" memory region. - const SymbolicRegion* getSymbolicRegion(SymbolRef sym); - - const StringRegion* getStringRegion(const StringLiteral* Str); - - /// getVarRegion - Retrieve or create the memory region associated with - /// a specified VarDecl and LocationContext. - const VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC); - - /// getVarRegion - Retrieve or create the memory region associated with - /// a specified VarDecl and super region. - const VarRegion* getVarRegion(const VarDecl *D, const MemRegion *superR); - - /// getElementRegion - Retrieve the memory region associated with the - /// associated element type, index, and super region. - const ElementRegion *getElementRegion(QualType elementType, SVal Idx, - const MemRegion *superRegion, - ASTContext &Ctx); - - const ElementRegion *getElementRegionWithSuper(const ElementRegion *ER, - const MemRegion *superRegion) { - return getElementRegion(ER->getElementType(), ER->getIndex(), - superRegion, ER->getContext()); - } - - /// getFieldRegion - Retrieve or create the memory region associated with - /// a specified FieldDecl. 'superRegion' corresponds to the containing - /// memory region (which typically represents the memory representing - /// a structure or class). - const FieldRegion *getFieldRegion(const FieldDecl* fd, - const MemRegion* superRegion); - - const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR, - const MemRegion *superRegion) { - return getFieldRegion(FR->getDecl(), superRegion); - } - - /// getObjCIvarRegion - Retrieve or create the memory region associated with - /// a specified Objective-c instance variable. 'superRegion' corresponds - /// to the containing region (which typically represents the Objective-C - /// object). - const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd, - const MemRegion* superRegion); - - const CXXObjectRegion *getCXXObjectRegion(Expr const *Ex, - LocationContext const *LC); - - const FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD); - const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD, - CanQualType locTy, - AnalysisContext *AC); - - /// getBlockDataRegion - Get the memory region associated with an instance - /// of a block. Unlike many other MemRegions, the LocationContext* - /// argument is allowed to be NULL for cases where we have no known - /// context. - const BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc, - const LocationContext *lc = NULL); - - bool isGlobalsRegion(const MemRegion* R) { - assert(R); - return R == globals; - } - -private: - template - RegionTy* getRegion(const A1 a1); - - template - RegionTy* getSubRegion(const A1 a1, const MemRegion* superRegion); - - template - RegionTy* getRegion(const A1 a1, const A2 a2); - - template - RegionTy* getSubRegion(const A1 a1, const A2 a2, - const MemRegion* superRegion); - - template - RegionTy* getSubRegion(const A1 a1, const A2 a2, const A3 a3, - const MemRegion* superRegion); - - template - const REG* LazyAllocate(REG*& region); - - template - const REG* LazyAllocate(REG*& region, ARG a); -}; - -//===----------------------------------------------------------------------===// -// Out-of-line member definitions. -//===----------------------------------------------------------------------===// - -inline ASTContext& MemRegion::getContext() const { - return getMemRegionManager()->getContext(); -} - -} // end clang namespace - -//===----------------------------------------------------------------------===// -// Pretty-printing regions. -//===----------------------------------------------------------------------===// - -namespace llvm { -static inline raw_ostream& operator<<(raw_ostream& os, - const clang::MemRegion* R) { - R->dumpToStream(os); - return os; -} -} // end llvm namespace - -#endif diff --git a/include/clang/Analysis/PathSensitive/SVals.h b/include/clang/Analysis/PathSensitive/SVals.h deleted file mode 100644 index 9206817989db..000000000000 --- a/include/clang/Analysis/PathSensitive/SVals.h +++ /dev/null @@ -1,499 +0,0 @@ -//== SVals.h - Abstract Values for Static Analysis ---------*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines SVal, Loc, and NonLoc, classes that represent -// abstract r-values for use with path-sensitive value tracking. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_RVALUE_H -#define LLVM_CLANG_ANALYSIS_RVALUE_H - -#include "clang/Analysis/PathSensitive/SymbolManager.h" -#include "llvm/Support/Casting.h" -#include "llvm/ADT/ImmutableList.h" - -namespace llvm { - class raw_ostream; -} - -//==------------------------------------------------------------------------==// -// Base SVal types. -//==------------------------------------------------------------------------==// - -namespace clang { - -class CompoundValData; -class LazyCompoundValData; -class GRState; -class BasicValueFactory; -class MemRegion; -class TypedRegion; -class MemRegionManager; -class GRStateManager; -class ValueManager; - -class SVal { -public: - enum BaseKind { UndefinedKind, UnknownKind, LocKind, NonLocKind }; - enum { BaseBits = 2, BaseMask = 0x3 }; - -protected: - void* Data; - unsigned Kind; - -protected: - SVal(const void* d, bool isLoc, unsigned ValKind) - : Data(const_cast(d)), - Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {} - - explicit SVal(BaseKind k, void* D = NULL) - : Data(D), Kind(k) {} - -public: - SVal() : Data(0), Kind(0) {} - ~SVal() {} - - /// BufferTy - A temporary buffer to hold a set of SVals. - typedef llvm::SmallVector BufferTy; - - inline unsigned getRawKind() const { return Kind; } - inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); } - inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; } - - inline void Profile(llvm::FoldingSetNodeID& ID) const { - ID.AddInteger((unsigned) getRawKind()); - ID.AddPointer(reinterpret_cast(Data)); - } - - inline bool operator==(const SVal& R) const { - return getRawKind() == R.getRawKind() && Data == R.Data; - } - - inline bool operator!=(const SVal& R) const { - return !(*this == R); - } - - inline bool isUnknown() const { - return getRawKind() == UnknownKind; - } - - inline bool isUndef() const { - return getRawKind() == UndefinedKind; - } - - inline bool isUnknownOrUndef() const { - return getRawKind() <= UnknownKind; - } - - inline bool isValid() const { - return getRawKind() > UnknownKind; - } - - bool isConstant() const; - - bool isZeroConstant() const; - - /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true; - bool hasConjuredSymbol() const; - - /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a - /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl. - /// Otherwise return 0. - const FunctionDecl* getAsFunctionDecl() const; - - /// getAsLocSymbol - If this SVal is a location (subclasses Loc) and - /// wraps a symbol, return that SymbolRef. Otherwise return a SymbolData* - SymbolRef getAsLocSymbol() const; - - /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef. - /// Otherwise return a SymbolRef where 'isValid()' returns false. - SymbolRef getAsSymbol() const; - - /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then - /// return that expression. Otherwise return NULL. - const SymExpr *getAsSymbolicExpression() const; - - const MemRegion *getAsRegion() const; - - void dumpToStream(llvm::raw_ostream& OS) const; - void dump() const; - - // Iterators. - class symbol_iterator { - llvm::SmallVector itr; - void expand(); - public: - symbol_iterator() {} - symbol_iterator(const SymExpr* SE); - - symbol_iterator& operator++(); - SymbolRef operator*(); - - bool operator==(const symbol_iterator& X) const; - bool operator!=(const symbol_iterator& X) const; - }; - - symbol_iterator symbol_begin() const { - const SymExpr *SE = getAsSymbolicExpression(); - if (SE) - return symbol_iterator(SE); - else - return symbol_iterator(); - } - - symbol_iterator symbol_end() const { return symbol_iterator(); } - - // Implement isa support. - static inline bool classof(const SVal*) { return true; } -}; - - -class UndefinedVal : public SVal { -public: - UndefinedVal() : SVal(UndefinedKind) {} - UndefinedVal(void* D) : SVal(UndefinedKind, D) {} - - static inline bool classof(const SVal* V) { - return V->getBaseKind() == UndefinedKind; - } - - void* getData() const { return Data; } -}; - -class DefinedOrUnknownSVal : public SVal { -private: - // Do not implement. We want calling these methods to be a compiler - // error since they are tautologically false. - bool isUndef() const; - bool isValid() const; - -protected: - explicit DefinedOrUnknownSVal(const void* d, bool isLoc, unsigned ValKind) - : SVal(d, isLoc, ValKind) {} - - explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL) - : SVal(k, D) {} - -public: - // Implement isa support. - static inline bool classof(const SVal *V) { - return !V->isUndef(); - } -}; - -class UnknownVal : public DefinedOrUnknownSVal { -public: - UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {} - - static inline bool classof(const SVal *V) { - return V->getBaseKind() == UnknownKind; - } -}; - -class DefinedSVal : public DefinedOrUnknownSVal { -private: - // Do not implement. We want calling these methods to be a compiler - // error since they are tautologically true/false. - bool isUnknown() const; - bool isUnknownOrUndef() const; - bool isValid() const; -protected: - DefinedSVal(const void* d, bool isLoc, unsigned ValKind) - : DefinedOrUnknownSVal(d, isLoc, ValKind) {} -public: - // Implement isa support. - static inline bool classof(const SVal *V) { - return !V->isUnknownOrUndef(); - } -}; - -class NonLoc : public DefinedSVal { -protected: - NonLoc(unsigned SubKind, const void* d) : DefinedSVal(d, false, SubKind) {} - -public: - void dumpToStream(llvm::raw_ostream& Out) const; - - // Implement isa support. - static inline bool classof(const SVal* V) { - return V->getBaseKind() == NonLocKind; - } -}; - -class Loc : public DefinedSVal { -protected: - Loc(unsigned SubKind, const void* D) - : DefinedSVal(const_cast(D), true, SubKind) {} - -public: - void dumpToStream(llvm::raw_ostream& Out) const; - - Loc(const Loc& X) : DefinedSVal(X.Data, true, X.getSubKind()) {} - Loc& operator=(const Loc& X) { memcpy(this, &X, sizeof(Loc)); return *this; } - - // Implement isa support. - static inline bool classof(const SVal* V) { - return V->getBaseKind() == LocKind; - } - - static inline bool IsLocType(QualType T) { - return T->isAnyPointerType() || T->isBlockPointerType() || - T->isReferenceType(); - } -}; - -//==------------------------------------------------------------------------==// -// Subclasses of NonLoc. -//==------------------------------------------------------------------------==// - -namespace nonloc { - -enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind, - LocAsIntegerKind, CompoundValKind, LazyCompoundValKind }; - -class SymbolVal : public NonLoc { -public: - SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {} - - SymbolRef getSymbol() const { - return (const SymbolData*) Data; - } - - static inline bool classof(const SVal* V) { - return V->getBaseKind() == NonLocKind && - V->getSubKind() == SymbolValKind; - } - - static inline bool classof(const NonLoc* V) { - return V->getSubKind() == SymbolValKind; - } -}; - -class SymExprVal : public NonLoc { -public: - SymExprVal(const SymExpr *SE) - : NonLoc(SymExprValKind, reinterpret_cast(SE)) {} - - const SymExpr *getSymbolicExpression() const { - return reinterpret_cast(Data); - } - - static inline bool classof(const SVal* V) { - return V->getBaseKind() == NonLocKind && - V->getSubKind() == SymExprValKind; - } - - static inline bool classof(const NonLoc* V) { - return V->getSubKind() == SymExprValKind; - } -}; - -class ConcreteInt : public NonLoc { -public: - ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {} - - const llvm::APSInt& getValue() const { - return *static_cast(Data); - } - - // Transfer functions for binary/unary operations on ConcreteInts. - SVal evalBinOp(ValueManager &ValMgr, BinaryOperator::Opcode Op, - const ConcreteInt& R) const; - - ConcreteInt evalComplement(ValueManager &ValMgr) const; - - ConcreteInt evalMinus(ValueManager &ValMgr) const; - - // Implement isa support. - static inline bool classof(const SVal* V) { - return V->getBaseKind() == NonLocKind && - V->getSubKind() == ConcreteIntKind; - } - - static inline bool classof(const NonLoc* V) { - return V->getSubKind() == ConcreteIntKind; - } -}; - -class LocAsInteger : public NonLoc { - friend class clang::ValueManager; - - LocAsInteger(const std::pair& data) : - NonLoc(LocAsIntegerKind, &data) { - assert (isa(data.first)); - } - -public: - - Loc getLoc() const { - return cast(((std::pair*) Data)->first); - } - - const Loc& getPersistentLoc() const { - const SVal& V = ((std::pair*) Data)->first; - return cast(V); - } - - unsigned getNumBits() const { - return ((std::pair*) Data)->second; - } - - // Implement isa support. - static inline bool classof(const SVal* V) { - return V->getBaseKind() == NonLocKind && - V->getSubKind() == LocAsIntegerKind; - } - - static inline bool classof(const NonLoc* V) { - return V->getSubKind() == LocAsIntegerKind; - } -}; - -class CompoundVal : public NonLoc { - friend class clang::ValueManager; - - CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {} - -public: - const CompoundValData* getValue() const { - return static_cast(Data); - } - - typedef llvm::ImmutableList::iterator iterator; - iterator begin() const; - iterator end() const; - - static bool classof(const SVal* V) { - return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind; - } - - static bool classof(const NonLoc* V) { - return V->getSubKind() == CompoundValKind; - } -}; - -class LazyCompoundVal : public NonLoc { - friend class clang::ValueManager; - - LazyCompoundVal(const LazyCompoundValData *D) - : NonLoc(LazyCompoundValKind, D) {} -public: - const LazyCompoundValData *getCVData() const { - return static_cast(Data); - } - const GRState *getState() const; - const TypedRegion *getRegion() const; - - static bool classof(const SVal *V) { - return V->getBaseKind() == NonLocKind && - V->getSubKind() == LazyCompoundValKind; - } - static bool classof(const NonLoc *V) { - return V->getSubKind() == LazyCompoundValKind; - } -}; - -} // end namespace clang::nonloc - -//==------------------------------------------------------------------------==// -// Subclasses of Loc. -//==------------------------------------------------------------------------==// - -namespace loc { - -enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind }; - -class GotoLabel : public Loc { -public: - GotoLabel(LabelStmt* Label) : Loc(GotoLabelKind, Label) {} - - LabelStmt* getLabel() const { - return static_cast(Data); - } - - static inline bool classof(const SVal* V) { - return V->getBaseKind() == LocKind && - V->getSubKind() == GotoLabelKind; - } - - static inline bool classof(const Loc* V) { - return V->getSubKind() == GotoLabelKind; - } -}; - - -class MemRegionVal : public Loc { -public: - MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {} - - const MemRegion* getRegion() const { - return static_cast(Data); - } - - const MemRegion* StripCasts() const; - - template - const REGION* getRegionAs() const { - return llvm::dyn_cast(getRegion()); - } - - inline bool operator==(const MemRegionVal& R) const { - return getRegion() == R.getRegion(); - } - - inline bool operator!=(const MemRegionVal& R) const { - return getRegion() != R.getRegion(); - } - - // Implement isa support. - static inline bool classof(const SVal* V) { - return V->getBaseKind() == LocKind && - V->getSubKind() == MemRegionKind; - } - - static inline bool classof(const Loc* V) { - return V->getSubKind() == MemRegionKind; - } -}; - -class ConcreteInt : public Loc { -public: - ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {} - - const llvm::APSInt& getValue() const { - return *static_cast(Data); - } - - // Transfer functions for binary/unary operations on ConcreteInts. - SVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, - const ConcreteInt& R) const; - - // Implement isa support. - static inline bool classof(const SVal* V) { - return V->getBaseKind() == LocKind && - V->getSubKind() == ConcreteIntKind; - } - - static inline bool classof(const Loc* V) { - return V->getSubKind() == ConcreteIntKind; - } -}; - -} // end clang::loc namespace -} // end clang namespace - -namespace llvm { -static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os, - clang::SVal V) { - V.dumpToStream(os); - return os; -} -} // end llvm namespace -#endif diff --git a/include/clang/Analysis/PathSensitive/SValuator.h b/include/clang/Analysis/PathSensitive/SValuator.h deleted file mode 100644 index 4a4b502c6271..000000000000 --- a/include/clang/Analysis/PathSensitive/SValuator.h +++ /dev/null @@ -1,91 +0,0 @@ -// SValuator.h - Construction of SVals from evaluating expressions -*- C++ -*--- -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines SValuator, a class that defines the interface for -// "symbolical evaluators" which construct an SVal from an expression. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_SVALUATOR -#define LLVM_CLANG_ANALYSIS_SVALUATOR - -#include "clang/AST/Expr.h" -#include "clang/Analysis/PathSensitive/SVals.h" - -namespace clang { - -class GRState; -class ValueManager; - -class SValuator { - friend class ValueManager; -protected: - ValueManager &ValMgr; - -public: - // FIXME: Make these protected again one RegionStoreManager correctly - // handles loads from differening bound value types. - virtual SVal EvalCastNL(NonLoc val, QualType castTy) = 0; - virtual SVal EvalCastL(Loc val, QualType castTy) = 0; - -public: - SValuator(ValueManager &valMgr) : ValMgr(valMgr) {} - virtual ~SValuator() {} - - template - class GenericCastResult : public std::pair { - public: - const GRState *getState() const { return this->first; } - T getSVal() const { return this->second; } - GenericCastResult(const GRState *s, T v) - : std::pair(s, v) {} - }; - - class CastResult : public GenericCastResult { - public: - CastResult(const GRState *s, SVal v) : GenericCastResult(s, v) {} - }; - - class DefinedOrUnknownCastResult : - public GenericCastResult { - public: - DefinedOrUnknownCastResult(const GRState *s, DefinedOrUnknownSVal v) - : GenericCastResult(s, v) {} - }; - - CastResult EvalCast(SVal V, const GRState *ST, - QualType castTy, QualType originalType); - - DefinedOrUnknownCastResult EvalCast(DefinedOrUnknownSVal V, const GRState *ST, - QualType castTy, QualType originalType); - - virtual SVal EvalMinus(NonLoc val) = 0; - - virtual SVal EvalComplement(NonLoc val) = 0; - - virtual SVal EvalBinOpNN(const GRState *state, BinaryOperator::Opcode Op, - NonLoc lhs, NonLoc rhs, QualType resultTy) = 0; - - virtual SVal EvalBinOpLL(BinaryOperator::Opcode Op, Loc lhs, Loc rhs, - QualType resultTy) = 0; - - virtual SVal EvalBinOpLN(const GRState *state, BinaryOperator::Opcode Op, - Loc lhs, NonLoc rhs, QualType resultTy) = 0; - - SVal EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op, - SVal L, SVal R, QualType T); - - DefinedOrUnknownSVal EvalEQ(const GRState *ST, DefinedOrUnknownSVal L, - DefinedOrUnknownSVal R); -}; - -SValuator* CreateSimpleSValuator(ValueManager &valMgr); - -} // end clang namespace -#endif diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h deleted file mode 100644 index 5606df0014f0..000000000000 --- a/include/clang/Analysis/PathSensitive/Store.h +++ /dev/null @@ -1,220 +0,0 @@ -//== Store.h - Interface for maps from Locations to Values ------*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defined the types Store and StoreManager. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_STORE_H -#define LLVM_CLANG_ANALYSIS_STORE_H - -#include "clang/Analysis/PathSensitive/MemRegion.h" -#include "clang/Analysis/PathSensitive/SVals.h" -#include "clang/Analysis/PathSensitive/ValueManager.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/SmallVector.h" - -namespace clang { - -typedef const void* Store; - -class GRState; -class GRStateManager; -class Stmt; -class Expr; -class ObjCIvarDecl; -class SubRegionMap; -class StackFrameContext; - -class StoreManager { -protected: - ValueManager &ValMgr; - GRStateManager &StateMgr; - - /// MRMgr - Manages region objects associated with this StoreManager. - MemRegionManager &MRMgr; - - StoreManager(GRStateManager &stateMgr); - -public: - virtual ~StoreManager() {} - - /// Return the value bound to specified location in a given state. - /// \param[in] state The analysis state. - /// \param[in] loc The symbolic memory location. - /// \param[in] T An optional type that provides a hint indicating the - /// expected type of the returned value. This is used if the value is - /// lazily computed. - /// \return The value bound to the location \c loc. - virtual SValuator::CastResult Retrieve(const GRState *state, Loc loc, - QualType T = QualType()) = 0; - - /// Return a state with the specified value bound to the given location. - /// \param[in] state The analysis state. - /// \param[in] loc The symbolic memory location. - /// \param[in] val The value to bind to location \c loc. - /// \return A pointer to a GRState object that contains the same bindings as - /// \c state with the addition of having the value specified by \c val bound - /// to the location given for \c loc. - virtual const GRState *Bind(const GRState *state, Loc loc, SVal val) = 0; - - virtual Store Remove(Store St, Loc L) = 0; - - /// BindCompoundLiteral - Return the store that has the bindings currently - /// in 'store' plus the bindings for the CompoundLiteral. 'R' is the region - /// for the compound literal and 'BegInit' and 'EndInit' represent an - /// array of initializer values. - virtual const GRState *BindCompoundLiteral(const GRState *state, - const CompoundLiteralExpr* cl, - const LocationContext *LC, - SVal v) = 0; - - /// getInitialStore - Returns the initial "empty" store representing the - /// value bindings upon entry to an analyzed function. - virtual Store getInitialStore(const LocationContext *InitLoc) = 0; - - /// getRegionManager - Returns the internal RegionManager object that is - /// used to query and manipulate MemRegion objects. - MemRegionManager& getRegionManager() { return MRMgr; } - - /// getSubRegionMap - Returns an opaque map object that clients can query - /// to get the subregions of a given MemRegion object. It is the - // caller's responsibility to 'delete' the returned map. - virtual SubRegionMap *getSubRegionMap(const GRState *state) = 0; - - virtual SVal getLValueVar(const VarDecl *VD, const LocationContext *LC) = 0; - - virtual SVal getLValueString(const StringLiteral* sl) = 0; - - SVal getLValueCompoundLiteral(const CompoundLiteralExpr* cl, - const LocationContext *LC); - - virtual SVal getLValueIvar(const ObjCIvarDecl* decl, SVal base) = 0; - - virtual SVal getLValueField(const FieldDecl* D, SVal Base) = 0; - - virtual SVal getLValueElement(QualType elementType, SVal offset, SVal Base)=0; - - // FIXME: Make out-of-line. - virtual DefinedOrUnknownSVal getSizeInElements(const GRState *state, - const MemRegion *region, - QualType EleTy) { - return UnknownVal(); - } - - /// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit - /// conversions between arrays and pointers. - virtual SVal ArrayToPointer(Loc Array) = 0; - - class CastResult { - const GRState *state; - const MemRegion *region; - public: - const GRState *getState() const { return state; } - const MemRegion* getRegion() const { return region; } - CastResult(const GRState *s, const MemRegion* r = 0) : state(s), region(r){} - }; - - /// CastRegion - Used by GRExprEngine::VisitCast to handle casts from - /// a MemRegion* to a specific location type. 'R' is the region being - /// casted and 'CastToTy' the result type of the cast. - const MemRegion *CastRegion(const MemRegion *region, QualType CastToTy); - - /// EvalBinOp - Perform pointer arithmetic. - virtual SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op, - Loc lhs, NonLoc rhs, QualType resultTy) { - return UnknownVal(); - } - - virtual void RemoveDeadBindings(GRState &state, Stmt* Loc, - SymbolReaper& SymReaper, - llvm::SmallVectorImpl& RegionRoots) = 0; - - virtual const GRState *BindDecl(const GRState *ST, const VarRegion *VR, - SVal initVal) = 0; - - virtual const GRState *BindDeclWithNoInit(const GRState *ST, - const VarRegion *VR) = 0; - - typedef llvm::DenseSet InvalidatedSymbols; - - virtual const GRState *InvalidateRegion(const GRState *state, - const MemRegion *R, - const Expr *E, unsigned Count, - InvalidatedSymbols *IS) = 0; - - virtual const GRState *InvalidateRegions(const GRState *state, - const MemRegion * const *Begin, - const MemRegion * const *End, - const Expr *E, unsigned Count, - InvalidatedSymbols *IS); - - // FIXME: Make out-of-line. - virtual const GRState *setExtent(const GRState *state, - const MemRegion *region, SVal extent) { - return state; - } - - /// EnterStackFrame - Let the StoreManager to do something when execution - /// engine is about to execute into a callee. - virtual const GRState *EnterStackFrame(const GRState *state, - const StackFrameContext *frame) { - return state; - } - - virtual void print(Store store, llvm::raw_ostream& Out, - const char* nl, const char *sep) = 0; - - class BindingsHandler { - public: - virtual ~BindingsHandler(); - virtual bool HandleBinding(StoreManager& SMgr, Store store, - const MemRegion *region, SVal val) = 0; - }; - - /// iterBindings - Iterate over the bindings in the Store. - virtual void iterBindings(Store store, BindingsHandler& f) = 0; - -protected: - const MemRegion *MakeElementRegion(const MemRegion *Base, - QualType pointeeTy, uint64_t index = 0); - - /// CastRetrievedVal - Used by subclasses of StoreManager to implement - /// implicit casts that arise from loads from regions that are reinterpreted - /// as another region. - SVal CastRetrievedVal(SVal val, const TypedRegion *R, QualType castTy, - bool performTestOnly = true); -}; - -// FIXME: Do we still need this? -/// SubRegionMap - An abstract interface that represents a queryable map -/// between MemRegion objects and their subregions. -class SubRegionMap { -public: - virtual ~SubRegionMap() {} - - class Visitor { - public: - virtual ~Visitor() {} - virtual bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) = 0; - }; - - virtual bool iterSubRegions(const MemRegion *region, Visitor& V) const = 0; -}; - -// FIXME: Do we need to pass GRStateManager anymore? -StoreManager *CreateBasicStoreManager(GRStateManager& StMgr); -StoreManager *CreateRegionStoreManager(GRStateManager& StMgr); -StoreManager *CreateFieldsOnlyRegionStoreManager(GRStateManager& StMgr); - -} // end clang namespace - -#endif diff --git a/include/clang/Analysis/PathSensitive/SymbolManager.h b/include/clang/Analysis/PathSensitive/SymbolManager.h deleted file mode 100644 index 8eb319647953..000000000000 --- a/include/clang/Analysis/PathSensitive/SymbolManager.h +++ /dev/null @@ -1,385 +0,0 @@ -//== SymbolManager.h - Management of Symbolic Values ------------*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines SymbolManager, a class that manages symbolic values -// created for use by GRExprEngine and related classes. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_SYMMGR_H -#define LLVM_CLANG_ANALYSIS_SYMMGR_H - -#include "clang/AST/Decl.h" -#include "clang/AST/Expr.h" -#include "clang/Analysis/Analyses/LiveVariables.h" -#include "llvm/System/DataTypes.h" -#include "llvm/Support/Allocator.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/DenseSet.h" - -namespace llvm { - class raw_ostream; -} - -namespace clang { - class ASTContext; - class BasicValueFactory; - class MemRegion; - class TypedRegion; - class VarRegion; - class StackFrameContext; -} - -namespace clang { - -class SymExpr : public llvm::FoldingSetNode { -public: - enum Kind { BEGIN_SYMBOLS, - RegionValueKind, ConjuredKind, DerivedKind, - END_SYMBOLS, - SymIntKind, SymSymKind }; -private: - Kind K; - -protected: - SymExpr(Kind k) : K(k) {} - -public: - virtual ~SymExpr() {} - - Kind getKind() const { return K; } - - void dump() const; - - virtual void dumpToStream(llvm::raw_ostream &os) const = 0; - - virtual QualType getType(ASTContext&) const = 0; - virtual void Profile(llvm::FoldingSetNodeID& profile) = 0; - - // Implement isa support. - static inline bool classof(const SymExpr*) { return true; } -}; - -typedef unsigned SymbolID; - -class SymbolData : public SymExpr { -private: - const SymbolID Sym; - -protected: - SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {} - -public: - virtual ~SymbolData() {} - - SymbolID getSymbolID() const { return Sym; } - - // Implement isa support. - static inline bool classof(const SymExpr* SE) { - Kind k = SE->getKind(); - return k > BEGIN_SYMBOLS && k < END_SYMBOLS; - } -}; - -typedef const SymbolData* SymbolRef; - -class SymbolRegionValue : public SymbolData { - const MemRegion *R; - // We may cast the region to another type, so the expected type of the symbol - // may be different from the region's original type. - QualType T; - -public: - SymbolRegionValue(SymbolID sym, const MemRegion *r, QualType t = QualType()) - : SymbolData(RegionValueKind, sym), R(r), T(t) {} - - const MemRegion* getRegion() const { return R; } - - static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion* R, - QualType T) { - profile.AddInteger((unsigned) RegionValueKind); - profile.AddPointer(R); - T.Profile(profile); - } - - virtual void Profile(llvm::FoldingSetNodeID& profile) { - Profile(profile, R, T); - } - - void dumpToStream(llvm::raw_ostream &os) const; - - QualType getType(ASTContext&) const; - - // Implement isa support. - static inline bool classof(const SymExpr* SE) { - return SE->getKind() == RegionValueKind; - } -}; - -class SymbolConjured : public SymbolData { - const Stmt* S; - QualType T; - unsigned Count; - const void* SymbolTag; - -public: - SymbolConjured(SymbolID sym, const Stmt* s, QualType t, unsigned count, - const void* symbolTag) - : SymbolData(ConjuredKind, sym), S(s), T(t), Count(count), - SymbolTag(symbolTag) {} - - const Stmt* getStmt() const { return S; } - unsigned getCount() const { return Count; } - const void* getTag() const { return SymbolTag; } - - QualType getType(ASTContext&) const; - - void dumpToStream(llvm::raw_ostream &os) const; - - static void Profile(llvm::FoldingSetNodeID& profile, const Stmt* S, - QualType T, unsigned Count, const void* SymbolTag) { - profile.AddInteger((unsigned) ConjuredKind); - profile.AddPointer(S); - profile.Add(T); - profile.AddInteger(Count); - profile.AddPointer(SymbolTag); - } - - virtual void Profile(llvm::FoldingSetNodeID& profile) { - Profile(profile, S, T, Count, SymbolTag); - } - - // Implement isa support. - static inline bool classof(const SymExpr* SE) { - return SE->getKind() == ConjuredKind; - } -}; - -class SymbolDerived : public SymbolData { - SymbolRef parentSymbol; - const TypedRegion *R; - -public: - SymbolDerived(SymbolID sym, SymbolRef parent, const TypedRegion *r) - : SymbolData(DerivedKind, sym), parentSymbol(parent), R(r) {} - - SymbolRef getParentSymbol() const { return parentSymbol; } - const TypedRegion *getRegion() const { return R; } - - QualType getType(ASTContext&) const; - - void dumpToStream(llvm::raw_ostream &os) const; - - static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent, - const TypedRegion *r) { - profile.AddInteger((unsigned) DerivedKind); - profile.AddPointer(r); - profile.AddPointer(parent); - } - - virtual void Profile(llvm::FoldingSetNodeID& profile) { - Profile(profile, parentSymbol, R); - } - - // Implement isa support. - static inline bool classof(const SymExpr* SE) { - return SE->getKind() == DerivedKind; - } -}; - -// SymIntExpr - Represents symbolic expression like 'x' + 3. -class SymIntExpr : public SymExpr { - const SymExpr *LHS; - BinaryOperator::Opcode Op; - const llvm::APSInt& RHS; - QualType T; - -public: - SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, - const llvm::APSInt& rhs, QualType t) - : SymExpr(SymIntKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} - - // FIXME: We probably need to make this out-of-line to avoid redundant - // generation of virtual functions. - QualType getType(ASTContext& C) const { return T; } - - BinaryOperator::Opcode getOpcode() const { return Op; } - - void dumpToStream(llvm::raw_ostream &os) const; - - const SymExpr *getLHS() const { return LHS; } - const llvm::APSInt &getRHS() const { return RHS; } - - static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, - BinaryOperator::Opcode op, const llvm::APSInt& rhs, - QualType t) { - ID.AddInteger((unsigned) SymIntKind); - ID.AddPointer(lhs); - ID.AddInteger(op); - ID.AddPointer(&rhs); - ID.Add(t); - } - - void Profile(llvm::FoldingSetNodeID& ID) { - Profile(ID, LHS, Op, RHS, T); - } - - // Implement isa support. - static inline bool classof(const SymExpr* SE) { - return SE->getKind() == SymIntKind; - } -}; - -// SymSymExpr - Represents symbolic expression like 'x' + 'y'. -class SymSymExpr : public SymExpr { - const SymExpr *LHS; - BinaryOperator::Opcode Op; - const SymExpr *RHS; - QualType T; - -public: - SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, - QualType t) - : SymExpr(SymSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} - - const SymExpr *getLHS() const { return LHS; } - const SymExpr *getRHS() const { return RHS; } - - // FIXME: We probably need to make this out-of-line to avoid redundant - // generation of virtual functions. - QualType getType(ASTContext& C) const { return T; } - - void dumpToStream(llvm::raw_ostream &os) const; - - static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, - BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) { - ID.AddInteger((unsigned) SymSymKind); - ID.AddPointer(lhs); - ID.AddInteger(op); - ID.AddPointer(rhs); - ID.Add(t); - } - - void Profile(llvm::FoldingSetNodeID& ID) { - Profile(ID, LHS, Op, RHS, T); - } - - // Implement isa support. - static inline bool classof(const SymExpr* SE) { - return SE->getKind() == SymSymKind; - } -}; - -class SymbolManager { - typedef llvm::FoldingSet DataSetTy; - DataSetTy DataSet; - unsigned SymbolCounter; - llvm::BumpPtrAllocator& BPAlloc; - BasicValueFactory &BV; - ASTContext& Ctx; - -public: - SymbolManager(ASTContext& ctx, BasicValueFactory &bv, - llvm::BumpPtrAllocator& bpalloc) - : SymbolCounter(0), BPAlloc(bpalloc), BV(bv), Ctx(ctx) {} - - ~SymbolManager(); - - static bool canSymbolicate(QualType T); - - /// Make a unique symbol for MemRegion R according to its kind. - const SymbolRegionValue* getRegionValueSymbol(const MemRegion* R, - QualType T = QualType()); - const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T, - unsigned VisitCount, - const void* SymbolTag = 0); - - const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount, - const void* SymbolTag = 0) { - return getConjuredSymbol(E, E->getType(), VisitCount, SymbolTag); - } - - const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol, - const TypedRegion *R); - - const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, - const llvm::APSInt& rhs, QualType t); - - const SymIntExpr *getSymIntExpr(const SymExpr &lhs, BinaryOperator::Opcode op, - const llvm::APSInt& rhs, QualType t) { - return getSymIntExpr(&lhs, op, rhs, t); - } - - const SymSymExpr *getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, - const SymExpr *rhs, QualType t); - - QualType getType(const SymExpr *SE) const { - return SE->getType(Ctx); - } - - ASTContext &getContext() { return Ctx; } - BasicValueFactory &getBasicVals() { return BV; } -}; - -class SymbolReaper { - typedef llvm::DenseSet SetTy; - - SetTy TheLiving; - SetTy TheDead; - LiveVariables& Liveness; - SymbolManager& SymMgr; - const StackFrameContext *CurrentStackFrame; - -public: - SymbolReaper(LiveVariables& liveness, SymbolManager& symmgr, - const StackFrameContext *currentStackFrame) - : Liveness(liveness), SymMgr(symmgr), CurrentStackFrame(currentStackFrame) - {} - - ~SymbolReaper() {} - - bool isLive(SymbolRef sym); - - bool isLive(const Stmt* Loc, const Stmt* ExprVal) const { - return Liveness.isLive(Loc, ExprVal); - } - - bool isLive(const Stmt* Loc, const VarRegion *VR) const; - - void markLive(SymbolRef sym); - bool maybeDead(SymbolRef sym); - - typedef SetTy::const_iterator dead_iterator; - dead_iterator dead_begin() const { return TheDead.begin(); } - dead_iterator dead_end() const { return TheDead.end(); } - - bool hasDeadSymbols() const { - return !TheDead.empty(); - } -}; - -class SymbolVisitor { -public: - // VisitSymbol - A visitor method invoked by - // GRStateManager::scanReachableSymbols. The method returns \c true if - // symbols should continue be scanned and \c false otherwise. - virtual bool VisitSymbol(SymbolRef sym) = 0; - virtual ~SymbolVisitor(); -}; - -} // end clang namespace - -namespace llvm { -static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os, - const clang::SymExpr *SE) { - SE->dumpToStream(os); - return os; -} -} // end llvm namespace -#endif diff --git a/include/clang/Analysis/PathSensitive/ValueManager.h b/include/clang/Analysis/PathSensitive/ValueManager.h deleted file mode 100644 index 9cec3c421fbe..000000000000 --- a/include/clang/Analysis/PathSensitive/ValueManager.h +++ /dev/null @@ -1,208 +0,0 @@ -//== ValueManager.h - Aggregate manager of symbols and SVals ----*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines ValueManager, a class that manages symbolic values -// and SVals created for use by GRExprEngine and related classes. It -// wraps and owns SymbolManager, MemRegionManager, and BasicValueFactory. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H -#define LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H - -#include "llvm/ADT/OwningPtr.h" -#include "clang/Analysis/PathSensitive/MemRegion.h" -#include "clang/Analysis/PathSensitive/SVals.h" -#include "clang/Analysis/PathSensitive/BasicValueFactory.h" -#include "clang/Analysis/PathSensitive/SymbolManager.h" -#include "clang/Analysis/PathSensitive/SValuator.h" - -namespace llvm { class BumpPtrAllocator; } - -namespace clang { - -class GRStateManager; - -class ValueManager { - - ASTContext &Context; - BasicValueFactory BasicVals; - - /// SymMgr - Object that manages the symbol information. - SymbolManager SymMgr; - - /// SVator - SValuator object that creates SVals from expressions. - llvm::OwningPtr SVator; - - MemRegionManager MemMgr; - - GRStateManager &StateMgr; - - const QualType ArrayIndexTy; - const unsigned ArrayIndexWidth; - -public: - ValueManager(llvm::BumpPtrAllocator &alloc, ASTContext &context, - GRStateManager &stateMgr) - : Context(context), BasicVals(context, alloc), - SymMgr(context, BasicVals, alloc), - MemMgr(context, alloc), StateMgr(stateMgr), - ArrayIndexTy(context.IntTy), - ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) { - // FIXME: Generalize later. - SVator.reset(clang::CreateSimpleSValuator(*this)); - } - - // Accessors to submanagers. - - ASTContext &getContext() { return Context; } - const ASTContext &getContext() const { return Context; } - - GRStateManager &getStateManager() { return StateMgr; } - - BasicValueFactory &getBasicValueFactory() { return BasicVals; } - const BasicValueFactory &getBasicValueFactory() const { return BasicVals; } - - SymbolManager &getSymbolManager() { return SymMgr; } - const SymbolManager &getSymbolManager() const { return SymMgr; } - - SValuator &getSValuator() { return *SVator.get(); } - - MemRegionManager &getRegionManager() { return MemMgr; } - const MemRegionManager &getRegionManager() const { return MemMgr; } - - // Forwarding methods to SymbolManager. - - const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T, - unsigned VisitCount, - const void* SymbolTag = 0) { - return SymMgr.getConjuredSymbol(E, T, VisitCount, SymbolTag); - } - - const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount, - const void* SymbolTag = 0) { - return SymMgr.getConjuredSymbol(E, VisitCount, SymbolTag); - } - - /// makeZeroVal - Construct an SVal representing '0' for the specified type. - DefinedOrUnknownSVal makeZeroVal(QualType T); - - /// getRegionValueSymbolVal - make a unique symbol for value of R. - DefinedOrUnknownSVal getRegionValueSymbolVal(const MemRegion *R, - QualType T = QualType()); - - DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag, - const Expr *E, unsigned Count); - DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag, - const Expr *E, QualType T, - unsigned Count); - - DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(SymbolRef parentSymbol, - const TypedRegion *R); - - DefinedSVal getFunctionPointer(const FunctionDecl *FD); - - DefinedSVal getBlockPointer(const BlockDecl *BD, CanQualType locTy, - const LocationContext *LC); - - NonLoc makeCompoundVal(QualType T, llvm::ImmutableList Vals) { - return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals)); - } - - NonLoc makeLazyCompoundVal(const GRState *state, const TypedRegion *R) { - return nonloc::LazyCompoundVal(BasicVals.getLazyCompoundValData(state, R)); - } - - NonLoc makeZeroArrayIndex() { - return nonloc::ConcreteInt(BasicVals.getValue(0, ArrayIndexTy)); - } - - NonLoc makeArrayIndex(uint64_t idx) { - return nonloc::ConcreteInt(BasicVals.getValue(idx, ArrayIndexTy)); - } - - SVal convertToArrayIndex(SVal V); - - nonloc::ConcreteInt makeIntVal(const IntegerLiteral* I) { - return nonloc::ConcreteInt(BasicVals.getValue(I->getValue(), - I->getType()->isUnsignedIntegerType())); - } - - nonloc::ConcreteInt makeIntVal(const llvm::APSInt& V) { - return nonloc::ConcreteInt(BasicVals.getValue(V)); - } - - loc::ConcreteInt makeIntLocVal(const llvm::APSInt &v) { - return loc::ConcreteInt(BasicVals.getValue(v)); - } - - NonLoc makeIntVal(const llvm::APInt& V, bool isUnsigned) { - return nonloc::ConcreteInt(BasicVals.getValue(V, isUnsigned)); - } - - DefinedSVal makeIntVal(uint64_t X, QualType T) { - if (Loc::IsLocType(T)) - return loc::ConcreteInt(BasicVals.getValue(X, T)); - - return nonloc::ConcreteInt(BasicVals.getValue(X, T)); - } - - NonLoc makeIntVal(uint64_t X, bool isUnsigned) { - return nonloc::ConcreteInt(BasicVals.getIntValue(X, isUnsigned)); - } - - NonLoc makeIntValWithPtrWidth(uint64_t X, bool isUnsigned) { - return nonloc::ConcreteInt(BasicVals.getIntWithPtrWidth(X, isUnsigned)); - } - - NonLoc makeIntVal(uint64_t X, unsigned BitWidth, bool isUnsigned) { - return nonloc::ConcreteInt(BasicVals.getValue(X, BitWidth, isUnsigned)); - } - - NonLoc makeLocAsInteger(Loc V, unsigned Bits) { - return nonloc::LocAsInteger(BasicVals.getPersistentSValWithData(V, Bits)); - } - - NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, - const llvm::APSInt& rhs, QualType T); - - NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, - const SymExpr *rhs, QualType T); - - NonLoc makeTruthVal(bool b, QualType T) { - return nonloc::ConcreteInt(BasicVals.getTruthValue(b, T)); - } - - NonLoc makeTruthVal(bool b) { - return nonloc::ConcreteInt(BasicVals.getTruthValue(b)); - } - - Loc makeNull() { - return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth()); - } - - Loc makeLoc(SymbolRef Sym) { - return loc::MemRegionVal(MemMgr.getSymbolicRegion(Sym)); - } - - Loc makeLoc(const MemRegion* R) { - return loc::MemRegionVal(R); - } - - Loc makeLoc(const AddrLabelExpr* E) { - return loc::GotoLabel(E->getLabel()); - } - - Loc makeLoc(const llvm::APSInt& V) { - return loc::ConcreteInt(BasicVals.getValue(V)); - } -}; -} // end clang namespace -#endif - diff --git a/include/clang/Analysis/Support/Optional.h b/include/clang/Analysis/Support/Optional.h index 40f38be020a9..a4e6d519a04f 100644 --- a/include/clang/Analysis/Support/Optional.h +++ b/include/clang/Analysis/Support/Optional.h @@ -20,19 +20,27 @@ namespace clang { template class Optional { - const T x; + T x; unsigned hasVal : 1; public: - explicit Optional() : hasVal(false) {} + explicit Optional() : x(), hasVal(false) {} Optional(const T &y) : x(y), hasVal(true) {} static inline Optional create(const T* y) { return y ? Optional(*y) : Optional(); } + Optional &operator=(const T &y) { + x = y; + hasVal = true; + return *this; + } + const T* getPointer() const { assert(hasVal); return &x; } + const T& getValue() const { assert(hasVal); return x; } operator bool() const { return hasVal; } + bool hasValue() const { return hasVal; } const T* operator->() const { return getPointer(); } const T& operator*() const { assert(hasVal); return x; } }; diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index 08945635e6c9..3251ec4b1f97 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -12,9 +12,6 @@ // //===----------------------------------------------------------------------===// -// FIXME: this needs to be the full list supported by GCC. Right now, I'm just -// adding stuff on demand. -// // FIXME: This should really be a .td file, but that requires modifying tblgen. // Perhaps tblgen should have plugins. @@ -52,6 +49,7 @@ // * -> pointer // & -> reference // C -> const +// D -> volatile // The third value provided to the macro specifies information about attributes // of the function. These must be kept in sync with the predicates in the @@ -235,7 +233,7 @@ BUILTIN(__builtin_islessgreater , "i.", "nc") BUILTIN(__builtin_isunordered , "i.", "nc") // Unary FP classification -// BUILTIN(__builtin_fpclassify, "iiiii.", "nc") +BUILTIN(__builtin_fpclassify, "iiiii.", "nc") BUILTIN(__builtin_isfinite, "i.", "nc") BUILTIN(__builtin_isinf, "i.", "nc") BUILTIN(__builtin_isinf_sign, "i.", "nc") @@ -277,7 +275,7 @@ BUILTIN(__builtin_va_copy, "vAA", "n") BUILTIN(__builtin_stdarg_start, "vA.", "n") BUILTIN(__builtin_bcmp, "iv*v*z", "n") BUILTIN(__builtin_bcopy, "vv*v*z", "n") -BUILTIN(__builtin_bzero, "vv*z", "n") +BUILTIN(__builtin_bzero, "vv*z", "nF") BUILTIN(__builtin_memchr, "v*vC*iz", "nF") BUILTIN(__builtin_memcmp, "ivC*vC*z", "nF") BUILTIN(__builtin_memcpy, "v*v*vC*z", "nF") @@ -308,11 +306,19 @@ BUILTIN(__builtin_extract_return_addr, "v*v*", "n") BUILTIN(__builtin_frame_address, "v*Ui", "n") BUILTIN(__builtin_flt_rounds, "i", "nc") BUILTIN(__builtin_setjmp, "iv**", "") -BUILTIN(__builtin_longjmp, "vv**i", "") +BUILTIN(__builtin_longjmp, "vv**i", "r") BUILTIN(__builtin_unwind_init, "v", "") BUILTIN(__builtin_eh_return_data_regno, "ii", "nc") BUILTIN(__builtin_vsnprintf, "ic*zcC*a", "nFP:2:") +// GCC exception builtins +BUILTIN(__builtin_eh_return, "vzv*", "") // FIXME: Takes intptr_t, not size_t! +BUILTIN(__builtin_frob_return_addr, "v*v*", "n") +BUILTIN(__builtin_dwarf_cfa, "v*", "n") +BUILTIN(__builtin_init_dwarf_reg_size_table, "vv*", "n") +BUILTIN(__builtin_dwarf_sp_column, "Ui", "n") +BUILTIN(__builtin_extend_pointer, "iv*", "n") + // GCC Object size checking builtins BUILTIN(__builtin_object_size, "zv*i", "n") BUILTIN(__builtin___memcpy_chk, "v*v*vC*zz", "nF") @@ -438,18 +444,18 @@ BUILTIN(__sync_nand_and_fetch_16, "LLLiLLLi*LLLi.", "n") BUILTIN(__sync_bool_compare_and_swap, "v.", "") -BUILTIN(__sync_bool_compare_and_swap_1, "bc*cc.", "n") -BUILTIN(__sync_bool_compare_and_swap_2, "bs*ss.", "n") -BUILTIN(__sync_bool_compare_and_swap_4, "bi*ii.", "n") -BUILTIN(__sync_bool_compare_and_swap_8, "bLLi*LLi.", "n") -BUILTIN(__sync_bool_compare_and_swap_16, "bLLLi*LLLiLLLi.", "n") +BUILTIN(__sync_bool_compare_and_swap_1, "bcD*cc.", "n") +BUILTIN(__sync_bool_compare_and_swap_2, "bsD*ss.", "n") +BUILTIN(__sync_bool_compare_and_swap_4, "biD*ii.", "n") +BUILTIN(__sync_bool_compare_and_swap_8, "bLLiD*LLiLLi.", "n") +BUILTIN(__sync_bool_compare_and_swap_16, "bLLLiD*LLLiLLLi.", "n") BUILTIN(__sync_val_compare_and_swap, "v.", "") -BUILTIN(__sync_val_compare_and_swap_1, "cc*cc.", "n") -BUILTIN(__sync_val_compare_and_swap_2, "ss*ss.", "n") -BUILTIN(__sync_val_compare_and_swap_4, "ii*ii.", "n") -BUILTIN(__sync_val_compare_and_swap_8, "LLiLLi*LLi.", "n") -BUILTIN(__sync_val_compare_and_swap_16, "LLLiLLLi*LLLiLLLi.", "n") +BUILTIN(__sync_val_compare_and_swap_1, "ccD*cc.", "n") +BUILTIN(__sync_val_compare_and_swap_2, "ssD*ss.", "n") +BUILTIN(__sync_val_compare_and_swap_4, "iiD*ii.", "n") +BUILTIN(__sync_val_compare_and_swap_8, "LLiLLiD*LLiLLi.", "n") +BUILTIN(__sync_val_compare_and_swap_16, "LLLiLLLiD*LLLiLLLi.", "n") BUILTIN(__sync_lock_test_and_set, "v.", "") BUILTIN(__sync_lock_test_and_set_1, "cc*c.", "n") @@ -527,6 +533,7 @@ LIBBUILTIN(strndup, "c*cC*z", "f", "string.h") // POSIX strings.h LIBBUILTIN(index, "c*cC*i", "f", "strings.h") LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h") +LIBBUILTIN(bzero, "vv*z", "f", "strings.h") // POSIX unistd.h LIBBUILTIN(_exit, "vi", "fr", "unistd.h") // POSIX setjmp.h diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index c5d6d7c71316..d2516f8695b8 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -23,16 +23,19 @@ namespace llvm { template class SmallVectorImpl; + class raw_ostream; } namespace clang { class DeclContext; class DiagnosticBuilder; class DiagnosticClient; + class FileManager; class IdentifierInfo; class LangOptions; class PartialDiagnostic; class Preprocessor; + class SourceManager; class SourceRange; // Import the diagnostic enums themselves. @@ -400,6 +403,13 @@ public: /// \brief Clear out the current diagnostic. void Clear() { CurDiagID = ~0U; } + /// Deserialize - Deserialize the first diagnostic within the memory + /// [Memory, MemoryEnd), producing a new diagnostic builder describing the + /// deserialized diagnostic. If the memory does not contain a + /// diagnostic, returns a diagnostic builder with no diagnostic ID. + DiagnosticBuilder Deserialize(FileManager &FM, SourceManager &SM, + const char *&Memory, const char *MemoryEnd); + private: /// getDiagnosticMappingInfo - Return the mapping info currently set for the /// specified builtin diagnostic. This returns the high bit encoding, or zero @@ -472,7 +482,7 @@ private: /// DiagRanges - The list of ranges added to this diagnostic. It currently /// only support 10 ranges, could easily be extended if needed. - const SourceRange *DiagRanges[10]; + SourceRange DiagRanges[10]; enum { MaxCodeModificationHints = 3 }; @@ -568,6 +578,9 @@ public: /// been emitted. ~DiagnosticBuilder() { Emit(); } + /// isActive - Determine whether this diagnostic is still active. + bool isActive() const { return DiagObj != 0; } + /// Operator bool: conversion of DiagnosticBuilder to bool always returns /// true. This allows is to be used in boolean error contexts like: /// return Diag(...); @@ -596,7 +609,7 @@ public: sizeof(DiagObj->DiagRanges)/sizeof(DiagObj->DiagRanges[0]) && "Too many arguments to diagnostic!"); if (DiagObj) - DiagObj->DiagRanges[NumRanges++] = &R; + DiagObj->DiagRanges[NumRanges++] = R; } void AddCodeModificationHint(const CodeModificationHint &Hint) const { @@ -759,9 +772,9 @@ public: return DiagObj->NumDiagRanges; } - const SourceRange &getRange(unsigned Idx) const { + SourceRange getRange(unsigned Idx) const { assert(Idx < DiagObj->NumDiagRanges && "Invalid diagnostic range index!"); - return *DiagObj->DiagRanges[Idx]; + return DiagObj->DiagRanges[Idx]; } unsigned getNumCodeModificationHints() const { @@ -786,6 +799,12 @@ public: /// output buffer using the arguments stored in this diagnostic. void FormatDiagnostic(const char *DiagStr, const char *DiagEnd, llvm::SmallVectorImpl &OutStr) const; + + /// Serialize - Serialize the given diagnostic (with its diagnostic + /// level) to the given stream. Serialization is a lossy operation, + /// since the specific diagnostic ID and any macro-instantiation + /// information is lost. + void Serialize(Diagnostic::Level DiagLevel, llvm::raw_ostream &OS) const; }; /// DiagnosticClient - This is an abstract interface implemented by clients of diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index f075aaaf422f..b6c2b13895d6 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -26,4 +26,33 @@ def err_asm_empty_symbolic_operand_name : Error< def err_asm_invalid_operand_number : Error< "invalid operand number in inline asm string">; +// Importing ASTs +def err_odr_variable_type_inconsistent : Error< + "external variable %0 declared with incompatible types in different " + "translation units (%1 vs. %2)">; +def err_odr_variable_multiple_def : Error< + "external variable %0 defined in multiple translation units">; +def note_odr_value_here : Note<"declared here with type %0">; +def note_odr_defined_here : Note<"also defined here">; +def err_odr_function_type_inconsistent : Error< + "external function %0 declared with incompatible types in different " + "translation units (%1 vs. %2)">; +def warn_odr_tag_type_inconsistent : Warning< + "type %0 has incompatible definitions in different translation units">; +def note_odr_tag_kind_here: Note< + "%0 is a %select{struct|union|class|enum}1 here">; +def note_odr_field : Note<"field %0 has type %1 here">; +def note_odr_missing_field : Note<"no corresponding field here">; +def note_odr_bit_field : Note<"bit-field %0 with type %1 and length %2 here">; +def note_odr_not_bit_field : Note<"field %0 is not a bit-field">; +def note_odr_base : Note<"class has base type %0">; +def note_odr_virtual_base : Note< + "%select{non-virtual|virtual}0 derivation here">; +def note_odr_missing_base : Note<"no corresponding base class here">; +def note_odr_number_of_bases : Note< + "class has %0 base %plural{1:class|:classes}0">; +def note_odr_enumerator : Note<"enumerator %0 with value %1 here">; +def note_odr_missing_enumerator : Note<"no corresponding enumerator here">; + +def err_unsupported_ast_node: Error<"cannot import unsupported AST node %0">; } diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index 7e14a329dcab..66f84dbbbabe 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -31,6 +31,9 @@ def note_also_found : Note<"also found">; // Parse && Lex def err_expected_colon : Error<"expected ':'">; +def err_expected_colon_after_setter_name : Error< + "method name referenced in property setter attribute " + "must end with ':'">; // Parse && Sema def err_no_declarators : Error<"declaration does not declare anything">; diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index 8cdf85082b16..dc5ccfdf5202 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -62,6 +62,8 @@ def err_drv_invalid_value : Error<"invalid value '%1' in '%0'">; def err_drv_invalid_int_value : Error<"invalid integral value '%1' in '%0'">; def err_drv_invalid_remap_file : Error< "invalid option '%0' not of the form ;">; +def err_drv_invalid_gcc_output_type : Error< + "invalid output type '%0' for use with gcc tool">; def warn_drv_input_file_unused : Warning< "%0: '%1' input unused when '%2' is present">; @@ -85,5 +87,7 @@ def warn_ignoring_ftabstop_value : Warning< "ignoring invalid -ftabstop value '%0', using default value %1">; def warn_drv_missing_resource_library : Warning< "missing resource library '%0', link may fail">; +def warn_drv_conflicting_deployment_targets : Warning< + "conflicting deployment targets, both MACOSX_DEPLOYMENT_TARGET '%0' and IPHONEOS_DEPLOYMENT_TARGET '%1' are present in environment">; } diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index 66a841a8afae..79147eac5f32 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -19,6 +19,8 @@ def err_fe_invalid_code_complete_file : Error< "cannot locate code-completion file %0">, DefaultFatal; def err_fe_stdout_binary : Error<"unable to change standard output to binary">, DefaultFatal; +def err_fe_stderr_binary : Error<"unable to change standard error to binary">, + DefaultFatal; def err_fe_dependency_file_requires_MT : Error< "-dependency-file requires at least one -MT option">; def err_fe_incompatible_options : Error< @@ -80,6 +82,8 @@ def note_fixit_main_file_unchanged : Note< def warn_fixit_no_changes : Note< "FIX-IT detected errors it could not fix; no output will be generated">; +def err_fe_clang : Error<"error invoking%s: %s">, DefaultFatal; + // PCH reader def err_relocatable_without_without_isysroot : Error< "must specify system root with -isysroot when building a relocatable " @@ -105,6 +109,10 @@ def warn_pch_objective_c2 : Error< def warn_pch_nonfragile_abi : Error< "PCH file was compiled with the %select{32-bit|non-fragile}0 Objective-C " "ABI but the %select{32-bit|non-fragile}1 Objective-C ABI is selected">; +def warn_pch_nonfragile_abi2 : Error< + "PCH file was compiled with the %select{32-bit|enhanced non-fragile}0 " + "Objective-C ABI but the %select{32-bit|enhanced non-fragile}1 " + "Objective-C ABI is selected">; def warn_pch_extensions : Error< "extensions were %select{enabled|disabled}0 in PCH file but are " "currently %select{enabled|disabled}1">; @@ -132,6 +140,9 @@ def warn_pch_elide_constructors : Error< def warn_pch_exceptions : Error< "exceptions were %select{disabled|enabled}0 in PCH file but " "are currently %select{disabled|enabled}1">; +def warn_pch_sjlj_exceptions : Error< + "sjlj-exceptions were %select{disabled|enabled}0 in PCH file but " + "are currently %select{disabled|enabled}1">; def warn_pch_objc_runtime : Error< "PCH file was compiled with the %select{NeXT|GNU}0 runtime but the " "%select{NeXT|GNU}1 runtime is selected">; diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 03aad8606352..82f9eca12960 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -96,7 +96,8 @@ def : DiagGroup<"strict-overflow">; def InvalidOffsetof : DiagGroup<"invalid-offsetof">; def : DiagGroup<"strict-prototypes">; def : DiagGroup<"strict-selector-match">; -def Switch : DiagGroup<"switch">; +def SwitchEnum : DiagGroup<"switch-enum">; +def Switch : DiagGroup<"switch", [SwitchEnum]>; def Trigraphs : DiagGroup<"trigraphs">; def : DiagGroup<"type-limits">; @@ -118,6 +119,7 @@ def VectorConversions : DiagGroup<"vector-conversions">; // clang specific def VolatileRegisterVar : DiagGroup<"volatile-register-var">; def : DiagGroup<"write-strings">; def CharSubscript : DiagGroup<"char-subscripts">; +def ForceAlignArgPointer : DiagGroup<"force-align-arg-pointer">; // Aggregation warning settings. @@ -178,4 +180,4 @@ def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment // A warning group for warnings that we want to have on by default in clang, // but which aren't on by default in GCC. def NonGCC : DiagGroup<"non-gcc", - [SignCompare, Conversion]>; + [SignCompare, Conversion, ForceAlignArgPointer]>; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index c6d060525285..bc26c3b0dad9 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -14,6 +14,8 @@ let Component = "Parse" in { def w_asm_qualifier_ignored : Warning<"ignored %0 qualifier on asm">; +def warn_file_asm_volatile : Warning< + "meaningless 'volatile' on asm outside function">; def ext_empty_source_file : Extension<"ISO C forbids an empty source file">; def ext_top_level_semi : Extension< @@ -158,12 +160,20 @@ def err_typename_invalid_functionspec : Error< "type name does not allow function specifier to be specified">; def err_invalid_decl_spec_combination : Error< "cannot combine with previous '%0' declaration specifier">; +def err_invalid_vector_decl_spec_combination : Error< + "cannot combine with previous '%0' declaration specifier. \"__vector\" must be first">; +def err_invalid_pixel_decl_spec_combination : Error< + "\"__pixel\" must be preceded by \"__vector\". '%0' declaration specifier not allowed here">; +def err_invalid_vector_double_decl_spec_combination : Error< + "cannot use \"double\" with \"__vector\"">; +def warn_vector_long_decl_spec_combination : Warning< + "Use of \"long\" with \"__vector\" is deprecated">; def err_friend_invalid_in_context : Error< "'friend' used outside of class">; def err_unknown_typename : Error< "unknown type name %0">; def err_use_of_tag_name_without_tag : Error< - "use of tagged type %0 without '%1' tag">; + "must use '%1' tag to refer to type %0%select{| in this scope}2">; def err_expected_ident_in_using : Error< "expected an identifier in using directive">; def err_unexected_colon_in_nested_name_spec : Error< @@ -303,6 +313,9 @@ def err_out_of_line_type_names_constructor : Error< def err_expected_qualified_after_typename : Error< "expected a qualified name after 'typename'">; +def err_expected_semi_after_tagdecl : Error< + "expected ';' after %0">; + def err_typename_refers_to_non_type_template : Error< "typename specifier refers to a non-template">; def err_expected_type_name_after_typename : Error< diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 8d75d2e25722..19b242e86b69 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -85,7 +85,11 @@ def warn_unused_variable : Warning<"unused variable %0">, InGroup, DefaultIgnore; def warn_decl_in_param_list : Warning< "declaration of %0 will not be visible outside of this function">; - +def err_array_star_in_function_definition : Error< + "variable length array must be bound in function definition">; +def warn_unused_function : Warning<"unused function %0">, + InGroup, DefaultIgnore; + def warn_implicit_function_decl : Warning< "implicit declaration of function %0">, InGroup, DefaultIgnore; @@ -388,6 +392,11 @@ def err_deleted_non_function : Error< def err_deleted_decl_not_first : Error< "deleted definition must be first declaration">; +def warn_weak_vtable : Warning< + "%0 has no out-of-line virtual method definitions; its vtable will be " + "emitted in every translation unit">, + InGroup>, DefaultIgnore; + // C++ exception specifications def err_exception_spec_in_typedef : Error< "exception specifications are not allowed in typedefs">; @@ -410,17 +419,20 @@ def err_deep_exception_specs_differ : Error< // C++ access checking def err_class_redeclared_with_different_access : Error< "%0 redeclared with '%1' access">; +def err_access_private : Error<"%0 is a private member of %1">; +def err_access_ctor_private : Error<"calling a private constructor of %0">; +// Say something about the context for these? +def err_access_protected : Error<"%0 is a protected member of %1">; +def err_access_ctor_protected : Error<"calling a protected constructor of %0">; def note_previous_access_declaration : Note< "previously declared '%1' here">; def err_access_outside_class : Error< "access to %select{private|protected}0 member outside any class context">; -def note_access_natural : Note<"declared %select{private|protected}0 here">; +def note_access_natural : Note< + "%select{|implicitly }1declared %select{private|protected}0 here">; def note_access_constrained_by_path : Note< - "access to decl constrained by %select{private|protected}0 inheritance">; -def err_access_protected : Error< - "access to protected member of %0 from %1, which is not a subclass">; -def err_access_private : Error< - "access to private member of %0 from %1">; + "constrained by %select{|implicitly }1%select{private|protected}0" + " inheritance here">; // C++ name lookup def err_incomplete_nested_name_spec : Error< @@ -446,10 +458,14 @@ def err_mutable_nonmember : Error< "'mutable' can only be applied to member variables">; def err_virtual_non_function : Error< "'virtual' can only appear on non-static member functions">; -def err_explicit_non_function : Error< - "'explicit' can only appear on non-static member functions">; def err_virtual_out_of_class : Error< "'virtual' can only be specified inside the class definition">; +def err_explicit_non_function : Error< + "'explicit' can only appear on non-static member functions">; +def err_explicit_out_of_class : Error< + "'explicit' can only be specified inside the class definition">; +def err_explicit_non_ctor_or_conv_function : Error< + "'explicit' can only be applied to a constructor or conversion function">; def err_static_not_bitfield : Error<"static member %0 cannot be a bit-field">; def err_static_out_of_line : Error< "'static' can only be specified inside the class definition">; @@ -498,9 +514,8 @@ def note_overridden_virtual_function : Note< "overridden virtual function is here">; def err_covariant_return_inaccessible_base : Error< - "return type of virtual function %2 is not covariant with the return type " - "of the function it overrides " - "(conversion from %0 to inaccessible base class %1)">, NoSFINAE; + "invalid covariant return for virtual function: %1 is a " + "%select{private|protected}2 base class of %0">, NoSFINAE; def err_covariant_return_ambiguous_derived_to_base_conv : Error< "return type of virtual function %3 is not covariant with the return type of " "the function it overrides (ambiguous conversion from derived class " @@ -547,7 +562,7 @@ def err_destructor_name : Error< def err_init_conversion_failed : Error< "cannot initialize %select{a variable|a parameter|return object|an " "exception object|a member subobject|an array element|a new value|a value|a " - "base class|an array element}0 of type %1 with an %select{rvalue|lvalue}2 of " + "base class|a vector element}0 of type %1 with an %select{rvalue|lvalue}2 of " "type %3">; def err_lvalue_to_rvalue_ref : Error<"rvalue reference cannot bind to lvalue">; @@ -556,14 +571,14 @@ def err_invalid_initialization : Error< def err_lvalue_to_rvalue_ambig_ref : Error<"rvalue reference cannot bind to lvalue " "due to multiple conversion functions">; def err_not_reference_to_const_init : Error< - "non-const lvalue reference to type %0 cannot be initialized " - "with a %select{value|temporary}1 of type %2">; + "%select{non-const|volatile}0 lvalue reference to type %1 cannot be " + "initialized with a %select{value|temporary}2 of type %3">; def err_lvalue_reference_bind_to_temporary : Error< - "non-const lvalue reference to type %0 cannot bind to a temporary of type " - "%1">; + "%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to a " + "temporary of type %2">; def err_lvalue_reference_bind_to_unrelated : Error< - "non-const lvalue reference to type %0 cannot bind to a value of unrelated " - "type %1">; + "%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to a " + "value of unrelated type %2">; def err_reference_bind_drops_quals : Error< "binding of reference to type %0 to a value of type %1 drops qualifiers">; def err_reference_bind_failed : Error< @@ -580,10 +595,14 @@ def err_reference_init_drops_quals : Error< "qualifiers">; def err_reference_bind_to_bitfield : Error< "%select{non-const|volatile}0 reference cannot bind to bit-field %1">; +def err_reference_bind_to_vector_element : Error< + "%select{non-const|volatile}0 reference cannot bind to vector element">; def err_reference_var_requires_init : Error< "declaration of reference variable %0 requires an initializer">; def err_const_var_requires_init : Error< "declaration of const variable '%0' requires an initializer">; +def err_reference_without_init : Error< + "reference to type %0 requires an initializer">; def err_reference_has_multiple_inits : Error< "reference cannot be initialized with multiple values">; def err_init_non_aggr_init_list : Error< @@ -597,13 +616,16 @@ def warn_field_is_uninit : Warning<"field is uninitialized when used here">, def err_temp_copy_no_viable : Error< "no viable copy constructor %select{copying variable|copying parameter|" - "returning object|throwing object}0 of type %1">; + "returning object|throwing object|copying member subobject|copying array " + "element}0 of type %1">; def err_temp_copy_ambiguous : Error< "ambiguous copy constructor call when %select{copying variable|copying " - "parameter|returning object|throwing object}0 of type %1">; + "parameter|returning object|throwing object|copying member subobject|copying " + "array element}0 of type %1">; def err_temp_copy_deleted : Error< "%select{copying variable|copying parameter|returning object|throwing " - "object}0 of type %1 invokes deleted copy constructor">; + "object|copying member subobject|copying array element}0 of type %1 invokes " + "deleted copy constructor">; // C++0x decltype def err_cannot_determine_declared_type_of_overloaded_function : Error< @@ -702,6 +724,9 @@ def err_attribute_aligned_not_power_of_two : Error< def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning< "'%0' redeclared without %1 attribute: previous %1 ignored">; def warn_attribute_ignored : Warning<"%0 attribute ignored">; +def warn_faap_attribute_ignored : Warning< + "force_align_arg_pointer used on function pointer; attribute ignored">, + InGroup; def warn_attribute_precede_definition : Warning< "attribute declaration must precede definition">; def warn_attribute_void_function : Warning< @@ -728,13 +753,18 @@ def err_attribute_wrong_decl_type : Error< "parameter or Objective-C method |function, method or block|" "virtual method or class|function, method, or parameter|class|virtual method" "|member}1 types">; +def warn_function_attribute_wrong_type : Warning< + "%0 only applies to function types; type here is %1">; def warn_gnu_inline_attribute_requires_inline : Warning< "'gnu_inline' attribute requires function to be marked 'inline'," " attribute ignored">; +def err_cconv_change : Error< + "function declared '%0' here was previously declared " + "%select{'%2'|without calling convention}1">; def err_cconv_knr : Error< - "function with no prototype cannot use '%0' calling convention">; + "function with no prototype cannot use %0 calling convention">; def err_cconv_varargs : Error< - "variadic function cannot use '%0' calling convention">; + "variadic function cannot use %0 calling convention">; def warn_impcast_vector_scalar : Warning< "implicit cast turns vector to scalar: %0 to %1">, @@ -873,10 +903,7 @@ def err_uninitialized_member_for_assign : Error< "assignment operator">; def note_first_required_here : Note< "synthesized method is first required here">; -def err_null_intialized_reference_member : Error< - "cannot initialize the member to null in default constructor because " - "reference member %0 cannot be null-initialized">; -def err_unintialized_member_in_ctor : Error< +def err_uninitialized_member_in_ctor : Error< "%select{|implicit default }0constructor for %1 must explicitly initialize " "the %select{reference|const}2 member %3">; @@ -915,6 +942,12 @@ def note_ovl_candidate : Note<"candidate " "is the implicit default constructor|" "is the implicit copy constructor|" "is the implicit copy assignment operator}0%1">; + +def note_ovl_candidate_bad_deduction : Note< + "candidate template ignored: failed template argument deduction">; +def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: " + "couldn't infer template argument %0">; + // Note that we don't treat templates differently for this diagnostic. def note_ovl_candidate_arity : Note<"candidate " "%select{function|function|constructor|function|function|constructor|" @@ -941,6 +974,13 @@ def note_ovl_candidate_bad_conv_incomplete : Note<"candidate " "constructor (the implicit copy constructor)|" "function (the implicit copy assignment operator)}0%1 " "not viable: cannot convert argument of incomplete type %2 to %3">; +def note_ovl_candidate_bad_overload : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "function (the implicit copy assignment operator)}0%1" + " not viable: no overload of %3 matching %2 for %ordinal4 argument">; def note_ovl_candidate_bad_conv : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" @@ -1068,9 +1108,6 @@ def err_template_tag_noparams : Error< def err_template_decl_ref : Error< "cannot refer to class template %0 without a template argument list">; -def err_typedef_in_def_scope : Error< - "cannot use typedef %0 in scope specifier for out-of-line declaration">; - // C++ Template Argument Lists def err_template_arg_list_different_arity : Error< "%select{too few|too many}0 template arguments for " @@ -1122,6 +1159,8 @@ def err_template_arg_no_ref_bind : Error< def err_template_arg_ref_bind_ignores_quals : Error< "reference binding of non-type template parameter of type %0 to template " "argument of type %1 ignores qualifiers">; +def err_template_arg_not_decl_ref : Error< + "non-type template argument does not refer to any declaration">; def err_template_arg_not_object_or_func_form : Error< "non-type template argument does not directly refer to an object or " "function">; @@ -1236,6 +1275,8 @@ def err_partial_spec_redeclared : Error< "class template partial specialization %0 cannot be redeclared">; def note_prev_partial_spec_here : Note< "previous declaration of class template partial specialization %0 is here">; +def err_partial_spec_fully_specialized : Error< + "partial specialization of %0 does not use any of its template parameters">; // C++ Function template specializations def err_function_template_spec_no_match : Error< @@ -1442,9 +1483,13 @@ def err_forward_ref_enum : Error< def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">; def err_duplicate_member : Error<"duplicate member %0">; def ext_enum_value_not_int : Extension< - "ISO C restricts enumerator values to range of 'int' (%0 is too large)">; + "ISO C restricts enumerator values to range of 'int' (%0 is too " + "%select{small|large}1)">; def warn_enum_too_large : Warning< "enumeration values exceed range of largest integer">; +def warn_enumerator_too_large : Warning< + "enumerator value %0 is not representable in the largest integer type">; + def warn_illegal_constant_array_size : Extension< "size of static array must be an integer constant expression">; def err_vla_decl_in_file_scope : Error< @@ -1677,6 +1722,8 @@ def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">; def err_no_member : Error<"no member named %0 in %1">; def err_member_redeclared : Error<"class member cannot be redeclared">; +def err_member_def_undefined_record : Error< + "out-of-line definition of %0 from class %1 without definition">; def err_member_def_does_not_match : Error< "out-of-line definition of %0 does not match any declaration in %1">; def err_nonstatic_member_out_of_line : Error< @@ -1824,7 +1871,11 @@ def ext_integer_complement_complex : Extension< def error_nosetter_property_assignment : Error< "setter method is needed to assign to object using property" " assignment syntax">; def error_no_subobject_property_setting : Error< - "cannot assign to a sub-structure of an ivar using property" " assignment syntax">; + "cannot assign to a sub-structure of an ivar using property" + " assignment syntax">; +def error_no_subobject_property_getter_setting : Error< + "cannot assign to a sub-structure returned via a getter using property" + " assignment syntax">; def ext_freestanding_complex : Extension< "complex numbers are an extension in a freestanding C99 implementation">; @@ -1915,7 +1966,9 @@ def err_ambiguous_base_to_derived_cast : Error< def err_static_downcast_via_virtual : Error< "cannot cast %0 to %1 via virtual base %2">; def err_downcast_from_inaccessible_base : Error< - "cannot cast %1 to %0 due to inaccessible conversion path">; + "cannot cast %select{private|protected}2 base class %1 to %0">; +def err_upcast_to_inaccessible_base : Error< + "cannot cast %0 to its %select{private|protected}2 base class %1">; def err_bad_dynamic_cast_not_ref_or_ptr : Error< "%0 is not a reference or pointer">; def err_bad_dynamic_cast_not_class : Error<"%0 is not a class">; @@ -1942,7 +1995,8 @@ def err_new_paren_array_nonconst : Error< def err_array_size_not_integral : Error< "array size expression must have integral or enumerated type, not %0">; def err_default_init_const : Error< - "default initialization of an object of const type %0">; + "default initialization of an object of const type %0" + "%select{| requires a user-provided default constructor}1">; def err_delete_operand : Error<"cannot delete expression of type %0">; def err_ambiguous_delete_operand : Error<"ambiguous conversion of delete " "expression of type %0 to a pointer">; @@ -2245,8 +2299,6 @@ def error_multiple_base_initialization : Error < def err_mem_init_not_member_or_class : Error< "member initializer %0 does not name a non-static data member or base " "class">; -def err_mem_initializer_mismatch : Error< - "Too many arguments for member initializer %0">; def warn_field_initialized : Warning< "member '%0' will be initialized after">, @@ -2435,11 +2487,16 @@ def warn_printf_write_back : Warning< def warn_printf_insufficient_data_args : Warning< "more '%%' conversions than data arguments">, InGroup; def warn_printf_too_many_data_args : Warning< - "more data arguments than '%%' conversions">, InGroup; + "more data arguments than format specifiers">, InGroup; def warn_printf_invalid_conversion : Warning< - "invalid conversion '%0'">, InGroup; + "invalid conversion specifier '%0'">, InGroup; +def warn_printf_incomplete_specifier : Warning< + "incomplete format specifier">, InGroup; def warn_printf_missing_format_string : Warning< "format string missing">, InGroup; +def warn_printf_conversion_argument_type_mismatch : Warning< + "conversion specifies type %0 but the argument has type %1">, + InGroup; def warn_null_arg : Warning< "null passed to a callee which requires a non-null argument">, InGroup; @@ -2454,12 +2511,18 @@ def warn_printf_asterisk_width_missing_arg : Warning< def warn_printf_asterisk_precision_missing_arg : Warning< "'.*' specified field precision is missing a matching 'int' argument">; def warn_printf_asterisk_width_wrong_type : Warning< - "field width should have type 'int', but argument has type %0">, + "field width should have type %0, but argument has type %1">, InGroup; def warn_printf_asterisk_precision_wrong_type : Warning< - "field precision should have type 'int', but argument has type %0">, + "field precision should have type %0, but argument has type %1">, InGroup; - +def warn_printf_nonsensical_precision: Warning< + "precision used in '%0' conversion specifier (where it has no meaning)">, + InGroup; +def warn_printf_nonsensical_flag: Warning< + "flag '%0' results in undefined behavior in '%1' conversion specifier">, + InGroup; + // CHECK: returning address/reference of stack memory def warn_ret_stack_addr : Warning< "address of stack memory associated with local variable %0 returned">; @@ -2511,6 +2574,10 @@ def warn_case_value_overflow : Warning< "overflow converting case value to switch condition type (%0 to %1)">; def err_duplicate_case : Error<"duplicate case value '%0'">; def warn_case_empty_range : Warning<"empty case range specified">; +def warn_missing_cases : Warning<"enumeration value %0 not handled in switch">, + InGroup >; +def not_in_enum : Warning<"case value not in enumerated type %0">, + InGroup >; def err_typecheck_statement_requires_scalar : Error< "statement requires expression of scalar type (%0 invalid)">; def err_typecheck_statement_requires_integer : Error< @@ -2679,6 +2746,7 @@ def err_undeclared_protocol_suggest : Error< "cannot find protocol declaration for %0; did you mean %1?">; def note_base_class_specified_here : Note< "base class %0 specified here">; + } diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index 2b6092dea309..d909f83e74d5 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -40,12 +40,14 @@ public: unsigned ObjC1 : 1; // Objective-C 1 support enabled. unsigned ObjC2 : 1; // Objective-C 2 support enabled. unsigned ObjCNonFragileABI : 1; // Objective-C modern abi enabled + unsigned ObjCNonFragileABI2 : 1; // Objective-C enhanced modern abi enabled unsigned PascalStrings : 1; // Allow Pascal strings unsigned WritableStrings : 1; // Allow writable strings unsigned LaxVectorConversions : 1; unsigned AltiVec : 1; // Support AltiVec-style vector initializers. unsigned Exceptions : 1; // Support exception handling. + unsigned SjLjExceptions : 1; // Use setjmp-longjump exception handling. unsigned RTTI : 1; // Support RTTI information. unsigned NeXTRuntime : 1; // Use NeXT runtime. @@ -95,7 +97,9 @@ public: // operators unsigned ElideConstructors : 1; // Whether C++ copy constructors should be // elided if possible. - unsigned CatchUndefined :1; // Generate code to check for undefined ops. + unsigned CatchUndefined : 1; // Generate code to check for undefined ops. + unsigned DumpVtableLayouts : 1; // Dump the layouts of all the emitted + // vtables. private: unsigned GC : 2; // Objective-C Garbage Collection modes. We // declare this enum as unsigned because MSVC @@ -124,10 +128,10 @@ public: Trigraphs = BCPLComment = Bool = DollarIdents = AsmPreprocessor = 0; GNUMode = ImplicitInt = Digraphs = 0; HexFloats = 0; - GC = ObjC1 = ObjC2 = ObjCNonFragileABI = 0; + GC = ObjC1 = ObjC2 = ObjCNonFragileABI = ObjCNonFragileABI2 = 0; C99 = Microsoft = CPlusPlus = CPlusPlus0x = 0; CXXOperatorNames = PascalStrings = WritableStrings = 0; - Exceptions = Freestanding = NoBuiltin = 0; + Exceptions = SjLjExceptions = Freestanding = NoBuiltin = 0; NeXTRuntime = 1; RTTI = 1; LaxVectorConversions = 1; @@ -136,8 +140,7 @@ public: SymbolVisibility = (unsigned) Default; - // FIXME: The default should be 1. - ThreadsafeStatics = 0; + ThreadsafeStatics = 1; POSIXThreads = 0; Blocks = 0; BlockIntrospection = 0; @@ -167,6 +170,7 @@ public: CharIsSigned = 1; ShortWChar = 0; CatchUndefined = 0; + DumpVtableLayouts = 0; } GCMode getGCMode() const { return (GCMode) GC; } diff --git a/include/clang/Basic/Linkage.h b/include/clang/Basic/Linkage.h new file mode 100644 index 000000000000..de0de348d351 --- /dev/null +++ b/include/clang/Basic/Linkage.h @@ -0,0 +1,57 @@ +//===--- Linkage.h - Linkage enumeration and utilities ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Linkage enumeration and various utility +// functions. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_LINKAGE_H +#define LLVM_CLANG_BASIC_LINKAGE_H + +namespace clang { + +/// \brief Describes the different kinds of linkage +/// (C++ [basic.link], C99 6.2.2) that an entity may have. +enum Linkage { + /// \brief No linkage, which means that the entity is unique and + /// can only be referred to from within its scope. + NoLinkage = 0, + + /// \brief Internal linkage, which indicates that the entity can + /// be referred to from within the translation unit (but not other + /// translation units). + InternalLinkage, + + /// \brief External linkage within a unique namespace. From the + /// langauge perspective, these entities have external + /// linkage. However, since they reside in an anonymous namespace, + /// their names are unique to this translation unit, which is + /// equivalent to having internal linkage from the code-generation + /// point of view. + UniqueExternalLinkage, + + /// \brief External linkage, which indicates that the entity can + /// be referred to from other translation units. + ExternalLinkage +}; + +/// \brief Determine whether the given linkage is semantically +/// external. +inline bool isExternalLinkage(Linkage L) { + return L == UniqueExternalLinkage || L == ExternalLinkage; +} + +/// \brief Compute the minimum linkage given two linages. +static inline Linkage minLinkage(Linkage L1, Linkage L2) { + return L1 < L2? L1 : L2; +} + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_LINKAGE_H diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h index 0d970123f745..873aaeecb6bf 100644 --- a/include/clang/Basic/PartialDiagnostic.h +++ b/include/clang/Basic/PartialDiagnostic.h @@ -1,4 +1,4 @@ -//===--- PartialDiagnostic.h - Diagnostic "closures" ----------------------===// +//===--- PartialDiagnostic.h - Diagnostic "closures" ------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index b4cf959dc551..15ece685104c 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -669,12 +669,20 @@ public: ::const_iterator fileinfo_iterator; fileinfo_iterator fileinfo_begin() const { return FileInfos.begin(); } fileinfo_iterator fileinfo_end() const { return FileInfos.end(); } + bool hasFileInfo(const FileEntry *File) const { + return FileInfos.find(File) != FileInfos.end(); + } /// PrintStats - Print statistics to stderr. /// void PrintStats() const; unsigned sloc_entry_size() const { return SLocEntryTable.size(); } + + // FIXME: Exposing this is a little gross; what we want is a good way + // to iterate the entries that were not defined in a PCH file (or + // any other external source). + unsigned sloc_loaded_entry_size() const { return SLocEntryLoaded.size(); } const SrcMgr::SLocEntry &getSLocEntry(unsigned ID) const { assert(ID < SLocEntryTable.size() && "Invalid id"); diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h index 4cace86dd18d..9e54762add7d 100644 --- a/include/clang/Basic/Specifiers.h +++ b/include/clang/Basic/Specifiers.h @@ -77,6 +77,7 @@ namespace clang { AS_private, AS_none }; -} + +} // end namespace clang #endif // LLVM_CLANG_BASIC_SPECIFIERS_H diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index 97e0495bfbe2..bc2cf198c3f5 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -226,11 +226,11 @@ public: /// isValidGCCRegisterName - Returns whether the passed in string /// is a valid register name according to GCC. This is used by Sema for /// inline asm statements. - bool isValidGCCRegisterName(const char *Name) const; + bool isValidGCCRegisterName(llvm::StringRef Name) const; // getNormalizedGCCRegisterName - Returns the "normalized" GCC register name. // For example, on x86 it will return "ax" when "eax" is passed in. - const char *getNormalizedGCCRegisterName(const char *Name) const; + llvm::StringRef getNormalizedGCCRegisterName(llvm::StringRef Name) const; struct ConstraintInfo { enum { @@ -246,10 +246,9 @@ public: std::string ConstraintStr; // constraint: "=rm" std::string Name; // Operand name: [foo] with no []'s. public: - ConstraintInfo(const char *str, unsigned strlen, const std::string &name) - : Flags(0), TiedOperand(-1), ConstraintStr(str, str+strlen), Name(name) {} - explicit ConstraintInfo(const std::string &Str, const std::string &name) - : Flags(0), TiedOperand(-1), ConstraintStr(Str), Name(name) {} + ConstraintInfo(llvm::StringRef ConstraintStr, llvm::StringRef Name) + : Flags(0), TiedOperand(-1), ConstraintStr(ConstraintStr.str()), + Name(Name.str()) {} const std::string &getConstraintStr() const { return ConstraintStr; } const std::string &getName() const { return Name; } @@ -321,12 +320,6 @@ public: virtual bool useGlobalsForAutomaticVariables() const { return false; } - /// getUnicodeStringSection - Return the section to use for unicode - /// string literals, or 0 if no special section is used. - virtual const char *getUnicodeStringSection() const { - return 0; - } - /// getCFStringSection - Return the section to use for CFString /// literals, or 0 if no special section is used. virtual const char *getCFStringSection() const { @@ -343,7 +336,7 @@ public: /// and give good diagnostics in cases when the assembler or code generator /// would otherwise reject the section specifier. /// - virtual std::string isValidSectionSpecifier(const llvm::StringRef &SR) const { + virtual std::string isValidSectionSpecifier(llvm::StringRef SR) const { return ""; } diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index bb022f11759d..522ac13b4e32 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -227,7 +227,7 @@ KEYWORD(__func__ , KEYALL) // C++ 2.11p1: Keywords. KEYWORD(asm , KEYCXX|KEYGNU) -KEYWORD(bool , BOOLSUPPORT) +KEYWORD(bool , BOOLSUPPORT|KEYALTIVEC) KEYWORD(catch , KEYCXX) KEYWORD(class , KEYCXX) KEYWORD(const_cast , KEYCXX) @@ -235,7 +235,7 @@ KEYWORD(delete , KEYCXX) KEYWORD(dynamic_cast , KEYCXX) KEYWORD(explicit , KEYCXX) KEYWORD(export , KEYCXX) -KEYWORD(false , BOOLSUPPORT) +KEYWORD(false , BOOLSUPPORT|KEYALTIVEC) KEYWORD(friend , KEYCXX) KEYWORD(mutable , KEYCXX) KEYWORD(namespace , KEYCXX) @@ -249,7 +249,7 @@ KEYWORD(static_cast , KEYCXX) KEYWORD(template , KEYCXX) KEYWORD(this , KEYCXX) KEYWORD(throw , KEYCXX) -KEYWORD(true , BOOLSUPPORT) +KEYWORD(true , BOOLSUPPORT|KEYALTIVEC) KEYWORD(try , KEYCXX) KEYWORD(typename , KEYCXX) KEYWORD(typeid , KEYCXX) @@ -340,6 +340,10 @@ KEYWORD(__ptr64 , KEYALL) KEYWORD(__w64 , KEYALL) KEYWORD(__forceinline , KEYALL) +// Altivec Extension. +KEYWORD(__vector , KEYALTIVEC) +KEYWORD(__pixel , KEYALTIVEC) + // Alternate spelling for various tokens. There are GCC extensions in all // languages, but should not be disabled in strict conformance mode. ALIAS("__attribute__", __attribute, KEYALL) diff --git a/include/clang/Basic/Version.h b/include/clang/Basic/Version.h index 4710b6b608e6..2728637ba497 100644 --- a/include/clang/Basic/Version.h +++ b/include/clang/Basic/Version.h @@ -56,16 +56,16 @@ namespace clang { /// \brief Retrieves the repository revision number (or identifer) from which /// this Clang was built. - llvm::StringRef getClangRevision(); + std::string getClangRevision(); /// \brief Retrieves the full repository version that is an amalgamation of /// the information in getClangRepositoryPath() and getClangRevision(). - llvm::StringRef getClangFullRepositoryVersion(); + std::string getClangFullRepositoryVersion(); /// \brief Retrieves a string representing the complete clang version, /// which includes the clang version number, the repository version, /// and the vendor tag. - const char *getClangFullVersion(); + std::string getClangFullVersion(); } #endif // LLVM_CLANG_BASIC_VERSION_H diff --git a/include/clang/Checker/BugReporter/BugReporter.h b/include/clang/Checker/BugReporter/BugReporter.h new file mode 100644 index 000000000000..6c41668ccece --- /dev/null +++ b/include/clang/Checker/BugReporter/BugReporter.h @@ -0,0 +1,477 @@ +//===--- BugReporter.h - Generate PathDiagnostics --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines BugReporter, a utility class for generating +// PathDiagnostics for analyses based on GRState. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_BUGREPORTER +#define LLVM_CLANG_ANALYSIS_BUGREPORTER + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Checker/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/ExplodedGraph.h" +#include "clang/Checker/BugReporter/BugType.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/ImmutableSet.h" +#include + +namespace clang { + +class PathDiagnostic; +class PathDiagnosticPiece; +class PathDiagnosticClient; +class ASTContext; +class Diagnostic; +class BugReporter; +class BugReporterContext; +class GRExprEngine; +class GRState; +class Stmt; +class BugType; +class ParentMap; + +//===----------------------------------------------------------------------===// +// Interface for individual bug reports. +//===----------------------------------------------------------------------===// + +class BugReporterVisitor { +public: + virtual ~BugReporterVisitor(); + virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N, + const ExplodedNode* PrevN, + BugReporterContext& BRC) = 0; + + virtual bool isOwnedByReporterContext() { return true; } +}; + +// FIXME: Combine this with RangedBugReport and remove RangedBugReport. +class BugReport : public BugReporterVisitor { +protected: + BugType& BT; + std::string ShortDescription; + std::string Description; + const ExplodedNode *EndNode; + SourceRange R; + +protected: + friend class BugReporter; + friend class BugReportEquivClass; + + virtual void Profile(llvm::FoldingSetNodeID& hash) const { + hash.AddInteger(getLocation().getRawEncoding()); + } + +public: + class NodeResolver { + public: + virtual ~NodeResolver() {} + virtual const ExplodedNode* + getOriginalNode(const ExplodedNode* N) = 0; + }; + + BugReport(BugType& bt, llvm::StringRef desc, const ExplodedNode *n) + : BT(bt), Description(desc), EndNode(n) {} + + BugReport(BugType& bt, llvm::StringRef shortDesc, llvm::StringRef desc, + const ExplodedNode *n) + : BT(bt), ShortDescription(shortDesc), Description(desc), EndNode(n) {} + + virtual ~BugReport(); + + virtual bool isOwnedByReporterContext() { return false; } + + const BugType& getBugType() const { return BT; } + BugType& getBugType() { return BT; } + + // FIXME: Perhaps this should be moved into a subclass? + const ExplodedNode* getEndNode() const { return EndNode; } + + // FIXME: Do we need this? Maybe getLocation() should return a ProgramPoint + // object. + // FIXME: If we do need it, we can probably just make it private to + // BugReporter. + const Stmt* getStmt() const; + + const llvm::StringRef getDescription() const { return Description; } + + const llvm::StringRef getShortDescription() const { + return ShortDescription.empty() ? Description : ShortDescription; + } + + // FIXME: Is this needed? + virtual std::pair getExtraDescriptiveText() { + return std::make_pair((const char**)0,(const char**)0); + } + + // FIXME: Perhaps move this into a subclass. + virtual PathDiagnosticPiece* getEndPath(BugReporterContext& BRC, + const ExplodedNode* N); + + /// getLocation - Return the "definitive" location of the reported bug. + /// While a bug can span an entire path, usually there is a specific + /// location that can be used to identify where the key issue occured. + /// This location is used by clients rendering diagnostics. + virtual SourceLocation getLocation() const; + + /// getRanges - Returns the source ranges associated with this bug. + virtual void getRanges(const SourceRange*& beg, const SourceRange*& end); + + virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N, + const ExplodedNode* PrevN, + BugReporterContext& BR); + + virtual void registerInitialVisitors(BugReporterContext& BRC, + const ExplodedNode* N) {} +}; + +//===----------------------------------------------------------------------===// +// BugTypes (collections of related reports). +//===----------------------------------------------------------------------===// + +class BugReportEquivClass : public llvm::FoldingSetNode { + // List of *owned* BugReport objects. + std::list Reports; + + friend class BugReporter; + void AddReport(BugReport* R) { Reports.push_back(R); } +public: + BugReportEquivClass(BugReport* R) { Reports.push_back(R); } + ~BugReportEquivClass(); + + void Profile(llvm::FoldingSetNodeID& ID) const { + assert(!Reports.empty()); + (*Reports.begin())->Profile(ID); + } + + class iterator { + std::list::iterator impl; + public: + iterator(std::list::iterator i) : impl(i) {} + iterator& operator++() { ++impl; return *this; } + bool operator==(const iterator& I) const { return I.impl == impl; } + bool operator!=(const iterator& I) const { return I.impl != impl; } + BugReport* operator*() const { return *impl; } + BugReport* operator->() const { return *impl; } + }; + + class const_iterator { + std::list::const_iterator impl; + public: + const_iterator(std::list::const_iterator i) : impl(i) {} + const_iterator& operator++() { ++impl; return *this; } + bool operator==(const const_iterator& I) const { return I.impl == impl; } + bool operator!=(const const_iterator& I) const { return I.impl != impl; } + const BugReport* operator*() const { return *impl; } + const BugReport* operator->() const { return *impl; } + }; + + iterator begin() { return iterator(Reports.begin()); } + iterator end() { return iterator(Reports.end()); } + + const_iterator begin() const { return const_iterator(Reports.begin()); } + const_iterator end() const { return const_iterator(Reports.end()); } +}; + + +//===----------------------------------------------------------------------===// +// Specialized subclasses of BugReport. +//===----------------------------------------------------------------------===// + +// FIXME: Collapse this with the default BugReport class. +class RangedBugReport : public BugReport { + std::vector Ranges; +public: + RangedBugReport(BugType& D, llvm::StringRef description, ExplodedNode *n) + : BugReport(D, description, n) {} + + RangedBugReport(BugType& D, llvm::StringRef shortDescription, + llvm::StringRef description, ExplodedNode *n) + : BugReport(D, shortDescription, description, n) {} + + ~RangedBugReport(); + + // FIXME: Move this out of line. + void addRange(SourceRange R) { + assert(R.isValid()); + Ranges.push_back(R); + } + + // FIXME: Move this out of line. + void getRanges(const SourceRange*& beg, const SourceRange*& end) { + + if (Ranges.empty()) { + beg = NULL; + end = NULL; + } + else { + beg = &Ranges[0]; + end = beg + Ranges.size(); + } + } +}; + +class EnhancedBugReport : public RangedBugReport { +public: + typedef void (*VisitorCreator)(BugReporterContext &BRcC, const void *data, + const ExplodedNode *N); + +private: + typedef std::vector > Creators; + Creators creators; + +public: + EnhancedBugReport(BugType& D, llvm::StringRef description, ExplodedNode *n) + : RangedBugReport(D, description, n) {} + + EnhancedBugReport(BugType& D, llvm::StringRef shortDescription, + llvm::StringRef description, ExplodedNode *n) + : RangedBugReport(D, shortDescription, description, n) {} + + ~EnhancedBugReport() {} + + void registerInitialVisitors(BugReporterContext& BRC, const ExplodedNode* N) { + for (Creators::iterator I = creators.begin(), E = creators.end(); I!=E; ++I) + I->first(BRC, I->second, N); + } + + void addVisitorCreator(VisitorCreator creator, const void *data) { + creators.push_back(std::make_pair(creator, data)); + } +}; + +//===----------------------------------------------------------------------===// +// BugReporter and friends. +//===----------------------------------------------------------------------===// + +class BugReporterData { +public: + virtual ~BugReporterData(); + virtual Diagnostic& getDiagnostic() = 0; + virtual PathDiagnosticClient* getPathDiagnosticClient() = 0; + virtual ASTContext& getASTContext() = 0; + virtual SourceManager& getSourceManager() = 0; +}; + +class BugReporter { +public: + enum Kind { BaseBRKind, GRBugReporterKind }; + +private: + typedef llvm::ImmutableSet BugTypesTy; + BugTypesTy::Factory F; + BugTypesTy BugTypes; + + const Kind kind; + BugReporterData& D; + + void FlushReport(BugReportEquivClass& EQ); + +protected: + BugReporter(BugReporterData& d, Kind k) : BugTypes(F.GetEmptySet()), kind(k), D(d) {} + +public: + BugReporter(BugReporterData& d) : BugTypes(F.GetEmptySet()), kind(BaseBRKind), D(d) {} + virtual ~BugReporter(); + + void FlushReports(); + + Kind getKind() const { return kind; } + + Diagnostic& getDiagnostic() { + return D.getDiagnostic(); + } + + PathDiagnosticClient* getPathDiagnosticClient() { + return D.getPathDiagnosticClient(); + } + + typedef BugTypesTy::iterator iterator; + iterator begin() { return BugTypes.begin(); } + iterator end() { return BugTypes.end(); } + + ASTContext& getContext() { return D.getASTContext(); } + + SourceManager& getSourceManager() { return D.getSourceManager(); } + + virtual void GeneratePathDiagnostic(PathDiagnostic& PD, + BugReportEquivClass& EQ) {} + + void Register(BugType *BT); + + void EmitReport(BugReport *R); + + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr, + SourceLocation Loc, + SourceRange* RangeBeg, unsigned NumRanges); + + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory, + llvm::StringRef BugStr, SourceLocation Loc, + SourceRange* RangeBeg, unsigned NumRanges); + + + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr, + SourceLocation Loc) { + EmitBasicReport(BugName, BugStr, Loc, 0, 0); + } + + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory, + llvm::StringRef BugStr, SourceLocation Loc) { + EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0); + } + + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr, + SourceLocation Loc, SourceRange R) { + EmitBasicReport(BugName, BugStr, Loc, &R, 1); + } + + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef Category, + llvm::StringRef BugStr, SourceLocation Loc, + SourceRange R) { + EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1); + } + + static bool classof(const BugReporter* R) { return true; } +}; + +// FIXME: Get rid of GRBugReporter. It's the wrong abstraction. +class GRBugReporter : public BugReporter { + GRExprEngine& Eng; + llvm::SmallSet NotableSymbols; +public: + GRBugReporter(BugReporterData& d, GRExprEngine& eng) + : BugReporter(d, GRBugReporterKind), Eng(eng) {} + + virtual ~GRBugReporter(); + + /// getEngine - Return the analysis engine used to analyze a given + /// function or method. + GRExprEngine &getEngine() { return Eng; } + + /// getGraph - Get the exploded graph created by the analysis engine + /// for the analyzed method or function. + ExplodedGraph &getGraph(); + + /// getStateManager - Return the state manager used by the analysis + /// engine. + GRStateManager &getStateManager(); + + virtual void GeneratePathDiagnostic(PathDiagnostic& PD, + BugReportEquivClass& R); + + void addNotableSymbol(SymbolRef Sym) { + NotableSymbols.insert(Sym); + } + + bool isNotable(SymbolRef Sym) const { + return (bool) NotableSymbols.count(Sym); + } + + /// classof - Used by isa<>, cast<>, and dyn_cast<>. + static bool classof(const BugReporter* R) { + return R->getKind() == GRBugReporterKind; + } +}; + +class BugReporterContext { + GRBugReporter &BR; + std::vector Callbacks; +public: + BugReporterContext(GRBugReporter& br) : BR(br) {} + virtual ~BugReporterContext(); + + void addVisitor(BugReporterVisitor* visitor) { + if (visitor) Callbacks.push_back(visitor); + } + + typedef std::vector::iterator visitor_iterator; + visitor_iterator visitor_begin() { return Callbacks.begin(); } + visitor_iterator visitor_end() { return Callbacks.end(); } + + GRBugReporter& getBugReporter() { return BR; } + + ExplodedGraph &getGraph() { return BR.getGraph(); } + + void addNotableSymbol(SymbolRef Sym) { + // FIXME: For now forward to GRBugReporter. + BR.addNotableSymbol(Sym); + } + + bool isNotable(SymbolRef Sym) const { + // FIXME: For now forward to GRBugReporter. + return BR.isNotable(Sym); + } + + GRStateManager& getStateManager() { + return BR.getStateManager(); + } + + ValueManager& getValueManager() { + return getStateManager().getValueManager(); + } + + ASTContext& getASTContext() { + return BR.getContext(); + } + + SourceManager& getSourceManager() { + return BR.getSourceManager(); + } + + virtual BugReport::NodeResolver& getNodeResolver() = 0; +}; + +class DiagBugReport : public RangedBugReport { + std::list Strs; + FullSourceLoc L; +public: + DiagBugReport(BugType& D, llvm::StringRef desc, FullSourceLoc l) : + RangedBugReport(D, desc, 0), L(l) {} + + virtual ~DiagBugReport() {} + + // FIXME: Move out-of-line (virtual function). + SourceLocation getLocation() const { return L; } + + void addString(llvm::StringRef s) { Strs.push_back(s); } + + typedef std::list::const_iterator str_iterator; + str_iterator str_begin() const { return Strs.begin(); } + str_iterator str_end() const { return Strs.end(); } +}; + +//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// + +namespace bugreporter { + +const Stmt *GetDerefExpr(const ExplodedNode *N); +const Stmt *GetReceiverExpr(const ExplodedNode *N); +const Stmt *GetDenomExpr(const ExplodedNode *N); +const Stmt *GetCalleeExpr(const ExplodedNode *N); +const Stmt *GetRetValExpr(const ExplodedNode *N); + +void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt, + const ExplodedNode* N); + +void registerFindLastStore(BugReporterContext& BRC, const void *memregion, + const ExplodedNode *N); + + +} // end namespace clang::bugreporter + +//===----------------------------------------------------------------------===// + +} // end clang namespace + +#endif diff --git a/include/clang/Checker/BugReporter/BugType.h b/include/clang/Checker/BugReporter/BugType.h new file mode 100644 index 000000000000..4f1523a5440d --- /dev/null +++ b/include/clang/Checker/BugReporter/BugType.h @@ -0,0 +1,75 @@ +//===--- BugType.h - Bug Information Desciption ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines BugType, a class representing a bug type. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE +#define LLVM_CLANG_ANALYSIS_BUGTYPE + +#include +#include + +namespace clang { + +class BugReportEquivClass; +class BugReporter; +class BuiltinBugReport; +class BugReporterContext; +class ExplodedNode; +class GRExprEngine; + +class BugType { +private: + const std::string Name; + const std::string Category; + llvm::FoldingSet EQClasses; + friend class BugReporter; + bool SuppressonSink; +public: + BugType(llvm::StringRef name, llvm::StringRef cat) + : Name(name), Category(cat), SuppressonSink(false) {} + virtual ~BugType(); + + // FIXME: Should these be made strings as well? + llvm::StringRef getName() const { return Name; } + llvm::StringRef getCategory() const { return Category; } + + /// isSuppressOnSink - Returns true if bug reports associated with this bug + /// type should be suppressed if the end node of the report is post-dominated + /// by a sink node. + bool isSuppressOnSink() const { return SuppressonSink; } + void setSuppressOnSink(bool x) { SuppressonSink = x; } + + virtual void FlushReports(BugReporter& BR); + + typedef llvm::FoldingSet::iterator iterator; + iterator begin() { return EQClasses.begin(); } + iterator end() { return EQClasses.end(); } + + typedef llvm::FoldingSet::const_iterator const_iterator; + const_iterator begin() const { return EQClasses.begin(); } + const_iterator end() const { return EQClasses.end(); } +}; + +class BuiltinBug : public BugType { + const std::string desc; +public: + BuiltinBug(const char *name, const char *description) + : BugType(name, "Logic error"), desc(description) {} + + BuiltinBug(const char *name) + : BugType(name, "Logic error"), desc(name) {} + + llvm::StringRef getDescription() const { return desc; } +}; + +} // end clang namespace +#endif diff --git a/include/clang/Checker/BugReporter/PathDiagnostic.h b/include/clang/Checker/BugReporter/PathDiagnostic.h new file mode 100644 index 000000000000..d380c45480cb --- /dev/null +++ b/include/clang/Checker/BugReporter/PathDiagnostic.h @@ -0,0 +1,494 @@ +//===--- PathDiagnostic.h - Path-Specific Diagnostic Handling ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PathDiagnostic-related interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H +#define LLVM_CLANG_PATH_DIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/FoldingSet.h" +#include +#include +#include +#include + +namespace clang { + +class Decl; +class SourceManager; +class Stmt; + +//===----------------------------------------------------------------------===// +// High-level interface for handlers of path-sensitive diagnostics. +//===----------------------------------------------------------------------===// + +class PathDiagnostic; + +class PathDiagnosticClient : public DiagnosticClient { +public: + PathDiagnosticClient() {} + + virtual ~PathDiagnosticClient() {} + + virtual void + FlushDiagnostics(llvm::SmallVectorImpl *FilesMade = 0) = 0; + + void FlushDiagnostics(llvm::SmallVectorImpl &FilesMade) { + FlushDiagnostics(&FilesMade); + } + + virtual llvm::StringRef getName() const = 0; + + virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, + const DiagnosticInfo &Info); + virtual void HandlePathDiagnostic(const PathDiagnostic* D) = 0; + + enum PathGenerationScheme { Minimal, Extensive }; + virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } + virtual bool supportsLogicalOpControlFlow() const { return false; } + virtual bool supportsAllBlockEdges() const { return false; } + virtual bool useVerboseDescription() const { return true; } +}; + +//===----------------------------------------------------------------------===// +// Path-sensitive diagnostics. +//===----------------------------------------------------------------------===// + +class PathDiagnosticRange : public SourceRange { +public: + const bool isPoint; + + PathDiagnosticRange(const SourceRange &R, bool isP = false) + : SourceRange(R), isPoint(isP) {} +}; + +class PathDiagnosticLocation { +private: + enum Kind { RangeK, SingleLocK, StmtK, DeclK } K; + SourceRange R; + const Stmt *S; + const Decl *D; + const SourceManager *SM; +public: + PathDiagnosticLocation() + : K(SingleLocK), S(0), D(0), SM(0) {} + + PathDiagnosticLocation(FullSourceLoc L) + : K(SingleLocK), R(L, L), S(0), D(0), SM(&L.getManager()) {} + + PathDiagnosticLocation(const Stmt *s, const SourceManager &sm) + : K(StmtK), S(s), D(0), SM(&sm) {} + + PathDiagnosticLocation(SourceRange r, const SourceManager &sm) + : K(RangeK), R(r), S(0), D(0), SM(&sm) {} + + PathDiagnosticLocation(const Decl *d, const SourceManager &sm) + : K(DeclK), S(0), D(d), SM(&sm) {} + + bool operator==(const PathDiagnosticLocation &X) const { + return K == X.K && R == X.R && S == X.S && D == X.D; + } + + bool operator!=(const PathDiagnosticLocation &X) const { + return K != X.K || R != X.R || S != X.S || D != X.D;; + } + + PathDiagnosticLocation& operator=(const PathDiagnosticLocation &X) { + K = X.K; + R = X.R; + S = X.S; + D = X.D; + SM = X.SM; + return *this; + } + + bool isValid() const { + return SM != 0; + } + + const SourceManager& getSourceManager() const { assert(isValid());return *SM;} + + FullSourceLoc asLocation() const; + PathDiagnosticRange asRange() const; + const Stmt *asStmt() const { assert(isValid()); return S; } + const Decl *asDecl() const { assert(isValid()); return D; } + + bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; } + + void invalidate() { + *this = PathDiagnosticLocation(); + } + + void flatten(); + + const SourceManager& getManager() const { assert(isValid()); return *SM; } + + void Profile(llvm::FoldingSetNodeID &ID) const; +}; + +class PathDiagnosticLocationPair { +private: + PathDiagnosticLocation Start, End; +public: + PathDiagnosticLocationPair(const PathDiagnosticLocation &start, + const PathDiagnosticLocation &end) + : Start(start), End(end) {} + + const PathDiagnosticLocation &getStart() const { return Start; } + const PathDiagnosticLocation &getEnd() const { return End; } + + void flatten() { + Start.flatten(); + End.flatten(); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + Start.Profile(ID); + End.Profile(ID); + } +}; + +//===----------------------------------------------------------------------===// +// Path "pieces" for path-sensitive diagnostics. +//===----------------------------------------------------------------------===// + +class PathDiagnosticPiece { +public: + enum Kind { ControlFlow, Event, Macro }; + enum DisplayHint { Above, Below }; + +private: + const std::string str; + std::vector CodeModificationHints; + const Kind kind; + const DisplayHint Hint; + std::vector ranges; + + // Do not implement: + PathDiagnosticPiece(); + PathDiagnosticPiece(const PathDiagnosticPiece &P); + PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P); + +protected: + PathDiagnosticPiece(llvm::StringRef s, Kind k, DisplayHint hint = Below); + + PathDiagnosticPiece(Kind k, DisplayHint hint = Below); + +public: + virtual ~PathDiagnosticPiece(); + + const std::string& getString() const { return str; } + + /// getDisplayHint - Return a hint indicating where the diagnostic should + /// be displayed by the PathDiagnosticClient. + DisplayHint getDisplayHint() const { return Hint; } + + virtual PathDiagnosticLocation getLocation() const = 0; + virtual void flattenLocations() = 0; + + Kind getKind() const { return kind; } + + void addRange(SourceRange R) { ranges.push_back(R); } + + void addRange(SourceLocation B, SourceLocation E) { + ranges.push_back(SourceRange(B,E)); + } + + void addCodeModificationHint(const CodeModificationHint& Hint) { + CodeModificationHints.push_back(Hint); + } + + typedef const SourceRange* range_iterator; + + range_iterator ranges_begin() const { + return ranges.empty() ? NULL : &ranges[0]; + } + + range_iterator ranges_end() const { + return ranges_begin() + ranges.size(); + } + + typedef const CodeModificationHint *code_modifications_iterator; + + code_modifications_iterator code_modifications_begin() const { + return CodeModificationHints.empty()? 0 : &CodeModificationHints[0]; + } + + code_modifications_iterator code_modifications_end() const { + return CodeModificationHints.empty()? 0 + : &CodeModificationHints[0] + CodeModificationHints.size(); + } + + static inline bool classof(const PathDiagnosticPiece* P) { + return true; + } + + virtual void Profile(llvm::FoldingSetNodeID &ID) const; +}; + +class PathDiagnosticSpotPiece : public PathDiagnosticPiece { +private: + PathDiagnosticLocation Pos; +public: + PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos, + llvm::StringRef s, + PathDiagnosticPiece::Kind k, + bool addPosRange = true) + : PathDiagnosticPiece(s, k), Pos(pos) { + assert(Pos.asLocation().isValid() && + "PathDiagnosticSpotPiece's must have a valid location."); + if (addPosRange && Pos.hasRange()) addRange(Pos.asRange()); + } + + PathDiagnosticLocation getLocation() const { return Pos; } + virtual void flattenLocations() { Pos.flatten(); } + + virtual void Profile(llvm::FoldingSetNodeID &ID) const; +}; + +class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { + +public: + PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, + llvm::StringRef s, bool addPosRange = true) + : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {} + + ~PathDiagnosticEventPiece(); + + static inline bool classof(const PathDiagnosticPiece* P) { + return P->getKind() == Event; + } +}; + +class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece { + std::vector LPairs; +public: + PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, + const PathDiagnosticLocation &endPos, + llvm::StringRef s) + : PathDiagnosticPiece(s, ControlFlow) { + LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); + } + + PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, + const PathDiagnosticLocation &endPos) + : PathDiagnosticPiece(ControlFlow) { + LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); + } + + ~PathDiagnosticControlFlowPiece(); + + PathDiagnosticLocation getStartLocation() const { + assert(!LPairs.empty() && + "PathDiagnosticControlFlowPiece needs at least one location."); + return LPairs[0].getStart(); + } + + PathDiagnosticLocation getEndLocation() const { + assert(!LPairs.empty() && + "PathDiagnosticControlFlowPiece needs at least one location."); + return LPairs[0].getEnd(); + } + + void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); } + + virtual PathDiagnosticLocation getLocation() const { + return getStartLocation(); + } + + typedef std::vector::iterator iterator; + iterator begin() { return LPairs.begin(); } + iterator end() { return LPairs.end(); } + + virtual void flattenLocations() { + for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten(); + } + + typedef std::vector::const_iterator + const_iterator; + const_iterator begin() const { return LPairs.begin(); } + const_iterator end() const { return LPairs.end(); } + + static inline bool classof(const PathDiagnosticPiece* P) { + return P->getKind() == ControlFlow; + } + + virtual void Profile(llvm::FoldingSetNodeID &ID) const; +}; + +class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece { + std::vector SubPieces; +public: + PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos) + : PathDiagnosticSpotPiece(pos, "", Macro) {} + + ~PathDiagnosticMacroPiece(); + + bool containsEvent() const; + + void push_back(PathDiagnosticPiece* P) { SubPieces.push_back(P); } + + typedef std::vector::iterator iterator; + iterator begin() { return SubPieces.begin(); } + iterator end() { return SubPieces.end(); } + + virtual void flattenLocations() { + PathDiagnosticSpotPiece::flattenLocations(); + for (iterator I=begin(), E=end(); I!=E; ++I) (*I)->flattenLocations(); + } + + typedef std::vector::const_iterator const_iterator; + const_iterator begin() const { return SubPieces.begin(); } + const_iterator end() const { return SubPieces.end(); } + + static inline bool classof(const PathDiagnosticPiece* P) { + return P->getKind() == Macro; + } + + virtual void Profile(llvm::FoldingSetNodeID &ID) const; +}; + +/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive +/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces, +/// each which represent the pieces of the path. +class PathDiagnostic : public llvm::FoldingSetNode { + std::deque path; + unsigned Size; + std::string BugType; + std::string Desc; + std::string Category; + std::deque OtherDesc; + +public: + PathDiagnostic(); + + PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc, + llvm::StringRef category); + + ~PathDiagnostic(); + + llvm::StringRef getDescription() const { return Desc; } + llvm::StringRef getBugType() const { return BugType; } + llvm::StringRef getCategory() const { return Category; } + + typedef std::deque::const_iterator meta_iterator; + meta_iterator meta_begin() const { return OtherDesc.begin(); } + meta_iterator meta_end() const { return OtherDesc.end(); } + void addMeta(llvm::StringRef s) { OtherDesc.push_back(s); } + + PathDiagnosticLocation getLocation() const { + assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic."); + return rbegin()->getLocation(); + } + + void push_front(PathDiagnosticPiece* piece) { + assert(piece); + path.push_front(piece); + ++Size; + } + + void push_back(PathDiagnosticPiece* piece) { + assert(piece); + path.push_back(piece); + ++Size; + } + + PathDiagnosticPiece* back() { + return path.back(); + } + + const PathDiagnosticPiece* back() const { + return path.back(); + } + + unsigned size() const { return Size; } + bool empty() const { return Size == 0; } + + void resetPath(bool deletePieces = true); + + class iterator { + public: + typedef std::deque::iterator ImplTy; + + typedef PathDiagnosticPiece value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + private: + ImplTy I; + + public: + iterator(const ImplTy& i) : I(i) {} + + bool operator==(const iterator& X) const { return I == X.I; } + bool operator!=(const iterator& X) const { return I != X.I; } + + PathDiagnosticPiece& operator*() const { return **I; } + PathDiagnosticPiece* operator->() const { return *I; } + + iterator& operator++() { ++I; return *this; } + iterator& operator--() { --I; return *this; } + }; + + class const_iterator { + public: + typedef std::deque::const_iterator ImplTy; + + typedef const PathDiagnosticPiece value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + private: + ImplTy I; + + public: + const_iterator(const ImplTy& i) : I(i) {} + + bool operator==(const const_iterator& X) const { return I == X.I; } + bool operator!=(const const_iterator& X) const { return I != X.I; } + + reference operator*() const { return **I; } + pointer operator->() const { return *I; } + + const_iterator& operator++() { ++I; return *this; } + const_iterator& operator--() { --I; return *this; } + }; + + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + // forward iterator creation methods. + + iterator begin() { return path.begin(); } + iterator end() { return path.end(); } + + const_iterator begin() const { return path.begin(); } + const_iterator end() const { return path.end(); } + + // reverse iterator creation methods. + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin());} + + void flattenLocations() { + for (iterator I = begin(), E = end(); I != E; ++I) I->flattenLocations(); + } + + void Profile(llvm::FoldingSetNodeID &ID) const; +}; +} //end clang namespace +#endif diff --git a/include/clang/Checker/Checkers/DereferenceChecker.h b/include/clang/Checker/Checkers/DereferenceChecker.h new file mode 100644 index 000000000000..a84183e7f27f --- /dev/null +++ b/include/clang/Checker/Checkers/DereferenceChecker.h @@ -0,0 +1,31 @@ +//== NullDerefChecker.h - Null dereference checker --------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines NullDerefChecker and UndefDerefChecker, two builtin checks +// in GRExprEngine that check for null and undefined pointers at loads +// and stores. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DEREFCHECKER +#define LLVM_CLANG_DEREFCHECKER + +#include + +namespace clang { + +class GRExprEngine; +class ExplodedNode; + +std::pair +GetImplicitNullDereferences(GRExprEngine &Eng); + +} // end clang namespace + +#endif diff --git a/include/clang/Checker/Checkers/LocalCheckers.h b/include/clang/Checker/Checkers/LocalCheckers.h new file mode 100644 index 000000000000..4a9e381a7c15 --- /dev/null +++ b/include/clang/Checker/Checkers/LocalCheckers.h @@ -0,0 +1,61 @@ +//==- LocalCheckers.h - Intra-Procedural+Flow-Sensitive Checkers -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface to call a set of intra-procedural (local) +// checkers that use flow/path-sensitive analyses to find bugs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_LOCALCHECKERS_H +#define LLVM_CLANG_ANALYSIS_LOCALCHECKERS_H + +namespace clang { + +class CFG; +class Decl; +class Diagnostic; +class ASTContext; +class PathDiagnosticClient; +class GRTransferFuncs; +class BugType; +class LangOptions; +class ParentMap; +class LiveVariables; +class BugReporter; +class ObjCImplementationDecl; +class LangOptions; +class GRExprEngine; +class TranslationUnitDecl; + +void CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &map, + BugReporter& BR); + +GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, + const LangOptions& lopts); + +void CheckObjCDealloc(const ObjCImplementationDecl* D, const LangOptions& L, + BugReporter& BR); + +void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID, + BugReporter& BR); + +void CheckObjCUnusedIvar(const ObjCImplementationDecl *D, BugReporter& BR); + +void RegisterAppleChecks(GRExprEngine& Eng, const Decl &D); +void RegisterExperimentalChecks(GRExprEngine &Eng); +void RegisterExperimentalInternalChecks(GRExprEngine &Eng); + +void CheckLLVMConventions(TranslationUnitDecl &TU, BugReporter &BR); +void CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR); +void CheckSizeofPointer(const Decl *D, BugReporter &BR); + +void RegisterCallInliner(GRExprEngine &Eng); +} // end namespace clang + +#endif diff --git a/include/clang/Checker/DomainSpecific/CocoaConventions.h b/include/clang/Checker/DomainSpecific/CocoaConventions.h new file mode 100644 index 000000000000..ee3d648b8608 --- /dev/null +++ b/include/clang/Checker/DomainSpecific/CocoaConventions.h @@ -0,0 +1,40 @@ +//===- CocoaConventions.h - Special handling of Cocoa conventions -*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CHECKER_DS_COCOA +#define LLVM_CLANG_CHECKER_DS_COCOA + +#include "clang/Basic/IdentifierTable.h" +#include "clang/AST/Type.h" + +namespace clang { +namespace cocoa { + + enum NamingConvention { NoConvention, CreateRule, InitRule }; + + NamingConvention deriveNamingConvention(Selector S); + + static inline bool followsFundamentalRule(Selector S) { + return deriveNamingConvention(S) == CreateRule; + } + + bool isRefType(QualType RetTy, llvm::StringRef Prefix, + llvm::StringRef Name = llvm::StringRef()); + + bool isCFObjectRef(QualType T); + + bool isCocoaObjectRef(QualType T); + +}} + +#endif diff --git a/include/clang/Checker/ManagerRegistry.h b/include/clang/Checker/ManagerRegistry.h new file mode 100644 index 000000000000..ebfd28e10930 --- /dev/null +++ b/include/clang/Checker/ManagerRegistry.h @@ -0,0 +1,53 @@ +//===-- ManagerRegistry.h - Pluggable analyzer module registry --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ManagerRegistry and Register* classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_MANAGER_REGISTRY_H +#define LLVM_CLANG_ANALYSIS_MANAGER_REGISTRY_H + +#include "clang/Checker/PathSensitive/GRState.h" + +namespace clang { + +/// ManagerRegistry - This class records manager creators registered at +/// runtime. The information is communicated to AnalysisManager through static +/// members. Better design is expected. + +class ManagerRegistry { +public: + static StoreManagerCreator StoreMgrCreator; + static ConstraintManagerCreator ConstraintMgrCreator; +}; + +/// RegisterConstraintManager - This class is used to setup the constraint +/// manager of the static analyzer. The constructor takes a creator function +/// pointer for creating the constraint manager. +/// +/// It is used like this: +/// +/// class MyConstraintManager {}; +/// ConstraintManager* CreateMyConstraintManager(GRStateManager& statemgr) { +/// return new MyConstraintManager(statemgr); +/// } +/// RegisterConstraintManager X(CreateMyConstraintManager); + +class RegisterConstraintManager { +public: + RegisterConstraintManager(ConstraintManagerCreator CMC) { + assert(ManagerRegistry::ConstraintMgrCreator == 0 + && "ConstraintMgrCreator already set!"); + ManagerRegistry::ConstraintMgrCreator = CMC; + } +}; + +} +#endif diff --git a/include/clang/Checker/PathSensitive/AnalysisManager.h b/include/clang/Checker/PathSensitive/AnalysisManager.h new file mode 100644 index 000000000000..fdf52a7dc770 --- /dev/null +++ b/include/clang/Checker/PathSensitive/AnalysisManager.h @@ -0,0 +1,149 @@ +//== AnalysisManager.h - Path sensitive analysis data manager ------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the AnalysisManager class that manages the data and policy +// for path sensitive analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSISMANAGER_H +#define LLVM_CLANG_ANALYSIS_ANALYSISMANAGER_H + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/PathDiagnostic.h" + +namespace clang { + +class AnalysisManager : public BugReporterData { + AnalysisContextManager AnaCtxMgr; + LocationContextManager LocCtxMgr; + + ASTContext &Ctx; + Diagnostic &Diags; + const LangOptions &LangInfo; + + llvm::OwningPtr PD; + + // Configurable components creators. + StoreManagerCreator CreateStoreMgr; + ConstraintManagerCreator CreateConstraintMgr; + + enum AnalysisScope { ScopeTU, ScopeDecl } AScope; + + bool VisualizeEGDot; + bool VisualizeEGUbi; + bool PurgeDead; + + /// EargerlyAssume - A flag indicating how the engine should handle + // expressions such as: 'x = (y != 0)'. When this flag is true then + // the subexpression 'y != 0' will be eagerly assumed to be true or false, + // thus evaluating it to the integers 0 or 1 respectively. The upside + // is that this can increase analysis precision until we have a better way + // to lazily evaluate such logic. The downside is that it eagerly + // bifurcates paths. + bool EagerlyAssume; + bool TrimGraph; + +public: + AnalysisManager(ASTContext &ctx, Diagnostic &diags, + const LangOptions &lang, PathDiagnosticClient *pd, + StoreManagerCreator storemgr, + ConstraintManagerCreator constraintmgr, + bool vizdot, bool vizubi, bool purge, bool eager, bool trim) + + : Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd), + CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), + AScope(ScopeDecl), + VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge), + EagerlyAssume(eager), TrimGraph(trim) {} + + ~AnalysisManager() { FlushDiagnostics(); } + + void ClearContexts() { + LocCtxMgr.clear(); + AnaCtxMgr.clear(); + } + + StoreManagerCreator getStoreManagerCreator() { + return CreateStoreMgr; + } + + ConstraintManagerCreator getConstraintManagerCreator() { + return CreateConstraintMgr; + } + + virtual ASTContext &getASTContext() { + return Ctx; + } + + virtual SourceManager &getSourceManager() { + return getASTContext().getSourceManager(); + } + + virtual Diagnostic &getDiagnostic() { + return Diags; + } + + const LangOptions &getLangOptions() const { + return LangInfo; + } + + virtual PathDiagnosticClient *getPathDiagnosticClient() { + return PD.get(); + } + + void FlushDiagnostics() { + if (PD.get()) + PD->FlushDiagnostics(); + } + + bool shouldVisualizeGraphviz() const { return VisualizeEGDot; } + + bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; } + + bool shouldVisualize() const { + return VisualizeEGDot || VisualizeEGUbi; + } + + bool shouldTrimGraph() const { return TrimGraph; } + + bool shouldPurgeDead() const { return PurgeDead; } + + bool shouldEagerlyAssume() const { return EagerlyAssume; } + + CFG *getCFG(Decl const *D) { + return AnaCtxMgr.getContext(D)->getCFG(); + } + + LiveVariables *getLiveVariables(Decl const *D) { + return AnaCtxMgr.getContext(D)->getLiveVariables(); + } + + ParentMap &getParentMap(Decl const *D) { + return AnaCtxMgr.getContext(D)->getParentMap(); + } + + // Get the top level stack frame. + const StackFrameContext *getStackFrame(Decl const *D) { + return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), 0, 0, 0, 0); + } + + // Get a stack frame with parent. + StackFrameContext const *getStackFrame(Decl const *D, + LocationContext const *Parent, + Stmt const *S, const CFGBlock *Blk, + unsigned Idx) { + return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), Parent, S, Blk,Idx); + } +}; + +} + +#endif diff --git a/include/clang/Checker/PathSensitive/BasicValueFactory.h b/include/clang/Checker/PathSensitive/BasicValueFactory.h new file mode 100644 index 000000000000..2f0b6c2a0348 --- /dev/null +++ b/include/clang/Checker/PathSensitive/BasicValueFactory.h @@ -0,0 +1,198 @@ +//=== BasicValueFactory.h - Basic values for Path Sens analysis --*- C++ -*---// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines BasicValueFactory, a class that manages the lifetime +// of APSInt objects and symbolic constraints used by GRExprEngine +// and related classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H +#define LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H + +#include "clang/Checker/PathSensitive/SymbolManager.h" +#include "clang/Checker/PathSensitive/SVals.h" +#include "clang/AST/ASTContext.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ImmutableList.h" + +namespace clang { + + class GRState; + +class CompoundValData : public llvm::FoldingSetNode { + QualType T; + llvm::ImmutableList L; + +public: + CompoundValData(QualType t, llvm::ImmutableList l) + : T(t), L(l) {} + + typedef llvm::ImmutableList::iterator iterator; + iterator begin() const { return L.begin(); } + iterator end() const { return L.end(); } + + static void Profile(llvm::FoldingSetNodeID& ID, QualType T, + llvm::ImmutableList L); + + void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, T, L); } +}; + +class LazyCompoundValData : public llvm::FoldingSetNode { + const void *store; + const TypedRegion *region; +public: + LazyCompoundValData(const void *st, const TypedRegion *r) + : store(st), region(r) {} + + const void *getStore() const { return store; } + const TypedRegion *getRegion() const { return region; } + + static void Profile(llvm::FoldingSetNodeID& ID, const void *store, + const TypedRegion *region); + + void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); } +}; + +class BasicValueFactory { + typedef llvm::FoldingSet > + APSIntSetTy; + + ASTContext& Ctx; + llvm::BumpPtrAllocator& BPAlloc; + + APSIntSetTy APSIntSet; + void* PersistentSVals; + void* PersistentSValPairs; + + llvm::ImmutableList::Factory SValListFactory; + llvm::FoldingSet CompoundValDataSet; + llvm::FoldingSet LazyCompoundValDataSet; + +public: + BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc) + : Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0), + SValListFactory(Alloc) {} + + ~BasicValueFactory(); + + ASTContext& getContext() const { return Ctx; } + + const llvm::APSInt& getValue(const llvm::APSInt& X); + const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned); + const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned); + const llvm::APSInt& getValue(uint64_t X, QualType T); + + /// Convert - Create a new persistent APSInt with the same value as 'From' + /// but with the bitwidth and signedness of 'To'. + const llvm::APSInt &Convert(const llvm::APSInt& To, + const llvm::APSInt& From) { + + if (To.isUnsigned() == From.isUnsigned() && + To.getBitWidth() == From.getBitWidth()) + return From; + + return getValue(From.getSExtValue(), To.getBitWidth(), To.isUnsigned()); + } + + const llvm::APSInt &Convert(QualType T, const llvm::APSInt &From) { + assert(T->isIntegerType() || Loc::IsLocType(T)); + unsigned bitwidth = Ctx.getTypeSize(T); + bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T); + + if (isUnsigned == From.isUnsigned() && bitwidth == From.getBitWidth()) + return From; + + return getValue(From.getSExtValue(), bitwidth, isUnsigned); + } + + const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) { + QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy; + return getValue(X, T); + } + + inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) { + return getValue(llvm::APSInt::getMaxValue(v.getBitWidth(), v.isUnsigned())); + } + + inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) { + return getValue(llvm::APSInt::getMinValue(v.getBitWidth(), v.isUnsigned())); + } + + inline const llvm::APSInt& getMaxValue(QualType T) { + assert(T->isIntegerType() || Loc::IsLocType(T)); + bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T); + return getValue(llvm::APSInt::getMaxValue(Ctx.getTypeSize(T), isUnsigned)); + } + + inline const llvm::APSInt& getMinValue(QualType T) { + assert(T->isIntegerType() || Loc::IsLocType(T)); + bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T); + return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned)); + } + + inline const llvm::APSInt& Add1(const llvm::APSInt& V) { + llvm::APSInt X = V; + ++X; + return getValue(X); + } + + inline const llvm::APSInt& Sub1(const llvm::APSInt& V) { + llvm::APSInt X = V; + --X; + return getValue(X); + } + + inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) { + return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); + } + + inline const llvm::APSInt &getIntWithPtrWidth(uint64_t X, bool isUnsigned) { + return getValue(X, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); + } + + inline const llvm::APSInt& getTruthValue(bool b, QualType T) { + return getValue(b ? 1 : 0, Ctx.getTypeSize(T), false); + } + + inline const llvm::APSInt& getTruthValue(bool b) { + return getTruthValue(b, Ctx.IntTy); + } + + const CompoundValData *getCompoundValData(QualType T, + llvm::ImmutableList Vals); + + const LazyCompoundValData *getLazyCompoundValData(const void *store, + const TypedRegion *region); + + llvm::ImmutableList getEmptySValList() { + return SValListFactory.GetEmptyList(); + } + + llvm::ImmutableList consVals(SVal X, llvm::ImmutableList L) { + return SValListFactory.Add(X, L); + } + + const llvm::APSInt* EvaluateAPSInt(BinaryOperator::Opcode Op, + const llvm::APSInt& V1, + const llvm::APSInt& V2); + + const std::pair& + getPersistentSValWithData(const SVal& V, uintptr_t Data); + + const std::pair& + getPersistentSValPair(const SVal& V1, const SVal& V2); + + const SVal* getPersistentSVal(SVal X); +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Checker/PathSensitive/Checker.h b/include/clang/Checker/PathSensitive/Checker.h new file mode 100644 index 000000000000..d498044b82ca --- /dev/null +++ b/include/clang/Checker/PathSensitive/Checker.h @@ -0,0 +1,281 @@ +//== Checker.h - Abstract interface for checkers -----------------*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines Checker and CheckerVisitor, classes used for creating +// domain-specific checks. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CHECKER +#define LLVM_CLANG_ANALYSIS_CHECKER +#include "clang/Analysis/Support/SaveAndRestore.h" +#include "clang/Checker/PathSensitive/GRCoreEngine.h" +#include "clang/Checker/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" + +//===----------------------------------------------------------------------===// +// Checker interface. +//===----------------------------------------------------------------------===// + +namespace clang { + class GRExprEngine; + +class CheckerContext { + ExplodedNodeSet &Dst; + GRStmtNodeBuilder &B; + GRExprEngine &Eng; + ExplodedNode *Pred; + SaveAndRestore OldSink; + SaveAndRestore OldTag; + SaveAndRestore OldPointKind; + SaveOr OldHasGen; + const GRState *ST; + const Stmt *statement; + const unsigned size; + bool DoneEvaluating; // FIXME: This is not a permanent API change. +public: + CheckerContext(ExplodedNodeSet &dst, GRStmtNodeBuilder &builder, + GRExprEngine &eng, ExplodedNode *pred, + const void *tag, ProgramPoint::Kind K, + const Stmt *stmt = 0, const GRState *st = 0) + : Dst(dst), B(builder), Eng(eng), Pred(pred), + OldSink(B.BuildSinks), + OldTag(B.Tag, tag), + OldPointKind(B.PointKind, K), + OldHasGen(B.HasGeneratedNode), + ST(st), statement(stmt), size(Dst.size()) {} + + ~CheckerContext(); + + GRExprEngine &getEngine() { + return Eng; + } + + AnalysisManager &getAnalysisManager() { + return Eng.getAnalysisManager(); + } + + ConstraintManager &getConstraintManager() { + return Eng.getConstraintManager(); + } + + StoreManager &getStoreManager() { + return Eng.getStoreManager(); + } + + ExplodedNodeSet &getNodeSet() { return Dst; } + GRStmtNodeBuilder &getNodeBuilder() { return B; } + ExplodedNode *&getPredecessor() { return Pred; } + const GRState *getState() { return ST ? ST : B.GetState(Pred); } + + ASTContext &getASTContext() { + return Eng.getContext(); + } + + BugReporter &getBugReporter() { + return Eng.getBugReporter(); + } + + SourceManager &getSourceManager() { + return getBugReporter().getSourceManager(); + } + + ValueManager &getValueManager() { + return Eng.getValueManager(); + } + + SValuator &getSValuator() { + return Eng.getSValuator(); + } + + ExplodedNode *GenerateNode(bool autoTransition = true) { + assert(statement && "Only transitions with statements currently supported"); + ExplodedNode *N = GenerateNodeImpl(statement, getState(), false); + if (N && autoTransition) + Dst.Add(N); + return N; + } + + ExplodedNode *GenerateNode(const Stmt *stmt, const GRState *state, + bool autoTransition = true) { + assert(state); + ExplodedNode *N = GenerateNodeImpl(stmt, state, false); + if (N && autoTransition) + addTransition(N); + return N; + } + + ExplodedNode *GenerateNode(const GRState *state, ExplodedNode *pred, + bool autoTransition = true) { + assert(statement && "Only transitions with statements currently supported"); + ExplodedNode *N = GenerateNodeImpl(statement, state, pred, false); + if (N && autoTransition) + addTransition(N); + return N; + } + + ExplodedNode *GenerateNode(const GRState *state, bool autoTransition = true) { + assert(statement && "Only transitions with statements currently supported"); + ExplodedNode *N = GenerateNodeImpl(statement, state, false); + if (N && autoTransition) + addTransition(N); + return N; + } + + ExplodedNode *GenerateSink(const Stmt *stmt, const GRState *state = 0) { + return GenerateNodeImpl(stmt, state ? state : getState(), true); + } + + ExplodedNode *GenerateSink(const GRState *state = 0) { + assert(statement && "Only transitions with statements currently supported"); + return GenerateNodeImpl(statement, state ? state : getState(), true); + } + + void addTransition(ExplodedNode *node) { + Dst.Add(node); + } + + void addTransition(const GRState *state) { + assert(state); + if (state != getState() || (ST && ST != B.GetState(Pred))) + GenerateNode(state, true); + else + Dst.Add(Pred); + } + + void EmitReport(BugReport *R) { + Eng.getBugReporter().EmitReport(R); + } + +private: + ExplodedNode *GenerateNodeImpl(const Stmt* stmt, const GRState *state, + bool markAsSink) { + ExplodedNode *node = B.generateNode(stmt, state, Pred); + if (markAsSink && node) + node->markAsSink(); + return node; + } + + ExplodedNode *GenerateNodeImpl(const Stmt* stmt, const GRState *state, + ExplodedNode *pred, bool markAsSink) { + ExplodedNode *node = B.generateNode(stmt, state, pred); + if (markAsSink && node) + node->markAsSink(); + return node; + } +}; + +class Checker { +private: + friend class GRExprEngine; + + // FIXME: Remove the 'tag' option. + void GR_Visit(ExplodedNodeSet &Dst, + GRStmtNodeBuilder &Builder, + GRExprEngine &Eng, + const Stmt *S, + ExplodedNode *Pred, void *tag, bool isPrevisit) { + CheckerContext C(Dst, Builder, Eng, Pred, tag, + isPrevisit ? ProgramPoint::PreStmtKind : + ProgramPoint::PostStmtKind, S); + if (isPrevisit) + _PreVisit(C, S); + else + _PostVisit(C, S); + } + + bool GR_EvalNilReceiver(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder, + GRExprEngine &Eng, const ObjCMessageExpr *ME, + ExplodedNode *Pred, const GRState *state, void *tag) { + CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind, + ME, state); + return EvalNilReceiver(C, ME); + } + + bool GR_EvalCallExpr(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder, + GRExprEngine &Eng, const CallExpr *CE, + ExplodedNode *Pred, void *tag) { + CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind, + CE); + return EvalCallExpr(C, CE); + } + + // FIXME: Remove the 'tag' option. + void GR_VisitBind(ExplodedNodeSet &Dst, + GRStmtNodeBuilder &Builder, GRExprEngine &Eng, + const Stmt *AssignE, + const Stmt *StoreE, ExplodedNode *Pred, void *tag, + SVal location, SVal val, + bool isPrevisit) { + CheckerContext C(Dst, Builder, Eng, Pred, tag, + isPrevisit ? ProgramPoint::PreStmtKind : + ProgramPoint::PostStmtKind, StoreE); + assert(isPrevisit && "Only previsit supported for now."); + PreVisitBind(C, AssignE, StoreE, location, val); + } + + // FIXME: Remove the 'tag' option. + void GR_VisitLocation(ExplodedNodeSet &Dst, + GRStmtNodeBuilder &Builder, + GRExprEngine &Eng, + const Stmt *S, + ExplodedNode *Pred, const GRState *state, + SVal location, + void *tag, bool isLoad) { + CheckerContext C(Dst, Builder, Eng, Pred, tag, + isLoad ? ProgramPoint::PreLoadKind : + ProgramPoint::PreStoreKind, S, state); + VisitLocation(C, S, location); + } + + void GR_EvalDeadSymbols(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder, + GRExprEngine &Eng, const Stmt *S, ExplodedNode *Pred, + SymbolReaper &SymReaper, void *tag) { + CheckerContext C(Dst, Builder, Eng, Pred, tag, + ProgramPoint::PostPurgeDeadSymbolsKind, S); + EvalDeadSymbols(C, S, SymReaper); + } + +public: + virtual ~Checker(); + virtual void _PreVisit(CheckerContext &C, const Stmt *S) {} + virtual void _PostVisit(CheckerContext &C, const Stmt *S) {} + virtual void VisitLocation(CheckerContext &C, const Stmt *S, SVal location) {} + virtual void PreVisitBind(CheckerContext &C, const Stmt *AssignE, + const Stmt *StoreE, SVal location, SVal val) {} + virtual void EvalDeadSymbols(CheckerContext &C, const Stmt *S, + SymbolReaper &SymReaper) {} + virtual void EvalEndPath(GREndPathNodeBuilder &B, void *tag, + GRExprEngine &Eng) {} + + virtual void VisitBranchCondition(GRBranchNodeBuilder &Builder, + GRExprEngine &Eng, + Stmt *Condition, void *tag) {} + + virtual bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME) { + return false; + } + + virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE) { + return false; + } + + virtual const GRState *EvalAssume(const GRState *state, SVal Cond, + bool Assumption) { + return state; + } +}; +} // end clang namespace + +#endif + diff --git a/include/clang/Checker/PathSensitive/CheckerVisitor.def b/include/clang/Checker/PathSensitive/CheckerVisitor.def new file mode 100644 index 000000000000..2edc4a37b7eb --- /dev/null +++ b/include/clang/Checker/PathSensitive/CheckerVisitor.def @@ -0,0 +1,37 @@ +//===-- CheckerVisitor.def - Metadata for CheckerVisitor ----------------*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the AST nodes accepted by the CheckerVisitor class. +// +//===---------------------------------------------------------------------===// + +#ifndef PREVISIT +#define PREVISIT(NODE, FALLBACK) +#endif + +#ifndef POSTVISIT +#define POSTVISIT(NODE, FALLBACK) +#endif + +PREVISIT(ArraySubscriptExpr, Stmt) +PREVISIT(BinaryOperator, Stmt) +PREVISIT(CallExpr, Stmt) +PREVISIT(CXXOperatorCallExpr, CallExpr) +PREVISIT(DeclStmt, Stmt) +PREVISIT(ObjCMessageExpr, Stmt) +PREVISIT(ReturnStmt, Stmt) + +POSTVISIT(BlockExpr, Stmt) +POSTVISIT(BinaryOperator, Stmt) +POSTVISIT(CallExpr, Stmt) +POSTVISIT(CXXOperatorCallExpr, CallExpr) +POSTVISIT(ObjCMessageExpr, Stmt) + +#undef PREVISIT +#undef POSTVISIT diff --git a/include/clang/Checker/PathSensitive/CheckerVisitor.h b/include/clang/Checker/PathSensitive/CheckerVisitor.h new file mode 100644 index 000000000000..72f0ae1375e8 --- /dev/null +++ b/include/clang/Checker/PathSensitive/CheckerVisitor.h @@ -0,0 +1,102 @@ +//== CheckerVisitor.h - Abstract visitor for checkers ------------*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines CheckerVisitor. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CHECKERVISITOR +#define LLVM_CLANG_ANALYSIS_CHECKERVISITOR +#include "clang/Checker/PathSensitive/Checker.h" + +namespace clang { + +//===----------------------------------------------------------------------===// +// Checker visitor interface. Used by subclasses of Checker to specify their +// own checker visitor logic. +//===----------------------------------------------------------------------===// + +/// CheckerVisitor - This class implements a simple visitor for Stmt subclasses. +/// Since Expr derives from Stmt, this also includes support for visiting Exprs. +template +class CheckerVisitor : public Checker { +public: + virtual void _PreVisit(CheckerContext &C, const Stmt *S) { + PreVisit(C, S); + } + + virtual void _PostVisit(CheckerContext &C, const Stmt *S) { + PostVisit(C, S); + } + + void PreVisit(CheckerContext &C, const Stmt *S) { + switch (S->getStmtClass()) { + default: + assert(false && "Unsupport statement."); + return; + + case Stmt::ImplicitCastExprClass: + case Stmt::CStyleCastExprClass: + static_cast(this)->PreVisitCastExpr(C, + static_cast(S)); + break; + + case Stmt::CompoundAssignOperatorClass: + static_cast(this)->PreVisitBinaryOperator(C, + static_cast(S)); + break; + +#define PREVISIT(NAME, FALLBACK) \ +case Stmt::NAME ## Class:\ +static_cast(this)->PreVisit ## NAME(C,static_cast(S));\ +break; +#include "clang/Checker/PathSensitive/CheckerVisitor.def" + } + } + + void PostVisit(CheckerContext &C, const Stmt *S) { + switch (S->getStmtClass()) { + default: + assert(false && "Unsupport statement."); + return; + case Stmt::CompoundAssignOperatorClass: + static_cast(this)->PostVisitBinaryOperator(C, + static_cast(S)); + break; + +#define POSTVISIT(NAME, FALLBACK) \ +case Stmt::NAME ## Class:\ +static_cast(this)->\ +PostVisit ## NAME(C,static_cast(S));\ +break; +#include "clang/Checker/PathSensitive/CheckerVisitor.def" + } + } + + void PreVisitStmt(CheckerContext &C, const Stmt *S) {} + void PostVisitStmt(CheckerContext &C, const Stmt *S) {} + + void PreVisitCastExpr(CheckerContext &C, const CastExpr *E) { + static_cast(this)->PreVisitStmt(C, E); + } + +#define PREVISIT(NAME, FALLBACK) \ +void PreVisit ## NAME(CheckerContext &C, const NAME* S) {\ + static_cast(this)->PreVisit ## FALLBACK(C, S);\ +} +#define POSTVISIT(NAME, FALLBACK) \ +void PostVisit ## NAME(CheckerContext &C, const NAME* S) {\ + static_cast(this)->PostVisit ## FALLBACK(C, S);\ +} +#include "clang/Checker/PathSensitive/CheckerVisitor.def" +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Checker/PathSensitive/ConstraintManager.h b/include/clang/Checker/PathSensitive/ConstraintManager.h new file mode 100644 index 000000000000..ce7d1b381714 --- /dev/null +++ b/include/clang/Checker/PathSensitive/ConstraintManager.h @@ -0,0 +1,75 @@ +//== ConstraintManager.h - Constraints on symbolic values.-------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defined the interface to manage constraints on symbolic values. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H +#define LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H + +// FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place. +#include "clang/Checker/PathSensitive/Store.h" + +namespace llvm { +class APSInt; +} + +namespace clang { + +class GRState; +class GRStateManager; +class GRSubEngine; +class SVal; + +class ConstraintManager { +public: + virtual ~ConstraintManager(); + virtual const GRState *Assume(const GRState *state, DefinedSVal Cond, + bool Assumption) = 0; + + virtual const GRState *AssumeInBound(const GRState *state, DefinedSVal Idx, + DefinedSVal UpperBound, bool Assumption) = 0; + + std::pair AssumeDual(const GRState *state, + DefinedSVal Cond) { + return std::make_pair(Assume(state, Cond, true), + Assume(state, Cond, false)); + } + + virtual const llvm::APSInt* getSymVal(const GRState *state, + SymbolRef sym) const = 0; + + virtual bool isEqual(const GRState *state, SymbolRef sym, + const llvm::APSInt& V) const = 0; + + virtual const GRState *RemoveDeadBindings(const GRState *state, + SymbolReaper& SymReaper) = 0; + + virtual void print(const GRState *state, llvm::raw_ostream& Out, + const char* nl, const char *sep) = 0; + + virtual void EndPath(const GRState *state) {} + + /// canReasonAbout - Not all ConstraintManagers can accurately reason about + /// all SVal values. This method returns true if the ConstraintManager can + /// reasonably handle a given SVal value. This is typically queried by + /// GRExprEngine to determine if the value should be replaced with a + /// conjured symbolic value in order to recover some precision. + virtual bool canReasonAbout(SVal X) const = 0; +}; + +ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr, + GRSubEngine &subengine); +ConstraintManager* CreateRangeConstraintManager(GRStateManager& statemgr, + GRSubEngine &subengine); + +} // end clang namespace + +#endif diff --git a/include/clang/Checker/PathSensitive/Environment.h b/include/clang/Checker/PathSensitive/Environment.h new file mode 100644 index 000000000000..0852c31faeb6 --- /dev/null +++ b/include/clang/Checker/PathSensitive/Environment.h @@ -0,0 +1,103 @@ +//== Environment.h - Map from Stmt* to Locations/Values ---------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defined the Environment and EnvironmentManager classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ENVIRONMENT_H +#define LLVM_CLANG_ANALYSIS_ENVIRONMENT_H + +// For using typedefs in StoreManager. Should find a better place for these +// typedefs. +#include "clang/Checker/PathSensitive/Store.h" + +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/SmallVector.h" +#include "clang/Checker/PathSensitive/SVals.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/FoldingSet.h" + +namespace clang { + +class AnalysisContext; +class EnvironmentManager; +class ValueManager; +class LiveVariables; + + +class Environment { +private: + friend class EnvironmentManager; + + // Type definitions. + typedef llvm::ImmutableMap BindingsTy; + + // Data. + BindingsTy ExprBindings; + AnalysisContext *ACtx; + + Environment(BindingsTy eb, AnalysisContext *aCtx) + : ExprBindings(eb), ACtx(aCtx) {} + +public: + typedef BindingsTy::iterator iterator; + iterator begin() const { return ExprBindings.begin(); } + iterator end() const { return ExprBindings.end(); } + + SVal LookupExpr(const Stmt* E) const { + const SVal* X = ExprBindings.lookup(E); + return X ? *X : UnknownVal(); + } + + SVal GetSVal(const Stmt* Ex, ValueManager& ValMgr) const; + + AnalysisContext &getAnalysisContext() const { return *ACtx; } + + /// Profile - Profile the contents of an Environment object for use + /// in a FoldingSet. + static void Profile(llvm::FoldingSetNodeID& ID, const Environment* E) { + E->ExprBindings.Profile(ID); + } + + /// Profile - Used to profile the contents of this object for inclusion + /// in a FoldingSet. + void Profile(llvm::FoldingSetNodeID& ID) const { + Profile(ID, this); + } + + bool operator==(const Environment& RHS) const { + return ExprBindings == RHS.ExprBindings; + } +}; + +class EnvironmentManager { +private: + typedef Environment::BindingsTy::Factory FactoryTy; + FactoryTy F; + +public: + EnvironmentManager(llvm::BumpPtrAllocator& Allocator) : F(Allocator) {} + ~EnvironmentManager() {} + + Environment getInitialEnvironment(AnalysisContext *ACtx) { + return Environment(F.GetEmptyMap(), ACtx); + } + + Environment BindExpr(Environment Env, const Stmt *S, SVal V, + bool Invalidate); + + Environment RemoveDeadBindings(Environment Env, const Stmt *S, + SymbolReaper &SymReaper, const GRState *ST, + llvm::SmallVectorImpl& RegionRoots); +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Checker/PathSensitive/ExplodedGraph.h b/include/clang/Checker/PathSensitive/ExplodedGraph.h new file mode 100644 index 000000000000..d6c4436c594c --- /dev/null +++ b/include/clang/Checker/PathSensitive/ExplodedGraph.h @@ -0,0 +1,432 @@ +//=-- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -*- C++ -*-------==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the template classes ExplodedNode and ExplodedGraph, +// which represent a path-sensitive, intra-procedural "exploded graph." +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH +#define LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH + +#include "clang/Analysis/ProgramPoint.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/AST/Decl.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/Support/Casting.h" +#include "clang/Analysis/Support/BumpVector.h" + +namespace clang { + +class GRState; +class CFG; +class ASTContext; +class ExplodedGraph; + +//===----------------------------------------------------------------------===// +// ExplodedGraph "implementation" classes. These classes are not typed to +// contain a specific kind of state. Typed-specialized versions are defined +// on top of these classes. +//===----------------------------------------------------------------------===// + +class ExplodedNode : public llvm::FoldingSetNode { + friend class ExplodedGraph; + friend class GRCoreEngine; + friend class GRStmtNodeBuilder; + friend class GRBranchNodeBuilder; + friend class GRIndirectGotoNodeBuilder; + friend class GRSwitchNodeBuilder; + friend class GREndPathNodeBuilder; + + class NodeGroup { + enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 }; + uintptr_t P; + + unsigned getKind() const { + return P & 0x1; + } + + void* getPtr() const { + assert (!getFlag()); + return reinterpret_cast(P & ~Mask); + } + + ExplodedNode *getNode() const { + return reinterpret_cast(getPtr()); + } + + public: + NodeGroup() : P(0) {} + + ExplodedNode **begin() const; + + ExplodedNode **end() const; + + unsigned size() const; + + bool empty() const { return (P & ~Mask) == 0; } + + void addNode(ExplodedNode* N, ExplodedGraph &G); + + void setFlag() { + assert(P == 0); + P = AuxFlag; + } + + bool getFlag() const { + return P & AuxFlag ? true : false; + } + }; + + /// Location - The program location (within a function body) associated + /// with this node. + const ProgramPoint Location; + + /// State - The state associated with this node. + const GRState* State; + + /// Preds - The predecessors of this node. + NodeGroup Preds; + + /// Succs - The successors of this node. + NodeGroup Succs; + +public: + + explicit ExplodedNode(const ProgramPoint& loc, const GRState* state) + : Location(loc), State(state) {} + + /// getLocation - Returns the edge associated with the given node. + ProgramPoint getLocation() const { return Location; } + + const LocationContext *getLocationContext() const { + return getLocation().getLocationContext(); + } + + const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); } + + CFG &getCFG() const { return *getLocationContext()->getCFG(); } + + ParentMap &getParentMap() const {return getLocationContext()->getParentMap();} + + LiveVariables &getLiveVariables() const { + return *getLocationContext()->getLiveVariables(); + } + + const GRState* getState() const { return State; } + + template + const T* getLocationAs() const { return llvm::dyn_cast(&Location); } + + static void Profile(llvm::FoldingSetNodeID &ID, + const ProgramPoint& Loc, const GRState* state) { + ID.Add(Loc); + ID.AddPointer(state); + } + + void Profile(llvm::FoldingSetNodeID& ID) const { + Profile(ID, getLocation(), getState()); + } + + /// addPredeccessor - Adds a predecessor to the current node, and + /// in tandem add this node as a successor of the other node. + void addPredecessor(ExplodedNode* V, ExplodedGraph &G); + + unsigned succ_size() const { return Succs.size(); } + unsigned pred_size() const { return Preds.size(); } + bool succ_empty() const { return Succs.empty(); } + bool pred_empty() const { return Preds.empty(); } + + bool isSink() const { return Succs.getFlag(); } + void markAsSink() { Succs.setFlag(); } + + ExplodedNode* getFirstPred() { + return pred_empty() ? NULL : *(pred_begin()); + } + + const ExplodedNode* getFirstPred() const { + return const_cast(this)->getFirstPred(); + } + + // Iterators over successor and predecessor vertices. + typedef ExplodedNode** succ_iterator; + typedef const ExplodedNode* const * const_succ_iterator; + typedef ExplodedNode** pred_iterator; + typedef const ExplodedNode* const * const_pred_iterator; + + pred_iterator pred_begin() { return Preds.begin(); } + pred_iterator pred_end() { return Preds.end(); } + + const_pred_iterator pred_begin() const { + return const_cast(this)->pred_begin(); + } + const_pred_iterator pred_end() const { + return const_cast(this)->pred_end(); + } + + succ_iterator succ_begin() { return Succs.begin(); } + succ_iterator succ_end() { return Succs.end(); } + + const_succ_iterator succ_begin() const { + return const_cast(this)->succ_begin(); + } + const_succ_iterator succ_end() const { + return const_cast(this)->succ_end(); + } + + // For debugging. + +public: + + class Auditor { + public: + virtual ~Auditor(); + virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst) = 0; + }; + + static void SetAuditor(Auditor* A); +}; + +// FIXME: Is this class necessary? +class InterExplodedGraphMap { + llvm::DenseMap M; + friend class ExplodedGraph; + +public: + ExplodedNode* getMappedNode(const ExplodedNode* N) const; + + InterExplodedGraphMap() {} + virtual ~InterExplodedGraphMap() {} +}; + +class ExplodedGraph { +protected: + friend class GRCoreEngine; + + // Type definitions. + typedef llvm::SmallVector RootsTy; + typedef llvm::SmallVector EndNodesTy; + + /// Roots - The roots of the simulation graph. Usually there will be only + /// one, but clients are free to establish multiple subgraphs within a single + /// SimulGraph. Moreover, these subgraphs can often merge when paths from + /// different roots reach the same state at the same program location. + RootsTy Roots; + + /// EndNodes - The nodes in the simulation graph which have been + /// specially marked as the endpoint of an abstract simulation path. + EndNodesTy EndNodes; + + /// Nodes - The nodes in the graph. + llvm::FoldingSet Nodes; + + /// BVC - Allocator and context for allocating nodes and their predecessor + /// and successor groups. + BumpVectorContext BVC; + + /// Ctx - The ASTContext used to "interpret" CodeDecl. + ASTContext& Ctx; + + /// NumNodes - The number of nodes in the graph. + unsigned NumNodes; + +public: + /// getNode - Retrieve the node associated with a (Location,State) pair, + /// where the 'Location' is a ProgramPoint in the CFG. If no node for + /// this pair exists, it is created. IsNew is set to true if + /// the node was freshly created. + + ExplodedNode* getNode(const ProgramPoint& L, const GRState *State, + bool* IsNew = 0); + + ExplodedGraph* MakeEmptyGraph() const { + return new ExplodedGraph(Ctx); + } + + /// addRoot - Add an untyped node to the set of roots. + ExplodedNode* addRoot(ExplodedNode* V) { + Roots.push_back(V); + return V; + } + + /// addEndOfPath - Add an untyped node to the set of EOP nodes. + ExplodedNode* addEndOfPath(ExplodedNode* V) { + EndNodes.push_back(V); + return V; + } + + ExplodedGraph(ASTContext& ctx) : Ctx(ctx), NumNodes(0) {} + + ~ExplodedGraph() {} + + unsigned num_roots() const { return Roots.size(); } + unsigned num_eops() const { return EndNodes.size(); } + + bool empty() const { return NumNodes == 0; } + unsigned size() const { return NumNodes; } + + // Iterators. + typedef ExplodedNode NodeTy; + typedef llvm::FoldingSet AllNodesTy; + typedef NodeTy** roots_iterator; + typedef NodeTy* const * const_roots_iterator; + typedef NodeTy** eop_iterator; + typedef NodeTy* const * const_eop_iterator; + typedef AllNodesTy::iterator node_iterator; + typedef AllNodesTy::const_iterator const_node_iterator; + + node_iterator nodes_begin() { return Nodes.begin(); } + + node_iterator nodes_end() { return Nodes.end(); } + + const_node_iterator nodes_begin() const { return Nodes.begin(); } + + const_node_iterator nodes_end() const { return Nodes.end(); } + + roots_iterator roots_begin() { return Roots.begin(); } + + roots_iterator roots_end() { return Roots.end(); } + + const_roots_iterator roots_begin() const { return Roots.begin(); } + + const_roots_iterator roots_end() const { return Roots.end(); } + + eop_iterator eop_begin() { return EndNodes.begin(); } + + eop_iterator eop_end() { return EndNodes.end(); } + + const_eop_iterator eop_begin() const { return EndNodes.begin(); } + + const_eop_iterator eop_end() const { return EndNodes.end(); } + + llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); } + BumpVectorContext &getNodeAllocator() { return BVC; } + + ASTContext& getContext() { return Ctx; } + + typedef llvm::DenseMap NodeMap; + + std::pair + Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd, + llvm::DenseMap *InverseMap = 0) const; + + ExplodedGraph* TrimInternal(const ExplodedNode* const * NBeg, + const ExplodedNode* const * NEnd, + InterExplodedGraphMap *M, + llvm::DenseMap *InverseMap) const; +}; + +class ExplodedNodeSet { + typedef llvm::SmallPtrSet ImplTy; + ImplTy Impl; + +public: + ExplodedNodeSet(ExplodedNode* N) { + assert (N && !static_cast(N)->isSink()); + Impl.insert(N); + } + + ExplodedNodeSet() {} + + inline void Add(ExplodedNode* N) { + if (N && !static_cast(N)->isSink()) Impl.insert(N); + } + + ExplodedNodeSet& operator=(const ExplodedNodeSet &X) { + Impl = X.Impl; + return *this; + } + + typedef ImplTy::iterator iterator; + typedef ImplTy::const_iterator const_iterator; + + unsigned size() const { return Impl.size(); } + bool empty() const { return Impl.empty(); } + + void clear() { Impl.clear(); } + void insert(const ExplodedNodeSet &S) { + if (empty()) + Impl = S.Impl; + else + Impl.insert(S.begin(), S.end()); + } + + inline iterator begin() { return Impl.begin(); } + inline iterator end() { return Impl.end(); } + + inline const_iterator begin() const { return Impl.begin(); } + inline const_iterator end() const { return Impl.end(); } +}; + +} // end clang namespace + +// GraphTraits + +namespace llvm { + template<> struct GraphTraits { + typedef clang::ExplodedNode NodeType; + typedef NodeType::succ_iterator ChildIteratorType; + typedef llvm::df_iterator nodes_iterator; + + static inline NodeType* getEntryNode(NodeType* N) { + return N; + } + + static inline ChildIteratorType child_begin(NodeType* N) { + return N->succ_begin(); + } + + static inline ChildIteratorType child_end(NodeType* N) { + return N->succ_end(); + } + + static inline nodes_iterator nodes_begin(NodeType* N) { + return df_begin(N); + } + + static inline nodes_iterator nodes_end(NodeType* N) { + return df_end(N); + } + }; + + template<> struct GraphTraits { + typedef const clang::ExplodedNode NodeType; + typedef NodeType::const_succ_iterator ChildIteratorType; + typedef llvm::df_iterator nodes_iterator; + + static inline NodeType* getEntryNode(NodeType* N) { + return N; + } + + static inline ChildIteratorType child_begin(NodeType* N) { + return N->succ_begin(); + } + + static inline ChildIteratorType child_end(NodeType* N) { + return N->succ_end(); + } + + static inline nodes_iterator nodes_begin(NodeType* N) { + return df_begin(N); + } + + static inline nodes_iterator nodes_end(NodeType* N) { + return df_end(N); + } + }; + +} // end llvm namespace + +#endif diff --git a/include/clang/Checker/PathSensitive/GRAuditor.h b/include/clang/Checker/PathSensitive/GRAuditor.h new file mode 100644 index 000000000000..015c82e80bb5 --- /dev/null +++ b/include/clang/Checker/PathSensitive/GRAuditor.h @@ -0,0 +1,35 @@ +//==- GRAuditor.h - Observers of the creation of ExplodedNodes------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines GRAuditor and its primary subclasses, an interface +// to audit the creation of ExplodedNodes. This interface can be used +// to implement simple checkers that do not mutate analysis state but +// instead operate by perfoming simple logical checks at key monitoring +// locations (e.g., function calls). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GRAUDITOR +#define LLVM_CLANG_ANALYSIS_GRAUDITOR + +namespace clang { + +class ExplodedNode; +class GRStateManager; + +class GRAuditor { +public: + virtual ~GRAuditor() {} + virtual bool Audit(ExplodedNode* N, GRStateManager& M) = 0; +}; + + +} // end clang namespace + +#endif diff --git a/include/clang/Checker/PathSensitive/GRBlockCounter.h b/include/clang/Checker/PathSensitive/GRBlockCounter.h new file mode 100644 index 000000000000..67ed9532db02 --- /dev/null +++ b/include/clang/Checker/PathSensitive/GRBlockCounter.h @@ -0,0 +1,50 @@ +//==- GRBlockCounter.h - ADT for counting block visits -------------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines GRBlockCounter, an abstract data type used to count +// the number of times a given block has been visited along a path +// analyzed by GRCoreEngine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER +#define LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER + +namespace llvm { + class BumpPtrAllocator; +} + +namespace clang { + +class GRBlockCounter { + void* Data; + + GRBlockCounter(void* D) : Data(D) {} + +public: + GRBlockCounter() : Data(0) {} + + unsigned getNumVisited(unsigned BlockID) const; + + class Factory { + void* F; + public: + Factory(llvm::BumpPtrAllocator& Alloc); + ~Factory(); + + GRBlockCounter GetEmptyCounter(); + GRBlockCounter IncrementCount(GRBlockCounter BC, unsigned BlockID); + }; + + friend class Factory; +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Checker/PathSensitive/GRCoreEngine.h b/include/clang/Checker/PathSensitive/GRCoreEngine.h new file mode 100644 index 000000000000..6da45815f996 --- /dev/null +++ b/include/clang/Checker/PathSensitive/GRCoreEngine.h @@ -0,0 +1,443 @@ +//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine --------------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a generic engine for intraprocedural, path-sensitive, +// dataflow analysis via graph reachability. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GRENGINE +#define LLVM_CLANG_ANALYSIS_GRENGINE + +#include "clang/AST/Expr.h" +#include "clang/Checker/PathSensitive/ExplodedGraph.h" +#include "clang/Checker/PathSensitive/GRWorkList.h" +#include "clang/Checker/PathSensitive/GRBlockCounter.h" +#include "clang/Checker/PathSensitive/GRAuditor.h" +#include "clang/Checker/PathSensitive/GRSubEngine.h" +#include "llvm/ADT/OwningPtr.h" + +namespace clang { + +//===----------------------------------------------------------------------===// +/// GRCoreEngine - Implements the core logic of the graph-reachability +/// analysis. It traverses the CFG and generates the ExplodedGraph. +/// Program "states" are treated as opaque void pointers. +/// The template class GRCoreEngine (which subclasses GRCoreEngine) +/// provides the matching component to the engine that knows the actual types +/// for states. Note that this engine only dispatches to transfer functions +/// at the statement and block-level. The analyses themselves must implement +/// any transfer function logic and the sub-expression level (if any). +class GRCoreEngine { + friend class GRStmtNodeBuilder; + friend class GRBranchNodeBuilder; + friend class GRIndirectGotoNodeBuilder; + friend class GRSwitchNodeBuilder; + friend class GREndPathNodeBuilder; + + GRSubEngine& SubEngine; + + /// G - The simulation graph. Each node is a (location,state) pair. + llvm::OwningPtr G; + + /// WList - A set of queued nodes that need to be processed by the + /// worklist algorithm. It is up to the implementation of WList to decide + /// the order that nodes are processed. + GRWorkList* WList; + + /// BCounterFactory - A factory object for created GRBlockCounter objects. + /// These are used to record for key nodes in the ExplodedGraph the + /// number of times different CFGBlocks have been visited along a path. + GRBlockCounter::Factory BCounterFactory; + + void GenerateNode(const ProgramPoint& Loc, const GRState* State, + ExplodedNode* Pred); + + void HandleBlockEdge(const BlockEdge& E, ExplodedNode* Pred); + void HandleBlockEntrance(const BlockEntrance& E, ExplodedNode* Pred); + void HandleBlockExit(CFGBlock* B, ExplodedNode* Pred); + void HandlePostStmt(const PostStmt& S, CFGBlock* B, + unsigned StmtIdx, ExplodedNode *Pred); + + void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B, + ExplodedNode* Pred); + + /// Get the initial state from the subengine. + const GRState* getInitialState(const LocationContext *InitLoc) { + return SubEngine.getInitialState(InitLoc); + } + + void ProcessEndPath(GREndPathNodeBuilder& Builder); + + void ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder); + + bool ProcessBlockEntrance(CFGBlock* Blk, const GRState* State, + GRBlockCounter BC); + + + void ProcessBranch(Stmt* Condition, Stmt* Terminator, + GRBranchNodeBuilder& Builder); + + + void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& Builder); + + + void ProcessSwitch(GRSwitchNodeBuilder& Builder); + +private: + GRCoreEngine(const GRCoreEngine&); // Do not implement. + GRCoreEngine& operator=(const GRCoreEngine&); + +public: + /// Construct a GRCoreEngine object to analyze the provided CFG using + /// a DFS exploration of the exploded graph. + GRCoreEngine(ASTContext& ctx, GRSubEngine& subengine) + : SubEngine(subengine), G(new ExplodedGraph(ctx)), + WList(GRWorkList::MakeBFS()), + BCounterFactory(G->getAllocator()) {} + + /// Construct a GRCoreEngine object to analyze the provided CFG and to + /// use the provided worklist object to execute the worklist algorithm. + /// The GRCoreEngine object assumes ownership of 'wlist'. + GRCoreEngine(ASTContext& ctx, GRWorkList* wlist, GRSubEngine& subengine) + : SubEngine(subengine), G(new ExplodedGraph(ctx)), WList(wlist), + BCounterFactory(G->getAllocator()) {} + + ~GRCoreEngine() { + delete WList; + } + + /// getGraph - Returns the exploded graph. + ExplodedGraph& getGraph() { return *G.get(); } + + /// takeGraph - Returns the exploded graph. Ownership of the graph is + /// transfered to the caller. + ExplodedGraph* takeGraph() { return G.take(); } + + /// ExecuteWorkList - Run the worklist algorithm for a maximum number of + /// steps. Returns true if there is still simulation state on the worklist. + bool ExecuteWorkList(const LocationContext *L, unsigned Steps); +}; + +class GRStmtNodeBuilder { + GRCoreEngine& Eng; + CFGBlock& B; + const unsigned Idx; + ExplodedNode* Pred; + ExplodedNode* LastNode; + GRStateManager& Mgr; + GRAuditor* Auditor; + +public: + bool PurgingDeadSymbols; + bool BuildSinks; + bool HasGeneratedNode; + ProgramPoint::Kind PointKind; + const void *Tag; + + const GRState* CleanedState; + + + typedef llvm::SmallPtrSet DeferredTy; + DeferredTy Deferred; + + void GenerateAutoTransition(ExplodedNode* N); + +public: + GRStmtNodeBuilder(CFGBlock* b, unsigned idx, ExplodedNode* N, + GRCoreEngine* e, GRStateManager &mgr); + + ~GRStmtNodeBuilder(); + + ExplodedNode* getBasePredecessor() const { return Pred; } + + ExplodedNode* getLastNode() const { + return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL; + } + + // FIXME: This should not be exposed. + GRWorkList *getWorkList() { return Eng.WList; } + + void SetCleanedState(const GRState* St) { + CleanedState = St; + } + + GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} + + unsigned getCurrentBlockCount() const { + return getBlockCounter().getNumVisited(B.getBlockID()); + } + + ExplodedNode* generateNode(PostStmt PP,const GRState* St,ExplodedNode* Pred) { + HasGeneratedNode = true; + return generateNodeInternal(PP, St, Pred); + } + + ExplodedNode* generateNode(const Stmt *S, const GRState *St, + ExplodedNode *Pred, ProgramPoint::Kind K) { + HasGeneratedNode = true; + + if (PurgingDeadSymbols) + K = ProgramPoint::PostPurgeDeadSymbolsKind; + + return generateNodeInternal(S, St, Pred, K, Tag); + } + + ExplodedNode* generateNode(const Stmt *S, const GRState *St, + ExplodedNode *Pred) { + return generateNode(S, St, Pred, PointKind); + } + + ExplodedNode* + generateNodeInternal(const ProgramPoint &PP, const GRState* State, + ExplodedNode* Pred); + + ExplodedNode* + generateNodeInternal(const Stmt* S, const GRState* State, ExplodedNode* Pred, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind, + const void *tag = 0); + + /// getStmt - Return the current block-level expression associated with + /// this builder. + Stmt* getStmt() const { return B[Idx]; } + + /// getBlock - Return the CFGBlock associated with the block-level expression + /// of this builder. + CFGBlock* getBlock() const { return &B; } + + unsigned getIndex() const { return Idx; } + + void setAuditor(GRAuditor* A) { Auditor = A; } + + const GRState* GetState(ExplodedNode* Pred) const { + if (Pred == getBasePredecessor()) + return CleanedState; + else + return Pred->getState(); + } + + ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred, + const GRState* St) { + return MakeNode(Dst, S, Pred, St, PointKind); + } + + ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred, + const GRState* St, ProgramPoint::Kind K) { + + const GRState* PredState = GetState(Pred); + + // If the state hasn't changed, don't generate a new node. + if (!BuildSinks && St == PredState && Auditor == 0) { + Dst.Add(Pred); + return NULL; + } + + ExplodedNode* N = generateNode(S, St, Pred, K); + + if (N) { + if (BuildSinks) + N->markAsSink(); + else { + if (Auditor && Auditor->Audit(N, Mgr)) + N->markAsSink(); + + Dst.Add(N); + } + } + + return N; + } + + ExplodedNode* MakeSinkNode(ExplodedNodeSet& Dst, Stmt* S, + ExplodedNode* Pred, const GRState* St) { + bool Tmp = BuildSinks; + BuildSinks = true; + ExplodedNode* N = MakeNode(Dst, S, Pred, St); + BuildSinks = Tmp; + return N; + } + +}; + +class GRBranchNodeBuilder { + GRCoreEngine& Eng; + CFGBlock* Src; + CFGBlock* DstT; + CFGBlock* DstF; + ExplodedNode* Pred; + + typedef llvm::SmallVector DeferredTy; + DeferredTy Deferred; + + bool GeneratedTrue; + bool GeneratedFalse; + bool InFeasibleTrue; + bool InFeasibleFalse; + +public: + GRBranchNodeBuilder(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF, + ExplodedNode* pred, GRCoreEngine* e) + : Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred), + GeneratedTrue(false), GeneratedFalse(false), + InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {} + + ~GRBranchNodeBuilder(); + + ExplodedNode* getPredecessor() const { return Pred; } + + const ExplodedGraph& getGraph() const { return *Eng.G; } + + GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();} + + ExplodedNode* generateNode(const GRState* State, bool branch); + + CFGBlock* getTargetBlock(bool branch) const { + return branch ? DstT : DstF; + } + + void markInfeasible(bool branch) { + if (branch) + InFeasibleTrue = GeneratedTrue = true; + else + InFeasibleFalse = GeneratedFalse = true; + } + + bool isFeasible(bool branch) { + return branch ? !InFeasibleTrue : !InFeasibleFalse; + } + + const GRState* getState() const { + return getPredecessor()->getState(); + } +}; + +class GRIndirectGotoNodeBuilder { + GRCoreEngine& Eng; + CFGBlock* Src; + CFGBlock& DispatchBlock; + Expr* E; + ExplodedNode* Pred; + +public: + GRIndirectGotoNodeBuilder(ExplodedNode* pred, CFGBlock* src, Expr* e, + CFGBlock* dispatch, GRCoreEngine* eng) + : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {} + + class iterator { + CFGBlock::succ_iterator I; + + friend class GRIndirectGotoNodeBuilder; + iterator(CFGBlock::succ_iterator i) : I(i) {} + public: + + iterator& operator++() { ++I; return *this; } + bool operator!=(const iterator& X) const { return I != X.I; } + + LabelStmt* getLabel() const { + return llvm::cast((*I)->getLabel()); + } + + CFGBlock* getBlock() const { + return *I; + } + }; + + iterator begin() { return iterator(DispatchBlock.succ_begin()); } + iterator end() { return iterator(DispatchBlock.succ_end()); } + + ExplodedNode* generateNode(const iterator& I, const GRState* State, + bool isSink = false); + + Expr* getTarget() const { return E; } + + const GRState* getState() const { return Pred->State; } +}; + +class GRSwitchNodeBuilder { + GRCoreEngine& Eng; + CFGBlock* Src; + Expr* Condition; + ExplodedNode* Pred; + +public: + GRSwitchNodeBuilder(ExplodedNode* pred, CFGBlock* src, + Expr* condition, GRCoreEngine* eng) + : Eng(*eng), Src(src), Condition(condition), Pred(pred) {} + + class iterator { + CFGBlock::succ_reverse_iterator I; + + friend class GRSwitchNodeBuilder; + iterator(CFGBlock::succ_reverse_iterator i) : I(i) {} + + public: + iterator& operator++() { ++I; return *this; } + bool operator!=(const iterator& X) const { return I != X.I; } + + CaseStmt* getCase() const { + return llvm::cast((*I)->getLabel()); + } + + CFGBlock* getBlock() const { + return *I; + } + }; + + iterator begin() { return iterator(Src->succ_rbegin()+1); } + iterator end() { return iterator(Src->succ_rend()); } + + ExplodedNode* generateCaseStmtNode(const iterator& I, const GRState* State); + + ExplodedNode* generateDefaultCaseNode(const GRState* State, + bool isSink = false); + + Expr* getCondition() const { return Condition; } + + const GRState* getState() const { return Pred->State; } +}; + +class GREndPathNodeBuilder { + GRCoreEngine &Eng; + CFGBlock& B; + ExplodedNode* Pred; + +public: + bool HasGeneratedNode; + +public: + GREndPathNodeBuilder(CFGBlock* b, ExplodedNode* N, GRCoreEngine* e) + : Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {} + + ~GREndPathNodeBuilder(); + + GRWorkList &getWorkList() { return *Eng.WList; } + + ExplodedNode* getPredecessor() const { return Pred; } + + GRBlockCounter getBlockCounter() const { + return Eng.WList->getBlockCounter(); + } + + unsigned getCurrentBlockCount() const { + return getBlockCounter().getNumVisited(B.getBlockID()); + } + + ExplodedNode* generateNode(const GRState* State, const void *tag = 0, + ExplodedNode *P = 0); + + CFGBlock* getBlock() const { return &B; } + + const GRState* getState() const { + return getPredecessor()->getState(); + } +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h new file mode 100644 index 000000000000..90a2cd55972a --- /dev/null +++ b/include/clang/Checker/PathSensitive/GRExprEngine.h @@ -0,0 +1,422 @@ +//===-- GRExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- C++ -*-= +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a meta-engine for path-sensitive dataflow analysis that +// is built on GRCoreEngine, but provides the boilerplate to execute transfer +// functions and build the ExplodedGraph at the expression level. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE +#define LLVM_CLANG_ANALYSIS_GREXPRENGINE + +#include "clang/Checker/PathSensitive/AnalysisManager.h" +#include "clang/Checker/PathSensitive/GRSubEngine.h" +#include "clang/Checker/PathSensitive/GRCoreEngine.h" +#include "clang/Checker/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/GRSimpleAPICheck.h" +#include "clang/Checker/PathSensitive/GRTransferFuncs.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/AST/Type.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprCXX.h" + +namespace clang { + + class PathDiagnosticClient; + class Diagnostic; + class ObjCForCollectionStmt; + class Checker; + +class GRExprEngine : public GRSubEngine { + AnalysisManager &AMgr; + + GRCoreEngine CoreEngine; + + /// G - the simulation graph. + ExplodedGraph& G; + + /// Builder - The current GRStmtNodeBuilder which is used when building the + /// nodes for a given statement. + GRStmtNodeBuilder* Builder; + + /// StateMgr - Object that manages the data for all created states. + GRStateManager StateMgr; + + /// SymMgr - Object that manages the symbol information. + SymbolManager& SymMgr; + + /// ValMgr - Object that manages/creates SVals. + ValueManager &ValMgr; + + /// SVator - SValuator object that creates SVals from expressions. + SValuator &SVator; + + /// EntryNode - The immediate predecessor node. + ExplodedNode* EntryNode; + + /// CleanedState - The state for EntryNode "cleaned" of all dead + /// variables and symbols (as determined by a liveness analysis). + const GRState* CleanedState; + + /// CurrentStmt - The current block-level statement. + Stmt* CurrentStmt; + + // Obj-C Class Identifiers. + IdentifierInfo* NSExceptionII; + + // Obj-C Selectors. + Selector* NSExceptionInstanceRaiseSelectors; + Selector RaiseSel; + + llvm::OwningPtr BatchAuditor; + + typedef llvm::DenseMap CheckerMap; + CheckerMap CheckerM; + + typedef std::vector > CheckersOrdered; + CheckersOrdered Checkers; + + /// BR - The BugReporter associated with this engine. It is important that + // this object be placed at the very end of member variables so that its + // destructor is called before the rest of the GRExprEngine is destroyed. + GRBugReporter BR; + + llvm::OwningPtr TF; + +public: + GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf); + + ~GRExprEngine(); + + void ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) { + CoreEngine.ExecuteWorkList(L, Steps); + } + + /// getContext - Return the ASTContext associated with this analysis. + ASTContext& getContext() const { return G.getContext(); } + + AnalysisManager &getAnalysisManager() const { return AMgr; } + + SValuator &getSValuator() { return SVator; } + + GRTransferFuncs& getTF() { return *TF; } + + BugReporter& getBugReporter() { return BR; } + + GRStmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; } + + // FIXME: Remove once GRTransferFuncs is no longer referenced. + void setTransferFunction(GRTransferFuncs* tf); + + /// ViewGraph - Visualize the ExplodedGraph created by executing the + /// simulation. + void ViewGraph(bool trim = false); + + void ViewGraph(ExplodedNode** Beg, ExplodedNode** End); + + /// getInitialState - Return the initial state used for the root vertex + /// in the ExplodedGraph. + const GRState* getInitialState(const LocationContext *InitLoc); + + ExplodedGraph& getGraph() { return G; } + const ExplodedGraph& getGraph() const { return G; } + + template + void registerCheck(CHECKER *check) { + unsigned entry = Checkers.size(); + void *tag = CHECKER::getTag(); + Checkers.push_back(std::make_pair(tag, check)); + CheckerM[tag] = entry; + } + + Checker *lookupChecker(void *tag) const; + + template + CHECKER *getChecker() const { + return static_cast(lookupChecker(CHECKER::getTag())); + } + + void AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C); + void AddCheck(GRSimpleAPICheck* A); + + /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor + /// nodes by processing the 'effects' of a block-level statement. + void ProcessStmt(CFGElement E, GRStmtNodeBuilder& builder); + + /// ProcessBlockEntrance - Called by GRCoreEngine when start processing + /// a CFGBlock. This method returns true if the analysis should continue + /// exploring the given path, and false otherwise. + bool ProcessBlockEntrance(CFGBlock* B, const GRState* St, + GRBlockCounter BC); + + /// ProcessBranch - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a branch condition. + void ProcessBranch(Stmt* Condition, Stmt* Term, GRBranchNodeBuilder& builder); + + /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a computed goto jump. + void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder); + + /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a switch statement. + void ProcessSwitch(GRSwitchNodeBuilder& builder); + + /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path + /// nodes when the control reaches the end of a function. + void ProcessEndPath(GREndPathNodeBuilder& builder); + + /// EvalAssume - Callback function invoked by the ConstraintManager when + /// making assumptions about state values. + const GRState *ProcessAssume(const GRState *state, SVal cond, bool assumption); + + GRStateManager& getStateManager() { return StateMgr; } + const GRStateManager& getStateManager() const { return StateMgr; } + + StoreManager& getStoreManager() { return StateMgr.getStoreManager(); } + + ConstraintManager& getConstraintManager() { + return StateMgr.getConstraintManager(); + } + + // FIXME: Remove when we migrate over to just using ValueManager. + BasicValueFactory& getBasicVals() { + return StateMgr.getBasicVals(); + } + const BasicValueFactory& getBasicVals() const { + return StateMgr.getBasicVals(); + } + + ValueManager &getValueManager() { return ValMgr; } + const ValueManager &getValueManager() const { return ValMgr; } + + // FIXME: Remove when we migrate over to just using ValueManager. + SymbolManager& getSymbolManager() { return SymMgr; } + const SymbolManager& getSymbolManager() const { return SymMgr; } + +protected: + const GRState* GetState(ExplodedNode* N) { + return N == EntryNode ? CleanedState : N->getState(); + } + +public: + ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred, + const GRState* St, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind, + const void *tag = 0); +protected: + /// CheckerVisit - Dispatcher for performing checker-specific logic + /// at specific statements. + void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, + bool isPrevisit); + + bool CheckerEvalCall(const CallExpr *CE, + ExplodedNodeSet &Dst, + ExplodedNode *Pred); + + void CheckerEvalNilReceiver(const ObjCMessageExpr *ME, + ExplodedNodeSet &Dst, + const GRState *state, + ExplodedNode *Pred); + + void CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, + ExplodedNodeSet &Dst, ExplodedNodeSet &Src, + SVal location, SVal val, bool isPrevisit); + + + /// Visit - Transfer function logic for all statements. Dispatches to + /// other functions that handle specific kinds of statements. + void Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst); + + /// VisitLValue - Evaluate the lvalue of the expression. For example, if Ex is + /// a DeclRefExpr, it evaluates to the MemRegionVal which represents its + /// storage location. Note that not all kinds of expressions has lvalue. + void VisitLValue(Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst); + + /// VisitArraySubscriptExpr - Transfer function for array accesses. + void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); + + /// VisitAsmStmt - Transfer function logic for inline asm. + void VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst); + + void VisitAsmStmtHelperOutputs(AsmStmt* A, + AsmStmt::outputs_iterator I, + AsmStmt::outputs_iterator E, + ExplodedNode* Pred, ExplodedNodeSet& Dst); + + void VisitAsmStmtHelperInputs(AsmStmt* A, + AsmStmt::inputs_iterator I, + AsmStmt::inputs_iterator E, + ExplodedNode* Pred, ExplodedNodeSet& Dst); + + /// VisitBlockExpr - Transfer function logic for BlockExprs. + void VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred, ExplodedNodeSet &Dst); + + /// VisitBinaryOperator - Transfer function logic for binary operators. + void VisitBinaryOperator(BinaryOperator* B, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); + + + /// VisitCall - Transfer function for function calls. + void VisitCall(CallExpr* CE, ExplodedNode* Pred, + CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, + ExplodedNodeSet& Dst, bool asLValue); + + /// VisitCast - Transfer function logic for all casts (implicit and explicit). + void VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst, bool asLValue); + + /// VisitCompoundLiteralExpr - Transfer function logic for compound literals. + void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); + + /// VisitDeclRefExpr - Transfer function logic for DeclRefExprs. + void VisitDeclRefExpr(DeclRefExpr* DR, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); + + /// VisitBlockDeclRefExpr - Transfer function logic for BlockDeclRefExprs. + void VisitBlockDeclRefExpr(BlockDeclRefExpr* DR, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); + + void VisitCommonDeclRefExpr(Expr* DR, const NamedDecl *D,ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); + + /// VisitDeclStmt - Transfer function logic for DeclStmts. + void VisitDeclStmt(DeclStmt* DS, ExplodedNode* Pred, ExplodedNodeSet& Dst); + + /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose + void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, ExplodedNode* Pred, + ExplodedNodeSet& Dst); + + /// VisitCondInit - Transfer function for handling the initialization + /// of a condition variable in an IfStmt, SwitchStmt, etc. + void VisitCondInit(VarDecl *VD, Stmt *S, ExplodedNode *Pred, + ExplodedNodeSet& Dst); + + void VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, + ExplodedNodeSet& Dst); + + /// VisitLogicalExpr - Transfer function logic for '&&', '||' + void VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, + ExplodedNodeSet& Dst); + + /// VisitMemberExpr - Transfer function for member expressions. + void VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, ExplodedNodeSet& Dst, + bool asLValue); + + /// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs. + void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); + + /// VisitObjCForCollectionStmt - Transfer function logic for + /// ObjCForCollectionStmt. + void VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, ExplodedNode* Pred, + ExplodedNodeSet& Dst); + + void VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, + ExplodedNode* Pred, + ExplodedNodeSet& Dst, SVal ElementV); + + /// VisitObjCMessageExpr - Transfer function for ObjC message expressions. + void VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); + + /// VisitReturnStmt - Transfer function logic for return statements. + void VisitReturnStmt(ReturnStmt* R, ExplodedNode* Pred, ExplodedNodeSet& Dst); + + /// VisitSizeOfAlignOfExpr - Transfer function for sizeof. + void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, ExplodedNode* Pred, + ExplodedNodeSet& Dst); + + /// VisitUnaryOperator - Transfer function logic for unary operators. + void VisitUnaryOperator(UnaryOperator* B, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); + + void VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, + ExplodedNodeSet & Dst); + + /// Create a C++ temporary object for an rvalue. + void CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// EvalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic + /// expressions of the form 'x != 0' and generate new nodes (stored in Dst) + /// with those assumptions. + void EvalEagerlyAssume(ExplodedNodeSet& Dst, ExplodedNodeSet& Src, Expr *Ex); + + SVal EvalMinus(SVal X) { + return X.isValid() ? SVator.EvalMinus(cast(X)) : X; + } + + SVal EvalComplement(SVal X) { + return X.isValid() ? SVator.EvalComplement(cast(X)) : X; + } + +public: + + SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op, + NonLoc L, NonLoc R, QualType T) { + return SVator.EvalBinOpNN(state, op, L, R, T); + } + + SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op, + NonLoc L, SVal R, QualType T) { + return R.isValid() ? SVator.EvalBinOpNN(state,op,L, cast(R), T) : R; + } + + SVal EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op, + SVal LHS, SVal RHS, QualType T) { + return SVator.EvalBinOp(ST, Op, LHS, RHS, T); + } + +protected: + void EvalObjCMessageExpr(ExplodedNodeSet& Dst, ObjCMessageExpr* ME, + ExplodedNode* Pred, const GRState *state) { + assert (Builder && "GRStmtNodeBuilder must be defined."); + getTF().EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred, state); + } + + const GRState* MarkBranch(const GRState* St, Stmt* Terminator, + bool branchTaken); + + /// EvalBind - Handle the semantics of binding a value to a specific location. + /// This method is used by EvalStore, VisitDeclStmt, and others. + void EvalBind(ExplodedNodeSet& Dst, Stmt *AssignE, + Stmt* StoreE, ExplodedNode* Pred, + const GRState* St, SVal location, SVal Val, + bool atDeclInit = false); + +public: + // FIXME: 'tag' should be removed, and a LocationContext should be used + // instead. + void EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, + const GRState* St, SVal location, const void *tag = 0, + QualType LoadTy = QualType()); + + // FIXME: 'tag' should be removed, and a LocationContext should be used + // instead. + void EvalStore(ExplodedNodeSet& Dst, Expr* AssignE, Expr* StoreE, + ExplodedNode* Pred, const GRState* St, SVal TargetLV, SVal Val, + const void *tag = 0); +private: + void EvalLoadCommon(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, + const GRState* St, SVal location, const void *tag, + QualType LoadTy); + + // FIXME: 'tag' should be removed, and a LocationContext should be used + // instead. + void EvalLocation(ExplodedNodeSet &Dst, Stmt *S, ExplodedNode* Pred, + const GRState* St, SVal location, + const void *tag, bool isLoad); +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Checker/PathSensitive/GRExprEngineBuilders.h b/include/clang/Checker/PathSensitive/GRExprEngineBuilders.h new file mode 100644 index 000000000000..5503412f7e45 --- /dev/null +++ b/include/clang/Checker/PathSensitive/GRExprEngineBuilders.h @@ -0,0 +1,76 @@ +//===-- GRExprEngineBuilders.h - "Builder" classes for GRExprEngine -*- C++ -*-= +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines smart builder "references" which are used to marshal +// builders between GRExprEngine objects and their related components. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS +#define LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/Support/SaveAndRestore.h" + +namespace clang { + +class GRStmtNodeBuilderRef { + ExplodedNodeSet &Dst; + GRStmtNodeBuilder &B; + GRExprEngine& Eng; + ExplodedNode* Pred; + const GRState* state; + const Stmt* stmt; + const unsigned OldSize; + const bool AutoCreateNode; + SaveAndRestore OldSink; + SaveAndRestore OldTag; + SaveOr OldHasGen; + +private: + friend class GRExprEngine; + + GRStmtNodeBuilderRef(); // do not implement + void operator=(const GRStmtNodeBuilderRef&); // do not implement + + GRStmtNodeBuilderRef(ExplodedNodeSet &dst, + GRStmtNodeBuilder &builder, + GRExprEngine& eng, + ExplodedNode* pred, + const GRState *st, + const Stmt* s, bool auto_create_node) + : Dst(dst), B(builder), Eng(eng), Pred(pred), + state(st), stmt(s), OldSize(Dst.size()), AutoCreateNode(auto_create_node), + OldSink(B.BuildSinks), OldTag(B.Tag), OldHasGen(B.HasGeneratedNode) {} + +public: + + ~GRStmtNodeBuilderRef() { + // Handle the case where no nodes where generated. Auto-generate that + // contains the updated state if we aren't generating sinks. + if (!B.BuildSinks && Dst.size() == OldSize && !B.HasGeneratedNode) { + if (AutoCreateNode) + B.MakeNode(Dst, const_cast(stmt), Pred, state); + else + Dst.Add(Pred); + } + } + + const GRState *getState() { return state; } + + GRStateManager& getStateManager() { + return Eng.getStateManager(); + } + + ExplodedNode* MakeNode(const GRState* state) { + return B.MakeNode(Dst, const_cast(stmt), Pred, state); + } +}; + +} // end clang namespace +#endif diff --git a/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h b/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h new file mode 100644 index 000000000000..383463b822cb --- /dev/null +++ b/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h @@ -0,0 +1,40 @@ +// GRCheckAPI.h - Simple API checks based on GRAuditor ------------*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface for building simple, path-sensitive checks +// that are stateless and only emit warnings at errors that occur at +// CallExpr or ObjCMessageExpr. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GRAPICHECKS +#define LLVM_CLANG_ANALYSIS_GRAPICHECKS + +#include "clang/Checker/PathSensitive/GRAuditor.h" +#include "clang/Checker/PathSensitive/GRState.h" + +namespace clang { + +class Diagnostic; +class BugReporter; +class ASTContext; +class GRExprEngine; +class PathDiagnosticClient; +class ExplodedGraph; + + +class GRSimpleAPICheck : public GRAuditor { +public: + GRSimpleAPICheck() {} + virtual ~GRSimpleAPICheck() {} +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Checker/PathSensitive/GRState.h b/include/clang/Checker/PathSensitive/GRState.h new file mode 100644 index 000000000000..4e44697a272f --- /dev/null +++ b/include/clang/Checker/PathSensitive/GRState.h @@ -0,0 +1,756 @@ +//== GRState*h - Path-Sens. "State" for tracking valuues -----*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines SymbolRef, ExprBindKey, and GRState* +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_VALUESTATE_H +#define LLVM_CLANG_ANALYSIS_VALUESTATE_H + +// FIXME: Reduce the number of includes. + +#include "clang/Checker/PathSensitive/Environment.h" +#include "clang/Checker/PathSensitive/Store.h" +#include "clang/Checker/PathSensitive/ConstraintManager.h" +#include "clang/Checker/PathSensitive/ValueManager.h" +#include "clang/Checker/PathSensitive/GRCoreEngine.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/ASTContext.h" +#include "clang/Analysis/Analyses/LiveVariables.h" +#include "llvm/Support/Casting.h" +#include "llvm/System/DataTypes.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/raw_ostream.h" + +#include + +namespace clang { + +class GRStateManager; +class Checker; + +typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&, + GRSubEngine&); +typedef StoreManager* (*StoreManagerCreator)(GRStateManager&); + +//===----------------------------------------------------------------------===// +// GRStateTrait - Traits used by the Generic Data Map of a GRState. +//===----------------------------------------------------------------------===// + +template struct GRStatePartialTrait; + +template struct GRStateTrait { + typedef typename T::data_type data_type; + static inline void* GDMIndex() { return &T::TagInt; } + static inline void* MakeVoidPtr(data_type D) { return (void*) D; } + static inline data_type MakeData(void* const* P) { + return P ? (data_type) *P : (data_type) 0; + } +}; + +//===----------------------------------------------------------------------===// +// GRState- An ImmutableMap type Stmt*/Decl*/Symbols to SVals. +//===----------------------------------------------------------------------===// + +class GRStateManager; + +/// GRState - This class encapsulates the actual data values for +/// for a "state" in our symbolic value tracking. It is intended to be +/// used as a functional object; that is once it is created and made +/// "persistent" in a FoldingSet its values will never change. +class GRState : public llvm::FoldingSetNode { +public: + typedef llvm::ImmutableSet IntSetTy; + typedef llvm::ImmutableMap GenericDataMap; + +private: + void operator=(const GRState& R) const; + + friend class GRStateManager; + + GRStateManager *StateMgr; + Environment Env; + Store St; + + // FIXME: Make these private. +public: + GenericDataMap GDM; + +public: + + /// This ctor is used when creating the first GRState object. + GRState(GRStateManager *mgr, const Environment& env, + Store st, GenericDataMap gdm) + : StateMgr(mgr), + Env(env), + St(st), + GDM(gdm) {} + + /// Copy ctor - We must explicitly define this or else the "Next" ptr + /// in FoldingSetNode will also get copied. + GRState(const GRState& RHS) + : llvm::FoldingSetNode(), + StateMgr(RHS.StateMgr), + Env(RHS.Env), + St(RHS.St), + GDM(RHS.GDM) {} + + /// getStateManager - Return the GRStateManager associated with this state. + GRStateManager &getStateManager() const { + return *StateMgr; + } + + /// getAnalysisContext - Return the AnalysisContext associated with this + /// state. + AnalysisContext &getAnalysisContext() const { + return Env.getAnalysisContext(); + } + + /// getEnvironment - Return the environment associated with this state. + /// The environment is the mapping from expressions to values. + const Environment& getEnvironment() const { return Env; } + + /// getStore - Return the store associated with this state. The store + /// is a mapping from locations to values. + Store getStore() const { return St; } + + void setStore(Store s) { St = s; } + + /// getGDM - Return the generic data map associated with this state. + GenericDataMap getGDM() const { return GDM; } + + void setGDM(GenericDataMap gdm) { GDM = gdm; } + + /// Profile - Profile the contents of a GRState object for use + /// in a FoldingSet. + static void Profile(llvm::FoldingSetNodeID& ID, const GRState* V) { + // FIXME: Do we need to include the AnalysisContext in the profile? + V->Env.Profile(ID); + ID.AddPointer(V->St); + V->GDM.Profile(ID); + } + + /// Profile - Used to profile the contents of this object for inclusion + /// in a FoldingSet. + void Profile(llvm::FoldingSetNodeID& ID) const { + Profile(ID, this); + } + + SVal LookupExpr(Expr* E) const { + return Env.LookupExpr(E); + } + + /// makeWithStore - Return a GRState with the same values as the current + /// state with the exception of using the specified Store. + const GRState *makeWithStore(Store store) const; + + BasicValueFactory &getBasicVals() const; + SymbolManager &getSymbolManager() const; + + //==---------------------------------------------------------------------==// + // Constraints on values. + //==---------------------------------------------------------------------==// + // + // Each GRState records constraints on symbolic values. These constraints + // are managed using the ConstraintManager associated with a GRStateManager. + // As constraints gradually accrue on symbolic values, added constraints + // may conflict and indicate that a state is infeasible (as no real values + // could satisfy all the constraints). This is the principal mechanism + // for modeling path-sensitivity in GRExprEngine/GRState. + // + // Various "Assume" methods form the interface for adding constraints to + // symbolic values. A call to "Assume" indicates an assumption being placed + // on one or symbolic values. Assume methods take the following inputs: + // + // (1) A GRState object representing the current state. + // + // (2) The assumed constraint (which is specific to a given "Assume" method). + // + // (3) A binary value "Assumption" that indicates whether the constraint is + // assumed to be true or false. + // + // The output of "Assume" are two values: + // + // (a) "isFeasible" is set to true or false to indicate whether or not + // the assumption is feasible. + // + // (b) A new GRState object with the added constraints. + // + // FIXME: (a) should probably disappear since it is redundant with (b). + // (i.e., (b) could just be set to NULL). + // + + const GRState *Assume(DefinedOrUnknownSVal cond, bool assumption) const; + + std::pair + Assume(DefinedOrUnknownSVal cond) const; + + const GRState *AssumeInBound(DefinedOrUnknownSVal idx, + DefinedOrUnknownSVal upperBound, + bool assumption) const; + + //==---------------------------------------------------------------------==// + // Utility methods for getting regions. + //==---------------------------------------------------------------------==// + + const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const; + + //==---------------------------------------------------------------------==// + // Binding and retrieving values to/from the environment and symbolic store. + //==---------------------------------------------------------------------==// + + /// BindCompoundLiteral - Return the state that has the bindings currently + /// in 'state' plus the bindings for the CompoundLiteral. 'R' is the region + /// for the compound literal and 'BegInit' and 'EndInit' represent an + /// array of initializer values. + const GRState *bindCompoundLiteral(const CompoundLiteralExpr* CL, + const LocationContext *LC, + SVal V) const; + + const GRState *BindExpr(const Stmt *S, SVal V, bool Invalidate = true) const; + + const GRState *bindDecl(const VarRegion *VR, SVal V) const; + + const GRState *bindDeclWithNoInit(const VarRegion *VR) const; + + const GRState *bindLoc(Loc location, SVal V) const; + + const GRState *bindLoc(SVal location, SVal V) const; + + const GRState *unbindLoc(Loc LV) const; + + /// Get the lvalue for a variable reference. + SVal getLValue(const VarDecl *D, const LocationContext *LC) const; + + /// Get the lvalue for a StringLiteral. + SVal getLValue(const StringLiteral *literal) const; + + SVal getLValue(const CompoundLiteralExpr *literal, + const LocationContext *LC) const; + + /// Get the lvalue for an ivar reference. + SVal getLValue(const ObjCIvarDecl *decl, SVal base) const; + + /// Get the lvalue for a field reference. + SVal getLValue(const FieldDecl *decl, SVal Base) const; + + /// Get the lvalue for an array index. + SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const; + + const llvm::APSInt *getSymVal(SymbolRef sym) const; + + SVal getSVal(const Stmt* Ex) const; + + SVal getSValAsScalarOrLoc(const Stmt *Ex) const; + + SVal getSVal(Loc LV, QualType T = QualType()) const; + + SVal getSVal(const MemRegion* R) const; + + SVal getSValAsScalarOrLoc(const MemRegion *R) const; + + const llvm::APSInt *getSymVal(SymbolRef sym); + + bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const; + + bool scanReachableSymbols(const SVal *I, const SVal *E, + SymbolVisitor &visitor) const; + + bool scanReachableSymbols(const MemRegion * const *I, + const MemRegion * const *E, + SymbolVisitor &visitor) const; + + template CB scanReachableSymbols(SVal val) const; + template CB scanReachableSymbols(const SVal *beg, + const SVal *end) const; + + template CB + scanReachableSymbols(const MemRegion * const *beg, + const MemRegion * const *end) const; + + //==---------------------------------------------------------------------==// + // Accessing the Generic Data Map (GDM). + //==---------------------------------------------------------------------==// + + void* const* FindGDM(void* K) const; + + template + const GRState *add(typename GRStateTrait::key_type K) const; + + template + typename GRStateTrait::data_type + get() const { + return GRStateTrait::MakeData(FindGDM(GRStateTrait::GDMIndex())); + } + + template + typename GRStateTrait::lookup_type + get(typename GRStateTrait::key_type key) const { + void* const* d = FindGDM(GRStateTrait::GDMIndex()); + return GRStateTrait::Lookup(GRStateTrait::MakeData(d), key); + } + + template + typename GRStateTrait::context_type get_context() const; + + + template + const GRState *remove(typename GRStateTrait::key_type K) const; + + template + const GRState *remove(typename GRStateTrait::key_type K, + typename GRStateTrait::context_type C) const; + + template + const GRState *set(typename GRStateTrait::data_type D) const; + + template + const GRState *set(typename GRStateTrait::key_type K, + typename GRStateTrait::value_type E) const; + + template + const GRState *set(typename GRStateTrait::key_type K, + typename GRStateTrait::value_type E, + typename GRStateTrait::context_type C) const; + + template + bool contains(typename GRStateTrait::key_type key) const { + void* const* d = FindGDM(GRStateTrait::GDMIndex()); + return GRStateTrait::Contains(GRStateTrait::MakeData(d), key); + } + + // State pretty-printing. + class Printer { + public: + virtual ~Printer() {} + virtual void Print(llvm::raw_ostream& Out, const GRState* state, + const char* nl, const char* sep) = 0; + }; + + // Pretty-printing. + void print(llvm::raw_ostream& Out, const char *nl = "\n", + const char *sep = "") const; + + void printStdErr() const; + + void printDOT(llvm::raw_ostream& Out) const; +}; + +class GRStateSet { + typedef llvm::SmallPtrSet ImplTy; + ImplTy Impl; +public: + GRStateSet() {} + + inline void Add(const GRState* St) { + Impl.insert(St); + } + + typedef ImplTy::const_iterator iterator; + + inline unsigned size() const { return Impl.size(); } + inline bool empty() const { return Impl.empty(); } + + inline iterator begin() const { return Impl.begin(); } + inline iterator end() const { return Impl.end(); } + + class AutoPopulate { + GRStateSet& S; + unsigned StartSize; + const GRState* St; + public: + AutoPopulate(GRStateSet& s, const GRState* st) + : S(s), StartSize(S.size()), St(st) {} + + ~AutoPopulate() { + if (StartSize == S.size()) + S.Add(St); + } + }; +}; + +//===----------------------------------------------------------------------===// +// GRStateManager - Factory object for GRStates. +//===----------------------------------------------------------------------===// + +class GRStateManager { + friend class GRState; + friend class GRExprEngine; // FIXME: Remove. +private: + EnvironmentManager EnvMgr; + llvm::OwningPtr StoreMgr; + llvm::OwningPtr ConstraintMgr; + + GRState::GenericDataMap::Factory GDMFactory; + + typedef llvm::DenseMap > GDMContextsTy; + GDMContextsTy GDMContexts; + + /// Printers - A set of printer objects used for pretty-printing a GRState. + /// GRStateManager owns these objects. + std::vector Printers; + + /// StateSet - FoldingSet containing all the states created for analyzing + /// a particular function. This is used to unique states. + llvm::FoldingSet StateSet; + + /// ValueMgr - Object that manages the data for all created SVals. + ValueManager ValueMgr; + + /// Alloc - A BumpPtrAllocator to allocate states. + llvm::BumpPtrAllocator &Alloc; + +public: + GRStateManager(ASTContext& Ctx, + StoreManagerCreator CreateStoreManager, + ConstraintManagerCreator CreateConstraintManager, + llvm::BumpPtrAllocator& alloc, + GRSubEngine &subeng) + : EnvMgr(alloc), + GDMFactory(alloc), + ValueMgr(alloc, Ctx, *this), + Alloc(alloc) { + StoreMgr.reset((*CreateStoreManager)(*this)); + ConstraintMgr.reset((*CreateConstraintManager)(*this, subeng)); + } + + ~GRStateManager(); + + const GRState *getInitialState(const LocationContext *InitLoc); + + ASTContext &getContext() { return ValueMgr.getContext(); } + const ASTContext &getContext() const { return ValueMgr.getContext(); } + + BasicValueFactory &getBasicVals() { + return ValueMgr.getBasicValueFactory(); + } + const BasicValueFactory& getBasicVals() const { + return ValueMgr.getBasicValueFactory(); + } + + SymbolManager &getSymbolManager() { + return ValueMgr.getSymbolManager(); + } + const SymbolManager &getSymbolManager() const { + return ValueMgr.getSymbolManager(); + } + + ValueManager &getValueManager() { return ValueMgr; } + const ValueManager &getValueManager() const { return ValueMgr; } + + llvm::BumpPtrAllocator& getAllocator() { return Alloc; } + + MemRegionManager& getRegionManager() { + return ValueMgr.getRegionManager(); + } + const MemRegionManager& getRegionManager() const { + return ValueMgr.getRegionManager(); + } + + StoreManager& getStoreManager() { return *StoreMgr; } + ConstraintManager& getConstraintManager() { return *ConstraintMgr; } + + const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc, + SymbolReaper& SymReaper); + +public: + + SVal ArrayToPointer(Loc Array) { + return StoreMgr->ArrayToPointer(Array); + } + + // Methods that manipulate the GDM. + const GRState* addGDM(const GRState* St, void* Key, void* Data); + + // Methods that query & manipulate the Store. + + void iterBindings(const GRState* state, StoreManager::BindingsHandler& F) { + StoreMgr->iterBindings(state->getStore(), F); + } + + const GRState* getPersistentState(GRState& Impl); + + bool isEqual(const GRState* state, const Expr* Ex, const llvm::APSInt& V); + bool isEqual(const GRState* state, const Expr* Ex, uint64_t); + + //==---------------------------------------------------------------------==// + // Generic Data Map methods. + //==---------------------------------------------------------------------==// + // + // GRStateManager and GRState support a "generic data map" that allows + // different clients of GRState objects to embed arbitrary data within a + // GRState object. The generic data map is essentially an immutable map + // from a "tag" (that acts as the "key" for a client) and opaque values. + // Tags/keys and values are simply void* values. The typical way that clients + // generate unique tags are by taking the address of a static variable. + // Clients are responsible for ensuring that data values referred to by a + // the data pointer are immutable (and thus are essentially purely functional + // data). + // + // The templated methods below use the GRStateTrait class + // to resolve keys into the GDM and to return data values to clients. + // + + // Trait based GDM dispatch. + template + const GRState* set(const GRState* st, typename GRStateTrait::data_type D) { + return addGDM(st, GRStateTrait::GDMIndex(), + GRStateTrait::MakeVoidPtr(D)); + } + + template + const GRState* set(const GRState* st, + typename GRStateTrait::key_type K, + typename GRStateTrait::value_type V, + typename GRStateTrait::context_type C) { + + return addGDM(st, GRStateTrait::GDMIndex(), + GRStateTrait::MakeVoidPtr(GRStateTrait::Set(st->get(), K, V, C))); + } + + template + const GRState* add(const GRState* st, + typename GRStateTrait::key_type K, + typename GRStateTrait::context_type C) { + return addGDM(st, GRStateTrait::GDMIndex(), + GRStateTrait::MakeVoidPtr(GRStateTrait::Add(st->get(), K, C))); + } + + template + const GRState* remove(const GRState* st, + typename GRStateTrait::key_type K, + typename GRStateTrait::context_type C) { + + return addGDM(st, GRStateTrait::GDMIndex(), + GRStateTrait::MakeVoidPtr(GRStateTrait::Remove(st->get(), K, C))); + } + + + void* FindGDMContext(void* index, + void* (*CreateContext)(llvm::BumpPtrAllocator&), + void (*DeleteContext)(void*)); + + template + typename GRStateTrait::context_type get_context() { + void* p = FindGDMContext(GRStateTrait::GDMIndex(), + GRStateTrait::CreateContext, + GRStateTrait::DeleteContext); + + return GRStateTrait::MakeContext(p); + } + + const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) { + return ConstraintMgr->getSymVal(St, sym); + } + + void EndPath(const GRState* St) { + ConstraintMgr->EndPath(St); + } +}; + + +//===----------------------------------------------------------------------===// +// Out-of-line method definitions for GRState. +//===----------------------------------------------------------------------===// + +inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) { + return getStateManager().getSymVal(this, sym); +} + +inline const VarRegion* GRState::getRegion(const VarDecl *D, + const LocationContext *LC) const { + return getStateManager().getRegionManager().getVarRegion(D, LC); +} + +inline const GRState *GRState::Assume(DefinedOrUnknownSVal Cond, + bool Assumption) const { + if (Cond.isUnknown()) + return this; + + return getStateManager().ConstraintMgr->Assume(this, cast(Cond), + Assumption); +} + +inline std::pair +GRState::Assume(DefinedOrUnknownSVal Cond) const { + if (Cond.isUnknown()) + return std::make_pair(this, this); + + return getStateManager().ConstraintMgr->AssumeDual(this, + cast(Cond)); +} + +inline const GRState *GRState::AssumeInBound(DefinedOrUnknownSVal Idx, + DefinedOrUnknownSVal UpperBound, + bool Assumption) const { + if (Idx.isUnknown() || UpperBound.isUnknown()) + return this; + + ConstraintManager &CM = *getStateManager().ConstraintMgr; + return CM.AssumeInBound(this, cast(Idx), + cast(UpperBound), Assumption); +} + +inline const GRState * +GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL, + const LocationContext *LC, SVal V) const { + Store new_store = + getStateManager().StoreMgr->BindCompoundLiteral(St, CL, LC, V); + return makeWithStore(new_store); +} + +inline const GRState *GRState::bindDecl(const VarRegion* VR, SVal IVal) const { + Store new_store = getStateManager().StoreMgr->BindDecl(St, VR, IVal); + return makeWithStore(new_store); +} + +inline const GRState *GRState::bindDeclWithNoInit(const VarRegion* VR) const { + Store new_store = getStateManager().StoreMgr->BindDeclWithNoInit(St, VR); + return makeWithStore(new_store); +} + +inline const GRState *GRState::bindLoc(Loc LV, SVal V) const { + Store new_store = getStateManager().StoreMgr->Bind(St, LV, V); + return makeWithStore(new_store); +} + +inline const GRState *GRState::bindLoc(SVal LV, SVal V) const { + return !isa(LV) ? this : bindLoc(cast(LV), V); +} + +inline SVal GRState::getLValue(const VarDecl* VD, + const LocationContext *LC) const { + return getStateManager().StoreMgr->getLValueVar(VD, LC); +} + +inline SVal GRState::getLValue(const StringLiteral *literal) const { + return getStateManager().StoreMgr->getLValueString(literal); +} + +inline SVal GRState::getLValue(const CompoundLiteralExpr *literal, + const LocationContext *LC) const { + return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, LC); +} + +inline SVal GRState::getLValue(const ObjCIvarDecl *D, SVal Base) const { + return getStateManager().StoreMgr->getLValueIvar(D, Base); +} + +inline SVal GRState::getLValue(const FieldDecl* D, SVal Base) const { + return getStateManager().StoreMgr->getLValueField(D, Base); +} + +inline SVal GRState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{ + return getStateManager().StoreMgr->getLValueElement(ElementType, Idx, Base); +} + +inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) const { + return getStateManager().getSymVal(this, sym); +} + +inline SVal GRState::getSVal(const Stmt* Ex) const { + return Env.GetSVal(Ex, getStateManager().ValueMgr); +} + +inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const { + if (const Expr *Ex = dyn_cast(S)) { + QualType T = Ex->getType(); + if (Loc::IsLocType(T) || T->isIntegerType()) + return getSVal(S); + } + + return UnknownVal(); +} + +inline SVal GRState::getSVal(Loc LV, QualType T) const { + return getStateManager().StoreMgr->Retrieve(St, LV, T); +} + +inline SVal GRState::getSVal(const MemRegion* R) const { + return getStateManager().StoreMgr->Retrieve(St, loc::MemRegionVal(R)); +} + +inline BasicValueFactory &GRState::getBasicVals() const { + return getStateManager().getBasicVals(); +} + +inline SymbolManager &GRState::getSymbolManager() const { + return getStateManager().getSymbolManager(); +} + +template +const GRState *GRState::add(typename GRStateTrait::key_type K) const { + return getStateManager().add(this, K, get_context()); +} + +template +typename GRStateTrait::context_type GRState::get_context() const { + return getStateManager().get_context(); +} + +template +const GRState *GRState::remove(typename GRStateTrait::key_type K) const { + return getStateManager().remove(this, K, get_context()); +} + +template +const GRState *GRState::remove(typename GRStateTrait::key_type K, + typename GRStateTrait::context_type C) const { + return getStateManager().remove(this, K, C); +} + +template +const GRState *GRState::set(typename GRStateTrait::data_type D) const { + return getStateManager().set(this, D); +} + +template +const GRState *GRState::set(typename GRStateTrait::key_type K, + typename GRStateTrait::value_type E) const { + return getStateManager().set(this, K, E, get_context()); +} + +template +const GRState *GRState::set(typename GRStateTrait::key_type K, + typename GRStateTrait::value_type E, + typename GRStateTrait::context_type C) const { + return getStateManager().set(this, K, E, C); +} + +template +CB GRState::scanReachableSymbols(SVal val) const { + CB cb(this); + scanReachableSymbols(val, cb); + return cb; +} + +template +CB GRState::scanReachableSymbols(const SVal *beg, const SVal *end) const { + CB cb(this); + scanReachableSymbols(beg, end, cb); + return cb; +} + +template +CB GRState::scanReachableSymbols(const MemRegion * const *beg, + const MemRegion * const *end) const { + CB cb(this); + scanReachableSymbols(beg, end, cb); + return cb; +} +} // end clang namespace + +#endif diff --git a/include/clang/Checker/PathSensitive/GRStateTrait.h b/include/clang/Checker/PathSensitive/GRStateTrait.h new file mode 100644 index 000000000000..5189a1f5aa7e --- /dev/null +++ b/include/clang/Checker/PathSensitive/GRStateTrait.h @@ -0,0 +1,148 @@ +//==- GRStateTrait.h - Partial implementations of GRStateTrait -----*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines partial implementations of template specializations of +// the class GRStateTrait<>. GRStateTrait<> is used by GRState to implement +// set/get methods for mapulating a GRState's generic data map. +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H +#define LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H + +namespace llvm { + class BumpPtrAllocator; + template class ImmutableMap; + template class ImmutableSet; + template class ImmutableList; + template class ImmutableListImpl; +} + +namespace clang { + template struct GRStatePartialTrait; + + // Partial-specialization for ImmutableMap. + + template + struct GRStatePartialTrait< llvm::ImmutableMap > { + typedef llvm::ImmutableMap data_type; + typedef typename data_type::Factory& context_type; + typedef Key key_type; + typedef Data value_type; + typedef const value_type* lookup_type; + + static inline data_type MakeData(void* const* p) { + return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0); + } + static inline void* MakeVoidPtr(data_type B) { + return B.getRoot(); + } + static lookup_type Lookup(data_type B, key_type K) { + return B.lookup(K); + } + static data_type Set(data_type B, key_type K, value_type E,context_type F){ + return F.Add(B, K, E); + } + + static data_type Remove(data_type B, key_type K, context_type F) { + return F.Remove(B, K); + } + + static inline context_type MakeContext(void* p) { + return *((typename data_type::Factory*) p); + } + + static void* CreateContext(llvm::BumpPtrAllocator& Alloc) { + return new typename data_type::Factory(Alloc); + } + + static void DeleteContext(void* Ctx) { + delete (typename data_type::Factory*) Ctx; + } + }; + + + // Partial-specialization for ImmutableSet. + + template + struct GRStatePartialTrait< llvm::ImmutableSet > { + typedef llvm::ImmutableSet data_type; + typedef typename data_type::Factory& context_type; + typedef Key key_type; + + static inline data_type MakeData(void* const* p) { + return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0); + } + + static inline void* MakeVoidPtr(data_type B) { + return B.getRoot(); + } + + static data_type Add(data_type B, key_type K, context_type F) { + return F.Add(B, K); + } + + static data_type Remove(data_type B, key_type K, context_type F) { + return F.Remove(B, K); + } + + static bool Contains(data_type B, key_type K) { + return B.contains(K); + } + + static inline context_type MakeContext(void* p) { + return *((typename data_type::Factory*) p); + } + + static void* CreateContext(llvm::BumpPtrAllocator& Alloc) { + return new typename data_type::Factory(Alloc); + } + + static void DeleteContext(void* Ctx) { + delete (typename data_type::Factory*) Ctx; + } + }; + + // Partial-specialization for ImmutableList. + + template + struct GRStatePartialTrait< llvm::ImmutableList > { + typedef llvm::ImmutableList data_type; + typedef T key_type; + typedef typename data_type::Factory& context_type; + + static data_type Add(data_type L, key_type K, context_type F) { + return F.Add(K, L); + } + + static inline data_type MakeData(void* const* p) { + return p ? data_type((const llvm::ImmutableListImpl*) *p) + : data_type(0); + } + + static inline void* MakeVoidPtr(data_type D) { + return (void*) D.getInternalPointer(); + } + + static inline context_type MakeContext(void* p) { + return *((typename data_type::Factory*) p); + } + + static void* CreateContext(llvm::BumpPtrAllocator& Alloc) { + return new typename data_type::Factory(Alloc); + } + + static void DeleteContext(void* Ctx) { + delete (typename data_type::Factory*) Ctx; + } + }; +} // end clang namespace + +#endif diff --git a/include/clang/Checker/PathSensitive/GRSubEngine.h b/include/clang/Checker/PathSensitive/GRSubEngine.h new file mode 100644 index 000000000000..ce57c2c68b4b --- /dev/null +++ b/include/clang/Checker/PathSensitive/GRSubEngine.h @@ -0,0 +1,75 @@ +//== GRSubEngine.h - Interface of the subengine of GRCoreEngine ----*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface of a subengine of the GRCoreEngine. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_ANALYSIS_GRSUBENGINE_H +#define LLVM_CLANG_ANALYSIS_GRSUBENGINE_H + +#include "clang/Checker/PathSensitive/SVals.h" + +namespace clang { + +class Stmt; +class CFGBlock; +class CFGElement; +class GRState; +class GRStateManager; +class GRBlockCounter; +class GRStmtNodeBuilder; +class GRBranchNodeBuilder; +class GRIndirectGotoNodeBuilder; +class GRSwitchNodeBuilder; +class GREndPathNodeBuilder; +class LocationContext; + +class GRSubEngine { +public: + virtual ~GRSubEngine() {} + + virtual const GRState* getInitialState(const LocationContext *InitLoc) = 0; + + virtual GRStateManager& getStateManager() = 0; + + /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor + /// nodes by processing the 'effects' of a block-level statement. + virtual void ProcessStmt(CFGElement E, GRStmtNodeBuilder& builder) = 0; + + /// ProcessBlockEntrance - Called by GRCoreEngine when start processing + /// a CFGBlock. This method returns true if the analysis should continue + /// exploring the given path, and false otherwise. + virtual bool ProcessBlockEntrance(CFGBlock* B, const GRState* St, + GRBlockCounter BC) = 0; + + /// ProcessBranch - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a branch condition. + virtual void ProcessBranch(Stmt* Condition, Stmt* Term, + GRBranchNodeBuilder& builder) = 0; + + /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a computed goto jump. + virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) = 0; + + /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a switch statement. + virtual void ProcessSwitch(GRSwitchNodeBuilder& builder) = 0; + + /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path + /// nodes when the control reaches the end of a function. + virtual void ProcessEndPath(GREndPathNodeBuilder& builder) = 0; + + /// EvalAssume - Called by ConstraintManager. Used to call checker-specific + /// logic for handling assumptions on symbolic values. + virtual const GRState* ProcessAssume(const GRState *state, + SVal cond, bool assumption) = 0; +}; +} + +#endif diff --git a/include/clang/Checker/PathSensitive/GRTransferFuncs.h b/include/clang/Checker/PathSensitive/GRTransferFuncs.h new file mode 100644 index 000000000000..04634effd587 --- /dev/null +++ b/include/clang/Checker/PathSensitive/GRTransferFuncs.h @@ -0,0 +1,85 @@ +//== GRTransferFuncs.h - Path-Sens. Transfer Functions Interface -*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines GRTransferFuncs, which provides a base-class that +// defines an interface for transfer functions used by GRExprEngine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GRTF +#define LLVM_CLANG_ANALYSIS_GRTF + +#include "clang/Checker/PathSensitive/SVals.h" +#include "clang/Checker/PathSensitive/GRCoreEngine.h" +#include "clang/Checker/PathSensitive/GRState.h" +#include + +namespace clang { + +class GRExprEngine; +class ObjCMessageExpr; +class GRStmtNodeBuilderRef; + +class GRTransferFuncs { +public: + GRTransferFuncs() {} + virtual ~GRTransferFuncs() {} + + virtual void RegisterPrinters(std::vector& Printers) {} + virtual void RegisterChecks(GRExprEngine& Eng) {} + + + // Calls. + + virtual void EvalCall(ExplodedNodeSet& Dst, + GRExprEngine& Engine, + GRStmtNodeBuilder& Builder, + CallExpr* CE, SVal L, + ExplodedNode* Pred) {} + + virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst, + GRExprEngine& Engine, + GRStmtNodeBuilder& Builder, + ObjCMessageExpr* ME, + ExplodedNode* Pred, + const GRState *state) {} + + // Stores. + + virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) {} + + // End-of-path and dead symbol notification. + + virtual void EvalEndPath(GRExprEngine& Engine, + GREndPathNodeBuilder& Builder) {} + + + virtual void EvalDeadSymbols(ExplodedNodeSet& Dst, + GRExprEngine& Engine, + GRStmtNodeBuilder& Builder, + ExplodedNode* Pred, + Stmt* S, const GRState* state, + SymbolReaper& SymReaper) {} + + // Return statements. + virtual void EvalReturn(ExplodedNodeSet& Dst, + GRExprEngine& Engine, + GRStmtNodeBuilder& Builder, + ReturnStmt* S, + ExplodedNode* Pred) {} + + // Assumptions. + virtual const GRState* EvalAssume(const GRState *state, + SVal Cond, bool Assumption) { + return state; + } +}; +} // end clang namespace + +#endif diff --git a/include/clang/Checker/PathSensitive/GRWorkList.h b/include/clang/Checker/PathSensitive/GRWorkList.h new file mode 100644 index 000000000000..b8f90fa1eea1 --- /dev/null +++ b/include/clang/Checker/PathSensitive/GRWorkList.h @@ -0,0 +1,79 @@ +//==- GRWorkList.h - Worklist class used by GRCoreEngine -----------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines GRWorkList, a pure virtual class that represents an opaque +// worklist used by GRCoreEngine to explore the reachability state space. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GRWORKLIST +#define LLVM_CLANG_ANALYSIS_GRWORKLIST + +#include "clang/Checker/PathSensitive/GRBlockCounter.h" +#include + +namespace clang { + +class CFGBlock; +class ExplodedNode; +class ExplodedNodeImpl; + +class GRWorkListUnit { + ExplodedNode* Node; + GRBlockCounter Counter; + CFGBlock* Block; + unsigned BlockIdx; // This is the index of the next statement. + +public: + GRWorkListUnit(ExplodedNode* N, GRBlockCounter C, + CFGBlock* B, unsigned idx) + : Node(N), + Counter(C), + Block(B), + BlockIdx(idx) {} + + explicit GRWorkListUnit(ExplodedNode* N, GRBlockCounter C) + : Node(N), + Counter(C), + Block(NULL), + BlockIdx(0) {} + + ExplodedNode* getNode() const { return Node; } + GRBlockCounter getBlockCounter() const { return Counter; } + CFGBlock* getBlock() const { return Block; } + unsigned getIndex() const { return BlockIdx; } +}; + +class GRWorkList { + GRBlockCounter CurrentCounter; +public: + virtual ~GRWorkList(); + virtual bool hasWork() const = 0; + + virtual void Enqueue(const GRWorkListUnit& U) = 0; + + void Enqueue(ExplodedNode* N, CFGBlock& B, unsigned idx) { + Enqueue(GRWorkListUnit(N, CurrentCounter, &B, idx)); + } + + void Enqueue(ExplodedNode* N) { + Enqueue(GRWorkListUnit(N, CurrentCounter)); + } + + virtual GRWorkListUnit Dequeue() = 0; + + void setBlockCounter(GRBlockCounter C) { CurrentCounter = C; } + GRBlockCounter getBlockCounter() const { return CurrentCounter; } + + static GRWorkList *MakeDFS(); + static GRWorkList *MakeBFS(); + static GRWorkList *MakeBFSBlockDFSContents(); +}; +} // end clang namespace +#endif diff --git a/include/clang/Checker/PathSensitive/MemRegion.h b/include/clang/Checker/PathSensitive/MemRegion.h new file mode 100644 index 000000000000..12bc0b795685 --- /dev/null +++ b/include/clang/Checker/PathSensitive/MemRegion.h @@ -0,0 +1,974 @@ +//== MemRegion.h - Abstract memory regions for static analysis --*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines MemRegion and its subclasses. MemRegion defines a +// partially-typed abstraction of memory useful for path-sensitive dataflow +// analyses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_MEMREGION_H +#define LLVM_CLANG_ANALYSIS_MEMREGION_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Checker/PathSensitive/SymbolManager.h" +#include "clang/Checker/PathSensitive/SVals.h" +#include "clang/AST/ASTContext.h" +#include "llvm/Support/Casting.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableList.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/Support/Allocator.h" +#include + +namespace llvm { class raw_ostream; } + +namespace clang { + +class MemRegionManager; +class MemSpaceRegion; +class LocationContext; +class StackFrameContext; +class VarRegion; + +//===----------------------------------------------------------------------===// +// Base region classes. +//===----------------------------------------------------------------------===// + +/// MemRegion - The root abstract class for all memory regions. +class MemRegion : public llvm::FoldingSetNode { + friend class MemRegionManager; +public: + enum Kind { + // Memory spaces. + BEG_MEMSPACES, + GenericMemSpaceRegionKind = BEG_MEMSPACES, + StackLocalsSpaceRegionKind, + StackArgumentsSpaceRegionKind, + HeapSpaceRegionKind, + UnknownSpaceRegionKind, + GlobalsSpaceRegionKind, + END_MEMSPACES = GlobalsSpaceRegionKind, + // Untyped regions. + SymbolicRegionKind, + AllocaRegionKind, + // Typed regions. + BEG_TYPED_REGIONS, + FunctionTextRegionKind = BEG_TYPED_REGIONS, + BlockTextRegionKind, + BlockDataRegionKind, + CompoundLiteralRegionKind, + CXXThisRegionKind, + StringRegionKind, + ElementRegionKind, + // Decl Regions. + BEG_DECL_REGIONS, + VarRegionKind = BEG_DECL_REGIONS, + FieldRegionKind, + ObjCIvarRegionKind, + CXXObjectRegionKind, + END_DECL_REGIONS = CXXObjectRegionKind, + END_TYPED_REGIONS = END_DECL_REGIONS + }; + +private: + const Kind kind; + +protected: + MemRegion(Kind k) : kind(k) {} + virtual ~MemRegion(); + +public: + ASTContext &getContext() const; + + virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0; + + virtual MemRegionManager* getMemRegionManager() const = 0; + + std::string getString() const; + + const MemSpaceRegion *getMemorySpace() const; + + const MemRegion *getBaseRegion() const; + + const MemRegion *StripCasts() const; + + bool hasGlobalsOrParametersStorage() const; + + bool hasStackStorage() const; + + bool hasStackNonParametersStorage() const; + + bool hasStackParametersStorage() const; + + virtual void dumpToStream(llvm::raw_ostream& os) const; + + void dump() const; + + Kind getKind() const { return kind; } + + template const RegionTy* getAs() const; + + virtual bool isBoundable() const { return false; } + + static bool classof(const MemRegion*) { return true; } +}; + +/// MemSpaceRegion - A memory region that represents and "memory space"; +/// for example, the set of global variables, the stack frame, etc. +class MemSpaceRegion : public MemRegion { +protected: + friend class MemRegionManager; + + MemRegionManager *Mgr; + + MemSpaceRegion(MemRegionManager *mgr, Kind k = GenericMemSpaceRegionKind) + : MemRegion(k), Mgr(mgr) { + assert(classof(this)); + } + + MemRegionManager* getMemRegionManager() const { return Mgr; } + +public: + bool isBoundable() const { return false; } + + void Profile(llvm::FoldingSetNodeID &ID) const; + + static bool classof(const MemRegion *R) { + Kind k = R->getKind(); + return k >= BEG_MEMSPACES && k <= END_MEMSPACES; + } +}; + +class GlobalsSpaceRegion : public MemSpaceRegion { + friend class MemRegionManager; + + GlobalsSpaceRegion(MemRegionManager *mgr) + : MemSpaceRegion(mgr, GlobalsSpaceRegionKind) {} +public: + static bool classof(const MemRegion *R) { + return R->getKind() == GlobalsSpaceRegionKind; + } +}; + +class HeapSpaceRegion : public MemSpaceRegion { + friend class MemRegionManager; + + HeapSpaceRegion(MemRegionManager *mgr) + : MemSpaceRegion(mgr, HeapSpaceRegionKind) {} +public: + static bool classof(const MemRegion *R) { + return R->getKind() == HeapSpaceRegionKind; + } +}; + +class UnknownSpaceRegion : public MemSpaceRegion { + friend class MemRegionManager; + UnknownSpaceRegion(MemRegionManager *mgr) + : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {} +public: + static bool classof(const MemRegion *R) { + return R->getKind() == UnknownSpaceRegionKind; + } +}; + +class StackSpaceRegion : public MemSpaceRegion { +private: + const StackFrameContext *SFC; + +protected: + StackSpaceRegion(MemRegionManager *mgr, Kind k, const StackFrameContext *sfc) + : MemSpaceRegion(mgr, k), SFC(sfc) { + assert(classof(this)); + } + +public: + const StackFrameContext *getStackFrame() const { return SFC; } + + void Profile(llvm::FoldingSetNodeID &ID) const; + + static bool classof(const MemRegion *R) { + Kind k = R->getKind(); + return k >= StackLocalsSpaceRegionKind && + k <= StackArgumentsSpaceRegionKind; + } +}; + +class StackLocalsSpaceRegion : public StackSpaceRegion { +private: + friend class MemRegionManager; + StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) + : StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {} +public: + static bool classof(const MemRegion *R) { + return R->getKind() == StackLocalsSpaceRegionKind; + } +}; + +class StackArgumentsSpaceRegion : public StackSpaceRegion { +private: + friend class MemRegionManager; + StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) + : StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {} +public: + static bool classof(const MemRegion *R) { + return R->getKind() == StackArgumentsSpaceRegionKind; + } +}; + +/// SubRegion - A region that subsets another larger region. Most regions +/// are subclasses of SubRegion. +class SubRegion : public MemRegion { +protected: + const MemRegion* superRegion; + SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {} +public: + const MemRegion* getSuperRegion() const { + return superRegion; + } + + MemRegionManager* getMemRegionManager() const; + + bool isSubRegionOf(const MemRegion* R) const; + + static bool classof(const MemRegion* R) { + return R->getKind() > END_MEMSPACES; + } +}; + +//===----------------------------------------------------------------------===// +// Auxillary data classes for use with MemRegions. +//===----------------------------------------------------------------------===// + +class ElementRegion; + +class RegionRawOffset { +private: + friend class ElementRegion; + + const MemRegion *Region; + int64_t Offset; + + RegionRawOffset(const MemRegion* reg, int64_t offset = 0) + : Region(reg), Offset(offset) {} + +public: + // FIXME: Eventually support symbolic offsets. + int64_t getByteOffset() const { return Offset; } + const MemRegion *getRegion() const { return Region; } + + void dumpToStream(llvm::raw_ostream& os) const; + void dump() const; +}; + +//===----------------------------------------------------------------------===// +// MemRegion subclasses. +//===----------------------------------------------------------------------===// + +/// AllocaRegion - A region that represents an untyped blob of bytes created +/// by a call to 'alloca'. +class AllocaRegion : public SubRegion { + friend class MemRegionManager; +protected: + unsigned Cnt; // Block counter. Used to distinguish different pieces of + // memory allocated by alloca at the same call site. + const Expr* Ex; + + AllocaRegion(const Expr* ex, unsigned cnt, const MemRegion *superRegion) + : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {} + +public: + + const Expr* getExpr() const { return Ex; } + + bool isBoundable() const { return true; } + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr* Ex, + unsigned Cnt, const MemRegion *superRegion); + + void dumpToStream(llvm::raw_ostream& os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == AllocaRegionKind; + } +}; + +/// TypedRegion - An abstract class representing regions that are typed. +class TypedRegion : public SubRegion { +protected: + TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {} + +public: + virtual QualType getValueType(ASTContext &C) const = 0; + + virtual QualType getLocationType(ASTContext& C) const { + // FIXME: We can possibly optimize this later to cache this value. + return C.getPointerType(getValueType(C)); + } + + QualType getDesugaredValueType(ASTContext& C) const { + QualType T = getValueType(C); + return T.getTypePtr() ? T.getDesugaredType() : T; + } + + QualType getDesugaredLocationType(ASTContext& C) const { + return getLocationType(C).getDesugaredType(); + } + + bool isBoundable() const { + return !getValueType(getContext()).isNull(); + } + + static bool classof(const MemRegion* R) { + unsigned k = R->getKind(); + return k >= BEG_TYPED_REGIONS && k <= END_TYPED_REGIONS; + } +}; + + +class CodeTextRegion : public TypedRegion { +protected: + CodeTextRegion(const MemRegion *sreg, Kind k) : TypedRegion(sreg, k) {} +public: + QualType getValueType(ASTContext &C) const { + // Do not get the object type of a CodeTextRegion. + assert(0); + return QualType(); + } + + bool isBoundable() const { return false; } + + static bool classof(const MemRegion* R) { + Kind k = R->getKind(); + return k >= FunctionTextRegionKind && k <= BlockTextRegionKind; + } +}; + +/// FunctionTextRegion - A region that represents code texts of function. +class FunctionTextRegion : public CodeTextRegion { + const FunctionDecl *FD; +public: + FunctionTextRegion(const FunctionDecl* fd, const MemRegion* sreg) + : CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) {} + + QualType getLocationType(ASTContext &C) const { + return C.getPointerType(FD->getType()); + } + + const FunctionDecl *getDecl() const { + return FD; + } + + virtual void dumpToStream(llvm::raw_ostream& os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FunctionDecl *FD, + const MemRegion*); + + static bool classof(const MemRegion* R) { + return R->getKind() == FunctionTextRegionKind; + } +}; + + +/// BlockTextRegion - A region that represents code texts of blocks (closures). +/// Blocks are represented with two kinds of regions. BlockTextRegions +/// represent the "code", while BlockDataRegions represent instances of blocks, +/// which correspond to "code+data". The distinction is important, because +/// like a closure a block captures the values of externally referenced +/// variables. +class BlockTextRegion : public CodeTextRegion { + friend class MemRegionManager; + + const BlockDecl *BD; + AnalysisContext *AC; + CanQualType locTy; + + BlockTextRegion(const BlockDecl *bd, CanQualType lTy, + AnalysisContext *ac, const MemRegion* sreg) + : CodeTextRegion(sreg, BlockTextRegionKind), BD(bd), AC(ac), locTy(lTy) {} + +public: + QualType getLocationType(ASTContext &C) const { + return locTy; + } + + const BlockDecl *getDecl() const { + return BD; + } + + AnalysisContext *getAnalysisContext() const { return AC; } + + virtual void dumpToStream(llvm::raw_ostream& os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD, + CanQualType, const AnalysisContext*, + const MemRegion*); + + static bool classof(const MemRegion* R) { + return R->getKind() == BlockTextRegionKind; + } +}; + +/// BlockDataRegion - A region that represents a block instance. +/// Blocks are represented with two kinds of regions. BlockTextRegions +/// represent the "code", while BlockDataRegions represent instances of blocks, +/// which correspond to "code+data". The distinction is important, because +/// like a closure a block captures the values of externally referenced +/// variables. +/// BlockDataRegion - A region that represents code texts of blocks (closures). +class BlockDataRegion : public SubRegion { + friend class MemRegionManager; + const BlockTextRegion *BC; + const LocationContext *LC; // Can be null */ + void *ReferencedVars; + + BlockDataRegion(const BlockTextRegion *bc, const LocationContext *lc, + const MemRegion *sreg) + : SubRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), ReferencedVars(0) {} + +public: + const BlockTextRegion *getCodeRegion() const { return BC; } + + const BlockDecl *getDecl() const { return BC->getDecl(); } + + class referenced_vars_iterator { + const MemRegion * const *R; + public: + explicit referenced_vars_iterator(const MemRegion * const *r) : R(r) {} + + operator const MemRegion * const *() const { + return R; + } + + const VarRegion* operator*() const { + return cast(*R); + } + + bool operator==(const referenced_vars_iterator &I) const { + return I.R == R; + } + bool operator!=(const referenced_vars_iterator &I) const { + return I.R != R; + } + referenced_vars_iterator& operator++() { + ++R; + return *this; + } + }; + + referenced_vars_iterator referenced_vars_begin() const; + referenced_vars_iterator referenced_vars_end() const; + + virtual void dumpToStream(llvm::raw_ostream& os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockTextRegion *, + const LocationContext *, const MemRegion *); + + static bool classof(const MemRegion* R) { + return R->getKind() == BlockDataRegionKind; + } +private: + void LazyInitializeReferencedVars(); +}; + +/// SymbolicRegion - A special, "non-concrete" region. Unlike other region +/// clases, SymbolicRegion represents a region that serves as an alias for +/// either a real region, a NULL pointer, etc. It essentially is used to +/// map the concept of symbolic values into the domain of regions. Symbolic +/// regions do not need to be typed. +class SymbolicRegion : public SubRegion { +protected: + const SymbolRef sym; + +public: + SymbolicRegion(const SymbolRef s, const MemRegion* sreg) + : SubRegion(sreg, SymbolicRegionKind), sym(s) {} + + SymbolRef getSymbol() const { + return sym; + } + + bool isBoundable() const { return true; } + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + SymbolRef sym, + const MemRegion* superRegion); + + void dumpToStream(llvm::raw_ostream& os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == SymbolicRegionKind; + } +}; + +/// StringRegion - Region associated with a StringLiteral. +class StringRegion : public TypedRegion { + friend class MemRegionManager; + const StringLiteral* Str; +protected: + + StringRegion(const StringLiteral* str, const MemRegion* sreg) + : TypedRegion(sreg, StringRegionKind), Str(str) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const StringLiteral* Str, + const MemRegion* superRegion); + +public: + + const StringLiteral* getStringLiteral() const { return Str; } + + QualType getValueType(ASTContext& C) const { + return Str->getType(); + } + + bool isBoundable() const { return false; } + + void Profile(llvm::FoldingSetNodeID& ID) const { + ProfileRegion(ID, Str, superRegion); + } + + void dumpToStream(llvm::raw_ostream& os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == StringRegionKind; + } +}; + +/// CompoundLiteralRegion - A memory region representing a compound literal. +/// Compound literals are essentially temporaries that are stack allocated +/// or in the global constant pool. +class CompoundLiteralRegion : public TypedRegion { +private: + friend class MemRegionManager; + const CompoundLiteralExpr* CL; + + CompoundLiteralRegion(const CompoundLiteralExpr* cl, const MemRegion* sReg) + : TypedRegion(sReg, CompoundLiteralRegionKind), CL(cl) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const CompoundLiteralExpr* CL, + const MemRegion* superRegion); +public: + QualType getValueType(ASTContext& C) const { + return C.getCanonicalType(CL->getType()); + } + + bool isBoundable() const { return !CL->isFileScope(); } + + void Profile(llvm::FoldingSetNodeID& ID) const; + + void dumpToStream(llvm::raw_ostream& os) const; + + const CompoundLiteralExpr* getLiteralExpr() const { return CL; } + + static bool classof(const MemRegion* R) { + return R->getKind() == CompoundLiteralRegionKind; + } +}; + +class DeclRegion : public TypedRegion { +protected: + const Decl* D; + + DeclRegion(const Decl* d, const MemRegion* sReg, Kind k) + : TypedRegion(sReg, k), D(d) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D, + const MemRegion* superRegion, Kind k); + +public: + const Decl* getDecl() const { return D; } + void Profile(llvm::FoldingSetNodeID& ID) const; + + static bool classof(const MemRegion* R) { + unsigned k = R->getKind(); + return k >= BEG_DECL_REGIONS && k <= END_DECL_REGIONS; + } +}; + +class VarRegion : public DeclRegion { + friend class MemRegionManager; + + // Constructors and private methods. + VarRegion(const VarDecl* vd, const MemRegion* sReg) + : DeclRegion(vd, sReg, VarRegionKind) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl* VD, + const MemRegion *superRegion) { + DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind); + } + + void Profile(llvm::FoldingSetNodeID& ID) const; + +public: + const VarDecl *getDecl() const { return cast(D); } + + const StackFrameContext *getStackFrame() const; + + QualType getValueType(ASTContext& C) const { + // FIXME: We can cache this if needed. + return C.getCanonicalType(getDecl()->getType()); + } + + void dumpToStream(llvm::raw_ostream& os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == VarRegionKind; + } +}; + +/// CXXThisRegion - Represents the region for the implicit 'this' parameter +/// in a call to a C++ method. This region doesn't represent the object +/// referred to by 'this', but rather 'this' itself. +class CXXThisRegion : public TypedRegion { + friend class MemRegionManager; + CXXThisRegion(const PointerType *thisPointerTy, + const MemRegion *sReg) + : TypedRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {} + + static void ProfileRegion(llvm::FoldingSetNodeID &ID, + const PointerType *PT, + const MemRegion *sReg); + + void Profile(llvm::FoldingSetNodeID &ID) const; + +public: + QualType getValueType(ASTContext &C) const { + return QualType(ThisPointerTy, 0); + } + + void dumpToStream(llvm::raw_ostream& os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == CXXThisRegionKind; + } + +private: + const PointerType *ThisPointerTy; +}; + +class FieldRegion : public DeclRegion { + friend class MemRegionManager; + + FieldRegion(const FieldDecl* fd, const MemRegion* sReg) + : DeclRegion(fd, sReg, FieldRegionKind) {} + +public: + + void dumpToStream(llvm::raw_ostream& os) const; + + const FieldDecl* getDecl() const { return cast(D); } + + QualType getValueType(ASTContext& C) const { + // FIXME: We can cache this if needed. + return C.getCanonicalType(getDecl()->getType()); + } + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl* FD, + const MemRegion* superRegion) { + DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind); + } + + static bool classof(const MemRegion* R) { + return R->getKind() == FieldRegionKind; + } +}; + +class ObjCIvarRegion : public DeclRegion { + + friend class MemRegionManager; + + ObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* sReg) + : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl* ivd, + const MemRegion* superRegion) { + DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind); + } + +public: + const ObjCIvarDecl* getDecl() const { return cast(D); } + QualType getValueType(ASTContext&) const { return getDecl()->getType(); } + + void dumpToStream(llvm::raw_ostream& os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == ObjCIvarRegionKind; + } +}; + +class ElementRegion : public TypedRegion { + friend class MemRegionManager; + + QualType ElementType; + SVal Index; + + ElementRegion(QualType elementType, SVal Idx, const MemRegion* sReg) + : TypedRegion(sReg, ElementRegionKind), + ElementType(elementType), Index(Idx) { + assert((!isa(&Idx) || + cast(&Idx)->getValue().isSigned()) && + "The index must be signed"); + } + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType, + SVal Idx, const MemRegion* superRegion); + +public: + + SVal getIndex() const { return Index; } + + QualType getValueType(ASTContext&) const { + return ElementType; + } + + QualType getElementType() const { + return ElementType; + } + + RegionRawOffset getAsRawOffset() const; + + void dumpToStream(llvm::raw_ostream& os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == ElementRegionKind; + } +}; + +// C++ temporary object associated with an expression. +class CXXObjectRegion : public TypedRegion { + friend class MemRegionManager; + + Expr const *Ex; + + CXXObjectRegion(Expr const *E, MemRegion const *sReg) + : TypedRegion(sReg, CXXObjectRegionKind), Ex(E) {} + + static void ProfileRegion(llvm::FoldingSetNodeID &ID, + Expr const *E, const MemRegion *sReg); + +public: + QualType getValueType(ASTContext& C) const { + return Ex->getType(); + } + + void Profile(llvm::FoldingSetNodeID &ID) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == CXXObjectRegionKind; + } +}; + +template +const RegionTy* MemRegion::getAs() const { + if (const RegionTy* RT = dyn_cast(this)) + return RT; + + return NULL; +} + +//===----------------------------------------------------------------------===// +// MemRegionManager - Factory object for creating regions. +//===----------------------------------------------------------------------===// + +class MemRegionManager { + ASTContext &C; + llvm::BumpPtrAllocator& A; + llvm::FoldingSet Regions; + + GlobalsSpaceRegion *globals; + + const StackFrameContext *cachedStackLocalsFrame; + StackLocalsSpaceRegion *cachedStackLocalsRegion; + + const StackFrameContext *cachedStackArgumentsFrame; + StackArgumentsSpaceRegion *cachedStackArgumentsRegion; + + HeapSpaceRegion *heap; + UnknownSpaceRegion *unknown; + MemSpaceRegion *code; + +public: + MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator& a) + : C(c), A(a), globals(0), + cachedStackLocalsFrame(0), cachedStackLocalsRegion(0), + cachedStackArgumentsFrame(0), cachedStackArgumentsRegion(0), + heap(0), unknown(0), code(0) {} + + ~MemRegionManager(); + + ASTContext &getContext() { return C; } + + llvm::BumpPtrAllocator &getAllocator() { return A; } + + /// getStackLocalsRegion - Retrieve the memory region associated with the + /// specified stack frame. + const StackLocalsSpaceRegion * + getStackLocalsRegion(const StackFrameContext *STC); + + /// getStackArgumentsRegion - Retrieve the memory region associated with + /// function/method arguments of the specified stack frame. + const StackArgumentsSpaceRegion * + getStackArgumentsRegion(const StackFrameContext *STC); + + /// getGlobalsRegion - Retrieve the memory region associated with + /// all global variables. + const GlobalsSpaceRegion *getGlobalsRegion(); + + /// getHeapRegion - Retrieve the memory region associated with the + /// generic "heap". + const HeapSpaceRegion *getHeapRegion(); + + /// getUnknownRegion - Retrieve the memory region associated with unknown + /// memory space. + const MemSpaceRegion *getUnknownRegion(); + + const MemSpaceRegion *getCodeRegion(); + + /// getAllocaRegion - Retrieve a region associated with a call to alloca(). + const AllocaRegion *getAllocaRegion(const Expr* Ex, unsigned Cnt, + const LocationContext *LC); + + /// getCompoundLiteralRegion - Retrieve the region associated with a + /// given CompoundLiteral. + const CompoundLiteralRegion* + getCompoundLiteralRegion(const CompoundLiteralExpr* CL, + const LocationContext *LC); + + /// getCXXThisRegion - Retrieve the [artifical] region associated with the + /// parameter 'this'. + const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy, + const LocationContext *LC); + + /// getSymbolicRegion - Retrieve or create a "symbolic" memory region. + const SymbolicRegion* getSymbolicRegion(SymbolRef sym); + + const StringRegion* getStringRegion(const StringLiteral* Str); + + /// getVarRegion - Retrieve or create the memory region associated with + /// a specified VarDecl and LocationContext. + const VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC); + + /// getVarRegion - Retrieve or create the memory region associated with + /// a specified VarDecl and super region. + const VarRegion* getVarRegion(const VarDecl *D, const MemRegion *superR); + + /// getElementRegion - Retrieve the memory region associated with the + /// associated element type, index, and super region. + const ElementRegion *getElementRegion(QualType elementType, SVal Idx, + const MemRegion *superRegion, + ASTContext &Ctx); + + const ElementRegion *getElementRegionWithSuper(const ElementRegion *ER, + const MemRegion *superRegion) { + return getElementRegion(ER->getElementType(), ER->getIndex(), + superRegion, ER->getContext()); + } + + /// getFieldRegion - Retrieve or create the memory region associated with + /// a specified FieldDecl. 'superRegion' corresponds to the containing + /// memory region (which typically represents the memory representing + /// a structure or class). + const FieldRegion *getFieldRegion(const FieldDecl* fd, + const MemRegion* superRegion); + + const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR, + const MemRegion *superRegion) { + return getFieldRegion(FR->getDecl(), superRegion); + } + + /// getObjCIvarRegion - Retrieve or create the memory region associated with + /// a specified Objective-c instance variable. 'superRegion' corresponds + /// to the containing region (which typically represents the Objective-C + /// object). + const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd, + const MemRegion* superRegion); + + const CXXObjectRegion *getCXXObjectRegion(Expr const *Ex, + LocationContext const *LC); + + const FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD); + const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD, + CanQualType locTy, + AnalysisContext *AC); + + /// getBlockDataRegion - Get the memory region associated with an instance + /// of a block. Unlike many other MemRegions, the LocationContext* + /// argument is allowed to be NULL for cases where we have no known + /// context. + const BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc, + const LocationContext *lc = NULL); + + bool isGlobalsRegion(const MemRegion* R) { + assert(R); + return R == globals; + } + +private: + template + RegionTy* getRegion(const A1 a1); + + template + RegionTy* getSubRegion(const A1 a1, const MemRegion* superRegion); + + template + RegionTy* getRegion(const A1 a1, const A2 a2); + + template + RegionTy* getSubRegion(const A1 a1, const A2 a2, + const MemRegion* superRegion); + + template + RegionTy* getSubRegion(const A1 a1, const A2 a2, const A3 a3, + const MemRegion* superRegion); + + template + const REG* LazyAllocate(REG*& region); + + template + const REG* LazyAllocate(REG*& region, ARG a); +}; + +//===----------------------------------------------------------------------===// +// Out-of-line member definitions. +//===----------------------------------------------------------------------===// + +inline ASTContext& MemRegion::getContext() const { + return getMemRegionManager()->getContext(); +} + +} // end clang namespace + +//===----------------------------------------------------------------------===// +// Pretty-printing regions. +//===----------------------------------------------------------------------===// + +namespace llvm { +static inline raw_ostream& operator<<(raw_ostream& os, + const clang::MemRegion* R) { + R->dumpToStream(os); + return os; +} +} // end llvm namespace + +#endif diff --git a/include/clang/Checker/PathSensitive/SVals.h b/include/clang/Checker/PathSensitive/SVals.h new file mode 100644 index 000000000000..65a8a2c01df5 --- /dev/null +++ b/include/clang/Checker/PathSensitive/SVals.h @@ -0,0 +1,499 @@ +//== SVals.h - Abstract Values for Static Analysis ---------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines SVal, Loc, and NonLoc, classes that represent +// abstract r-values for use with path-sensitive value tracking. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_RVALUE_H +#define LLVM_CLANG_ANALYSIS_RVALUE_H + +#include "clang/Checker/PathSensitive/SymbolManager.h" +#include "llvm/Support/Casting.h" +#include "llvm/ADT/ImmutableList.h" + +namespace llvm { + class raw_ostream; +} + +//==------------------------------------------------------------------------==// +// Base SVal types. +//==------------------------------------------------------------------------==// + +namespace clang { + +class CompoundValData; +class LazyCompoundValData; +class GRState; +class BasicValueFactory; +class MemRegion; +class TypedRegion; +class MemRegionManager; +class GRStateManager; +class ValueManager; + +class SVal { +public: + enum BaseKind { UndefinedKind, UnknownKind, LocKind, NonLocKind }; + enum { BaseBits = 2, BaseMask = 0x3 }; + +protected: + void* Data; + unsigned Kind; + +protected: + SVal(const void* d, bool isLoc, unsigned ValKind) + : Data(const_cast(d)), + Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {} + + explicit SVal(BaseKind k, void* D = NULL) + : Data(D), Kind(k) {} + +public: + SVal() : Data(0), Kind(0) {} + ~SVal() {} + + /// BufferTy - A temporary buffer to hold a set of SVals. + typedef llvm::SmallVector BufferTy; + + inline unsigned getRawKind() const { return Kind; } + inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); } + inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; } + + inline void Profile(llvm::FoldingSetNodeID& ID) const { + ID.AddInteger((unsigned) getRawKind()); + ID.AddPointer(reinterpret_cast(Data)); + } + + inline bool operator==(const SVal& R) const { + return getRawKind() == R.getRawKind() && Data == R.Data; + } + + inline bool operator!=(const SVal& R) const { + return !(*this == R); + } + + inline bool isUnknown() const { + return getRawKind() == UnknownKind; + } + + inline bool isUndef() const { + return getRawKind() == UndefinedKind; + } + + inline bool isUnknownOrUndef() const { + return getRawKind() <= UnknownKind; + } + + inline bool isValid() const { + return getRawKind() > UnknownKind; + } + + bool isConstant() const; + + bool isZeroConstant() const; + + /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true; + bool hasConjuredSymbol() const; + + /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a + /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl. + /// Otherwise return 0. + const FunctionDecl* getAsFunctionDecl() const; + + /// getAsLocSymbol - If this SVal is a location (subclasses Loc) and + /// wraps a symbol, return that SymbolRef. Otherwise return a SymbolData* + SymbolRef getAsLocSymbol() const; + + /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef. + /// Otherwise return a SymbolRef where 'isValid()' returns false. + SymbolRef getAsSymbol() const; + + /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then + /// return that expression. Otherwise return NULL. + const SymExpr *getAsSymbolicExpression() const; + + const MemRegion *getAsRegion() const; + + void dumpToStream(llvm::raw_ostream& OS) const; + void dump() const; + + // Iterators. + class symbol_iterator { + llvm::SmallVector itr; + void expand(); + public: + symbol_iterator() {} + symbol_iterator(const SymExpr* SE); + + symbol_iterator& operator++(); + SymbolRef operator*(); + + bool operator==(const symbol_iterator& X) const; + bool operator!=(const symbol_iterator& X) const; + }; + + symbol_iterator symbol_begin() const { + const SymExpr *SE = getAsSymbolicExpression(); + if (SE) + return symbol_iterator(SE); + else + return symbol_iterator(); + } + + symbol_iterator symbol_end() const { return symbol_iterator(); } + + // Implement isa support. + static inline bool classof(const SVal*) { return true; } +}; + + +class UndefinedVal : public SVal { +public: + UndefinedVal() : SVal(UndefinedKind) {} + UndefinedVal(void* D) : SVal(UndefinedKind, D) {} + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == UndefinedKind; + } + + void* getData() const { return Data; } +}; + +class DefinedOrUnknownSVal : public SVal { +private: + // Do not implement. We want calling these methods to be a compiler + // error since they are tautologically false. + bool isUndef() const; + bool isValid() const; + +protected: + explicit DefinedOrUnknownSVal(const void* d, bool isLoc, unsigned ValKind) + : SVal(d, isLoc, ValKind) {} + + explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL) + : SVal(k, D) {} + +public: + // Implement isa support. + static inline bool classof(const SVal *V) { + return !V->isUndef(); + } +}; + +class UnknownVal : public DefinedOrUnknownSVal { +public: + UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {} + + static inline bool classof(const SVal *V) { + return V->getBaseKind() == UnknownKind; + } +}; + +class DefinedSVal : public DefinedOrUnknownSVal { +private: + // Do not implement. We want calling these methods to be a compiler + // error since they are tautologically true/false. + bool isUnknown() const; + bool isUnknownOrUndef() const; + bool isValid() const; +protected: + DefinedSVal(const void* d, bool isLoc, unsigned ValKind) + : DefinedOrUnknownSVal(d, isLoc, ValKind) {} +public: + // Implement isa support. + static inline bool classof(const SVal *V) { + return !V->isUnknownOrUndef(); + } +}; + +class NonLoc : public DefinedSVal { +protected: + NonLoc(unsigned SubKind, const void* d) : DefinedSVal(d, false, SubKind) {} + +public: + void dumpToStream(llvm::raw_ostream& Out) const; + + // Implement isa support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind; + } +}; + +class Loc : public DefinedSVal { +protected: + Loc(unsigned SubKind, const void* D) + : DefinedSVal(const_cast(D), true, SubKind) {} + +public: + void dumpToStream(llvm::raw_ostream& Out) const; + + Loc(const Loc& X) : DefinedSVal(X.Data, true, X.getSubKind()) {} + Loc& operator=(const Loc& X) { memcpy(this, &X, sizeof(Loc)); return *this; } + + // Implement isa support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind; + } + + static inline bool IsLocType(QualType T) { + return T->isAnyPointerType() || T->isBlockPointerType() || + T->isReferenceType(); + } +}; + +//==------------------------------------------------------------------------==// +// Subclasses of NonLoc. +//==------------------------------------------------------------------------==// + +namespace nonloc { + +enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind, + LocAsIntegerKind, CompoundValKind, LazyCompoundValKind }; + +class SymbolVal : public NonLoc { +public: + SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {} + + SymbolRef getSymbol() const { + return (const SymbolData*) Data; + } + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == SymbolValKind; + } + + static inline bool classof(const NonLoc* V) { + return V->getSubKind() == SymbolValKind; + } +}; + +class SymExprVal : public NonLoc { +public: + SymExprVal(const SymExpr *SE) + : NonLoc(SymExprValKind, reinterpret_cast(SE)) {} + + const SymExpr *getSymbolicExpression() const { + return reinterpret_cast(Data); + } + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == SymExprValKind; + } + + static inline bool classof(const NonLoc* V) { + return V->getSubKind() == SymExprValKind; + } +}; + +class ConcreteInt : public NonLoc { +public: + ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {} + + const llvm::APSInt& getValue() const { + return *static_cast(Data); + } + + // Transfer functions for binary/unary operations on ConcreteInts. + SVal evalBinOp(ValueManager &ValMgr, BinaryOperator::Opcode Op, + const ConcreteInt& R) const; + + ConcreteInt evalComplement(ValueManager &ValMgr) const; + + ConcreteInt evalMinus(ValueManager &ValMgr) const; + + // Implement isa support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == ConcreteIntKind; + } + + static inline bool classof(const NonLoc* V) { + return V->getSubKind() == ConcreteIntKind; + } +}; + +class LocAsInteger : public NonLoc { + friend class clang::ValueManager; + + LocAsInteger(const std::pair& data) : + NonLoc(LocAsIntegerKind, &data) { + assert (isa(data.first)); + } + +public: + + Loc getLoc() const { + return cast(((std::pair*) Data)->first); + } + + const Loc& getPersistentLoc() const { + const SVal& V = ((std::pair*) Data)->first; + return cast(V); + } + + unsigned getNumBits() const { + return ((std::pair*) Data)->second; + } + + // Implement isa support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == LocAsIntegerKind; + } + + static inline bool classof(const NonLoc* V) { + return V->getSubKind() == LocAsIntegerKind; + } +}; + +class CompoundVal : public NonLoc { + friend class clang::ValueManager; + + CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {} + +public: + const CompoundValData* getValue() const { + return static_cast(Data); + } + + typedef llvm::ImmutableList::iterator iterator; + iterator begin() const; + iterator end() const; + + static bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind; + } + + static bool classof(const NonLoc* V) { + return V->getSubKind() == CompoundValKind; + } +}; + +class LazyCompoundVal : public NonLoc { + friend class clang::ValueManager; + + LazyCompoundVal(const LazyCompoundValData *D) + : NonLoc(LazyCompoundValKind, D) {} +public: + const LazyCompoundValData *getCVData() const { + return static_cast(Data); + } + const void *getStore() const; + const TypedRegion *getRegion() const; + + static bool classof(const SVal *V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == LazyCompoundValKind; + } + static bool classof(const NonLoc *V) { + return V->getSubKind() == LazyCompoundValKind; + } +}; + +} // end namespace clang::nonloc + +//==------------------------------------------------------------------------==// +// Subclasses of Loc. +//==------------------------------------------------------------------------==// + +namespace loc { + +enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind }; + +class GotoLabel : public Loc { +public: + GotoLabel(LabelStmt* Label) : Loc(GotoLabelKind, Label) {} + + LabelStmt* getLabel() const { + return static_cast(Data); + } + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind && + V->getSubKind() == GotoLabelKind; + } + + static inline bool classof(const Loc* V) { + return V->getSubKind() == GotoLabelKind; + } +}; + + +class MemRegionVal : public Loc { +public: + MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {} + + const MemRegion* getRegion() const { + return static_cast(Data); + } + + const MemRegion* StripCasts() const; + + template + const REGION* getRegionAs() const { + return llvm::dyn_cast(getRegion()); + } + + inline bool operator==(const MemRegionVal& R) const { + return getRegion() == R.getRegion(); + } + + inline bool operator!=(const MemRegionVal& R) const { + return getRegion() != R.getRegion(); + } + + // Implement isa support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind && + V->getSubKind() == MemRegionKind; + } + + static inline bool classof(const Loc* V) { + return V->getSubKind() == MemRegionKind; + } +}; + +class ConcreteInt : public Loc { +public: + ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {} + + const llvm::APSInt& getValue() const { + return *static_cast(Data); + } + + // Transfer functions for binary/unary operations on ConcreteInts. + SVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, + const ConcreteInt& R) const; + + // Implement isa support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind && + V->getSubKind() == ConcreteIntKind; + } + + static inline bool classof(const Loc* V) { + return V->getSubKind() == ConcreteIntKind; + } +}; + +} // end clang::loc namespace +} // end clang namespace + +namespace llvm { +static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os, + clang::SVal V) { + V.dumpToStream(os); + return os; +} +} // end llvm namespace +#endif diff --git a/include/clang/Checker/PathSensitive/SValuator.h b/include/clang/Checker/PathSensitive/SValuator.h new file mode 100644 index 000000000000..9beb8cb08661 --- /dev/null +++ b/include/clang/Checker/PathSensitive/SValuator.h @@ -0,0 +1,66 @@ +// SValuator.h - Construction of SVals from evaluating expressions -*- C++ -*--- +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines SValuator, a class that defines the interface for +// "symbolical evaluators" which construct an SVal from an expression. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_SVALUATOR +#define LLVM_CLANG_ANALYSIS_SVALUATOR + +#include "clang/AST/Expr.h" +#include "clang/Checker/PathSensitive/SVals.h" + +namespace clang { + +class GRState; +class ValueManager; + +class SValuator { + friend class ValueManager; +protected: + ValueManager &ValMgr; + +public: + // FIXME: Make these protected again one RegionStoreManager correctly + // handles loads from differening bound value types. + virtual SVal EvalCastNL(NonLoc val, QualType castTy) = 0; + virtual SVal EvalCastL(Loc val, QualType castTy) = 0; + +public: + SValuator(ValueManager &valMgr) : ValMgr(valMgr) {} + virtual ~SValuator() {} + + SVal EvalCast(SVal V, QualType castTy, QualType originalType); + + virtual SVal EvalMinus(NonLoc val) = 0; + + virtual SVal EvalComplement(NonLoc val) = 0; + + virtual SVal EvalBinOpNN(const GRState *state, BinaryOperator::Opcode Op, + NonLoc lhs, NonLoc rhs, QualType resultTy) = 0; + + virtual SVal EvalBinOpLL(BinaryOperator::Opcode Op, Loc lhs, Loc rhs, + QualType resultTy) = 0; + + virtual SVal EvalBinOpLN(const GRState *state, BinaryOperator::Opcode Op, + Loc lhs, NonLoc rhs, QualType resultTy) = 0; + + SVal EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op, + SVal L, SVal R, QualType T); + + DefinedOrUnknownSVal EvalEQ(const GRState *ST, DefinedOrUnknownSVal L, + DefinedOrUnknownSVal R); +}; + +SValuator* CreateSimpleSValuator(ValueManager &valMgr); + +} // end clang namespace +#endif diff --git a/include/clang/Checker/PathSensitive/Store.h b/include/clang/Checker/PathSensitive/Store.h new file mode 100644 index 000000000000..c660e7b7feee --- /dev/null +++ b/include/clang/Checker/PathSensitive/Store.h @@ -0,0 +1,230 @@ +//== Store.h - Interface for maps from Locations to Values ------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defined the types Store and StoreManager. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_STORE_H +#define LLVM_CLANG_ANALYSIS_STORE_H + +#include "clang/Checker/PathSensitive/MemRegion.h" +#include "clang/Checker/PathSensitive/SVals.h" +#include "clang/Checker/PathSensitive/ValueManager.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +typedef const void* Store; + +class GRState; +class GRStateManager; +class Stmt; +class Expr; +class ObjCIvarDecl; +class SubRegionMap; +class StackFrameContext; + +class StoreManager { +protected: + ValueManager &ValMgr; + GRStateManager &StateMgr; + + /// MRMgr - Manages region objects associated with this StoreManager. + MemRegionManager &MRMgr; + ASTContext &Ctx; + + StoreManager(GRStateManager &stateMgr); + +public: + virtual ~StoreManager() {} + + /// Return the value bound to specified location in a given state. + /// \param[in] state The analysis state. + /// \param[in] loc The symbolic memory location. + /// \param[in] T An optional type that provides a hint indicating the + /// expected type of the returned value. This is used if the value is + /// lazily computed. + /// \return The value bound to the location \c loc. + virtual SVal Retrieve(Store store, Loc loc, QualType T = QualType()) = 0; + + /// Return a state with the specified value bound to the given location. + /// \param[in] state The analysis state. + /// \param[in] loc The symbolic memory location. + /// \param[in] val The value to bind to location \c loc. + /// \return A pointer to a GRState object that contains the same bindings as + /// \c state with the addition of having the value specified by \c val bound + /// to the location given for \c loc. + virtual Store Bind(Store store, Loc loc, SVal val) = 0; + + virtual Store Remove(Store St, Loc L) = 0; + + /// BindCompoundLiteral - Return the store that has the bindings currently + /// in 'store' plus the bindings for the CompoundLiteral. 'R' is the region + /// for the compound literal and 'BegInit' and 'EndInit' represent an + /// array of initializer values. + virtual Store BindCompoundLiteral(Store store, + const CompoundLiteralExpr* cl, + const LocationContext *LC, SVal v) = 0; + + /// getInitialStore - Returns the initial "empty" store representing the + /// value bindings upon entry to an analyzed function. + virtual Store getInitialStore(const LocationContext *InitLoc) = 0; + + /// getRegionManager - Returns the internal RegionManager object that is + /// used to query and manipulate MemRegion objects. + MemRegionManager& getRegionManager() { return MRMgr; } + + /// getSubRegionMap - Returns an opaque map object that clients can query + /// to get the subregions of a given MemRegion object. It is the + // caller's responsibility to 'delete' the returned map. + virtual SubRegionMap *getSubRegionMap(Store store) = 0; + + virtual SVal getLValueVar(const VarDecl *VD, const LocationContext *LC) { + return ValMgr.makeLoc(MRMgr.getVarRegion(VD, LC)); + } + + virtual SVal getLValueString(const StringLiteral* S) { + return ValMgr.makeLoc(MRMgr.getStringRegion(S)); + } + + SVal getLValueCompoundLiteral(const CompoundLiteralExpr* CL, + const LocationContext *LC) { + return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)); + } + + virtual SVal getLValueIvar(const ObjCIvarDecl* decl, SVal base) { + return getLValueFieldOrIvar(decl, base); + } + + virtual SVal getLValueField(const FieldDecl* D, SVal Base) { + return getLValueFieldOrIvar(D, Base); + } + + virtual SVal getLValueElement(QualType elementType, SVal offset, SVal Base); + + // FIXME: Make out-of-line. + virtual DefinedOrUnknownSVal getSizeInElements(const GRState *state, + const MemRegion *region, + QualType EleTy) { + return UnknownVal(); + } + + /// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit + /// conversions between arrays and pointers. + virtual SVal ArrayToPointer(Loc Array) = 0; + + class CastResult { + const GRState *state; + const MemRegion *region; + public: + const GRState *getState() const { return state; } + const MemRegion* getRegion() const { return region; } + CastResult(const GRState *s, const MemRegion* r = 0) : state(s), region(r){} + }; + + /// CastRegion - Used by GRExprEngine::VisitCast to handle casts from + /// a MemRegion* to a specific location type. 'R' is the region being + /// casted and 'CastToTy' the result type of the cast. + const MemRegion *CastRegion(const MemRegion *region, QualType CastToTy); + + /// EvalBinOp - Perform pointer arithmetic. + virtual SVal EvalBinOp(BinaryOperator::Opcode Op, + Loc lhs, NonLoc rhs, QualType resultTy) { + return UnknownVal(); + } + + virtual Store RemoveDeadBindings(Store store, Stmt* Loc, + SymbolReaper& SymReaper, + llvm::SmallVectorImpl& RegionRoots) = 0; + + virtual Store BindDecl(Store store, const VarRegion *VR, SVal initVal) = 0; + + virtual Store BindDeclWithNoInit(Store store, const VarRegion *VR) = 0; + + typedef llvm::DenseSet InvalidatedSymbols; + + virtual Store InvalidateRegion(Store store, + const MemRegion *R, + const Expr *E, unsigned Count, + InvalidatedSymbols *IS) = 0; + + virtual Store InvalidateRegions(Store store, + const MemRegion * const *Begin, + const MemRegion * const *End, + const Expr *E, unsigned Count, + InvalidatedSymbols *IS); + + // FIXME: Make out-of-line. + virtual const GRState *setExtent(const GRState *state, + const MemRegion *region, SVal extent) { + return state; + } + + /// EnterStackFrame - Let the StoreManager to do something when execution + /// engine is about to execute into a callee. + virtual const GRState *EnterStackFrame(const GRState *state, + const StackFrameContext *frame) { + return state; + } + + virtual void print(Store store, llvm::raw_ostream& Out, + const char* nl, const char *sep) = 0; + + class BindingsHandler { + public: + virtual ~BindingsHandler(); + virtual bool HandleBinding(StoreManager& SMgr, Store store, + const MemRegion *region, SVal val) = 0; + }; + + /// iterBindings - Iterate over the bindings in the Store. + virtual void iterBindings(Store store, BindingsHandler& f) = 0; + +protected: + const MemRegion *MakeElementRegion(const MemRegion *Base, + QualType pointeeTy, uint64_t index = 0); + + /// CastRetrievedVal - Used by subclasses of StoreManager to implement + /// implicit casts that arise from loads from regions that are reinterpreted + /// as another region. + SVal CastRetrievedVal(SVal val, const TypedRegion *R, QualType castTy, + bool performTestOnly = true); + +private: + SVal getLValueFieldOrIvar(const Decl* D, SVal Base); +}; + +// FIXME: Do we still need this? +/// SubRegionMap - An abstract interface that represents a queryable map +/// between MemRegion objects and their subregions. +class SubRegionMap { +public: + virtual ~SubRegionMap() {} + + class Visitor { + public: + virtual ~Visitor() {} + virtual bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) = 0; + }; + + virtual bool iterSubRegions(const MemRegion *region, Visitor& V) const = 0; +}; + +// FIXME: Do we need to pass GRStateManager anymore? +StoreManager *CreateBasicStoreManager(GRStateManager& StMgr); +StoreManager *CreateRegionStoreManager(GRStateManager& StMgr); +StoreManager *CreateFieldsOnlyRegionStoreManager(GRStateManager& StMgr); +StoreManager *CreateFlatStoreManager(GRStateManager &StMgr); +} // end clang namespace + +#endif diff --git a/include/clang/Checker/PathSensitive/SummaryManager.h b/include/clang/Checker/PathSensitive/SummaryManager.h new file mode 100644 index 000000000000..fd23189491b3 --- /dev/null +++ b/include/clang/Checker/PathSensitive/SummaryManager.h @@ -0,0 +1,57 @@ +//== SummaryManager.h - Generic handling of function summaries --*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines SummaryManager and related classes, which provides +// a generic mechanism for managing function summaries. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CHECKER_SUMMARY +#define LLVM_CLANG_CHECKER_SUMMARY + +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Allocator.h" + +namespace clang { + +namespace summMgr { + + +/* Key kinds: + + - C functions + - C++ functions (name + parameter types) + - ObjC methods: + - Class, selector (class method) + - Class, selector (instance method) + - Category, selector (instance method) + - Protocol, selector (instance method) + - C++ methods + - Class, function name + parameter types + const + */ + +class SummaryKey { + +}; + +} // end namespace clang::summMgr + +class SummaryManagerImpl { + +}; + + +template +class SummaryManager : SummaryManagerImpl { + +}; + +} // end clang namespace + +#endif diff --git a/include/clang/Checker/PathSensitive/SymbolManager.h b/include/clang/Checker/PathSensitive/SymbolManager.h new file mode 100644 index 000000000000..8eb319647953 --- /dev/null +++ b/include/clang/Checker/PathSensitive/SymbolManager.h @@ -0,0 +1,385 @@ +//== SymbolManager.h - Management of Symbolic Values ------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines SymbolManager, a class that manages symbolic values +// created for use by GRExprEngine and related classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_SYMMGR_H +#define LLVM_CLANG_ANALYSIS_SYMMGR_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/Analysis/Analyses/LiveVariables.h" +#include "llvm/System/DataTypes.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/DenseSet.h" + +namespace llvm { + class raw_ostream; +} + +namespace clang { + class ASTContext; + class BasicValueFactory; + class MemRegion; + class TypedRegion; + class VarRegion; + class StackFrameContext; +} + +namespace clang { + +class SymExpr : public llvm::FoldingSetNode { +public: + enum Kind { BEGIN_SYMBOLS, + RegionValueKind, ConjuredKind, DerivedKind, + END_SYMBOLS, + SymIntKind, SymSymKind }; +private: + Kind K; + +protected: + SymExpr(Kind k) : K(k) {} + +public: + virtual ~SymExpr() {} + + Kind getKind() const { return K; } + + void dump() const; + + virtual void dumpToStream(llvm::raw_ostream &os) const = 0; + + virtual QualType getType(ASTContext&) const = 0; + virtual void Profile(llvm::FoldingSetNodeID& profile) = 0; + + // Implement isa support. + static inline bool classof(const SymExpr*) { return true; } +}; + +typedef unsigned SymbolID; + +class SymbolData : public SymExpr { +private: + const SymbolID Sym; + +protected: + SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {} + +public: + virtual ~SymbolData() {} + + SymbolID getSymbolID() const { return Sym; } + + // Implement isa support. + static inline bool classof(const SymExpr* SE) { + Kind k = SE->getKind(); + return k > BEGIN_SYMBOLS && k < END_SYMBOLS; + } +}; + +typedef const SymbolData* SymbolRef; + +class SymbolRegionValue : public SymbolData { + const MemRegion *R; + // We may cast the region to another type, so the expected type of the symbol + // may be different from the region's original type. + QualType T; + +public: + SymbolRegionValue(SymbolID sym, const MemRegion *r, QualType t = QualType()) + : SymbolData(RegionValueKind, sym), R(r), T(t) {} + + const MemRegion* getRegion() const { return R; } + + static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion* R, + QualType T) { + profile.AddInteger((unsigned) RegionValueKind); + profile.AddPointer(R); + T.Profile(profile); + } + + virtual void Profile(llvm::FoldingSetNodeID& profile) { + Profile(profile, R, T); + } + + void dumpToStream(llvm::raw_ostream &os) const; + + QualType getType(ASTContext&) const; + + // Implement isa support. + static inline bool classof(const SymExpr* SE) { + return SE->getKind() == RegionValueKind; + } +}; + +class SymbolConjured : public SymbolData { + const Stmt* S; + QualType T; + unsigned Count; + const void* SymbolTag; + +public: + SymbolConjured(SymbolID sym, const Stmt* s, QualType t, unsigned count, + const void* symbolTag) + : SymbolData(ConjuredKind, sym), S(s), T(t), Count(count), + SymbolTag(symbolTag) {} + + const Stmt* getStmt() const { return S; } + unsigned getCount() const { return Count; } + const void* getTag() const { return SymbolTag; } + + QualType getType(ASTContext&) const; + + void dumpToStream(llvm::raw_ostream &os) const; + + static void Profile(llvm::FoldingSetNodeID& profile, const Stmt* S, + QualType T, unsigned Count, const void* SymbolTag) { + profile.AddInteger((unsigned) ConjuredKind); + profile.AddPointer(S); + profile.Add(T); + profile.AddInteger(Count); + profile.AddPointer(SymbolTag); + } + + virtual void Profile(llvm::FoldingSetNodeID& profile) { + Profile(profile, S, T, Count, SymbolTag); + } + + // Implement isa support. + static inline bool classof(const SymExpr* SE) { + return SE->getKind() == ConjuredKind; + } +}; + +class SymbolDerived : public SymbolData { + SymbolRef parentSymbol; + const TypedRegion *R; + +public: + SymbolDerived(SymbolID sym, SymbolRef parent, const TypedRegion *r) + : SymbolData(DerivedKind, sym), parentSymbol(parent), R(r) {} + + SymbolRef getParentSymbol() const { return parentSymbol; } + const TypedRegion *getRegion() const { return R; } + + QualType getType(ASTContext&) const; + + void dumpToStream(llvm::raw_ostream &os) const; + + static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent, + const TypedRegion *r) { + profile.AddInteger((unsigned) DerivedKind); + profile.AddPointer(r); + profile.AddPointer(parent); + } + + virtual void Profile(llvm::FoldingSetNodeID& profile) { + Profile(profile, parentSymbol, R); + } + + // Implement isa support. + static inline bool classof(const SymExpr* SE) { + return SE->getKind() == DerivedKind; + } +}; + +// SymIntExpr - Represents symbolic expression like 'x' + 3. +class SymIntExpr : public SymExpr { + const SymExpr *LHS; + BinaryOperator::Opcode Op; + const llvm::APSInt& RHS; + QualType T; + +public: + SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t) + : SymExpr(SymIntKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} + + // FIXME: We probably need to make this out-of-line to avoid redundant + // generation of virtual functions. + QualType getType(ASTContext& C) const { return T; } + + BinaryOperator::Opcode getOpcode() const { return Op; } + + void dumpToStream(llvm::raw_ostream &os) const; + + const SymExpr *getLHS() const { return LHS; } + const llvm::APSInt &getRHS() const { return RHS; } + + static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, + BinaryOperator::Opcode op, const llvm::APSInt& rhs, + QualType t) { + ID.AddInteger((unsigned) SymIntKind); + ID.AddPointer(lhs); + ID.AddInteger(op); + ID.AddPointer(&rhs); + ID.Add(t); + } + + void Profile(llvm::FoldingSetNodeID& ID) { + Profile(ID, LHS, Op, RHS, T); + } + + // Implement isa support. + static inline bool classof(const SymExpr* SE) { + return SE->getKind() == SymIntKind; + } +}; + +// SymSymExpr - Represents symbolic expression like 'x' + 'y'. +class SymSymExpr : public SymExpr { + const SymExpr *LHS; + BinaryOperator::Opcode Op; + const SymExpr *RHS; + QualType T; + +public: + SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, + QualType t) + : SymExpr(SymSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} + + const SymExpr *getLHS() const { return LHS; } + const SymExpr *getRHS() const { return RHS; } + + // FIXME: We probably need to make this out-of-line to avoid redundant + // generation of virtual functions. + QualType getType(ASTContext& C) const { return T; } + + void dumpToStream(llvm::raw_ostream &os) const; + + static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, + BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) { + ID.AddInteger((unsigned) SymSymKind); + ID.AddPointer(lhs); + ID.AddInteger(op); + ID.AddPointer(rhs); + ID.Add(t); + } + + void Profile(llvm::FoldingSetNodeID& ID) { + Profile(ID, LHS, Op, RHS, T); + } + + // Implement isa support. + static inline bool classof(const SymExpr* SE) { + return SE->getKind() == SymSymKind; + } +}; + +class SymbolManager { + typedef llvm::FoldingSet DataSetTy; + DataSetTy DataSet; + unsigned SymbolCounter; + llvm::BumpPtrAllocator& BPAlloc; + BasicValueFactory &BV; + ASTContext& Ctx; + +public: + SymbolManager(ASTContext& ctx, BasicValueFactory &bv, + llvm::BumpPtrAllocator& bpalloc) + : SymbolCounter(0), BPAlloc(bpalloc), BV(bv), Ctx(ctx) {} + + ~SymbolManager(); + + static bool canSymbolicate(QualType T); + + /// Make a unique symbol for MemRegion R according to its kind. + const SymbolRegionValue* getRegionValueSymbol(const MemRegion* R, + QualType T = QualType()); + const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T, + unsigned VisitCount, + const void* SymbolTag = 0); + + const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount, + const void* SymbolTag = 0) { + return getConjuredSymbol(E, E->getType(), VisitCount, SymbolTag); + } + + const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol, + const TypedRegion *R); + + const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t); + + const SymIntExpr *getSymIntExpr(const SymExpr &lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t) { + return getSymIntExpr(&lhs, op, rhs, t); + } + + const SymSymExpr *getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const SymExpr *rhs, QualType t); + + QualType getType(const SymExpr *SE) const { + return SE->getType(Ctx); + } + + ASTContext &getContext() { return Ctx; } + BasicValueFactory &getBasicVals() { return BV; } +}; + +class SymbolReaper { + typedef llvm::DenseSet SetTy; + + SetTy TheLiving; + SetTy TheDead; + LiveVariables& Liveness; + SymbolManager& SymMgr; + const StackFrameContext *CurrentStackFrame; + +public: + SymbolReaper(LiveVariables& liveness, SymbolManager& symmgr, + const StackFrameContext *currentStackFrame) + : Liveness(liveness), SymMgr(symmgr), CurrentStackFrame(currentStackFrame) + {} + + ~SymbolReaper() {} + + bool isLive(SymbolRef sym); + + bool isLive(const Stmt* Loc, const Stmt* ExprVal) const { + return Liveness.isLive(Loc, ExprVal); + } + + bool isLive(const Stmt* Loc, const VarRegion *VR) const; + + void markLive(SymbolRef sym); + bool maybeDead(SymbolRef sym); + + typedef SetTy::const_iterator dead_iterator; + dead_iterator dead_begin() const { return TheDead.begin(); } + dead_iterator dead_end() const { return TheDead.end(); } + + bool hasDeadSymbols() const { + return !TheDead.empty(); + } +}; + +class SymbolVisitor { +public: + // VisitSymbol - A visitor method invoked by + // GRStateManager::scanReachableSymbols. The method returns \c true if + // symbols should continue be scanned and \c false otherwise. + virtual bool VisitSymbol(SymbolRef sym) = 0; + virtual ~SymbolVisitor(); +}; + +} // end clang namespace + +namespace llvm { +static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os, + const clang::SymExpr *SE) { + SE->dumpToStream(os); + return os; +} +} // end llvm namespace +#endif diff --git a/include/clang/Checker/PathSensitive/ValueManager.h b/include/clang/Checker/PathSensitive/ValueManager.h new file mode 100644 index 000000000000..ea3af57ed3e4 --- /dev/null +++ b/include/clang/Checker/PathSensitive/ValueManager.h @@ -0,0 +1,208 @@ +//== ValueManager.h - Aggregate manager of symbols and SVals ----*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines ValueManager, a class that manages symbolic values +// and SVals created for use by GRExprEngine and related classes. It +// wraps and owns SymbolManager, MemRegionManager, and BasicValueFactory. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H +#define LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H + +#include "llvm/ADT/OwningPtr.h" +#include "clang/Checker/PathSensitive/MemRegion.h" +#include "clang/Checker/PathSensitive/SVals.h" +#include "clang/Checker/PathSensitive/BasicValueFactory.h" +#include "clang/Checker/PathSensitive/SymbolManager.h" +#include "clang/Checker/PathSensitive/SValuator.h" + +namespace llvm { class BumpPtrAllocator; } + +namespace clang { + +class GRStateManager; + +class ValueManager { + + ASTContext &Context; + BasicValueFactory BasicVals; + + /// SymMgr - Object that manages the symbol information. + SymbolManager SymMgr; + + /// SVator - SValuator object that creates SVals from expressions. + llvm::OwningPtr SVator; + + MemRegionManager MemMgr; + + GRStateManager &StateMgr; + + const QualType ArrayIndexTy; + const unsigned ArrayIndexWidth; + +public: + ValueManager(llvm::BumpPtrAllocator &alloc, ASTContext &context, + GRStateManager &stateMgr) + : Context(context), BasicVals(context, alloc), + SymMgr(context, BasicVals, alloc), + MemMgr(context, alloc), StateMgr(stateMgr), + ArrayIndexTy(context.IntTy), + ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) { + // FIXME: Generalize later. + SVator.reset(clang::CreateSimpleSValuator(*this)); + } + + // Accessors to submanagers. + + ASTContext &getContext() { return Context; } + const ASTContext &getContext() const { return Context; } + + GRStateManager &getStateManager() { return StateMgr; } + + BasicValueFactory &getBasicValueFactory() { return BasicVals; } + const BasicValueFactory &getBasicValueFactory() const { return BasicVals; } + + SymbolManager &getSymbolManager() { return SymMgr; } + const SymbolManager &getSymbolManager() const { return SymMgr; } + + SValuator &getSValuator() { return *SVator.get(); } + + MemRegionManager &getRegionManager() { return MemMgr; } + const MemRegionManager &getRegionManager() const { return MemMgr; } + + // Forwarding methods to SymbolManager. + + const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T, + unsigned VisitCount, + const void* SymbolTag = 0) { + return SymMgr.getConjuredSymbol(E, T, VisitCount, SymbolTag); + } + + const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount, + const void* SymbolTag = 0) { + return SymMgr.getConjuredSymbol(E, VisitCount, SymbolTag); + } + + /// makeZeroVal - Construct an SVal representing '0' for the specified type. + DefinedOrUnknownSVal makeZeroVal(QualType T); + + /// getRegionValueSymbolVal - make a unique symbol for value of R. + DefinedOrUnknownSVal getRegionValueSymbolVal(const MemRegion *R, + QualType T = QualType()); + + DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag, + const Expr *E, unsigned Count); + DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag, + const Expr *E, QualType T, + unsigned Count); + + DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(SymbolRef parentSymbol, + const TypedRegion *R); + + DefinedSVal getFunctionPointer(const FunctionDecl *FD); + + DefinedSVal getBlockPointer(const BlockDecl *BD, CanQualType locTy, + const LocationContext *LC); + + NonLoc makeCompoundVal(QualType T, llvm::ImmutableList Vals) { + return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals)); + } + + NonLoc makeLazyCompoundVal(const void *store, const TypedRegion *R) { + return nonloc::LazyCompoundVal(BasicVals.getLazyCompoundValData(store, R)); + } + + NonLoc makeZeroArrayIndex() { + return nonloc::ConcreteInt(BasicVals.getValue(0, ArrayIndexTy)); + } + + NonLoc makeArrayIndex(uint64_t idx) { + return nonloc::ConcreteInt(BasicVals.getValue(idx, ArrayIndexTy)); + } + + SVal convertToArrayIndex(SVal V); + + nonloc::ConcreteInt makeIntVal(const IntegerLiteral* I) { + return nonloc::ConcreteInt(BasicVals.getValue(I->getValue(), + I->getType()->isUnsignedIntegerType())); + } + + nonloc::ConcreteInt makeIntVal(const llvm::APSInt& V) { + return nonloc::ConcreteInt(BasicVals.getValue(V)); + } + + loc::ConcreteInt makeIntLocVal(const llvm::APSInt &v) { + return loc::ConcreteInt(BasicVals.getValue(v)); + } + + NonLoc makeIntVal(const llvm::APInt& V, bool isUnsigned) { + return nonloc::ConcreteInt(BasicVals.getValue(V, isUnsigned)); + } + + DefinedSVal makeIntVal(uint64_t X, QualType T) { + if (Loc::IsLocType(T)) + return loc::ConcreteInt(BasicVals.getValue(X, T)); + + return nonloc::ConcreteInt(BasicVals.getValue(X, T)); + } + + NonLoc makeIntVal(uint64_t X, bool isUnsigned) { + return nonloc::ConcreteInt(BasicVals.getIntValue(X, isUnsigned)); + } + + NonLoc makeIntValWithPtrWidth(uint64_t X, bool isUnsigned) { + return nonloc::ConcreteInt(BasicVals.getIntWithPtrWidth(X, isUnsigned)); + } + + NonLoc makeIntVal(uint64_t X, unsigned BitWidth, bool isUnsigned) { + return nonloc::ConcreteInt(BasicVals.getValue(X, BitWidth, isUnsigned)); + } + + NonLoc makeLocAsInteger(Loc V, unsigned Bits) { + return nonloc::LocAsInteger(BasicVals.getPersistentSValWithData(V, Bits)); + } + + NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType T); + + NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, + const SymExpr *rhs, QualType T); + + NonLoc makeTruthVal(bool b, QualType T) { + return nonloc::ConcreteInt(BasicVals.getTruthValue(b, T)); + } + + NonLoc makeTruthVal(bool b) { + return nonloc::ConcreteInt(BasicVals.getTruthValue(b)); + } + + Loc makeNull() { + return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth()); + } + + Loc makeLoc(SymbolRef Sym) { + return loc::MemRegionVal(MemMgr.getSymbolicRegion(Sym)); + } + + Loc makeLoc(const MemRegion* R) { + return loc::MemRegionVal(R); + } + + Loc makeLoc(const AddrLabelExpr* E) { + return loc::GotoLabel(E->getLabel()); + } + + Loc makeLoc(const llvm::APSInt& V) { + return loc::ConcreteInt(BasicVals.getValue(V)); + } +}; +} // end clang namespace +#endif + diff --git a/include/clang/CodeGen/CodeGenOptions.h b/include/clang/CodeGen/CodeGenOptions.h index 8682715ce552..e1d4ad1b1cce 100644 --- a/include/clang/CodeGen/CodeGenOptions.h +++ b/include/clang/CodeGen/CodeGenOptions.h @@ -41,6 +41,8 @@ public: unsigned NoCommon : 1; /// Set when -fno-common or C++ is enabled. unsigned NoImplicitFloat : 1; /// Set when -mno-implicit-float is enabled. unsigned NoZeroInitializedInBSS : 1; /// -fno-zero-initialized-in-bss + unsigned ObjCLegacyDispatch: 1; /// Use legacy Objective-C dispatch, even with + /// 2.0 runtime. unsigned OptimizationLevel : 3; /// The -O[0-4] option specified. unsigned OptimizeSize : 1; /// If -Os is specified. unsigned SoftFloat : 1; /// -soft-float. @@ -90,12 +92,13 @@ public: NoCommon = 0; NoImplicitFloat = 0; NoZeroInitializedInBSS = 0; + ObjCLegacyDispatch = 0; OptimizationLevel = 0; OptimizeSize = 0; - UnrollLoops = 0; SoftFloat = 0; TimePasses = 0; UnitAtATime = 1; + UnrollLoops = 0; UnwindTables = 0; VerifyModule = 1; diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index 2511dfb7677a..047363ea597b 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -38,19 +38,21 @@ def analysis_CFGView : Flag<"-cfg-view">, HelpText<"View Control-Flow Graphs using GraphViz">; def analysis_DisplayLiveVariables : Flag<"-dump-live-variables">, HelpText<"Print results of live variable analysis">; -def analysis_SecuritySyntacticChecks : Flag<"-warn-security-syntactic">, +def analysis_LLVMConventionChecker : Flag<"-analyzer-check-llvm-conventions">, + HelpText<"Check code for LLVM codebase conventions (domain-specific)">; +def analysis_SecuritySyntacticChecks : Flag<"-analyzer-check-security-syntactic">, HelpText<"Perform quick security checks that require no data flow">; -def analysis_WarnDeadStores : Flag<"-warn-dead-stores">, +def analysis_WarnDeadStores : Flag<"-analyzer-check-dead-stores">, HelpText<"Warn about stores to dead variables">; def analysis_WarnUninitVals : Flag<"-warn-uninit-values">, HelpText<"Warn about uses of uninitialized variables">; -def analysis_WarnObjCMethSigs : Flag<"-warn-objc-methodsigs">, +def analysis_WarnObjCMethSigs : Flag<"-analyzer-check-objc-methodsigs">, HelpText<"Warn about Objective-C method signatures with type incompatibilities">; -def analysis_WarnObjCDealloc : Flag<"-warn-objc-missing-dealloc">, +def analysis_WarnObjCDealloc : Flag<"-analyzer-check-objc-missing-dealloc">, HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">; -def analysis_WarnObjCUnusedIvars : Flag<"-warn-objc-unused-ivars">, +def analysis_WarnObjCUnusedIvars : Flag<"-analyzer-check-objc-unused-ivars">, HelpText<"Warn about private ivars that are never used">; -def analysis_CheckerCFRef : Flag<"-checker-cfref">, +def analysis_ObjCMemChecker : Flag<"-analyzer-check-objc-mem">, HelpText<"Run the [Core] Foundation reference count checker">; def analysis_WarnSizeofPointer : Flag<"-warn-sizeof-pointer">, HelpText<"Warn about unintended use of sizeof() on pointer expressions">; @@ -102,6 +104,8 @@ def analyzer_viz_egraph_ubigraph : Flag<"-analyzer-viz-egraph-ubigraph">, def disable_llvm_optzns : Flag<"-disable-llvm-optzns">, HelpText<"Don't run LLVM optimization passes">; +def disable_llvm_verifier : Flag<"-disable-llvm-verifier">, + HelpText<"Don't run the LLVM IR verifier pass">; def disable_red_zone : Flag<"-disable-red-zone">, HelpText<"Do not emit code that uses the red zone.">; def dwarf_debug_flags : Separate<"-dwarf-debug-flags">, @@ -115,6 +119,10 @@ def no_implicit_float : Flag<"-no-implicit-float">, HelpText<"Don't generate implicit floating point instructions (x86-only)">; def fno_merge_all_constants : Flag<"-fno-merge-all-constants">, HelpText<"Disallow merging of constants.">; +def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">, + HelpText<"Do not emit code to make initialization of local statics thread safe">; +def fdump_vtable_layouts : Flag<"-fdump-vtable-layouts">, + HelpText<"Dump the layouts of all vtables that will be emitted in a translation unit">; def masm_verbose : Flag<"-masm-verbose">, HelpText<"Generate verbose assembly output">; def mcode_model : Separate<"-mcode-model">, @@ -165,6 +173,7 @@ def fno_caret_diagnostics : Flag<"-fno-caret-diagnostics">, HelpText<"Do not include source line and caret with diagnostics">; def fno_diagnostics_fixit_info : Flag<"-fno-diagnostics-fixit-info">, HelpText<"Do not include fixit information in diagnostics">; +def fdiagnostics_binary : Flag<"-fdiagnostics-binary">; def w : Flag<"-w">, HelpText<"Suppress all warnings">; def pedantic : Flag<"-pedantic">; def pedantic_errors : Flag<"-pedantic-errors">; @@ -197,6 +206,9 @@ def verify : Flag<"-verify">, // CompilerInvocation out of a driver-derived argument vector. def cc1 : Flag<"-cc1">; +def ast_merge : Separate<"-ast-merge">, + MetaVarName<"">, + HelpText<"Merge the given AST file into the translation unit being compiled.">; def code_completion_at : Separate<"-code-completion-at">, MetaVarName<"::">, HelpText<"Dump code-completion information at a location">; @@ -280,6 +292,8 @@ def emit_llvm_bc : Flag<"-emit-llvm-bc">, HelpText<"Build ASTs then convert to LLVM, emit .bc file">; def emit_llvm_only : Flag<"-emit-llvm-only">, HelpText<"Build ASTs and convert to LLVM, discarding output">; +def emit_obj : Flag<"-emit-obj">, + HelpText<"Emit native object files">; def rewrite_test : Flag<"-rewrite-test">, HelpText<"Rewriter playground">; def rewrite_objc : Flag<"-rewrite-objc">, @@ -319,6 +333,8 @@ def fblocks : Flag<"-fblocks">, def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">; def fexceptions : Flag<"-fexceptions">, HelpText<"Enable support for exception handling">; +def fsjlj_exceptions : Flag<"-fsjlj-exceptions">, + HelpText<"Use SjLj style exceptions">; def ffreestanding : Flag<"-ffreestanding">, HelpText<"Assert that the compilation takes place in a freestanding environment">; def fgnu_runtime : Flag<"-fgnu-runtime">, @@ -346,10 +362,14 @@ def fobjc_gc : Flag<"-fobjc-gc">, HelpText<"Enable Objective-C garbage collection">; def fobjc_gc_only : Flag<"-fobjc-gc-only">, HelpText<"Use GC exclusively for Objective-C related memory management">; +def fobjc_legacy_dispatch : Flag<"-fobjc-legacy-dispatch">, + HelpText<"Use legacy dispatch with the Objective-C non-fragile ABI">; def print_ivar_layout : Flag<"-print-ivar-layout">, HelpText<"Enable Objective-C Ivar layout bitmap print trace">; def fobjc_nonfragile_abi : Flag<"-fobjc-nonfragile-abi">, HelpText<"enable objective-c's nonfragile abi">; +def fobjc_nonfragile_abi2 : Flag<"-fobjc-nonfragile-abi2">, + HelpText<"enable objective-c's enhanced nonfragile abi">; def ftrapv : Flag<"-ftrapv">, HelpText<"Trap on integer overflow">; def pic_level : Separate<"-pic-level">, diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h index 3186471ce613..64f88ed98318 100644 --- a/include/clang/Driver/Driver.h +++ b/include/clang/Driver/Driver.h @@ -77,32 +77,36 @@ public: /// Information about the host which can be overriden by the user. std::string HostBits, HostMachine, HostSystem, HostRelease; + /// Name to use when calling the generic gcc. + std::string CCCGenericGCCName; + /// Whether the driver should follow g++ like behavior. - bool CCCIsCXX : 1; + unsigned CCCIsCXX : 1; /// Echo commands while executing (in -v style). - bool CCCEcho : 1; + unsigned CCCEcho : 1; /// Only print tool bindings, don't build any jobs. - bool CCCPrintBindings : 1; - - /// Name to use when calling the generic gcc. - std::string CCCGenericGCCName; + unsigned CCCPrintBindings : 1; private: + /// Whether to check that input files exist when constructing compilation + /// jobs. + unsigned CheckInputsExist : 1; + /// Use the clang compiler where possible. - bool CCCUseClang : 1; + unsigned CCCUseClang : 1; /// Use clang for handling C++ and Objective-C++ inputs. - bool CCCUseClangCXX : 1; + unsigned CCCUseClangCXX : 1; /// Use clang as a preprocessor (clang's preprocessor will still be /// used where an integrated CPP would). - bool CCCUseClangCPP : 1; + unsigned CCCUseClangCPP : 1; public: /// Use lazy precompiled headers for PCH support. - bool CCCUsePCH; + unsigned CCCUsePCH : 1; private: /// Only use clang for the given architectures (only used when @@ -129,6 +133,10 @@ public: const Diagnostic &getDiags() const { return Diags; } + bool getCheckInputsExist() const { return CheckInputsExist; } + + void setCheckInputsExist(bool Value) { CheckInputsExist = Value; } + /// @} /// @name Primary Functionality /// @{ diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 955d98e4e914..4693e5c1433c 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -252,6 +252,7 @@ def fconstant_string_class_EQ : Joined<"-fconstant-string-class=">, Group, Group; def fdebug_pass_arguments : Flag<"-fdebug-pass-arguments">, Group; def fdebug_pass_structure : Flag<"-fdebug-pass-structure">, Group; +def fdiagnostics_binary : Flag<"-fdiagnostics-binary">, Group, Flags<[HelpHidden]>; def fdiagnostics_fixit_info : Flag<"-fdiagnostics-fixit-info">, Group; def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-range-info">, Group; def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, Group; @@ -302,6 +303,7 @@ def fno_keep_inline_functions : Flag<"-fno-keep-inline-functions">, Group, Group; def fno_merge_all_constants : Flag<"-fno-merge-all-constants">, Group; def fno_ms_extensions : Flag<"-fno-ms-extensions">, Group; +def fno_objc_legacy_dispatch : Flag<"-fno-objc-legacy-dispatch">, Group; def fno_omit_frame_pointer : Flag<"-fno-omit-frame-pointer">, Group; def fno_pascal_strings : Flag<"-fno-pascal-strings">, Group; def fno_rtti : Flag<"-fno-rtti">, Group; @@ -309,6 +311,7 @@ def fno_show_column : Flag<"-fno-show-column">, Group; def fno_show_source_location : Flag<"-fno-show-source-location">, Group; def fno_stack_protector : Flag<"-fno-stack-protector">, Group; def fno_strict_aliasing : Flag<"-fno-strict-aliasing">, Group; +def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">, Group; def fno_unit_at_a_time : Flag<"-fno-unit-at-a-time">, Group; def fno_unwind_tables : Flag<"-fno-unwind-tables">, Group; def fno_working_directory : Flag<"-fno-working-directory">, Group; @@ -317,8 +320,10 @@ def fobjc_atdefs : Flag<"-fobjc-atdefs">, Group; def fobjc_call_cxx_cdtors : Flag<"-fobjc-call-cxx-cdtors">, Group; def fobjc_gc_only : Flag<"-fobjc-gc-only">, Group; def fobjc_gc : Flag<"-fobjc-gc">, Group; +def fobjc_legacy_dispatch : Flag<"-fobjc-legacy-dispatch">, Group; def fobjc_new_property : Flag<"-fobjc-new-property">, Group; def fobjc_nonfragile_abi : Flag<"-fobjc-nonfragile-abi">, Group; +def fobjc_nonfragile_abi2 : Flag<"-fobjc-nonfragile-abi2">, Group; def fobjc_sender_dependent_dispatch : Flag<"-fobjc-sender-dependent-dispatch">, Group; def fobjc : Flag<"-fobjc">, Group; def fomit_frame_pointer : Flag<"-fomit-frame-pointer">, Group; @@ -348,6 +353,7 @@ def fsyntax_only : Flag<"-fsyntax-only">, Flags<[DriverOption]>; def ftabstop_EQ : Joined<"-ftabstop=">, Group; def ftemplate_depth_ : Joined<"-ftemplate-depth-">, Group; def fterminated_vtables : Flag<"-fterminated-vtables">, Group; +def fthreadsafe_statics : Flag<"-fthreadsafe-statics">, Group; def ftime_report : Flag<"-ftime-report">, Group; def ftrapv : Flag<"-ftrapv">, Group; def funit_at_a_time : Flag<"-funit-at-a-time">, Group; @@ -374,6 +380,7 @@ def image__base : Separate<"-image_base">; def include_ : JoinedOrSeparate<"-include">, Group, EnumName<"include">; def init : Separate<"-init">; def install__name : Separate<"-install_name">; +def integrated_as : Flag<"-integrated-as">, Flags<[DriverOption]>; def iprefix : JoinedOrSeparate<"-iprefix">, Group; def iquote : JoinedOrSeparate<"-iquote">, Group; def isysroot : JoinedOrSeparate<"-isysroot">, Group; @@ -398,10 +405,10 @@ def mfix_and_continue : Flag<"-mfix-and-continue">, Group def mfloat_abi_EQ : Joined<"-mfloat-abi=">, Group; def mfpu_EQ : Joined<"-mfpu=">, Group; def mhard_float : Flag<"-mhard-float">, Group; -def miphoneos_version_min_EQ : Joined<"-miphoneos-version-min=">, Group; +def miphoneos_version_min_EQ : Joined<"-miphoneos-version-min=">, Group, Flags<[DriverOption]>; def mkernel : Flag<"-mkernel">, Group; def mllvm : Separate<"-mllvm">; -def mmacosx_version_min_EQ : Joined<"-mmacosx-version-min=">, Group; +def mmacosx_version_min_EQ : Joined<"-mmacosx-version-min=">, Group, Flags<[DriverOption]>; def mmmx : Flag<"-mmmx">, Group; def mno_3dnowa : Flag<"-mno-3dnowa">, Group; def mno_3dnow : Flag<"-mno-3dnow">, Group; @@ -416,7 +423,10 @@ def mno_sse4a : Flag<"-mno-sse4a">, Group; def mno_sse4 : Flag<"-mno-sse4">, Group; def mno_sse : Flag<"-mno-sse">, Group; def mno_ssse3 : Flag<"-mno-ssse3">, Group; + def mno_thumb : Flag<"-mno-thumb">, Group; +def marm : Flag<"-marm">, Alias; + def mno_warn_nonportable_cfstrings : Flag<"-mno-warn-nonportable-cfstrings">, Group; def mpascal_strings : Flag<"-mpascal-strings">, Group; def mred_zone : Flag<"-mred-zone">, Group; @@ -438,6 +448,7 @@ def m_Joined : Joined<"-m">, Group; def no_canonical_prefixes : Flag<"-no-canonical-prefixes">, Flags<[DriverOption, HelpHidden]>, HelpText<"Use relative instead of canonical paths">; def no_cpp_precomp : Flag<"-no-cpp-precomp">; +def no_integrated_as : Flag<"-no-integrated-as">, Flags<[DriverOption]>; def no_integrated_cpp : Flag<"-no-integrated-cpp">, Flags<[DriverOption]>; def no__dead__strip__inits__and__terms : Flag<"-no_dead_strip_inits_and_terms">; def nobuiltininc : Flag<"-nobuiltininc">; @@ -481,6 +492,8 @@ def pthread : Flag<"-pthread">; def p : Flag<"-p">; def read__only__relocs : Separate<"-read_only_relocs">; def remap : Flag<"-remap">; +def rewrite_objc : Flag<"-rewrite-objc">, Flags<[DriverOption]>, + HelpText<"Rewrite Objective-C source to C++">; def rpath : Separate<"-rpath">, Flags<[LinkerInput]>; def r : Flag<"-r">; def save_temps : Flag<"-save-temps">, Flags<[DriverOption]>, diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h index 8a89f01e0f4b..851e4235b00e 100644 --- a/include/clang/Driver/Tool.h +++ b/include/clang/Driver/Tool.h @@ -45,6 +45,7 @@ public: virtual bool acceptsPipedInput() const = 0; virtual bool canPipeOutput() const = 0; + virtual bool hasIntegratedAssembler() const { return false; } virtual bool hasIntegratedCPP() const = 0; /// ConstructJob - Construct jobs to perform the action \arg JA, diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h index cc8d438db3e9..9a82973dca27 100644 --- a/include/clang/Driver/ToolChain.h +++ b/include/clang/Driver/ToolChain.h @@ -53,9 +53,9 @@ public: const Driver &getDriver() const; const llvm::Triple &getTriple() const { return Triple; } - std::string getArchName() const { return Triple.getArchName(); } - std::string getPlatform() const { return Triple.getVendorName(); } - std::string getOS() const { return Triple.getOSName(); } + llvm::StringRef getArchName() const { return Triple.getArchName(); } + llvm::StringRef getPlatform() const { return Triple.getVendorName(); } + llvm::StringRef getOS() const { return Triple.getOSName(); } std::string getTripleString() const { return Triple.getTriple(); @@ -90,10 +90,19 @@ public: /// IsBlocksDefault - Does this tool chain enable -fblocks by default. virtual bool IsBlocksDefault() const { return false; } + /// IsIntegratedAssemblerDefault - Does this tool chain enable -integrated-as + /// by default. + virtual bool IsIntegratedAssemblerDefault() const { return false; } + /// IsObjCNonFragileABIDefault - Does this tool chain set /// -fobjc-nonfragile-abi by default. virtual bool IsObjCNonFragileABIDefault() const { return false; } + /// IsObjCLegacyDispatchDefault - Does this tool chain set + /// -fobjc-legacy-dispatch by default (this is only used with the non-fragile + /// ABI). + virtual bool IsObjCLegacyDispatchDefault() const { return false; } + /// GetDefaultStackProtectorLevel - Get the default stack protector level for /// this tool chain (0=off, 1=on, 2=all). virtual unsigned GetDefaultStackProtectorLevel() const { return 0; } @@ -114,6 +123,9 @@ public: /// UseDwarfDebugFlags - Embed the compile options to clang into the Dwarf /// compile unit information. virtual bool UseDwarfDebugFlags() const { return false; } + + /// UseSjLjExceptions - Does this tool chain use SjLj exceptions. + virtual bool UseSjLjExceptions() const { return false; } }; } // end namespace driver diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def index d66fe9221a30..61a5043b34fc 100644 --- a/include/clang/Driver/Types.def +++ b/include/clang/Driver/Types.def @@ -72,6 +72,7 @@ TYPE("ast", AST, INVALID, "ast", "u") TYPE("llvm-asm", LLVMAsm, INVALID, "s", "") TYPE("llvm-bc", LLVMBC, INVALID, "o", "") TYPE("plist", Plist, INVALID, "plist", "") +TYPE("rewritten-objc", RewrittenObjC,INVALID, "cpp", "") TYPE("precompiled-header", PCH, INVALID, "gch", "A") TYPE("object", Object, INVALID, "o", "") TYPE("treelang", Treelang, INVALID, 0, "u") diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h index 978b0d2b2aa6..7ec5063b5334 100644 --- a/include/clang/Frontend/ASTConsumers.h +++ b/include/clang/Frontend/ASTConsumers.h @@ -73,10 +73,11 @@ ASTConsumer *CreateObjCRewriter(const std::string &InFile, // assembly. This runs optimizations depending on the CodeGenOptions // parameter. The output depends on the Action parameter. enum BackendAction { - Backend_EmitAssembly, // Emit native assembly - Backend_EmitBC, // Emit LLVM bitcode file + Backend_EmitAssembly, // Emit native assembly files + Backend_EmitBC, // Emit LLVM bitcode files Backend_EmitLL, // Emit human-readable LLVM assembly - Backend_EmitNothing // Don't emit anything (benchmarking mode) + Backend_EmitNothing, // Don't emit anything (benchmarking mode) + Backend_EmitObj // Emit native object files }; ASTConsumer *CreateBackendConsumer(BackendAction Action, Diagnostic &Diags, diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 2659dbb2a30c..f122dd954d3e 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -53,6 +53,10 @@ class ASTUnit { llvm::OwningPtr Ctx; bool tempFile; + /// Optional owned invocation, just used to make the invocation used in + /// LoadFromCommandLine available. + llvm::OwningPtr Invocation; + // OnlyLocalDecls - when true, walking this AST should only visit declarations // that come from the AST itself, not from included precompiled headers. // FIXME: This is temporary; eventually, CIndex will always do this. @@ -131,7 +135,6 @@ public: static ASTUnit *LoadFromPCHFile(const std::string &Filename, Diagnostic &Diags, bool OnlyLocalDecls = false, - bool UseBumpAllocator = false, RemappedFile *RemappedFiles = 0, unsigned NumRemappedFiles = 0); @@ -139,14 +142,14 @@ public: /// CompilerInvocation object. /// /// \param CI - The compiler invocation to use; it must have exactly one input - /// source file. + /// source file. The ASTUnit takes ownership of the CompilerInvocation object. /// /// \param Diags - The diagnostics engine to use for reporting errors; its /// lifetime is expected to extend past that of the returned ASTUnit. // // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we // shouldn't need to specify them at construction time. - static ASTUnit *LoadFromCompilerInvocation(const CompilerInvocation &CI, + static ASTUnit *LoadFromCompilerInvocation(CompilerInvocation *CI, Diagnostic &Diags, bool OnlyLocalDecls = false); @@ -169,7 +172,6 @@ public: Diagnostic &Diags, llvm::StringRef ResourceFilesPath, bool OnlyLocalDecls = false, - bool UseBumpAllocator = false, RemappedFile *RemappedFiles = 0, unsigned NumRemappedFiles = 0); }; diff --git a/include/clang/Frontend/Analyses.def b/include/clang/Frontend/Analyses.def index 7d55673a612f..287c67ebb7ef 100644 --- a/include/clang/Frontend/Analyses.def +++ b/include/clang/Frontend/Analyses.def @@ -24,28 +24,32 @@ ANALYSIS(CFGView, "cfg-view", ANALYSIS(DisplayLiveVariables, "dump-live-variables", "Print results of live variable analysis", Code) -ANALYSIS(SecuritySyntacticChecks, "warn-security-syntactic", +ANALYSIS(SecuritySyntacticChecks, "analyzer-check-security-syntactic", "Perform quick security checks that require no data flow", Code) -ANALYSIS(WarnDeadStores, "warn-dead-stores", +ANALYSIS(LLVMConventionChecker, "analyzer-check-llvm-conventions", + "Check code for LLVM codebase conventions (domain-specific)", + TranslationUnit) + +ANALYSIS(WarnDeadStores, "analyzer-check-dead-stores", "Warn about stores to dead variables", Code) ANALYSIS(WarnUninitVals, "warn-uninit-values", "Warn about uses of uninitialized variables", Code) -ANALYSIS(WarnObjCMethSigs, "warn-objc-methodsigs", +ANALYSIS(WarnObjCMethSigs, "analyzer-check-objc-methodsigs", "Warn about Objective-C method signatures with type incompatibilities", ObjCImplementation) -ANALYSIS(WarnObjCDealloc, "warn-objc-missing-dealloc", +ANALYSIS(WarnObjCDealloc, "analyzer-check-objc-missing-dealloc", "Warn about Objective-C classes that lack a correct implementation of -dealloc", ObjCImplementation) -ANALYSIS(WarnObjCUnusedIvars, "warn-objc-unused-ivars", +ANALYSIS(WarnObjCUnusedIvars, "analyzer-check-objc-unused-ivars", "Warn about private ivars that are never used", ObjCImplementation) -ANALYSIS(CheckerCFRef, "checker-cfref", +ANALYSIS(ObjCMemChecker, "analyzer-check-objc-mem", "Run the [Core] Foundation reference count checker", Code) ANALYSIS(WarnSizeofPointer, "warn-sizeof-pointer", @@ -61,6 +65,7 @@ ANALYSIS(InlineCall, "inline-call", ANALYSIS_STORE(BasicStore, "basic", "Use basic analyzer store", CreateBasicStoreManager) ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateRegionStoreManager) +ANALYSIS_STORE(FlatStore, "flat", "Use flat analyzer store", CreateFlatStoreManager) #ifndef ANALYSIS_CONSTRAINTS #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index edafe623a4f6..1be4118e5542 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -58,11 +58,10 @@ class TargetInfo; /// and a long form that takes explicit instances of any required objects. class CompilerInstance { /// The LLVM context used for this instance. - llvm::LLVMContext *LLVMContext; - bool OwnsLLVMContext; + llvm::OwningPtr LLVMContext; /// The options used in this compiler instance. - CompilerInvocation Invocation; + llvm::OwningPtr Invocation; /// The diagnostics engine instance. llvm::OwningPtr Diagnostics; @@ -97,11 +96,10 @@ class CompilerInstance { /// The list of active output files. std::list< std::pair > OutputFiles; + void operator=(const CompilerInstance &); // DO NOT IMPLEMENT + CompilerInstance(const CompilerInstance&); // DO NOT IMPLEMENT public: - /// Create a new compiler instance with the given LLVM context, optionally - /// taking ownership of it. - CompilerInstance(llvm::LLVMContext *_LLVMContext = 0, - bool _OwnsLLVMContext = true); + CompilerInstance(); ~CompilerInstance(); /// @name High-Level Operations @@ -150,93 +148,101 @@ public: return *LLVMContext; } + llvm::LLVMContext *takeLLVMContext() { return LLVMContext.take(); } + /// setLLVMContext - Replace the current LLVM context and take ownership of /// \arg Value. - void setLLVMContext(llvm::LLVMContext *Value, bool TakeOwnership = true) { - LLVMContext = Value; - OwnsLLVMContext = TakeOwnership; - } + void setLLVMContext(llvm::LLVMContext *Value); /// } /// @name Compiler Invocation and Options /// { - CompilerInvocation &getInvocation() { return Invocation; } - const CompilerInvocation &getInvocation() const { return Invocation; } - void setInvocation(const CompilerInvocation &Value) { Invocation = Value; } + bool hasInvocation() const { return Invocation != 0; } + + CompilerInvocation &getInvocation() { + assert(Invocation && "Compiler instance has no invocation!"); + return *Invocation; + } + + CompilerInvocation *takeInvocation() { return Invocation.take(); } + + /// setInvocation - Replace the current invocation; the compiler instance + /// takes ownership of \arg Value. + void setInvocation(CompilerInvocation *Value); /// } /// @name Forwarding Methods /// { AnalyzerOptions &getAnalyzerOpts() { - return Invocation.getAnalyzerOpts(); + return Invocation->getAnalyzerOpts(); } const AnalyzerOptions &getAnalyzerOpts() const { - return Invocation.getAnalyzerOpts(); + return Invocation->getAnalyzerOpts(); } CodeGenOptions &getCodeGenOpts() { - return Invocation.getCodeGenOpts(); + return Invocation->getCodeGenOpts(); } const CodeGenOptions &getCodeGenOpts() const { - return Invocation.getCodeGenOpts(); + return Invocation->getCodeGenOpts(); } DependencyOutputOptions &getDependencyOutputOpts() { - return Invocation.getDependencyOutputOpts(); + return Invocation->getDependencyOutputOpts(); } const DependencyOutputOptions &getDependencyOutputOpts() const { - return Invocation.getDependencyOutputOpts(); + return Invocation->getDependencyOutputOpts(); } DiagnosticOptions &getDiagnosticOpts() { - return Invocation.getDiagnosticOpts(); + return Invocation->getDiagnosticOpts(); } const DiagnosticOptions &getDiagnosticOpts() const { - return Invocation.getDiagnosticOpts(); + return Invocation->getDiagnosticOpts(); } FrontendOptions &getFrontendOpts() { - return Invocation.getFrontendOpts(); + return Invocation->getFrontendOpts(); } const FrontendOptions &getFrontendOpts() const { - return Invocation.getFrontendOpts(); + return Invocation->getFrontendOpts(); } HeaderSearchOptions &getHeaderSearchOpts() { - return Invocation.getHeaderSearchOpts(); + return Invocation->getHeaderSearchOpts(); } const HeaderSearchOptions &getHeaderSearchOpts() const { - return Invocation.getHeaderSearchOpts(); + return Invocation->getHeaderSearchOpts(); } LangOptions &getLangOpts() { - return Invocation.getLangOpts(); + return Invocation->getLangOpts(); } const LangOptions &getLangOpts() const { - return Invocation.getLangOpts(); + return Invocation->getLangOpts(); } PreprocessorOptions &getPreprocessorOpts() { - return Invocation.getPreprocessorOpts(); + return Invocation->getPreprocessorOpts(); } const PreprocessorOptions &getPreprocessorOpts() const { - return Invocation.getPreprocessorOpts(); + return Invocation->getPreprocessorOpts(); } PreprocessorOutputOptions &getPreprocessorOutputOpts() { - return Invocation.getPreprocessorOutputOpts(); + return Invocation->getPreprocessorOutputOpts(); } const PreprocessorOutputOptions &getPreprocessorOutputOpts() const { - return Invocation.getPreprocessorOutputOpts(); + return Invocation->getPreprocessorOutputOpts(); } TargetOptions &getTargetOpts() { - return Invocation.getTargetOpts(); + return Invocation->getTargetOpts(); } const TargetOptions &getTargetOpts() const { - return Invocation.getTargetOpts(); + return Invocation->getTargetOpts(); } /// } diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h index 13039bb5063e..b37c18057f0f 100644 --- a/include/clang/Frontend/DiagnosticOptions.h +++ b/include/clang/Frontend/DiagnosticOptions.h @@ -31,9 +31,12 @@ public: unsigned ShowOptionNames : 1; /// Show the diagnostic name for mappable /// diagnostics. unsigned ShowColors : 1; /// Show diagnostics with ANSI color sequences. - unsigned VerifyDiagnostics; /// Check that diagnostics match the expected + unsigned VerifyDiagnostics: 1; /// Check that diagnostics match the expected /// diagnostics, indicated by markers in the /// input source file. + unsigned BinaryOutput : 1; /// Emit diagnostics via the diagnostic + /// binary serialization mechanism, to be + /// deserialized by, e.g., the CIndex library. /// The distance between tab stops. unsigned TabStop; @@ -66,6 +69,7 @@ public: ShowOptionNames = 0; ShowSourceRanges = 0; VerifyDiagnostics = 0; + BinaryOutput = 0; } }; diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h index 3042767af874..7b7db3785cf3 100644 --- a/include/clang/Frontend/FrontendAction.h +++ b/include/clang/Frontend/FrontendAction.h @@ -18,6 +18,7 @@ namespace clang { class ASTUnit; class ASTConsumer; class CompilerInstance; +class ASTMergeAction; /// FrontendAction - Abstract base class for actions which can be performed by /// the frontend. @@ -25,6 +26,7 @@ class FrontendAction { std::string CurrentFile; llvm::OwningPtr CurrentASTUnit; CompilerInstance *Instance; + friend class ASTMergeAction; protected: /// @name Implementation Action Interface @@ -104,6 +106,10 @@ public: return *CurrentASTUnit; } + ASTUnit *takeCurrentASTUnit() { + return CurrentASTUnit.take(); + } + void setCurrentFile(llvm::StringRef Value, ASTUnit *AST = 0); /// @} @@ -167,7 +173,7 @@ public: }; /// ASTFrontendAction - Abstract base class to use for AST consumer based -/// frontend actios. +/// frontend actions. class ASTFrontendAction : public FrontendAction { /// ExecuteAction - Implement the ExecuteAction interface by running Sema on /// the already initialized AST consumer. diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h index 33bb8aaf6e1d..cbb3508c8a76 100644 --- a/include/clang/Frontend/FrontendActions.h +++ b/include/clang/Frontend/FrontendActions.h @@ -11,6 +11,8 @@ #define LLVM_CLANG_FRONTEND_FRONTENDACTIONS_H #include "clang/Frontend/FrontendAction.h" +#include +#include namespace clang { class FixItRewriter; @@ -119,6 +121,43 @@ public: virtual bool hasCodeCompletionSupport() const { return true; } }; +/** + * \brief Frontend action adaptor that merges ASTs together. + * + * This action takes an existing AST file and "merges" it into the AST + * context, producing a merged context. This action is an action + * adaptor, which forwards most of its calls to another action that + * will consume the merged context. + */ +class ASTMergeAction : public FrontendAction { + /// \brief The action that the merge action adapts. + FrontendAction *AdaptedAction; + + /// \brief The set of AST files to merge. + std::vector ASTFiles; + +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile); + + virtual bool BeginSourceFileAction(CompilerInstance &CI, + llvm::StringRef Filename); + + virtual void ExecuteAction(); + virtual void EndSourceFileAction(); + +public: + ASTMergeAction(FrontendAction *AdaptedAction, + std::string *ASTFiles, unsigned NumASTFiles); + virtual ~ASTMergeAction(); + + virtual bool usesPreprocessorOnly() const; + virtual bool usesCompleteTranslationUnit(); + virtual bool hasPCHSupport() const; + virtual bool hasASTSupport() const; + virtual bool hasCodeCompletionSupport() const; +}; + //===----------------------------------------------------------------------===// // Code Gen AST Actions //===----------------------------------------------------------------------===// @@ -154,6 +193,11 @@ public: EmitLLVMOnlyAction(); }; +class EmitObjAction : public CodeGenAction { +public: + EmitObjAction(); +}; + //===----------------------------------------------------------------------===// // Preprocessor Actions //===----------------------------------------------------------------------===// diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h index 735a86a70fcb..80ba77864a5b 100644 --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -31,6 +31,7 @@ namespace frontend { EmitHTML, ///< Translate input source into HTML. EmitLLVM, ///< Emit a .ll file. EmitLLVMOnly, ///< Generate LLVM IR, but do not + EmitObj, ///< Emit a .o file. FixIt, ///< Parse and apply any fixits to the source. GeneratePCH, ///< Generate pre-compiled header. GeneratePTH, ///< Generate pre-tokenized header. @@ -109,6 +110,9 @@ public: /// The list of plugins to load. std::vector Plugins; + /// \brief The list of AST files to merge. + std::vector ASTMergeFiles; + public: FrontendOptions() { DebugCodeCompletionPrinter = 1; diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index 1a9f4ceab933..e22d37ba34f5 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -221,7 +221,11 @@ namespace clang { /// \brief Record code for the version control branch and revision /// information of the compiler used to build this PCH file. - VERSION_CONTROL_BRANCH_REVISION = 21 + VERSION_CONTROL_BRANCH_REVISION = 21, + + /// \brief Record code for the array of unused static functions. + UNUSED_STATIC_FUNCS = 22 + }; /// \brief Record types used within a source manager block. @@ -686,7 +690,11 @@ namespace clang { // \brief A CXXConstCastExpr record. EXPR_CXX_CONST_CAST, // \brief A CXXFunctionalCastExpr record. - EXPR_CXX_FUNCTIONAL_CAST + EXPR_CXX_FUNCTIONAL_CAST, + // \brief A CXXBoolLiteralExpr record. + EXPR_CXX_BOOL_LITERAL, + // \brief A CXXNullPtrLiteralExpr record. + EXPR_CXX_NULL_PTR_LITERAL }; /// \brief The kinds of designators that can occur in a diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index 9665ce189f4a..065006fce5c4 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -306,6 +306,10 @@ private: /// \brief The set of tentative definitions stored in the the PCH /// file. llvm::SmallVector TentativeDefinitions; + + /// \brief The set of tentative definitions stored in the the PCH + /// file. + llvm::SmallVector UnusedStaticFuncs; /// \brief The set of locally-scoped external declarations stored in /// the the PCH file. diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h index 0f36df43e232..6a6e319463f0 100644 --- a/include/clang/Lex/Lexer.h +++ b/include/clang/Lex/Lexer.h @@ -199,6 +199,9 @@ public: /// the current file. SourceLocation getSourceLocation() { return getSourceLocation(BufferPtr); } + /// \brief Return the current location in the buffer. + const char *getBufferLocation() const { return BufferPtr; } + /// Stringify - Convert the specified string into a C string by escaping '\' /// and " characters. This does not add surrounding ""'s to the string. /// If Charify is true, this escapes the ' character instead of ". diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h index 604eae1027aa..b5dde9a700e8 100644 --- a/include/clang/Lex/Token.h +++ b/include/clang/Lex/Token.h @@ -124,6 +124,10 @@ public: UintData = L.getRawEncoding(); } + SourceLocation getLastLoc() const { + return isAnnotation() ? getAnnotationEndLoc() : getLocation(); + } + /// getAnnotationRange - SourceRange of the group of tokens that this /// annotation token represents. SourceRange getAnnotationRange() const { diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index ff33f5039d5d..ec542f08c303 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -459,6 +459,8 @@ public: virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D) { return DeclPtrTy(); } + virtual void ActOnObjCCatchParam(DeclPtrTy D) { + } /// AddInitializerToDecl - This action is called immediately after /// ActOnDeclarator (when an initializer is present). The code is factored @@ -808,6 +810,11 @@ public: return StmtEmpty(); } + /// ActOnSwitchBodyError - This is called if there is an error parsing the + /// body of the switch stmt instead of ActOnFinishSwitchStmt. + virtual void ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch, + StmtArg Body) {} + virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, StmtArg Body) { return StmtEmpty(); @@ -897,7 +904,7 @@ public: bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, - std::string *Names, + IdentifierInfo **Names, MultiExprArg Constraints, MultiExprArg Exprs, ExprArg AsmString, @@ -1270,7 +1277,8 @@ public: /// definition. virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc, IdentifierInfo *Ident, - SourceLocation LBrace) { + SourceLocation LBrace, + AttributeList *AttrList) { return DeclPtrTy(); } @@ -1649,9 +1657,12 @@ public: /// a well-formed program), ColonLoc is the location of the ':' that /// starts the constructor initializer, and MemInit/NumMemInits /// contains the individual member (and base) initializers. + /// AnyErrors will be true if there were any invalid member initializers + /// that are not represented in the list. virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, - MemInitTy **MemInits, unsigned NumMemInits){ + MemInitTy **MemInits, unsigned NumMemInits, + bool AnyErrors){ } virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {} diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index f923b5e910db..4fe81a7eb5c2 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -153,6 +153,8 @@ private: /*TSC*/unsigned TypeSpecComplex : 2; /*TSS*/unsigned TypeSpecSign : 2; /*TST*/unsigned TypeSpecType : 5; + bool TypeAltiVecVector : 1; + bool TypeAltiVecPixel : 1; bool TypeSpecOwned : 1; // type-qualifiers @@ -193,7 +195,7 @@ private: SourceRange Range; SourceLocation StorageClassSpecLoc, SCS_threadLoc; - SourceLocation TSWLoc, TSCLoc, TSSLoc, TSTLoc; + SourceLocation TSWLoc, TSCLoc, TSSLoc, TSTLoc, AltiVecLoc; SourceRange TypeofParensRange; SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc; SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc; @@ -213,6 +215,8 @@ public: TypeSpecComplex(TSC_unspecified), TypeSpecSign(TSS_unspecified), TypeSpecType(TST_unspecified), + TypeAltiVecVector(false), + TypeAltiVecPixel(false), TypeSpecOwned(false), TypeQualifiers(TSS_unspecified), FS_inline_specified(false), @@ -250,6 +254,8 @@ public: TSC getTypeSpecComplex() const { return (TSC)TypeSpecComplex; } TSS getTypeSpecSign() const { return (TSS)TypeSpecSign; } TST getTypeSpecType() const { return (TST)TypeSpecType; } + bool isTypeAltiVecVector() const { return TypeAltiVecVector; } + bool isTypeAltiVecPixel() const { return TypeAltiVecPixel; } bool isTypeSpecOwned() const { return TypeSpecOwned; } void *getTypeRep() const { return TypeRep; } CXXScopeSpec &getTypeSpecScope() { return TypeScope; } @@ -260,6 +266,7 @@ public: SourceLocation getTypeSpecComplexLoc() const { return TSCLoc; } SourceLocation getTypeSpecSignLoc() const { return TSSLoc; } SourceLocation getTypeSpecTypeLoc() const { return TSTLoc; } + SourceLocation getAltiVecLoc() const { return AltiVecLoc; } SourceRange getTypeofParensRange() const { return TypeofParensRange; } void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; } @@ -344,6 +351,10 @@ public: unsigned &DiagID); bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, void *Rep = 0, bool Owned = false); + bool SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID); + bool SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID); bool SetTypeSpecError(); void UpdateTypeRep(void *Rep) { TypeRep = Rep; } diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index e7cb0a2493d3..f4d3d3e54d51 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -81,6 +81,11 @@ class Parser { /// Ident_super - IdentifierInfo for "super", to support fast /// comparison. IdentifierInfo *Ident_super; + /// Ident_vector and Ident_pixel - cached IdentifierInfo's for + /// "vector" and "pixel" fast comparison. Only present if + /// AltiVec enabled. + IdentifierInfo *Ident_vector; + IdentifierInfo *Ident_pixel; llvm::OwningPtr PackHandler; llvm::OwningPtr UnusedHandler; @@ -320,6 +325,81 @@ private: /// annotated. bool TryAnnotateCXXScopeToken(bool EnteringContext = false); + /// TryAltiVecToken - Check for context-sensitive AltiVec identifier tokens, + /// replacing them with the non-context-sensitive keywords. This returns + /// true if the token was replaced. + bool TryAltiVecToken(DeclSpec &DS, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, bool &isInvalid) { + if (getLang().AltiVec) { + if (Tok.getIdentifierInfo() == Ident_vector) { + const Token nextToken = NextToken(); + switch (nextToken.getKind()) { + case tok::kw_short: + case tok::kw_long: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_char: + case tok::kw_int: + case tok::kw_float: + case tok::kw_double: + case tok::kw_bool: + case tok::kw___pixel: + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + return true; + case tok::identifier: + if (nextToken.getIdentifierInfo() == Ident_pixel) { + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + return true; + } + break; + default: + break; + } + } else if ((Tok.getIdentifierInfo() == Ident_pixel) && + DS.isTypeAltiVecVector()) { + isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); + return true; + } + } + return false; + } + + /// TryAltiVecVectorToken - Check for context-sensitive AltiVec vector + /// identifier token, replacing it with the non-context-sensitive __vector. + /// This returns true if the token was replaced. + bool TryAltiVecVectorToken() { + if (getLang().AltiVec) { + if (Tok.getIdentifierInfo() == Ident_vector) { + const Token nextToken = NextToken(); + switch (nextToken.getKind()) { + case tok::kw_short: + case tok::kw_long: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_char: + case tok::kw_int: + case tok::kw_float: + case tok::kw_double: + case tok::kw_bool: + case tok::kw___pixel: + Tok.setKind(tok::kw___vector); + return true; + case tok::identifier: + if (nextToken.getIdentifierInfo() == Ident_pixel) { + Tok.setKind(tok::kw___vector); + return true; + } + break; + default: + break; + } + } + } + return false; + } + /// TentativeParsingAction - An object that is used as a kind of "tentative /// parsing transaction". It gets instantiated to mark the token position and /// after the token consumption is done, Commit() or Revert() is called to @@ -1009,9 +1089,9 @@ private: OwningStmtResult ParseReturnStatement(AttributeList *Attr); OwningStmtResult ParseAsmStatement(bool &msAsm); OwningStmtResult FuzzyParseMicrosoftAsmStatement(); - bool ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, - llvm::SmallVectorImpl &Constraints, - llvm::SmallVectorImpl &Exprs); + bool ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, + llvm::SmallVectorImpl &Constraints, + llvm::SmallVectorImpl &Exprs); //===--------------------------------------------------------------------===// // C++ 6: Statements and Blocks @@ -1065,7 +1145,8 @@ private: bool ParseOptionalTypeSpecifier(DeclSpec &DS, bool &isInvalid, const char *&PrevSpec, unsigned &DiagID, - const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), + bool SuppressDeclarations = false); void ParseSpecifierQualifierList(DeclSpec &DS); @@ -1311,7 +1392,8 @@ private: void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), - AccessSpecifier AS = AS_none); + AccessSpecifier AS = AS_none, + bool SuppressDeclarations = false); void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType, DeclPtrTy TagDecl); void ParseCXXClassMemberDeclaration(AccessSpecifier AS, -- cgit v1.2.3