mirror of
https://github.com/opnsense/src.git
synced 2026-04-29 10:11:09 -04:00
Update clang to r84119.
This commit is contained in:
parent
5362a71c02
commit
4c8b24812d
1226 changed files with 106269 additions and 41376 deletions
|
|
@ -1,3 +1,26 @@
|
|||
# Clang version information
|
||||
|
||||
# Make sure that CMake reconfigures when the version changes.
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/VER
|
||||
${CMAKE_CURRENT_BINARY_DIR}/VER)
|
||||
|
||||
set(CLANG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(CLANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# Compute the Clang version from the contents of VER
|
||||
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/VER CLANG_VERSION_DATA)
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION
|
||||
${CLANG_VERSION_DATA})
|
||||
message(STATUS "Clang version: ${CLANG_VERSION}")
|
||||
|
||||
# Add appropriate flags for GCC
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
# FIXME: Turn off exceptions, RTTI:
|
||||
# -fno-exceptions -fno-rtti
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual -pedantic -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings")
|
||||
endif ()
|
||||
|
||||
macro(add_clang_library name)
|
||||
set(srcs ${ARGN})
|
||||
if(MSVC_IDE OR XCODE)
|
||||
|
|
@ -11,10 +34,27 @@ macro(add_clang_library name)
|
|||
../../include/clang${dir}/*.def)
|
||||
set(srcs ${srcs} ${headers})
|
||||
endif(MSVC_IDE OR XCODE)
|
||||
add_library( ${name} ${srcs} )
|
||||
if (SHARED_LIBRARY)
|
||||
set(libkind SHARED)
|
||||
else()
|
||||
set(libkind)
|
||||
endif()
|
||||
add_library( ${name} ${libkind} ${srcs} )
|
||||
if( LLVM_COMMON_DEPENDS )
|
||||
add_dependencies( ${name} ${LLVM_COMMON_DEPENDS} )
|
||||
endif( LLVM_COMMON_DEPENDS )
|
||||
if( LLVM_USED_LIBS )
|
||||
foreach(lib ${LLVM_USED_LIBS})
|
||||
target_link_libraries( ${name} ${lib} )
|
||||
endforeach(lib)
|
||||
endif( LLVM_USED_LIBS )
|
||||
if( LLVM_LINK_COMPONENTS )
|
||||
llvm_config(${name} ${LLVM_LINK_COMPONENTS})
|
||||
endif( LLVM_LINK_COMPONENTS )
|
||||
get_system_libs(llvm_system_libs)
|
||||
if( llvm_system_libs )
|
||||
target_link_libraries(${name} ${llvm_system_libs})
|
||||
endif( llvm_system_libs )
|
||||
add_dependencies(${name} ClangDiagnosticCommon)
|
||||
if(MSVC)
|
||||
get_target_property(cflag ${name} COMPILE_FLAGS)
|
||||
|
|
@ -36,8 +76,6 @@ macro(add_clang_executable name)
|
|||
set(srcs ${srcs} ${headers})
|
||||
endif(MSVC_IDE)
|
||||
add_llvm_executable( ${name} ${srcs} )
|
||||
install(TARGETS ${name}
|
||||
RUNTIME DESTINATION bin)
|
||||
endmacro(add_clang_executable)
|
||||
|
||||
include_directories(
|
||||
|
|
@ -57,4 +95,5 @@ add_subdirectory(lib)
|
|||
add_subdirectory(tools)
|
||||
|
||||
# TODO: docs.
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(test)
|
||||
|
||||
|
|
|
|||
51
INPUTS/all-std-headers.cpp
Normal file
51
INPUTS/all-std-headers.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <cfloat>
|
||||
#include <ciso646>
|
||||
#include <climits>
|
||||
#include <clocale>
|
||||
#include <cmath>
|
||||
#include <complex>
|
||||
#include <csetjmp>
|
||||
#include <csignal>
|
||||
#include <cstdarg>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <cwchar>
|
||||
#include <cwctype>
|
||||
#include <deque>
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <ios>
|
||||
#include <iosfwd>
|
||||
#include <iostream>
|
||||
#include <istream>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <locale>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <numeric>
|
||||
#include <ostream>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <stdexcept>
|
||||
#include <streambuf>
|
||||
#include <string>
|
||||
#include <strstream>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
#include <valarray>
|
||||
#include <vector>
|
||||
49
INSTALL.txt
Normal file
49
INSTALL.txt
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
// Clang Installation Instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
These instructions describe how to build and install Clang.
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Step 1: Organization
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
Clang is designed to be built as part of an LLVM build. Assuming that the LLVM
|
||||
source code is located at $LLVM_SRC_ROOT, then the clang source code should be
|
||||
installed as:
|
||||
|
||||
$LLVM_SRC_ROOT/tools/clang
|
||||
|
||||
The directory is not required to be called clang, but doing so will allow the
|
||||
LLVM build system to automatically recognize it and build it along with LLVM.
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Step 2: Configure and Build LLVM
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
Configure and build your copy of LLVM (see $LLVM_SRC_ROOT/GettingStarted.html
|
||||
for more information).
|
||||
|
||||
Assuming you installed clang at $LLVM_SRC_ROOT/tools/clang then Clang will
|
||||
automatically be built with LLVM. Otherwise, run 'make' in the Clang source
|
||||
directory to build Clang.
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Step 3: (Optional) Verify Your Build
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
It is a good idea to run the Clang tests to make sure your build works
|
||||
correctly. From inside the Clang build directory, run 'make test' to run the
|
||||
tests.
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Step 4: Install Clang
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
From inside the Clang build directory, run 'make install' to install the Clang
|
||||
compiler and header files into the prefix directory selected when LLVM was
|
||||
configured.
|
||||
|
||||
The Clang compiler is available as 'clang' and supports a gcc like command line
|
||||
interface. See the man page for clang (installed into $prefix/share/man/man1)
|
||||
for more information.
|
||||
|
|
@ -4,7 +4,7 @@ LLVM Release License
|
|||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2007 University of Illinois at Urbana-Champaign.
|
||||
Copyright (c) 2007-2009 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
|
|
|||
29
Makefile
29
Makefile
|
|
@ -4,7 +4,7 @@ DIRS := include lib tools docs
|
|||
include $(LEVEL)/Makefile.common
|
||||
|
||||
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
|
||||
test::
|
||||
all::
|
||||
$(Verb) if [ ! -f test/Makefile ]; then \
|
||||
$(MKDIR) test; \
|
||||
$(CP) $(PROJ_SRC_DIR)/test/Makefile test/Makefile; \
|
||||
|
|
@ -30,3 +30,30 @@ cscope.files:
|
|||
-or -name '*.h' > cscope.files
|
||||
|
||||
.PHONY: test report clean cscope.files
|
||||
|
||||
install-local::
|
||||
$(Echo) Installing include files
|
||||
$(Verb) $(MKDIR) $(PROJ_includedir)
|
||||
$(Verb) if test -d "$(PROJ_SRC_ROOT)/tools/clang/include" ; then \
|
||||
cd $(PROJ_SRC_ROOT)/tools/clang/include && \
|
||||
for hdr in `find . -type f '!' '(' -name '*~' \
|
||||
-o -name '.#*' -o -name '*.in' -o -name '*.txt' \
|
||||
-o -name 'Makefile' -o -name '*.td' ')' -print \
|
||||
| grep -v CVS | grep -v .svn` ; do \
|
||||
instdir=`dirname "$(PROJ_includedir)/$$hdr"` ; \
|
||||
if test \! -d "$$instdir" ; then \
|
||||
$(EchoCmd) Making install directory $$instdir ; \
|
||||
$(MKDIR) $$instdir ;\
|
||||
fi ; \
|
||||
$(DataInstall) $$hdr $(PROJ_includedir)/$$hdr ; \
|
||||
done ; \
|
||||
fi
|
||||
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
|
||||
$(Verb) if test -d "$(PROJ_OBJ_ROOT)/tools/clang/include" ; then \
|
||||
cd $(PROJ_OBJ_ROOT)/tools/clang/include && \
|
||||
for hdr in `find . -type f '!' '(' -name 'Makefile' ')' -print \
|
||||
| grep -v CVS | grep -v .tmp` ; do \
|
||||
$(DataInstall) $$hdr $(PROJ_includedir)/$$hdr ; \
|
||||
done ; \
|
||||
fi
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ This is similar to -Eonly.
|
|||
Creating and using a PTH file for performance measurement (use a release-asserts
|
||||
build).
|
||||
|
||||
$ clang -x objective-c-header INPUTS/Cocoa_h.m -o /tmp/tokencache
|
||||
$ clang -token-cache /tmp/tokencache INPUTS/Cocoa_h.m
|
||||
$ clang -ccc-pch-is-pth -x objective-c-header INPUTS/Cocoa_h.m -o /tmp/tokencache
|
||||
$ clang-cc -token-cache /tmp/tokencache INPUTS/Cocoa_h.m
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
|
|
|
|||
186
README.txt
186
README.txt
|
|
@ -1,178 +1,26 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
// C Language Family Front-end
|
||||
//===----------------------------------------------------------------------===//
|
||||
Chris Lattner
|
||||
|
||||
I. Introduction:
|
||||
|
||||
clang: noun
|
||||
1. A loud, resonant, metallic sound.
|
||||
2. The strident call of a crane or goose.
|
||||
3. C-language family front-end toolkit.
|
||||
Welcome to Clang. This is a compiler front-end for the C family of languages
|
||||
(C, C++, Objective-C, and Objective-C++) which is built as part of the LLVM
|
||||
compiler intrastructure project.
|
||||
|
||||
The world needs better compiler tools, tools which are built as libraries. This
|
||||
design point allows reuse of the tools in new and novel ways. However, building
|
||||
the tools as libraries isn't enough: they must have clean APIs, be as
|
||||
decoupled from each other as possible, and be easy to modify/extend. This
|
||||
requires clean layering, decent design, and avoiding tying the libraries to a
|
||||
specific use. Oh yeah, did I mention that we want the resultant libraries to
|
||||
be as fast as possible? :)
|
||||
Unlike many other compiler frontends, Clang is useful for a number of things
|
||||
beyond just compiling code: we intend for Clang to be host to a number of
|
||||
different source level tools. One example of this is the Clang Static Analyzer.
|
||||
|
||||
This front-end is built as a component of the LLVM toolkit that can be used
|
||||
with the LLVM backend or independently of it. In this spirit, the API has been
|
||||
carefully designed as the following components:
|
||||
|
||||
libsupport - Basic support library, reused from LLVM.
|
||||
If you're interested in more (including how to build Clang) it is best to read
|
||||
the relevant web sites. Here are some pointers:
|
||||
|
||||
libsystem - System abstraction library, reused from LLVM.
|
||||
|
||||
libbasic - Diagnostics, SourceLocations, SourceBuffer abstraction,
|
||||
file system caching for input source files. This depends on
|
||||
libsupport and libsystem.
|
||||
Information on Clang: http://clang.llvm.org/
|
||||
Building and using Clang: http://clang.llvm.org/get_started.html
|
||||
Clang Static Analyzer: http://clang-analyzer.llvm.org/
|
||||
Information on the LLVM project: http://llvm.org/
|
||||
|
||||
libast - Provides classes to represent the C AST, the C type system,
|
||||
builtin functions, and various helpers for analyzing and
|
||||
manipulating the AST (visitors, pretty printers, etc). This
|
||||
library depends on libbasic.
|
||||
|
||||
|
||||
liblex - C/C++/ObjC lexing and preprocessing, identifier hash table,
|
||||
pragma handling, tokens, and macros. This depends on libbasic.
|
||||
|
||||
libparse - C (for now) parsing and local semantic analysis. This library
|
||||
invokes coarse-grained 'Actions' provided by the client to do
|
||||
stuff (e.g. libsema builds ASTs). This depends on liblex.
|
||||
|
||||
libsema - Provides a set of parser actions to build a standardized AST
|
||||
for programs. AST's are 'streamed' out a top-level declaration
|
||||
at a time, allowing clients to use decl-at-a-time processing,
|
||||
build up entire translation units, or even build 'whole
|
||||
program' ASTs depending on how they use the APIs. This depends
|
||||
on libast and libparse.
|
||||
|
||||
librewrite - Fast, scalable rewriting of source code. This operates on
|
||||
the raw syntactic text of source code, allowing a client
|
||||
to insert and delete text in very large source files using
|
||||
the same source location information embedded in ASTs. This
|
||||
is intended to be a low-level API that is useful for
|
||||
higher-level clients and libraries such as code refactoring.
|
||||
|
||||
libanalysis - Source-level dataflow analysis useful for performing analyses
|
||||
such as computing live variables. It also includes a
|
||||
path-sensitive "graph-reachability" engine for writing
|
||||
analyses that reason about different possible paths of
|
||||
execution through source code. This is currently being
|
||||
employed to write a set of checks for finding bugs in software.
|
||||
|
||||
libcodegen - Lower the AST to LLVM IR for optimization & codegen. Depends
|
||||
on libast.
|
||||
|
||||
clang - An example driver, client of the libraries at various levels.
|
||||
This depends on all these libraries, and on LLVM VMCore.
|
||||
|
||||
This front-end has been intentionally built as a DAG of libraries, making it
|
||||
easy to reuse individual parts or replace pieces if desired. For example, to
|
||||
build a preprocessor, you take the Basic and Lexer libraries. If you want an
|
||||
indexer, you take those plus the Parser library and provide some actions for
|
||||
indexing. If you want a refactoring, static analysis, or source-to-source
|
||||
compiler tool, it makes sense to take those plus the AST building and semantic
|
||||
analyzer library. Finally, if you want to use this with the LLVM backend,
|
||||
you'd take these components plus the AST to LLVM lowering code.
|
||||
|
||||
In the future I hope this toolkit will grow to include new and interesting
|
||||
components, including a C++ front-end, ObjC support, and a whole lot of other
|
||||
things.
|
||||
|
||||
Finally, it should be pointed out that the goal here is to build something that
|
||||
is high-quality and industrial-strength: all the obnoxious features of the C
|
||||
family must be correctly supported (trigraphs, preprocessor arcana, K&R-style
|
||||
prototypes, GCC/MS extensions, etc). It cannot be used if it is not 'real'.
|
||||
|
||||
|
||||
II. Usage of clang driver:
|
||||
|
||||
* Basic Command-Line Options:
|
||||
- Help: clang --help
|
||||
- Standard GCC options accepted: -E, -I*, -i*, -pedantic, -std=c90, etc.
|
||||
- To make diagnostics more gcc-like: -fno-caret-diagnostics -fno-show-column
|
||||
- Enable metric printing: -stats
|
||||
|
||||
* -fsyntax-only is currently the default mode.
|
||||
|
||||
* -E mode works the same way as GCC.
|
||||
|
||||
* -Eonly mode does all preprocessing, but does not print the output,
|
||||
useful for timing the preprocessor.
|
||||
|
||||
* -fsyntax-only is currently partially implemented, lacking some
|
||||
semantic analysis (some errors and warnings are not produced).
|
||||
|
||||
* -parse-noop parses code without building an AST. This is useful
|
||||
for timing the cost of the parser without including AST building
|
||||
time.
|
||||
|
||||
* -parse-ast builds ASTs, but doesn't print them. This is most
|
||||
useful for timing AST building vs -parse-noop.
|
||||
|
||||
* -parse-ast-print pretty prints most expression and statements nodes.
|
||||
|
||||
* -parse-ast-check checks that diagnostic messages that are expected
|
||||
are reported and that those which are reported are expected.
|
||||
|
||||
* -dump-cfg builds ASTs and then CFGs. CFGs are then pretty-printed.
|
||||
|
||||
* -view-cfg builds ASTs and then CFGs. CFGs are then visualized by
|
||||
invoking Graphviz.
|
||||
|
||||
For more information on getting Graphviz to work with clang/LLVM,
|
||||
see: http://llvm.org/docs/ProgrammersManual.html#ViewGraph
|
||||
|
||||
|
||||
III. Current advantages over GCC:
|
||||
|
||||
* Column numbers are fully tracked (no 256 col limit, no GCC-style pruning).
|
||||
* All diagnostics have column numbers, includes 'caret diagnostics', and they
|
||||
highlight regions of interesting code (e.g. the LHS and RHS of a binop).
|
||||
* Full diagnostic customization by client (can format diagnostics however they
|
||||
like, e.g. in an IDE or refactoring tool) through DiagnosticClient interface.
|
||||
* Built as a framework, can be reused by multiple tools.
|
||||
* All languages supported linked into same library (no cc1,cc1obj, ...).
|
||||
* mmap's code in read-only, does not dirty the pages like GCC (mem footprint).
|
||||
* LLVM License, can be linked into non-GPL projects.
|
||||
* Full diagnostic control, per diagnostic. Diagnostics are identified by ID.
|
||||
* Significantly faster than GCC at semantic analysis, parsing, preprocessing
|
||||
and lexing.
|
||||
* Defers exposing platform-specific stuff to as late as possible, tracks use of
|
||||
platform-specific features (e.g. #ifdef PPC) to allow 'portable bytecodes'.
|
||||
* The lexer doesn't rely on the "lexer hack": it has no notion of scope and
|
||||
does not categorize identifiers as types or variables -- this is up to the
|
||||
parser to decide.
|
||||
|
||||
Potential Future Features:
|
||||
|
||||
* Fine grained diag control within the source (#pragma enable/disable warning).
|
||||
* Better token tracking within macros? (Token came from this line, which is
|
||||
a macro argument instantiated here, recursively instantiated here).
|
||||
* Fast #import with a module system.
|
||||
* Dependency tracking: change to header file doesn't recompile every function
|
||||
that texually depends on it: recompile only those functions that need it.
|
||||
This is aka 'incremental parsing'.
|
||||
|
||||
|
||||
IV. Missing Functionality / Improvements
|
||||
|
||||
Lexer:
|
||||
* Source character mapping. GCC supports ASCII and UTF-8.
|
||||
See GCC options: -ftarget-charset and -ftarget-wide-charset.
|
||||
* Universal character support. Experimental in GCC, enabled with
|
||||
-fextended-identifiers.
|
||||
* -fpreprocessed mode.
|
||||
|
||||
Preprocessor:
|
||||
* #assert/#unassert
|
||||
* MSExtension: "L#param" stringizes to a wide string literal.
|
||||
* Add support for -M*
|
||||
|
||||
Traditional Preprocessor:
|
||||
* Currently, we have none. :)
|
||||
If you have questions or comments about Clang, a great place to discuss them is
|
||||
on the Clang development mailing list:
|
||||
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
|
||||
|
||||
If you find a bug in Clang, please file it in the LLVM bug tracker:
|
||||
http://llvm.org/bugs/
|
||||
|
|
|
|||
1
VER
Normal file
1
VER
Normal file
|
|
@ -0,0 +1 @@
|
|||
1.1
|
||||
|
|
@ -30,18 +30,27 @@
|
|||
1A30A9E90B93A4C800201A91 /* ExprCXX.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A30A9E80B93A4C800201A91 /* ExprCXX.h */; };
|
||||
1A32C17F0E1C87AD00A6B483 /* ExprConstant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A32C17E0E1C87AD00A6B483 /* ExprConstant.cpp */; };
|
||||
1A376A2D0D4AED9B002A1C52 /* CGExprConstant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */; };
|
||||
1A410F850FBCE51100351440 /* SemaTemplateInstantiateExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A410F840FBCE51100351440 /* SemaTemplateInstantiateExpr.cpp */; };
|
||||
1A471AB50F437BC500753CE8 /* CGBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A471AB40F437BC500753CE8 /* CGBlocks.cpp */; };
|
||||
1A5119C40FBDF71000A1FF22 /* SemaTemplateInstantiateStmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A5119C30FBDF71000A1FF22 /* SemaTemplateInstantiateStmt.cpp */; };
|
||||
1A4C41BF105B4C0B0047B5E7 /* CGCXXClass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A4C41BE105B4C0B0047B5E7 /* CGCXXClass.cpp */; };
|
||||
1A535ED9107BC45E000C3AE7 /* CXXInheritance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A535ED8107BC45E000C3AE7 /* CXXInheritance.cpp */; };
|
||||
1A5D5E580E5E81010023C059 /* CGCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A5D5E570E5E81010023C059 /* CGCXX.cpp */; };
|
||||
1A6B6CD410693FC900BB4A8F /* CodeCompleteConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */; };
|
||||
1A6B6CD510693FC900BB4A8F /* SemaCodeComplete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */; };
|
||||
1A6B6E9A1069833600BB4A8F /* CGCXXExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6E991069833600BB4A8F /* CGCXXExpr.cpp */; };
|
||||
1A6C01F7108128710072DEE4 /* CGRtti.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6C01F6108128710072DEE4 /* CGRtti.cpp */; };
|
||||
1A6FE7090FD6F85800E00CA9 /* CGCXXTemp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */; };
|
||||
1A701B640F7C8FE400FEC4D1 /* SemaAccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */; };
|
||||
1A7342480C7B57D500122F56 /* CGObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A7342470C7B57D500122F56 /* CGObjC.cpp */; };
|
||||
1A81AA19108144F40094E50B /* CGVtable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A81AA18108144F40094E50B /* CGVtable.cpp */; };
|
||||
1A869A700BA2164C008DA07A /* LiteralSupport.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */; };
|
||||
1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */; };
|
||||
1AA1D91810125DE30078DEBC /* RecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */; };
|
||||
1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */; };
|
||||
1ADF47AF0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */; };
|
||||
1AE4EE3E103B89ED00888A23 /* StmtProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */; };
|
||||
1AE4EE40103B8A0A00888A23 /* TargetABIInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */; };
|
||||
1AFEF4070F8A6B2300476F2B /* clang-cc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFEF4050F8A6B2300476F2B /* clang-cc.cpp */; };
|
||||
1AFF8AE31012BFC900D248DA /* CGRecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */; };
|
||||
3507E4C20E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */; };
|
||||
352246E70F5C6BE000D0D279 /* HTMLDiagnostics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */; };
|
||||
352246E80F5C6BE000D0D279 /* InitHeaderSearch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E20F5C6BE000D0D279 /* InitHeaderSearch.cpp */; };
|
||||
|
|
@ -66,7 +75,6 @@
|
|||
35544B890F5C7FD700D92AA9 /* SimpleConstraintManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35544B860F5C7FD700D92AA9 /* SimpleConstraintManager.cpp */; };
|
||||
35544B8C0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */; };
|
||||
3557D1A90EB136B100C59739 /* InheritViz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3557D1A80EB136B100C59739 /* InheritViz.cpp */; };
|
||||
3557D1F00EB13BB700C59739 /* SemaInherit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3557D1EF0EB13BB700C59739 /* SemaInherit.cpp */; };
|
||||
35585DC00EAFBC4500D0A97A /* SemaOverload.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35585DBE0EAFBC4500D0A97A /* SemaOverload.cpp */; };
|
||||
3558F76D0E267C8300A5B0DF /* BasicStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3558F76C0E267C8300A5B0DF /* BasicStore.cpp */; };
|
||||
356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */; };
|
||||
|
|
@ -92,7 +100,7 @@
|
|||
35D55B270D81D8C60092E734 /* BasicValueFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35D55B240D81D8C60092E734 /* BasicValueFactory.cpp */; };
|
||||
35D55B280D81D8C60092E734 /* CFRefCount.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35D55B250D81D8C60092E734 /* CFRefCount.cpp */; };
|
||||
35E194690ECB82FB00F21733 /* SemaCXXScopeSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35E194670ECB82FB00F21733 /* SemaCXXScopeSpec.cpp */; };
|
||||
35E1946A0ECB82FB00F21733 /* SemaNamedCast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35E194680ECB82FB00F21733 /* SemaNamedCast.cpp */; };
|
||||
35E1946A0ECB82FB00F21733 /* SemaCXXCast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35E194680ECB82FB00F21733 /* SemaCXXCast.cpp */; };
|
||||
35E1946D0ECB83C100F21733 /* PTHLexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35E1946C0ECB83C100F21733 /* PTHLexer.cpp */; };
|
||||
35EE48B10E0C4CCA00715C54 /* DeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35EE48AF0E0C4CCA00715C54 /* DeclCXX.cpp */; };
|
||||
35EE48B20E0C4CCA00715C54 /* ParentMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35EE48B00E0C4CCA00715C54 /* ParentMap.cpp */; };
|
||||
|
|
@ -105,7 +113,22 @@
|
|||
84AF36A10CB17A3B00C820A5 /* DeclObjC.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84AF36A00CB17A3B00C820A5 /* DeclObjC.h */; };
|
||||
84D9A8880C1A57E100AC7ABC /* AttributeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */; };
|
||||
84D9A88C0C1A581300AC7ABC /* AttributeList.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84D9A88B0C1A581300AC7ABC /* AttributeList.h */; };
|
||||
9012911D1048068D0083456D /* ASTUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9012911C1048068D0083456D /* ASTUnit.cpp */; };
|
||||
90129121104812F90083456D /* CIndex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9012911F104812F90083456D /* CIndex.cpp */; };
|
||||
906BF4B00F83BA2E001071FA /* ConvertUTF.c in Sources */ = {isa = PBXBuildFile; fileRef = 906BF4AF0F83BA2E001071FA /* ConvertUTF.c */; };
|
||||
90F9EFAA104ABDED00D09A15 /* c-index-test.c in Sources */ = {isa = PBXBuildFile; fileRef = 90F9EFA9104ABDED00D09A15 /* c-index-test.c */; };
|
||||
90FD6D7B103C3D49005F5B73 /* Analyzer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D6D103C3D49005F5B73 /* Analyzer.cpp */; };
|
||||
90FD6D7C103C3D49005F5B73 /* ASTLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D6E103C3D49005F5B73 /* ASTLocation.cpp */; };
|
||||
90FD6D7D103C3D49005F5B73 /* DeclReferenceMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D70103C3D49005F5B73 /* DeclReferenceMap.cpp */; };
|
||||
90FD6D7E103C3D49005F5B73 /* Entity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D71103C3D49005F5B73 /* Entity.cpp */; };
|
||||
90FD6D7F103C3D49005F5B73 /* GlobalSelector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D73103C3D49005F5B73 /* GlobalSelector.cpp */; };
|
||||
90FD6D80103C3D49005F5B73 /* Handlers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D74103C3D49005F5B73 /* Handlers.cpp */; };
|
||||
90FD6D81103C3D49005F5B73 /* Indexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D75103C3D49005F5B73 /* Indexer.cpp */; };
|
||||
90FD6D82103C3D49005F5B73 /* IndexProvider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D76103C3D49005F5B73 /* IndexProvider.cpp */; };
|
||||
90FD6D83103C3D49005F5B73 /* Program.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D77103C3D49005F5B73 /* Program.cpp */; };
|
||||
90FD6D84103C3D49005F5B73 /* ResolveLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D79103C3D49005F5B73 /* ResolveLocation.cpp */; };
|
||||
90FD6D85103C3D49005F5B73 /* SelectorMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D7A103C3D49005F5B73 /* SelectorMap.cpp */; };
|
||||
90FD6DB6103D977E005F5B73 /* index-test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6DB5103D977E005F5B73 /* index-test.cpp */; };
|
||||
BDF87CF70FD746F300BBF872 /* SemaTemplateDeduction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */; };
|
||||
DE01DA490B12ADA300AC22CE /* PPCallbacks.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE01DA480B12ADA300AC22CE /* PPCallbacks.h */; };
|
||||
DE06756C0C051CFE00EBBFD8 /* ParseExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */; };
|
||||
|
|
@ -188,8 +211,6 @@
|
|||
DEB076CF0F3A222200F5A2BE /* DeclTemplate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */; };
|
||||
DEB077990F44F97800F5A2BE /* TokenConcatenation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEB077980F44F97800F5A2BE /* TokenConcatenation.cpp */; };
|
||||
DEB07AC80F4A427E00F5A2BE /* SemaAttr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */; };
|
||||
DEC63B1A0C7B940200DBF169 /* CFG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEC63B190C7B940200DBF169 /* CFG.cpp */; };
|
||||
DEC63B1C0C7B940600DBF169 /* CFG.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEC63B1B0C7B940600DBF169 /* CFG.h */; };
|
||||
DEC8D9910A9433CD00353FCA /* Decl.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEC8D9900A9433CD00353FCA /* Decl.h */; };
|
||||
DEC8D9A40A94346E00353FCA /* AST.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEC8D9A30A94346E00353FCA /* AST.h */; };
|
||||
DECAB0D00DB3C84200E13CCB /* RewriteRope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DECAB0CF0DB3C84200E13CCB /* RewriteRope.cpp */; };
|
||||
|
|
@ -307,7 +328,6 @@
|
|||
DE6951C70C4D1F5D00A5826B /* RecordLayout.h in CopyFiles */,
|
||||
DE6954640C5121BD00A5826B /* Token.h in CopyFiles */,
|
||||
DEF2E95F0C5FBD74000C4259 /* InternalsManual.html in CopyFiles */,
|
||||
DEC63B1C0C7B940600DBF169 /* CFG.h in CopyFiles */,
|
||||
DEF7D9F70C9C8B1A0001F598 /* Rewriter.h in CopyFiles */,
|
||||
84AF36A10CB17A3B00C820A5 /* DeclObjC.h in CopyFiles */,
|
||||
DE3986F00CB8D4B300223765 /* IdentifierTable.h in CopyFiles */,
|
||||
|
|
@ -324,7 +344,7 @@
|
|||
1A2193CC0F45EEB700C0713D /* Mangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Mangle.cpp; path = lib/CodeGen/Mangle.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A2193CD0F45EEB700C0713D /* Mangle.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Mangle.h; path = lib/CodeGen/Mangle.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AnalysisConsumer.cpp; path = lib/Frontend/AnalysisConsumer.cpp; sourceTree = "<group>"; };
|
||||
1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTConsumers.cpp; path = lib/Frontend/ASTConsumers.cpp; sourceTree = "<group>"; };
|
||||
1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ASTConsumers.cpp; path = lib/Frontend/ASTConsumers.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Backend.cpp; path = lib/Frontend/Backend.cpp; sourceTree = "<group>"; };
|
||||
1A2A54A70FD1DD1C00F4CE45 /* CacheTokens.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CacheTokens.cpp; path = lib/Frontend/CacheTokens.cpp; sourceTree = "<group>"; };
|
||||
1A2A54A80FD1DD1C00F4CE45 /* DependencyFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DependencyFile.cpp; path = lib/Frontend/DependencyFile.cpp; sourceTree = "<group>"; };
|
||||
|
|
@ -336,19 +356,25 @@
|
|||
1A2A54AE0FD1DD1C00F4CE45 /* PrintPreprocessedOutput.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PrintPreprocessedOutput.cpp; path = lib/Frontend/PrintPreprocessedOutput.cpp; sourceTree = "<group>"; };
|
||||
1A2A54AF0FD1DD1C00F4CE45 /* RewriteBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteBlocks.cpp; path = lib/Frontend/RewriteBlocks.cpp; sourceTree = "<group>"; };
|
||||
1A2A54B00FD1DD1C00F4CE45 /* RewriteMacros.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteMacros.cpp; path = lib/Frontend/RewriteMacros.cpp; sourceTree = "<group>"; };
|
||||
1A2A54B10FD1DD1C00F4CE45 /* RewriteObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteObjC.cpp; path = lib/Frontend/RewriteObjC.cpp; sourceTree = "<group>"; };
|
||||
1A2A54B10FD1DD1C00F4CE45 /* RewriteObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteObjC.cpp; path = lib/Frontend/RewriteObjC.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A2A54B20FD1DD1C00F4CE45 /* RewriteTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteTest.cpp; path = lib/Frontend/RewriteTest.cpp; sourceTree = "<group>"; };
|
||||
1A2A54B30FD1DD1C00F4CE45 /* StmtXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StmtXML.cpp; path = lib/Frontend/StmtXML.cpp; sourceTree = "<group>"; };
|
||||
1A2A54B40FD1DD1C00F4CE45 /* Warnings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Warnings.cpp; path = lib/Frontend/Warnings.cpp; sourceTree = "<group>"; };
|
||||
1A30A9E80B93A4C800201A91 /* ExprCXX.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExprCXX.h; path = clang/AST/ExprCXX.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A32C17E0E1C87AD00A6B483 /* ExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ExprConstant.cpp; path = lib/AST/ExprConstant.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprConstant.cpp; path = lib/CodeGen/CGExprConstant.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A410F840FBCE51100351440 /* SemaTemplateInstantiateExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateExpr.cpp; path = lib/Sema/SemaTemplateInstantiateExpr.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A471AB40F437BC500753CE8 /* CGBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBlocks.cpp; path = lib/CodeGen/CGBlocks.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A5119C30FBDF71000A1FF22 /* SemaTemplateInstantiateStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateStmt.cpp; path = lib/Sema/SemaTemplateInstantiateStmt.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A4C41BE105B4C0B0047B5E7 /* CGCXXClass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXClass.cpp; path = lib/CodeGen/CGCXXClass.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A535ED8107BC45E000C3AE7 /* CXXInheritance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CXXInheritance.cpp; path = lib/AST/CXXInheritance.cpp; sourceTree = "<group>"; };
|
||||
1A535EDB107BC47B000C3AE7 /* CanonicalType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CanonicalType.h; path = clang/AST/CanonicalType.h; sourceTree = "<group>"; };
|
||||
1A5D5E570E5E81010023C059 /* CGCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXX.cpp; path = lib/CodeGen/CGCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A649E1D0F9599D9005B965E /* CGBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CGBlocks.h; path = lib/CodeGen/CGBlocks.h; sourceTree = "<group>"; };
|
||||
1A649E1E0F9599DA005B965E /* CGCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CGCXX.h; path = lib/CodeGen/CGCXX.h; sourceTree = "<group>"; };
|
||||
1A649E1E0F9599DA005B965E /* CGCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGCXX.h; path = lib/CodeGen/CGCXX.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CodeCompleteConsumer.cpp; path = lib/Sema/CodeCompleteConsumer.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCodeComplete.cpp; path = lib/Sema/SemaCodeComplete.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A6B6CD310693FC900BB4A8F /* SemaTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SemaTemplate.h; path = lib/Sema/SemaTemplate.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A6B6E991069833600BB4A8F /* CGCXXExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXExpr.cpp; path = lib/CodeGen/CGCXXExpr.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A6C01F6108128710072DEE4 /* CGRtti.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRtti.cpp; path = lib/CodeGen/CGRtti.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXTemp.cpp; path = lib/CodeGen/CGCXXTemp.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A7019E90F79BC1100FEC4D1 /* DiagnosticAnalysisKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticAnalysisKinds.td; sourceTree = "<group>"; };
|
||||
1A7019EA0F79BC1100FEC4D1 /* DiagnosticASTKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticASTKinds.td; sourceTree = "<group>"; };
|
||||
|
|
@ -361,11 +387,21 @@
|
|||
1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaAccess.cpp; path = lib/Sema/SemaAccess.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A72BEAC0D641E9400B085E9 /* Attr.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Attr.h; path = clang/AST/Attr.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A7342470C7B57D500122F56 /* CGObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGObjC.cpp; path = lib/CodeGen/CGObjC.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A81AA18108144F40094E50B /* CGVtable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGVtable.cpp; path = lib/CodeGen/CGVtable.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A81AA5D108278A20094E50B /* CGVtable.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGVtable.h; path = lib/CodeGen/CGVtable.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A869A6E0BA2164C008DA07A /* LiteralSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralSupport.h; sourceTree = "<group>"; };
|
||||
1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = "<group>"; };
|
||||
1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RecordLayoutBuilder.cpp; path = lib/AST/RecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1AA1D91710125DE30078DEBC /* RecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = RecordLayoutBuilder.h; path = lib/AST/RecordLayoutBuilder.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1AB290021045858B00FE33D8 /* PartialDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = PartialDiagnostic.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = lib/CodeGen/CGBuiltin.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateDecl.cpp; path = lib/Sema/SemaTemplateInstantiateDecl.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1AE4EE3B103B89CA00888A23 /* TreeTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TreeTransform.h; path = lib/Sema/TreeTransform.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtProfile.cpp; path = lib/AST/StmtProfile.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = TargetABIInfo.cpp; path = lib/CodeGen/TargetABIInfo.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1AFEF4050F8A6B2300476F2B /* clang-cc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = "clang-cc.cpp"; path = "tools/clang-cc/clang-cc.cpp"; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRecordLayoutBuilder.cpp; path = lib/CodeGen/CGRecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGRecordLayoutBuilder.h; path = lib/CodeGen/CGRecordLayoutBuilder.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckObjCInstMethSignature.cpp; path = lib/Analysis/CheckObjCInstMethSignature.cpp; sourceTree = "<group>"; };
|
||||
352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLDiagnostics.cpp; path = lib/Frontend/HTMLDiagnostics.cpp; sourceTree = "<group>"; };
|
||||
352246E20F5C6BE000D0D279 /* InitHeaderSearch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InitHeaderSearch.cpp; path = lib/Frontend/InitHeaderSearch.cpp; sourceTree = "<group>"; };
|
||||
|
|
@ -406,7 +442,6 @@
|
|||
35544B870F5C7FD700D92AA9 /* SimpleConstraintManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SimpleConstraintManager.h; path = lib/Analysis/SimpleConstraintManager.h; sourceTree = "<group>"; };
|
||||
35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiate.cpp; path = lib/Sema/SemaTemplateInstantiate.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
3557D1A80EB136B100C59739 /* InheritViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = InheritViz.cpp; path = lib/AST/InheritViz.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
3557D1EF0EB13BB700C59739 /* SemaInherit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaInherit.cpp; path = lib/Sema/SemaInherit.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
35585DBD0EAFBC4500D0A97A /* CXXFieldCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CXXFieldCollector.h; path = lib/Sema/CXXFieldCollector.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
35585DBE0EAFBC4500D0A97A /* SemaOverload.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaOverload.cpp; path = lib/Sema/SemaOverload.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
35585DBF0EAFBC4500D0A97A /* SemaOverload.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SemaOverload.h; path = lib/Sema/SemaOverload.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
|
|
@ -453,7 +488,7 @@
|
|||
35D55B250D81D8C60092E734 /* CFRefCount.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CFRefCount.cpp; path = lib/Analysis/CFRefCount.cpp; sourceTree = "<group>"; };
|
||||
35D55B290D81D8E50092E734 /* BasicValueFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BasicValueFactory.h; path = clang/Analysis/PathSensitive/BasicValueFactory.h; sourceTree = "<group>"; };
|
||||
35E194670ECB82FB00F21733 /* SemaCXXScopeSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCXXScopeSpec.cpp; path = lib/Sema/SemaCXXScopeSpec.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
35E194680ECB82FB00F21733 /* SemaNamedCast.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaNamedCast.cpp; path = lib/Sema/SemaNamedCast.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
35E194680ECB82FB00F21733 /* SemaCXXCast.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCXXCast.cpp; path = lib/Sema/SemaCXXCast.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
35E1946C0ECB83C100F21733 /* PTHLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PTHLexer.cpp; sourceTree = "<group>"; };
|
||||
35EE48AD0E0C4CB200715C54 /* DeclCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclCXX.h; path = clang/AST/DeclCXX.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
35EE48AE0E0C4CB200715C54 /* ParentMap.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ParentMap.h; path = clang/AST/ParentMap.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
|
|
@ -471,10 +506,15 @@
|
|||
35F9B1560D1C6B2E00DDFDAE /* UninitializedValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UninitializedValues.h; path = clang/Analysis/Analyses/UninitializedValues.h; sourceTree = "<group>"; };
|
||||
35FE6BCE0DF6EE1F00739712 /* DeclBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclBase.cpp; path = lib/AST/DeclBase.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
72D16C1E0D9975C400E6DA4A /* HTMLRewrite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLRewrite.cpp; path = lib/Rewrite/HTMLRewrite.cpp; sourceTree = "<group>"; };
|
||||
7F270AFE107A90010031B377 /* CodeCompleteConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CodeCompleteConsumer.h; path = clang/Sema/CodeCompleteConsumer.h; sourceTree = "<group>"; };
|
||||
84AF36A00CB17A3B00C820A5 /* DeclObjC.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclObjC.h; path = clang/AST/DeclObjC.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = lib/Parse/AttributeList.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
84D9A88B0C1A581300AC7ABC /* AttributeList.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = AttributeList.h; path = clang/Parse/AttributeList.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = clang; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9012911510470FCE0083456D /* Index.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Index.h; path = "clang-c/Index.h"; sourceTree = "<group>"; };
|
||||
9012911C1048068D0083456D /* ASTUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTUnit.cpp; path = lib/Frontend/ASTUnit.cpp; sourceTree = "<group>"; };
|
||||
9012911F104812F90083456D /* CIndex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CIndex.cpp; path = tools/CIndex/CIndex.cpp; sourceTree = "<group>"; };
|
||||
90129120104812F90083456D /* CIndex.exports */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CIndex.exports; path = tools/CIndex/CIndex.exports; sourceTree = "<group>"; };
|
||||
9063F2210F9E8BDF002F7251 /* ExternalSemaSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExternalSemaSource.h; path = clang/Sema/ExternalSemaSource.h; sourceTree = "<group>"; };
|
||||
9063F2220F9E8BDF002F7251 /* SemaConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaConsumer.h; path = clang/Sema/SemaConsumer.h; sourceTree = "<group>"; };
|
||||
9063F2280F9E911F002F7251 /* OnDiskHashTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OnDiskHashTable.h; sourceTree = "<group>"; };
|
||||
|
|
@ -482,9 +522,50 @@
|
|||
9063F22A0F9E911F002F7251 /* TemplateKinds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemplateKinds.h; sourceTree = "<group>"; };
|
||||
906BF4AE0F83BA16001071FA /* ConvertUTF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConvertUTF.h; sourceTree = "<group>"; };
|
||||
906BF4AF0F83BA2E001071FA /* ConvertUTF.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ConvertUTF.c; sourceTree = "<group>"; };
|
||||
90F9EFA9104ABDED00D09A15 /* c-index-test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "c-index-test.c"; path = "tools/c-index-test/c-index-test.c"; sourceTree = "<group>"; };
|
||||
90FB99DE0F98FB1D008F9415 /* DeclContextInternals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclContextInternals.h; path = clang/AST/DeclContextInternals.h; sourceTree = "<group>"; };
|
||||
90FB99DF0F98FB1D008F9415 /* DeclVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclVisitor.h; path = clang/AST/DeclVisitor.h; sourceTree = "<group>"; };
|
||||
90FB99E00F98FB1D008F9415 /* ExternalASTSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExternalASTSource.h; path = clang/AST/ExternalASTSource.h; sourceTree = "<group>"; };
|
||||
90FD6D5F103C3D21005F5B73 /* Analyzer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Analyzer.h; path = clang/Index/Analyzer.h; sourceTree = "<group>"; };
|
||||
90FD6D60103C3D21005F5B73 /* ASTLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTLocation.h; path = clang/Index/ASTLocation.h; sourceTree = "<group>"; };
|
||||
90FD6D61103C3D21005F5B73 /* DeclReferenceMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclReferenceMap.h; path = clang/Index/DeclReferenceMap.h; sourceTree = "<group>"; };
|
||||
90FD6D62103C3D21005F5B73 /* Entity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Entity.h; path = clang/Index/Entity.h; sourceTree = "<group>"; };
|
||||
90FD6D63103C3D21005F5B73 /* GlobalSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GlobalSelector.h; path = clang/Index/GlobalSelector.h; sourceTree = "<group>"; };
|
||||
90FD6D64103C3D21005F5B73 /* Handlers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Handlers.h; path = clang/Index/Handlers.h; sourceTree = "<group>"; };
|
||||
90FD6D65103C3D21005F5B73 /* Indexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Indexer.h; path = clang/Index/Indexer.h; sourceTree = "<group>"; };
|
||||
90FD6D66103C3D21005F5B73 /* IndexProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IndexProvider.h; path = clang/Index/IndexProvider.h; sourceTree = "<group>"; };
|
||||
90FD6D67103C3D21005F5B73 /* Program.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Program.h; path = clang/Index/Program.h; sourceTree = "<group>"; };
|
||||
90FD6D68103C3D21005F5B73 /* SelectorMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SelectorMap.h; path = clang/Index/SelectorMap.h; sourceTree = "<group>"; };
|
||||
90FD6D69103C3D21005F5B73 /* STLExtras.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STLExtras.h; path = clang/Index/STLExtras.h; sourceTree = "<group>"; };
|
||||
90FD6D6A103C3D21005F5B73 /* TranslationUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TranslationUnit.h; path = clang/Index/TranslationUnit.h; sourceTree = "<group>"; };
|
||||
90FD6D6B103C3D21005F5B73 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = clang/Index/Utils.h; sourceTree = "<group>"; };
|
||||
90FD6D6D103C3D49005F5B73 /* Analyzer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Analyzer.cpp; path = lib/Index/Analyzer.cpp; sourceTree = "<group>"; };
|
||||
90FD6D6E103C3D49005F5B73 /* ASTLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTLocation.cpp; path = lib/Index/ASTLocation.cpp; sourceTree = "<group>"; };
|
||||
90FD6D6F103C3D49005F5B73 /* ASTVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTVisitor.h; path = lib/Index/ASTVisitor.h; sourceTree = "<group>"; };
|
||||
90FD6D70103C3D49005F5B73 /* DeclReferenceMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclReferenceMap.cpp; path = lib/Index/DeclReferenceMap.cpp; sourceTree = "<group>"; };
|
||||
90FD6D71103C3D49005F5B73 /* Entity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Entity.cpp; path = lib/Index/Entity.cpp; sourceTree = "<group>"; };
|
||||
90FD6D72103C3D49005F5B73 /* EntityImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EntityImpl.h; path = lib/Index/EntityImpl.h; sourceTree = "<group>"; };
|
||||
90FD6D73103C3D49005F5B73 /* GlobalSelector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GlobalSelector.cpp; path = lib/Index/GlobalSelector.cpp; sourceTree = "<group>"; };
|
||||
90FD6D74103C3D49005F5B73 /* Handlers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Handlers.cpp; path = lib/Index/Handlers.cpp; sourceTree = "<group>"; };
|
||||
90FD6D75103C3D49005F5B73 /* Indexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Indexer.cpp; path = lib/Index/Indexer.cpp; sourceTree = "<group>"; };
|
||||
90FD6D76103C3D49005F5B73 /* IndexProvider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IndexProvider.cpp; path = lib/Index/IndexProvider.cpp; sourceTree = "<group>"; };
|
||||
90FD6D77103C3D49005F5B73 /* Program.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Program.cpp; path = lib/Index/Program.cpp; sourceTree = "<group>"; };
|
||||
90FD6D78103C3D49005F5B73 /* ProgramImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgramImpl.h; path = lib/Index/ProgramImpl.h; sourceTree = "<group>"; };
|
||||
90FD6D79103C3D49005F5B73 /* ResolveLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ResolveLocation.cpp; path = lib/Index/ResolveLocation.cpp; sourceTree = "<group>"; };
|
||||
90FD6D7A103C3D49005F5B73 /* SelectorMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SelectorMap.cpp; path = lib/Index/SelectorMap.cpp; sourceTree = "<group>"; };
|
||||
90FD6D86103C3D80005F5B73 /* Analyses.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Analyses.def; path = clang/Frontend/Analyses.def; sourceTree = "<group>"; };
|
||||
90FD6D87103C3D80005F5B73 /* AnalysisConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AnalysisConsumer.h; path = clang/Frontend/AnalysisConsumer.h; sourceTree = "<group>"; };
|
||||
90FD6D88103C3D80005F5B73 /* ASTConsumers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTConsumers.h; path = clang/Frontend/ASTConsumers.h; sourceTree = "<group>"; };
|
||||
90FD6D89103C3D80005F5B73 /* ASTUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTUnit.h; path = clang/Frontend/ASTUnit.h; sourceTree = "<group>"; };
|
||||
90FD6D8A103C3D80005F5B73 /* CommandLineSourceLoc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandLineSourceLoc.h; path = clang/Frontend/CommandLineSourceLoc.h; sourceTree = "<group>"; };
|
||||
90FD6D8B103C3D80005F5B73 /* DeclContextXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = DeclContextXML.def; path = clang/Frontend/DeclContextXML.def; sourceTree = "<group>"; };
|
||||
90FD6D8C103C3D80005F5B73 /* DeclXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = DeclXML.def; path = clang/Frontend/DeclXML.def; sourceTree = "<group>"; };
|
||||
90FD6D8D103C3D80005F5B73 /* DocumentXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = DocumentXML.def; path = clang/Frontend/DocumentXML.def; sourceTree = "<group>"; };
|
||||
90FD6D8E103C3D80005F5B73 /* DocumentXML.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DocumentXML.h; path = clang/Frontend/DocumentXML.h; sourceTree = "<group>"; };
|
||||
90FD6D8F103C3D80005F5B73 /* StmtXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = StmtXML.def; path = clang/Frontend/StmtXML.def; sourceTree = "<group>"; };
|
||||
90FD6D90103C3D80005F5B73 /* TypeXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = TypeXML.def; path = clang/Frontend/TypeXML.def; sourceTree = "<group>"; };
|
||||
90FD6D91103C3D80005F5B73 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = clang/Frontend/Utils.h; sourceTree = "<group>"; };
|
||||
90FD6DB5103D977E005F5B73 /* index-test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "index-test.cpp"; path = "tools/index-test/index-test.cpp"; sourceTree = "<group>"; };
|
||||
BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateDeduction.cpp; path = lib/Sema/SemaTemplateDeduction.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = "<group>"; };
|
||||
DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExprCXX.cpp; path = lib/Parse/ParseExprCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
|
|
@ -530,7 +611,6 @@
|
|||
DE3986EF0CB8D4B300223765 /* IdentifierTable.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = IdentifierTable.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
DE3986F30CB8D50C00223765 /* IdentifierTable.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = IdentifierTable.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
DE3B90DE0EAC5EF200D01046 /* ExtensionRAIIObject.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExtensionRAIIObject.h; path = lib/Parse/ExtensionRAIIObject.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
DE3B921C0EB1A81400D01046 /* SemaInherit.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SemaInherit.h; path = lib/Sema/SemaInherit.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
DE3B92230EB5152000D01046 /* Designator.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Designator.h; path = clang/Parse/Designator.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
DE41211D0D7F1BBE0080F80A /* GRWorkList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRWorkList.h; path = clang/Analysis/PathSensitive/GRWorkList.h; sourceTree = "<group>"; };
|
||||
DE41211E0D7F1BBE0080F80A /* SymbolManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SymbolManager.h; path = clang/Analysis/PathSensitive/SymbolManager.h; sourceTree = "<group>"; };
|
||||
|
|
@ -603,8 +683,6 @@
|
|||
DEB077980F44F97800F5A2BE /* TokenConcatenation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TokenConcatenation.cpp; sourceTree = "<group>"; };
|
||||
DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaAttr.cpp; path = lib/Sema/SemaAttr.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
DEB089EE0F12F1D900522C07 /* TypeTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypeTraits.h; sourceTree = "<group>"; };
|
||||
DEC63B190C7B940200DBF169 /* CFG.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CFG.cpp; path = lib/AST/CFG.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
DEC63B1B0C7B940600DBF169 /* CFG.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CFG.h; path = clang/AST/CFG.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
DEC8D9900A9433CD00353FCA /* Decl.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Decl.h; path = clang/AST/Decl.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
DEC8D9A30A94346E00353FCA /* AST.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = AST.h; path = clang/AST/AST.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
DECAB0CF0DB3C84200E13CCB /* RewriteRope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteRope.cpp; path = lib/Rewrite/RewriteRope.cpp; sourceTree = "<group>"; };
|
||||
|
|
@ -741,6 +819,7 @@
|
|||
08FB7795FE84155DC02AAC07 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
90FD6D6C103C3D2D005F5B73 /* Index */,
|
||||
DED7D7500A5242C7003AD0FB /* Basic */,
|
||||
DED7D78C0A5242E6003AD0FB /* Lex */,
|
||||
DE1F22600A7D8C9B00FBF588 /* Parse */,
|
||||
|
|
@ -817,6 +896,7 @@
|
|||
352246E00F5C6BC000D0D279 /* Frontend */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9012911C1048068D0083456D /* ASTUnit.cpp */,
|
||||
1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */,
|
||||
1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */,
|
||||
1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */,
|
||||
|
|
@ -957,6 +1037,80 @@
|
|||
name = Analyses;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9012911210470FAF0083456D /* clang-c */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9012911510470FCE0083456D /* Index.h */,
|
||||
);
|
||||
name = "clang-c";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9012911E104812DA0083456D /* CIndex */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9012911F104812F90083456D /* CIndex.cpp */,
|
||||
90129120104812F90083456D /* CIndex.exports */,
|
||||
);
|
||||
name = CIndex;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
90F9EFA8104ABDC400D09A15 /* c-index-test */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
90F9EFA9104ABDED00D09A15 /* c-index-test.c */,
|
||||
);
|
||||
name = "c-index-test";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
90FD6D5E103C3D03005F5B73 /* Index */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
90FD6D5F103C3D21005F5B73 /* Analyzer.h */,
|
||||
90FD6D60103C3D21005F5B73 /* ASTLocation.h */,
|
||||
90FD6D61103C3D21005F5B73 /* DeclReferenceMap.h */,
|
||||
90FD6D62103C3D21005F5B73 /* Entity.h */,
|
||||
90FD6D63103C3D21005F5B73 /* GlobalSelector.h */,
|
||||
90FD6D64103C3D21005F5B73 /* Handlers.h */,
|
||||
90FD6D65103C3D21005F5B73 /* Indexer.h */,
|
||||
90FD6D66103C3D21005F5B73 /* IndexProvider.h */,
|
||||
90FD6D67103C3D21005F5B73 /* Program.h */,
|
||||
90FD6D68103C3D21005F5B73 /* SelectorMap.h */,
|
||||
90FD6D69103C3D21005F5B73 /* STLExtras.h */,
|
||||
90FD6D6A103C3D21005F5B73 /* TranslationUnit.h */,
|
||||
90FD6D6B103C3D21005F5B73 /* Utils.h */,
|
||||
);
|
||||
name = Index;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
90FD6D6C103C3D2D005F5B73 /* Index */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
90FD6D6D103C3D49005F5B73 /* Analyzer.cpp */,
|
||||
90FD6D6E103C3D49005F5B73 /* ASTLocation.cpp */,
|
||||
90FD6D6F103C3D49005F5B73 /* ASTVisitor.h */,
|
||||
90FD6D70103C3D49005F5B73 /* DeclReferenceMap.cpp */,
|
||||
90FD6D71103C3D49005F5B73 /* Entity.cpp */,
|
||||
90FD6D72103C3D49005F5B73 /* EntityImpl.h */,
|
||||
90FD6D73103C3D49005F5B73 /* GlobalSelector.cpp */,
|
||||
90FD6D74103C3D49005F5B73 /* Handlers.cpp */,
|
||||
90FD6D75103C3D49005F5B73 /* Indexer.cpp */,
|
||||
90FD6D76103C3D49005F5B73 /* IndexProvider.cpp */,
|
||||
90FD6D77103C3D49005F5B73 /* Program.cpp */,
|
||||
90FD6D78103C3D49005F5B73 /* ProgramImpl.h */,
|
||||
90FD6D79103C3D49005F5B73 /* ResolveLocation.cpp */,
|
||||
90FD6D7A103C3D49005F5B73 /* SelectorMap.cpp */,
|
||||
);
|
||||
name = Index;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
90FD6DB4103D9763005F5B73 /* index-test */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
90FD6DB5103D977E005F5B73 /* index-test.cpp */,
|
||||
);
|
||||
name = "index-test";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C6859E8C029090F304C91782 /* Documentation */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -1037,6 +1191,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
35585DBD0EAFBC4500D0A97A /* CXXFieldCollector.h */,
|
||||
1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */,
|
||||
3527124F0DAFE54700C76352 /* IdentifierResolver.h */,
|
||||
352712500DAFE54700C76352 /* IdentifierResolver.cpp */,
|
||||
DECB6D640F9AE26600F5FBC7 /* JumpDiagnostics.cpp */,
|
||||
|
|
@ -1052,23 +1207,22 @@
|
|||
35EF676F0DAD1D2C00B19414 /* SemaDeclCXX.cpp */,
|
||||
DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */,
|
||||
DE67E7100C020ED400F66BC5 /* SemaExpr.cpp */,
|
||||
DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */,
|
||||
DE47999B0D2EBE1A00706D2D /* SemaExprObjC.cpp */,
|
||||
3557D1EF0EB13BB700C59739 /* SemaInherit.cpp */,
|
||||
DE3B921C0EB1A81400D01046 /* SemaInherit.h */,
|
||||
DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */,
|
||||
3599299A0DE2425300A8A33E /* SemaInit.cpp */,
|
||||
357EA27C0F2526F300439B60 /* SemaLookup.cpp */,
|
||||
35E194680ECB82FB00F21733 /* SemaNamedCast.cpp */,
|
||||
1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */,
|
||||
35E194680ECB82FB00F21733 /* SemaCXXCast.cpp */,
|
||||
35585DBE0EAFBC4500D0A97A /* SemaOverload.cpp */,
|
||||
35585DBF0EAFBC4500D0A97A /* SemaOverload.h */,
|
||||
DE67E70C0C020ECA00F66BC5 /* SemaStmt.cpp */,
|
||||
3591853E0EFB1088000039AF /* SemaTemplate.cpp */,
|
||||
1A6B6CD310693FC900BB4A8F /* SemaTemplate.h */,
|
||||
BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */,
|
||||
35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */,
|
||||
1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */,
|
||||
1A410F840FBCE51100351440 /* SemaTemplateInstantiateExpr.cpp */,
|
||||
1A5119C30FBDF71000A1FF22 /* SemaTemplateInstantiateStmt.cpp */,
|
||||
DE67E70A0C020EC500F66BC5 /* SemaType.cpp */,
|
||||
1AE4EE3B103B89CA00888A23 /* TreeTransform.h */,
|
||||
);
|
||||
name = Sema;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -1076,6 +1230,7 @@
|
|||
DE67E7260C02108300F66BC5 /* Sema */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7F270AFE107A90010031B377 /* CodeCompleteConsumer.h */,
|
||||
9063F2210F9E8BDF002F7251 /* ExternalSemaSource.h */,
|
||||
9063F2220F9E8BDF002F7251 /* SemaConsumer.h */,
|
||||
DE67E7270C02109800F66BC5 /* ParseAST.h */,
|
||||
|
|
@ -1096,6 +1251,8 @@
|
|||
35475B220E7997680000BFE4 /* CGCall.h */,
|
||||
1A5D5E570E5E81010023C059 /* CGCXX.cpp */,
|
||||
1A649E1E0F9599DA005B965E /* CGCXX.h */,
|
||||
1A4C41BE105B4C0B0047B5E7 /* CGCXXClass.cpp */,
|
||||
1A6B6E991069833600BB4A8F /* CGCXXExpr.cpp */,
|
||||
1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */,
|
||||
35A3E7000DD3874400757F74 /* CGDebugInfo.cpp */,
|
||||
35A3E7010DD3874400757F74 /* CGDebugInfo.h */,
|
||||
|
|
@ -1109,8 +1266,13 @@
|
|||
DE38CD4E0D794CF900A273B6 /* CGObjCRuntime.h */,
|
||||
DE38CD4F0D794D0100A273B6 /* CGObjCGNU.cpp */,
|
||||
3552E7580E520DD7003A8CA5 /* CGObjCMac.cpp */,
|
||||
1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */,
|
||||
1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */,
|
||||
1A6C01F6108128710072DEE4 /* CGRtti.cpp */,
|
||||
DE4772F90C10EAE5002239E8 /* CGStmt.cpp */,
|
||||
35475B230E7997680000BFE4 /* CGValue.h */,
|
||||
1A81AA18108144F40094E50B /* CGVtable.cpp */,
|
||||
1A81AA5D108278A20094E50B /* CGVtable.h */,
|
||||
DE928B800C0A615B00231DA4 /* CodeGenFunction.h */,
|
||||
DE928B820C0A616000231DA4 /* CodeGenFunction.cpp */,
|
||||
DE928B7C0C0A615100231DA4 /* CodeGenModule.h */,
|
||||
|
|
@ -1120,6 +1282,7 @@
|
|||
1A2193CC0F45EEB700C0713D /* Mangle.cpp */,
|
||||
1A2193CD0F45EEB700C0713D /* Mangle.h */,
|
||||
DE928B120C05659200231DA4 /* ModuleBuilder.cpp */,
|
||||
1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */,
|
||||
);
|
||||
name = CodeGen;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -1142,10 +1305,10 @@
|
|||
DE75ED280B044DC90020CF81 /* ASTContext.h */,
|
||||
DEA09A6E0F31756F000C2258 /* ASTDiagnostic.h */,
|
||||
1A72BEAC0D641E9400B085E9 /* Attr.h */,
|
||||
1A535EDB107BC47B000C3AE7 /* CanonicalType.h */,
|
||||
90FB99DE0F98FB1D008F9415 /* DeclContextInternals.h */,
|
||||
90FB99DF0F98FB1D008F9415 /* DeclVisitor.h */,
|
||||
90FB99E00F98FB1D008F9415 /* ExternalASTSource.h */,
|
||||
DEC63B1B0C7B940600DBF169 /* CFG.h */,
|
||||
DEC8D9900A9433CD00353FCA /* Decl.h */,
|
||||
3538FDB60ED24A2C005EC283 /* DeclarationName.h */,
|
||||
035611470DA6A45C00D2EF2A /* DeclBase.h */,
|
||||
|
|
@ -1182,7 +1345,7 @@
|
|||
DE8823CA0ED0046600CBC30A /* APValue.cpp */,
|
||||
35BB2D7E0D19954000944DB5 /* ASTConsumer.cpp */,
|
||||
DE1732FF0B068B700080B521 /* ASTContext.cpp */,
|
||||
DEC63B190C7B940200DBF169 /* CFG.cpp */,
|
||||
1A535ED8107BC45E000C3AE7 /* CXXInheritance.cpp */,
|
||||
35FE6BCE0DF6EE1F00739712 /* DeclBase.cpp */,
|
||||
DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */,
|
||||
3538FDB70ED24A4E005EC283 /* DeclarationName.cpp */,
|
||||
|
|
@ -1197,10 +1360,13 @@
|
|||
3557D1A80EB136B100C59739 /* InheritViz.cpp */,
|
||||
DEDFE5CE0F7206E40035BD10 /* NestedNameSpecifier.cpp */,
|
||||
35EE48B00E0C4CCA00715C54 /* ParentMap.cpp */,
|
||||
1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */,
|
||||
1AA1D91710125DE30078DEBC /* RecordLayoutBuilder.h */,
|
||||
DE3452400AEF1A2D00DBC861 /* Stmt.cpp */,
|
||||
DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */,
|
||||
DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */,
|
||||
35847BE40CC7DBAF00C40FFF /* StmtIterator.cpp */,
|
||||
DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */,
|
||||
1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */,
|
||||
35CFFDFF0CA1CBCB00E6F2BE /* StmtViz.cpp */,
|
||||
DEDFF8870F848CF80035BD10 /* TemplateName.cpp */,
|
||||
DE75EDF00B06880E0020CF81 /* Type.cpp */,
|
||||
|
|
@ -1218,9 +1384,11 @@
|
|||
DE67E7260C02108300F66BC5 /* Sema */,
|
||||
DE928B140C05659A00231DA4 /* CodeGen */,
|
||||
356EF9AF0C8F7DA4006650F5 /* Analysis */,
|
||||
90FD6D5E103C3D03005F5B73 /* Index */,
|
||||
DEF7D9F40C9C8B020001F598 /* Rewrite */,
|
||||
DEF1615D0F65C7FC0098507F /* Frontend */,
|
||||
DEF165020F8D46810098507F /* Driver */,
|
||||
9012911210470FAF0083456D /* clang-c */,
|
||||
);
|
||||
path = include;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -1250,6 +1418,7 @@
|
|||
9063F2280F9E911F002F7251 /* OnDiskHashTable.h */,
|
||||
DE8824560ED1244600CBC30A /* OperatorKinds.def */,
|
||||
DE8824530ED1243E00CBC30A /* OperatorKinds.h */,
|
||||
1AB290021045858B00FE33D8 /* PartialDiagnostic.h */,
|
||||
DEAABDF70F5F477C0098928A /* PrettyStackTrace.h */,
|
||||
DED7D7350A524295003AD0FB /* SourceLocation.h */,
|
||||
DED7D7360A524295003AD0FB /* SourceManager.h */,
|
||||
|
|
@ -1339,6 +1508,9 @@
|
|||
DEDFE61F0F7B3AE10035BD10 /* Tools */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
90F9EFA8104ABDC400D09A15 /* c-index-test */,
|
||||
9012911E104812DA0083456D /* CIndex */,
|
||||
90FD6DB4103D9763005F5B73 /* index-test */,
|
||||
DEDFE6200F7B3AE90035BD10 /* clang-cc */,
|
||||
DEDFE6210F7B3AF10035BD10 /* clang */,
|
||||
);
|
||||
|
|
@ -1389,6 +1561,18 @@
|
|||
DEF1615D0F65C7FC0098507F /* Frontend */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
90FD6D86103C3D80005F5B73 /* Analyses.def */,
|
||||
90FD6D87103C3D80005F5B73 /* AnalysisConsumer.h */,
|
||||
90FD6D88103C3D80005F5B73 /* ASTConsumers.h */,
|
||||
90FD6D89103C3D80005F5B73 /* ASTUnit.h */,
|
||||
90FD6D8A103C3D80005F5B73 /* CommandLineSourceLoc.h */,
|
||||
90FD6D8B103C3D80005F5B73 /* DeclContextXML.def */,
|
||||
90FD6D8C103C3D80005F5B73 /* DeclXML.def */,
|
||||
90FD6D8D103C3D80005F5B73 /* DocumentXML.def */,
|
||||
90FD6D8E103C3D80005F5B73 /* DocumentXML.h */,
|
||||
90FD6D8F103C3D80005F5B73 /* StmtXML.def */,
|
||||
90FD6D90103C3D80005F5B73 /* TypeXML.def */,
|
||||
90FD6D91103C3D80005F5B73 /* Utils.h */,
|
||||
DEF161620F65C81C0098507F /* CompileOptions.h */,
|
||||
DEF168620F9549250098507F /* FixItRewriter.h */,
|
||||
DEF169220F9645960098507F /* FrontendDiagnostic.h */,
|
||||
|
|
@ -1545,7 +1729,6 @@
|
|||
1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */,
|
||||
DE224FF80C7AA98800D370A5 /* CGExprComplex.cpp in Sources */,
|
||||
1A7342480C7B57D500122F56 /* CGObjC.cpp in Sources */,
|
||||
DEC63B1A0C7B940200DBF169 /* CFG.cpp in Sources */,
|
||||
DE2252700C7E82D000D370A5 /* CGExprScalar.cpp in Sources */,
|
||||
35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */,
|
||||
DE2255FC0C8004E600D370A5 /* ParseDeclCXX.cpp in Sources */,
|
||||
|
|
@ -1617,9 +1800,8 @@
|
|||
35A057E30EAE2D950069249F /* SVals.cpp in Sources */,
|
||||
35585DC00EAFBC4500D0A97A /* SemaOverload.cpp in Sources */,
|
||||
3557D1A90EB136B100C59739 /* InheritViz.cpp in Sources */,
|
||||
3557D1F00EB13BB700C59739 /* SemaInherit.cpp in Sources */,
|
||||
35E194690ECB82FB00F21733 /* SemaCXXScopeSpec.cpp in Sources */,
|
||||
35E1946A0ECB82FB00F21733 /* SemaNamedCast.cpp in Sources */,
|
||||
35E1946A0ECB82FB00F21733 /* SemaCXXCast.cpp in Sources */,
|
||||
35E1946D0ECB83C100F21733 /* PTHLexer.cpp in Sources */,
|
||||
3537AA0E0ECD08A4008F7CDC /* PreprocessorLexer.cpp in Sources */,
|
||||
DE8823CB0ED0046600CBC30A /* APValue.cpp in Sources */,
|
||||
|
|
@ -1672,8 +1854,6 @@
|
|||
DECB77790FA579B000F5FBC7 /* PCHReaderDecl.cpp in Sources */,
|
||||
DECB77F70FA5850200F5FBC7 /* PCHWriterDecl.cpp in Sources */,
|
||||
DECB78170FA5882F00F5FBC7 /* PCHWriterStmt.cpp in Sources */,
|
||||
1A410F850FBCE51100351440 /* SemaTemplateInstantiateExpr.cpp in Sources */,
|
||||
1A5119C40FBDF71000A1FF22 /* SemaTemplateInstantiateStmt.cpp in Sources */,
|
||||
1A2A54B50FD1DD1C00F4CE45 /* AnalysisConsumer.cpp in Sources */,
|
||||
1A2A54B60FD1DD1C00F4CE45 /* ASTConsumers.cpp in Sources */,
|
||||
1A2A54B70FD1DD1C00F4CE45 /* Backend.cpp in Sources */,
|
||||
|
|
@ -1695,6 +1875,32 @@
|
|||
BDF87CF70FD746F300BBF872 /* SemaTemplateDeduction.cpp in Sources */,
|
||||
1A14D3A70FD78A3F00DA2835 /* DeclPrinter.cpp in Sources */,
|
||||
DE37252E0FE481AD00CF2CC2 /* Builtins.cpp in Sources */,
|
||||
1AA1D91810125DE30078DEBC /* RecordLayoutBuilder.cpp in Sources */,
|
||||
1AFF8AE31012BFC900D248DA /* CGRecordLayoutBuilder.cpp in Sources */,
|
||||
1AE4EE3E103B89ED00888A23 /* StmtProfile.cpp in Sources */,
|
||||
1AE4EE40103B8A0A00888A23 /* TargetABIInfo.cpp in Sources */,
|
||||
90FD6D7B103C3D49005F5B73 /* Analyzer.cpp in Sources */,
|
||||
90FD6D7C103C3D49005F5B73 /* ASTLocation.cpp in Sources */,
|
||||
90FD6D7D103C3D49005F5B73 /* DeclReferenceMap.cpp in Sources */,
|
||||
90FD6D7E103C3D49005F5B73 /* Entity.cpp in Sources */,
|
||||
90FD6D7F103C3D49005F5B73 /* GlobalSelector.cpp in Sources */,
|
||||
90FD6D80103C3D49005F5B73 /* Handlers.cpp in Sources */,
|
||||
90FD6D81103C3D49005F5B73 /* Indexer.cpp in Sources */,
|
||||
90FD6D82103C3D49005F5B73 /* IndexProvider.cpp in Sources */,
|
||||
90FD6D83103C3D49005F5B73 /* Program.cpp in Sources */,
|
||||
90FD6D84103C3D49005F5B73 /* ResolveLocation.cpp in Sources */,
|
||||
90FD6D85103C3D49005F5B73 /* SelectorMap.cpp in Sources */,
|
||||
90FD6DB6103D977E005F5B73 /* index-test.cpp in Sources */,
|
||||
9012911D1048068D0083456D /* ASTUnit.cpp in Sources */,
|
||||
90129121104812F90083456D /* CIndex.cpp in Sources */,
|
||||
90F9EFAA104ABDED00D09A15 /* c-index-test.c in Sources */,
|
||||
1A4C41BF105B4C0B0047B5E7 /* CGCXXClass.cpp in Sources */,
|
||||
1A6B6CD410693FC900BB4A8F /* CodeCompleteConsumer.cpp in Sources */,
|
||||
1A6B6CD510693FC900BB4A8F /* SemaCodeComplete.cpp in Sources */,
|
||||
1A6B6E9A1069833600BB4A8F /* CGCXXExpr.cpp in Sources */,
|
||||
1A535ED9107BC45E000C3AE7 /* CXXInheritance.cpp in Sources */,
|
||||
1A6C01F7108128710072DEE4 /* CGRtti.cpp in Sources */,
|
||||
1A81AA19108144F40094E50B /* CGVtable.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@
|
|||
|
||||
<p>Once the arguments are parsed, the tree of subprocess
|
||||
jobs needed for the desired compilation sequence are
|
||||
constructed. This involves determing the input files and
|
||||
constructed. This involves determining the input files and
|
||||
their types, what work is to be done on them (preprocess,
|
||||
compile, assemble, link, etc.), and constructing a list of
|
||||
Action instances for each task. The result is a list of
|
||||
|
|
@ -312,7 +312,7 @@
|
|||
to run. Conceptually, the driver performs a top down
|
||||
matching to assign Action(s) to Tools. The ToolChain is
|
||||
responsible for selecting the tool to perform a particular
|
||||
action; once seleected the driver interacts with the tool
|
||||
action; once selected the driver interacts with the tool
|
||||
to see if it can match additional actions (for example, by
|
||||
having an integrated preprocessor).
|
||||
|
||||
|
|
@ -397,7 +397,7 @@
|
|||
|
||||
<p>The driver constructs a Compilation object for each set of
|
||||
command line arguments. The Driver itself is intended to be
|
||||
invariant during construct of a Compilation; an IDE should be
|
||||
invariant during construction of a Compilation; an IDE should be
|
||||
able to construct a single long lived driver instance to use
|
||||
for an entire build, for example.</p>
|
||||
|
||||
|
|
@ -409,7 +409,7 @@
|
|||
|
||||
<h4 id="int_unified_parsing">Unified Parsing & Pipelining</h4>
|
||||
|
||||
<p>Parsing and pipeling both occur without reference to a
|
||||
<p>Parsing and pipelining both occur without reference to a
|
||||
Compilation instance. This is by design; the driver expects that
|
||||
both of these phases are platform neutral, with a few very well
|
||||
defined exceptions such as whether the platform uses a driver
|
||||
|
|
@ -425,11 +425,11 @@
|
|||
stop seeing some arguments the user provided, and see new ones
|
||||
instead).</p>
|
||||
|
||||
<p>For example, on Darwin <tt>-gfull</tt> gets translated into
|
||||
two separate arguments, <tt>-g</tt>
|
||||
and <tt>-fno-eliminate-unused-debug-symbols</tt>. Trying to
|
||||
write Tool logic to do something with <tt>-gfull</tt> will not
|
||||
work, because at Tools run after the arguments have been
|
||||
<p>For example, on Darwin <tt>-gfull</tt> gets translated into two
|
||||
separate arguments, <tt>-g</tt>
|
||||
and <tt>-fno-eliminate-unused-debug-symbols</tt>. Trying to write Tool
|
||||
logic to do something with <tt>-gfull</tt> will not work, because Tool
|
||||
argument translation is done after the arguments have been
|
||||
translated.</p>
|
||||
|
||||
<p>A long term goal is to remove this tool chain specific
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ td {
|
|||
<li><a href="#Constants">Constant Folding in the Clang AST</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="libIndex.html">The Index Library</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
|
@ -528,12 +529,6 @@ describe the location of the characters corresponding to the token and the
|
|||
location where the token was used (i.e. the macro instantiation point or the
|
||||
location of the _Pragma itself).</p>
|
||||
|
||||
<p>For efficiency, we only track one level of macro instantiations: if a token was
|
||||
produced by multiple instantiations, we only track the source and ultimate
|
||||
destination. Though we could track the intermediate instantiation points, this
|
||||
would require extra bookkeeping and no known client would benefit substantially
|
||||
from this.</p>
|
||||
|
||||
<p>The Clang front-end inherently depends on the location of a token being
|
||||
tracked correctly. If it is ever incorrect, the front-end may get confused and
|
||||
die. The reason for this is that the notion of the 'spelling' of a Token in
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ td {
|
|||
<li><a href="#builtins">Builtin Functions</a>
|
||||
<ul>
|
||||
<li><a href="#__builtin_shufflevector">__builtin_shufflevector</a></li>
|
||||
<li><a href="#__builtin_unreachable">__builtin_unreachable</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#targetspecific">Target-Specific Extensions</a>
|
||||
|
|
@ -264,7 +265,7 @@ builtins that we need to implement.</p>
|
|||
<h3 id="__builtin_shufflevector">__builtin_shufflevector</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p><tt>__builtin_shufflevector</tt> is used to expression generic vector
|
||||
<p><tt>__builtin_shufflevector</tt> is used to express generic vector
|
||||
permutation/shuffle/swizzle operations. This builtin is also very important for
|
||||
the implementation of various target-specific header files like
|
||||
<tt><xmmintrin.h></tt>.
|
||||
|
|
@ -310,6 +311,47 @@ with the same element type as vec1/vec2 but that has an element count equal to
|
|||
the number of indices specified.
|
||||
</p>
|
||||
|
||||
<p>Query for this feature with __has_builtin(__builtin_shufflevector).</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="__builtin_unreachable">__builtin_unreachable</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p><tt>__builtin_unreachable</tt> is used to indicate that a specific point in
|
||||
the program cannot be reached, even if the compiler might otherwise think it
|
||||
can. This is useful to improve optimization and eliminates certain warnings.
|
||||
For example, without the <tt>__builtin_unreachable</tt> in the example below,
|
||||
the compiler assumes that the inline asm can fall through and prints a "function
|
||||
declared 'noreturn' should not return" warning.
|
||||
</p>
|
||||
|
||||
<p><b>Syntax:</b></p>
|
||||
|
||||
<pre>
|
||||
__builtin_unreachable()
|
||||
</pre>
|
||||
|
||||
<p><b>Example of Use:</b></p>
|
||||
|
||||
<pre>
|
||||
void myabort(void) __attribute__((noreturn));
|
||||
void myabort(void) {
|
||||
asm("int3");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p><b>Description:</b></p>
|
||||
|
||||
<p>The __builtin_unreachable() builtin has completely undefined behavior. Since
|
||||
it has undefined behavior, it is a statement that it is never reached and the
|
||||
optimizer can take advantage of this to produce better code. This builtin takes
|
||||
no arguments and produces a void result.
|
||||
</p>
|
||||
|
||||
<p>Query for this feature with __has_builtin(__builtin_unreachable).</p>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="targetspecific">Target-Specific Extensions</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
|
|
|||
|
|
@ -33,6 +33,12 @@ td {
|
|||
<li><a href="#general_features">Language and Target-Independent Features</a>
|
||||
<ul>
|
||||
<li><a href="#diagnostics">Controlling Errors and Warnings</a></li>
|
||||
<ul>
|
||||
<li><a href="#diagnostics_display">Controlling How Clang Displays Diagnostics</a></li>
|
||||
<li><a href="#diagnostics_mappings">Diagnostic Mappings</a></li>
|
||||
<li><a href="#diagnostics_commandline">Controlling Diagnostics via Command Line Flags</a></li>
|
||||
<li><a href="#diagnostics_pragmas">Controlling Diagnostics via Pragmas</a></li>
|
||||
</ul>
|
||||
<li><a href="#precompiledheaders">Precompiled Headers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -362,7 +368,7 @@ by commenting them out.</p>
|
|||
<p>Clang provides a number of ways to control which code constructs cause it to
|
||||
emit errors and warning messages, and how they are displayed to the console.</p>
|
||||
|
||||
<h4>Controlling How Clang Displays Diagnostics</h4>
|
||||
<h4 id="diagnostics_display">Controlling How Clang Displays Diagnostics</h4>
|
||||
|
||||
<p>When Clang emits a diagnostic, it includes rich information in the output,
|
||||
and gives you fine-grain control over which information is printed. Clang has
|
||||
|
|
@ -394,18 +400,64 @@ it:</p>
|
|||
<p>For more information please see <a href="#cl_diag_formatting">Formatting of
|
||||
Diagnostics</a>.</p>
|
||||
|
||||
<h4>Controlling Which Diagnostics Clang Generates</h4>
|
||||
<h4 id="diagnostics_mappings">Diagnostic Mappings</h4>
|
||||
|
||||
<p>mappings: ignore, note, warning, error, fatal</p>
|
||||
<p>All diagnostics are mapped into one of these 5 classes:</p>
|
||||
|
||||
<p>
|
||||
The two major classes are control from the command line and control via pragmas
|
||||
in your code.</p>
|
||||
<ul>
|
||||
<li>Ignored</li>
|
||||
<li>Note</li>
|
||||
<li>Warning</li>
|
||||
<li>Error</li>
|
||||
<li>Fatal</li>
|
||||
</ul></p>
|
||||
|
||||
<h4 id="diagnostics_commandline">Controlling Diagnostics via Command Line Flags</h4>
|
||||
|
||||
<p>-W flags, -pedantic, etc</p>
|
||||
|
||||
<p>pragma GCC diagnostic</p>
|
||||
<h4 id="diagnostics_pragmas">Controlling Diagnostics via Pragmas</h4>
|
||||
|
||||
<p>Clang can also control what diagnostics are enabled through the use of
|
||||
pragmas in the source code. This is useful for turning off specific warnings
|
||||
in a section of source code. Clang supports GCC's pragma for compatibility
|
||||
with existing source code, as well as several extensions. </p>
|
||||
|
||||
<p>The pragma may control any warning that can be used from the command line.
|
||||
Warnings may be set to ignored, warning, error, or fatal. The following
|
||||
example code will tell Clang or GCC to ignore the -Wall warnings:</p>
|
||||
|
||||
<pre>
|
||||
#pragma GCC diagnostic ignored "-Wall"
|
||||
</pre>
|
||||
|
||||
<p>In addition to all of the functionality of provided by GCC's pragma, Clang
|
||||
also allows you to push and pop the current warning state. This is particularly
|
||||
useful when writing a header file that will be compiled by other people, because
|
||||
you don't know what warning flags they build with.</p>
|
||||
|
||||
<p>In the below example
|
||||
-Wmultichar is ignored for only a single line of code, after which the
|
||||
diagnostics return to whatever state had previously existed.</p>
|
||||
|
||||
<pre>
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmultichar"
|
||||
|
||||
char b = 'df'; // no warning.
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
</pre>
|
||||
|
||||
<p>The push and pop pragmas will save and restore the full diagnostic state of
|
||||
the compiler, regardless of how it was set. That means that it is possible to
|
||||
use push and pop around GCC compatible diagnostics and Clang will push and pop
|
||||
them appropriately, while GCC will ignore the pushes and pops as unknown
|
||||
pragmas. It should be noted that while Clang supports the GCC pragma, Clang and
|
||||
GCC do not support the exact same set of warnings, so even when using GCC
|
||||
compatible #pragmas there is no guarantee that they will have identical behaviour
|
||||
on both compilers. </p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="precompiledheaders">Precompiled Headers</h3>
|
||||
|
|
@ -465,6 +517,50 @@ for headers that are directly included within a source file. For example:</p>
|
|||
<tt>test.h</tt> since <tt>test.h</tt> was included directly in the source file
|
||||
and not specified on the command line using <tt>-include</tt>.</p>
|
||||
|
||||
<h4>Relocatable PCH Files</h4>
|
||||
<p>It is sometimes necessary to build a precompiled header from headers that
|
||||
are not yet in their final, installed locations. For example, one might build a
|
||||
precompiled header within the build tree that is then meant to be installed
|
||||
alongside the headers. Clang permits the creation of "relocatable" precompiled
|
||||
headers, which are built with a given path (into the build directory) and can
|
||||
later be used from an installed location.</p>
|
||||
|
||||
<p>To build a relocatable precompiled header, place your headers into a
|
||||
subdirectory whose structure mimics the installed location. For example, if you
|
||||
want to build a precompiled header for the header <code>mylib.h</code> that
|
||||
will be installed into <code>/usr/include</code>, create a subdirectory
|
||||
<code>build/usr/include</code> and place the header <code>mylib.h</code> into
|
||||
that subdirectory. If <code>mylib.h</code> depends on other headers, then
|
||||
they can be stored within <code>build/usr/include</code> in a way that mimics
|
||||
the installed location.</p>
|
||||
|
||||
<p>Building a relocatable precompiled header requires two additional arguments.
|
||||
First, pass the <code>--relocatable-pch</code> flag to indicate that the
|
||||
resulting PCH file should be relocatable. Second, pass
|
||||
<code>-isysroot /path/to/build</code>, which makes all includes for your
|
||||
library relative to the build directory. For example:</p>
|
||||
|
||||
<pre>
|
||||
# clang -x c-header --relocatable-pch -isysroot /path/to/build /path/to/build/mylib.h mylib.h.pch
|
||||
</pre>
|
||||
|
||||
<p>When loading the relocatable PCH file, the various headers used in the PCH
|
||||
file are found from the system header root. For example, <code>mylib.h</code>
|
||||
can be found in <code>/usr/include/mylib.h</code>. If the headers are installed
|
||||
in some other system root, the <code>-isysroot</code> option can be used provide
|
||||
a different system root from which the headers will be based. For example,
|
||||
<code>-isysroot /Developer/SDKs/MacOSX10.4u.sdk</code> will look for
|
||||
<code>mylib.h</code> in
|
||||
<code>/Developer/SDKs/MacOSX10.4u.sdk/usr/include/mylib.h</code>.</p>
|
||||
|
||||
<p>Relocatable precompiled headers are intended to be used in a limited number
|
||||
of cases where the compilation environment is tightly controlled and the
|
||||
precompiled header cannot be generated after headers have been installed.
|
||||
Relocatable precompiled headers also have some performance impact, because
|
||||
the difference in location between the header locations at PCH build time vs.
|
||||
at the time of PCH use requires one of the PCH optimizations,
|
||||
<code>stat()</code> caching, to be disabled. However, this change is only
|
||||
likely to affect PCH files that reference a large number of headers.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="c">C Language Features</h2>
|
||||
|
|
@ -500,7 +596,6 @@ variants "__asm__" and "__typeof__" are recognized in all modes.</li>
|
|||
<li>The Apple "blocks" extension is recognized by default in gnu* modes
|
||||
on some platforms; it can be enabled in any mode with the "-fblocks"
|
||||
option.</li>
|
||||
<li>Some warnings are different.</li>
|
||||
</ul>
|
||||
|
||||
<p>Differences between *89 and *99 modes:</p>
|
||||
|
|
|
|||
267
docs/libIndex.html
Normal file
267
docs/libIndex.html
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>The Index Library</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../content.css" />
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>The Index Library</h1>
|
||||
|
||||
<p><b>Table of Contents</b></p>
|
||||
<ul>
|
||||
<li><a href="#philosophy">Design Philosophy</a></li>
|
||||
<li><a href="#classes">Classes</a>
|
||||
<ul>
|
||||
<li><a href="#entity">Entity</a></li>
|
||||
<li><a href="#astlocation">ASTLocation</a></li>
|
||||
<li><a href="#declreferencemap">DeclReferenceMap</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#functions">Functions</a>
|
||||
<ul>
|
||||
<li><a href="#resolveloc">ResolveLocationInAST</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#astfiles">AST Files</a></li>
|
||||
<li><a href="#indextest">index-test tool</a>
|
||||
<ul>
|
||||
<li><a href="#indextestusage">Usage</a></li>
|
||||
<li><a href="#indextestexamples">Examples</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="philosophy">Design Philosophy</h2>
|
||||
|
||||
<p> The Index library is meant to provide the basic infrastructure for
|
||||
cross-translation-unit analysis and is primarily focused on indexing
|
||||
related functionality. It provides an API for clients that need to
|
||||
accurately map the AST nodes of the ASTContext to the locations in the source files.
|
||||
It also allows them to analyze information across multiple translation units.</p>
|
||||
|
||||
<p>As a "general rule", ASTContexts are considered the primary source of
|
||||
information that a client wants about a translation unit. There will be no such class as an
|
||||
"indexing database" that stores, for example, source locations of identifiers separately from ASTContext.
|
||||
All the information that a client needs from a translation unit will be extracted from the ASTContext.</p>
|
||||
|
||||
<h2 id="classes">Classes</h2>
|
||||
|
||||
<h3 id="entity">Entity</h3>
|
||||
|
||||
<p>To be able to reason about semantically the same Decls that are contained in multiple ASTContexts, the 'Entity' class was introduced.
|
||||
An Entity is an ASTContext-independent "token" that can be created from a Decl (and a typename in the future) with
|
||||
the purpose to "resolve" it into a Decl belonging to another ASTContext. Some examples to make the concept of Entities more clear:</p>
|
||||
|
||||
<p>
|
||||
t1.c:
|
||||
<pre class="code_example">
|
||||
void foo(void);
|
||||
void bar(void);
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
t2.c:
|
||||
<pre class="code_example">
|
||||
void foo(void) {
|
||||
}
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Translation unit <code>t1.c</code> contains 2 Entities <code>foo</code> and <code>bar</code>, while <code>t2.c</code> contains 1 Entity <code>foo</code>.
|
||||
Entities are uniqued in such a way that the Entity* pointer for <code>t1.c/foo</code> is the same as the Entity* pointer for <code>t2.c/foo</code>.
|
||||
An Entity doesn't convey any information about the declaration, it is more like an opaque pointer used only to get the
|
||||
associated Decl out of an ASTContext so that the actual information for the declaration can be accessed.
|
||||
Another important aspect of Entities is that they can only be created/associated for declarations that are visible outside the
|
||||
translation unit. This means that for:
|
||||
</p>
|
||||
<p>
|
||||
t3.c:
|
||||
<pre class="code_example">
|
||||
static void foo(void);
|
||||
</pre>
|
||||
</p>
|
||||
<p>
|
||||
there can be no Entity (if you ask for the Entity* of the static function <code>foo</code> you'll get a null pointer).
|
||||
This is for 2 reasons:
|
||||
<ul>
|
||||
<li>To preserve the invariant that the same Entity* pointers refer to the same semantic Decls.
|
||||
In the above example <code>t1.c/foo</code> and <code>t2.c/foo</code> are the same, while <code>t3.c/foo</code> is different.</li>
|
||||
<li>The purpose of Entity is to get the same semantic Decl from multiple ASTContexts. For a Decl that is not visible
|
||||
outside of its own translation unit, you don't need an Entity since it won't appear in another ASTContext.</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<h3 id="astlocation">ASTLocation</h3>
|
||||
|
||||
Encapsulates a "point" in the AST tree of the ASTContext.
|
||||
It represents either a Decl*, or a Stmt* along with its immediate Decl* parent.
|
||||
An example for its usage is that libIndex will provide the references of <code>foo</code> in the form of ASTLocations,
|
||||
"pointing" at the expressions that reference <code>foo</code>.
|
||||
|
||||
<h3 id="declreferencemap">DeclReferenceMap</h3>
|
||||
|
||||
Accepts an ASTContext and creates a mapping from NamedDecls to the ASTLocations that reference them (in the same ASTContext).
|
||||
|
||||
<h2 id="functions">Functions</h2>
|
||||
|
||||
<h3 id="resolveloc">ResolveLocationInAST</h3>
|
||||
|
||||
A function that accepts an ASTContext and a SourceLocation which it resolves into an ASTLocation.
|
||||
|
||||
<h2 id="astfiles">AST Files</h2>
|
||||
|
||||
The precompiled headers implementation of clang (<a href="http://clang.llvm.org/docs/PCHInternals.html">PCH</a>) is ideal for storing an ASTContext in a compact form that
|
||||
will be loaded later for AST analysis. An "AST file" refers to a translation unit that was "compiled" into a precompiled header file.
|
||||
|
||||
<h2 id="indextest">index-test tool</h2>
|
||||
|
||||
<h3 id="indextestusage">Usage</h3>
|
||||
|
||||
A command-line tool that exercises the libIndex API, useful for testing its features.
|
||||
As input it accepts multiple AST files (representing multiple translation units) and a few options:
|
||||
|
||||
<p>
|
||||
<pre class="code_example">
|
||||
-point-at [file:line:column]
|
||||
</pre>
|
||||
Resolves a [file:line:column] triplet into a ASTLocation from the first AST file. If no other option is specified, it prints the ASTLocation.
|
||||
It also prints a declaration's associated doxygen comment, if one is available.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<pre class="code_example">
|
||||
-print-refs
|
||||
</pre>
|
||||
Prints the ASTLocations that reference the declaration that was resolved out of the [file:line:column] triplet
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<pre class="code_example">
|
||||
-print-defs
|
||||
</pre>
|
||||
Prints the ASTLocations that define the resolved declaration
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<pre class="code_example">
|
||||
-print-decls
|
||||
</pre>
|
||||
Prints the ASTLocations that declare the resolved declaration
|
||||
</p>
|
||||
|
||||
<h3 id="indextestexamples">Examples</h3>
|
||||
|
||||
<p>
|
||||
Here's an example of using index-test:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We have 3 files,
|
||||
</p>
|
||||
|
||||
<p>
|
||||
foo.h:
|
||||
<pre class="code_example">
|
||||
extern int global_var;
|
||||
|
||||
void foo_func(int param1);
|
||||
void bar_func(void);
|
||||
</pre>
|
||||
|
||||
t1.c:
|
||||
<pre class="code_example">
|
||||
#include "foo.h"
|
||||
|
||||
void foo_func(int param1) {
|
||||
int local_var = global_var;
|
||||
for (int for_var = 100; for_var < 500; ++for_var) {
|
||||
local_var = param1 + for_var;
|
||||
}
|
||||
bar_func();
|
||||
}
|
||||
</pre>
|
||||
|
||||
t2.c:
|
||||
<pre class="code_example">
|
||||
#include "foo.h"
|
||||
|
||||
int global_var = 10;
|
||||
|
||||
void bar_func(void) {
|
||||
global_var += 100;
|
||||
foo_func(global_var);
|
||||
}
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You first get AST files out of <code>t1.c</code> and <code>t2.c</code>:
|
||||
|
||||
<pre class="code_example">
|
||||
$ clang-cc -emit-pch t1.c -o t1.ast
|
||||
$ clang-cc -emit-pch t2.c -o t2.ast
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Find the ASTLocation under this position of <code>t1.c</code>:
|
||||
<pre class="code_example">
|
||||
[...]
|
||||
void foo_func(int param1) {
|
||||
int local_var = global_var;
|
||||
^
|
||||
[...]
|
||||
</pre>
|
||||
|
||||
<pre class="code_example">
|
||||
$ index-test t1.ast -point-at t1.c:4:23
|
||||
> [Decl: Var local_var | Stmt: DeclRefExpr global_var] <t1.c:4:19, t1.c:4:19>
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Find the declaration:
|
||||
|
||||
<pre class="code_example">
|
||||
$ index-test t1.ast -point-at t1.c:4:23 -print-decls
|
||||
> [Decl: Var global_var] <foo.h:1:12, foo.h:1:12>
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Find the references:
|
||||
|
||||
<pre class="code_example">
|
||||
$ index-test t1.ast t2.ast -point-at t1.c:4:23 -print-refs
|
||||
> [Decl: Var local_var | Stmt: DeclRefExpr global_var] <t1.c:4:19, t1.c:4:19>
|
||||
> [Decl: Function bar_func | Stmt: DeclRefExpr global_var] <t2.c:6:3, t2.c:6:3>
|
||||
> [Decl: Function bar_func | Stmt: DeclRefExpr global_var] <t2.c:7:12, t2.c:7:12>
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Find definitions:
|
||||
|
||||
<pre class="code_example">
|
||||
$ index-test t1.ast t2.ast -point-at t1.c:4:23 -print-defs
|
||||
> [Decl: Var global_var] <t2.c:3:5, t2.c:3:18>
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -21,6 +21,7 @@ SRC_DOC_DIR=
|
|||
DST_HTML_DIR=html/
|
||||
DST_MAN_DIR=man/man1/
|
||||
DST_PS_DIR=ps/
|
||||
CLANG_VERSION := trunk
|
||||
|
||||
# If we are in BUILD_FOR_WEBSITE mode, default to the all target.
|
||||
all:: html man ps
|
||||
|
|
@ -39,6 +40,8 @@ else
|
|||
LEVEL := ../../../..
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
CLANG_VERSION := $(shell cat $(PROJ_SRC_DIR)/../../VER)
|
||||
|
||||
SRC_DOC_DIR=$(PROJ_SRC_DIR)/
|
||||
DST_HTML_DIR=$(PROJ_OBJ_DIR)/
|
||||
DST_MAN_DIR=$(PROJ_OBJ_DIR)/
|
||||
|
|
@ -66,7 +69,7 @@ $(DST_HTML_DIR)%.html: %.pod $(DST_HTML_DIR)/.dir
|
|||
--podpath=. --infile=$< --outfile=$@ --title=$*
|
||||
|
||||
$(DST_MAN_DIR)%.1: %.pod $(DST_MAN_DIR)/.dir
|
||||
pod2man --release "clang 1.0" --center="Clang Tools Documentation" $< $@
|
||||
pod2man --release "clang $(CLANG_VERSION)" --center="Clang Tools Documentation" $< $@
|
||||
|
||||
$(DST_PS_DIR)%.ps: $(DST_MAN_DIR)%.1 $(DST_PS_DIR)/.dir
|
||||
groff -Tps -man $< > $@
|
||||
|
|
|
|||
|
|
@ -378,8 +378,7 @@ Show commands to run and use verbose output.
|
|||
|
||||
=over
|
||||
|
||||
=item
|
||||
B<-fshow-column>
|
||||
=item B<-fshow-column>
|
||||
B<-fshow-source-location>
|
||||
B<-fcaret-diagnostics>
|
||||
B<-fdiagnostics-fixit-info>
|
||||
|
|
@ -428,13 +427,14 @@ Do not search the standard system directories for include files.
|
|||
=cut
|
||||
|
||||
## TODO, but do we really want people using this stuff?
|
||||
=item B<-idirafter>I<directory>
|
||||
=item B<-iquote>I<directory>
|
||||
=item B<-isystem>I<directory>
|
||||
=item B<-iprefix>I<directory>
|
||||
=item B<-iwithprefix>I<directory>
|
||||
=item B<-iwithprefixbefore>I<directory>
|
||||
=item B<-isysroot>
|
||||
#=item B<-idirafter>I<directory>
|
||||
#=item B<-iquote>I<directory>
|
||||
#=item B<-isystem>I<directory>
|
||||
#=item B<-iprefix>I<directory>
|
||||
#=item B<-iwithprefix>I<directory>
|
||||
#=item B<-iwithprefixbefore>I<directory>
|
||||
#=item B<-isysroot>
|
||||
|
||||
=pod
|
||||
|
||||
|
||||
|
|
@ -445,21 +445,21 @@ Do not search the standard system directories for include files.
|
|||
=cut
|
||||
|
||||
### TODO someday.
|
||||
=head2 Warning Control Options
|
||||
=over
|
||||
=back
|
||||
=head2 Code Generation and Optimization Options
|
||||
=over
|
||||
=back
|
||||
=head2 Assembler Options
|
||||
=over
|
||||
=back
|
||||
=head2 Linker Options
|
||||
=over
|
||||
=back
|
||||
=head2 Static Analyzer Options
|
||||
=over
|
||||
=back
|
||||
#=head2 Warning Control Options
|
||||
#=over
|
||||
#=back
|
||||
#=head2 Code Generation and Optimization Options
|
||||
#=over
|
||||
#=back
|
||||
#=head2 Assembler Options
|
||||
#=over
|
||||
#=back
|
||||
#=head2 Linker Options
|
||||
#=over
|
||||
#=back
|
||||
#=head2 Static Analyzer Options
|
||||
#=over
|
||||
#=back
|
||||
|
||||
=pod
|
||||
|
||||
|
|
|
|||
220
include/clang-c/Index.h
Normal file
220
include/clang-c/Index.h
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
/*===-- clang-c/Index.h - Indexing Public C Interface -------------*- C -*-===*\
|
||||
|* *|
|
||||
|* The LLVM Compiler Infrastructure *|
|
||||
|* *|
|
||||
|* This file is distributed under the University of Illinois Open Source *|
|
||||
|* License. See LICENSE.TXT for details. *|
|
||||
|* *|
|
||||
|*===----------------------------------------------------------------------===*|
|
||||
|* *|
|
||||
|* This header provides a public inferface to a Clang library for extracting *|
|
||||
|* high-level symbol information from source files without exposing the full *|
|
||||
|* Clang C++ API. *|
|
||||
|* *|
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
|
||||
#ifndef CLANG_C_INDEX_H
|
||||
#define CLANG_C_INDEX_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
Clang indeX abstractions. The backing store for the following API's will be
|
||||
clangs AST file (currently based on PCH). AST files are created as follows:
|
||||
|
||||
"clang -emit-ast <sourcefile.langsuffix> -o <sourcefile.ast>".
|
||||
|
||||
Naming Conventions: To avoid namespace pollution, data types are prefixed
|
||||
with "CX" and functions are prefixed with "clang_".
|
||||
*/
|
||||
typedef void *CXIndex; /* An indexing instance. */
|
||||
|
||||
typedef void *CXTranslationUnit; /* A translation unit instance. */
|
||||
|
||||
typedef void *CXDecl; /* A specific declaration within a translation unit. */
|
||||
typedef void *CXStmt; /* A specific statement within a function/method */
|
||||
|
||||
/* Cursors represent declarations, definitions, and references. */
|
||||
enum CXCursorKind {
|
||||
/* Declarations */
|
||||
CXCursor_FirstDecl = 1,
|
||||
CXCursor_TypedefDecl = 2,
|
||||
CXCursor_StructDecl = 3,
|
||||
CXCursor_UnionDecl = 4,
|
||||
CXCursor_ClassDecl = 5,
|
||||
CXCursor_EnumDecl = 6,
|
||||
CXCursor_FieldDecl = 7,
|
||||
CXCursor_EnumConstantDecl = 8,
|
||||
CXCursor_FunctionDecl = 9,
|
||||
CXCursor_VarDecl = 10,
|
||||
CXCursor_ParmDecl = 11,
|
||||
CXCursor_ObjCInterfaceDecl = 12,
|
||||
CXCursor_ObjCCategoryDecl = 13,
|
||||
CXCursor_ObjCProtocolDecl = 14,
|
||||
CXCursor_ObjCPropertyDecl = 15,
|
||||
CXCursor_ObjCIvarDecl = 16,
|
||||
CXCursor_ObjCInstanceMethodDecl = 17,
|
||||
CXCursor_ObjCClassMethodDecl = 18,
|
||||
CXCursor_LastDecl = 18,
|
||||
|
||||
/* Definitions */
|
||||
CXCursor_FirstDefn = 32,
|
||||
CXCursor_FunctionDefn = 32,
|
||||
CXCursor_ObjCClassDefn = 33,
|
||||
CXCursor_ObjCCategoryDefn = 34,
|
||||
CXCursor_ObjCInstanceMethodDefn = 35,
|
||||
CXCursor_ObjCClassMethodDefn = 36,
|
||||
CXCursor_LastDefn = 36,
|
||||
|
||||
/* References */
|
||||
CXCursor_FirstRef = 40, /* Decl references */
|
||||
CXCursor_ObjCSuperClassRef = 40,
|
||||
CXCursor_ObjCProtocolRef = 41,
|
||||
CXCursor_ObjCClassRef = 42,
|
||||
|
||||
CXCursor_ObjCSelectorRef = 43, /* Expression references */
|
||||
CXCursor_ObjCIvarRef = 44,
|
||||
CXCursor_VarRef = 45,
|
||||
CXCursor_FunctionRef = 46,
|
||||
CXCursor_EnumConstantRef = 47,
|
||||
CXCursor_MemberRef = 48,
|
||||
CXCursor_LastRef = 48,
|
||||
|
||||
/* Error conditions */
|
||||
CXCursor_FirstInvalid = 70,
|
||||
CXCursor_InvalidFile = 70,
|
||||
CXCursor_NoDeclFound = 71,
|
||||
CXCursor_NotImplemented = 72,
|
||||
CXCursor_LastInvalid = 72
|
||||
};
|
||||
|
||||
/* A cursor into the CXTranslationUnit. */
|
||||
|
||||
typedef struct {
|
||||
enum CXCursorKind kind;
|
||||
CXDecl decl;
|
||||
CXStmt stmt; /* expression reference */
|
||||
} CXCursor;
|
||||
|
||||
/* A unique token for looking up "visible" CXDecls from a CXTranslationUnit. */
|
||||
typedef void *CXEntity;
|
||||
|
||||
CXIndex clang_createIndex();
|
||||
void clang_disposeIndex(CXIndex);
|
||||
|
||||
const char *clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit);
|
||||
|
||||
CXTranslationUnit clang_createTranslationUnit(
|
||||
CXIndex, const char *ast_filename
|
||||
);
|
||||
void clang_disposeTranslationUnit(CXTranslationUnit);
|
||||
|
||||
/*
|
||||
Usage: clang_loadTranslationUnit(). Will load the toplevel declarations
|
||||
within a translation unit, issuing a 'callback' for each one.
|
||||
|
||||
void printObjCInterfaceNames(CXTranslationUnit X, CXCursor C) {
|
||||
if (clang_getCursorKind(C) == Cursor_Declaration) {
|
||||
CXDecl D = clang_getCursorDecl(C);
|
||||
if (clang_getDeclKind(D) == CXDecl_ObjC_interface)
|
||||
printf("@interface %s in file %s on line %d column %d\n",
|
||||
clang_getDeclSpelling(D), clang_getCursorSource(C),
|
||||
clang_getCursorLine(C), clang_getCursorColumn(C));
|
||||
}
|
||||
}
|
||||
static void usage {
|
||||
clang_loadTranslationUnit(CXTranslationUnit, printObjCInterfaceNames);
|
||||
}
|
||||
*/
|
||||
typedef void *CXClientData;
|
||||
typedef void (*CXTranslationUnitIterator)(CXTranslationUnit, CXCursor,
|
||||
CXClientData);
|
||||
void clang_loadTranslationUnit(CXTranslationUnit, CXTranslationUnitIterator,
|
||||
CXClientData);
|
||||
|
||||
/*
|
||||
Usage: clang_loadDeclaration(). Will load the declaration, issuing a
|
||||
'callback' for each declaration/reference within the respective declaration.
|
||||
|
||||
For interface declarations, this will index the super class, protocols,
|
||||
ivars, methods, etc. For structure declarations, this will index the fields.
|
||||
For functions, this will index the parameters (and body, for function
|
||||
definitions), local declarations/references.
|
||||
|
||||
void getInterfaceDetails(CXDecl X, CXCursor C) {
|
||||
switch (clang_getCursorKind(C)) {
|
||||
case Cursor_ObjC_ClassRef:
|
||||
CXDecl SuperClass = clang_getCursorDecl(C);
|
||||
case Cursor_ObjC_ProtocolRef:
|
||||
CXDecl AdoptsProtocol = clang_getCursorDecl(C);
|
||||
case Cursor_Declaration:
|
||||
CXDecl AnIvarOrMethod = clang_getCursorDecl(C);
|
||||
}
|
||||
}
|
||||
static void usage() {
|
||||
if (clang_getDeclKind(D) == CXDecl_ObjC_interface) {
|
||||
clang_loadDeclaration(D, getInterfaceDetails);
|
||||
}
|
||||
}
|
||||
*/
|
||||
typedef void (*CXDeclIterator)(CXDecl, CXCursor, CXClientData);
|
||||
|
||||
void clang_loadDeclaration(CXDecl, CXDeclIterator, CXClientData);
|
||||
|
||||
/*
|
||||
* CXEntity Operations.
|
||||
*/
|
||||
const char *clang_getDeclarationName(CXEntity);
|
||||
const char *clang_getURI(CXEntity);
|
||||
CXEntity clang_getEntity(const char *URI);
|
||||
/*
|
||||
* CXDecl Operations.
|
||||
*/
|
||||
CXCursor clang_getCursorFromDecl(CXDecl);
|
||||
CXEntity clang_getEntityFromDecl(CXDecl);
|
||||
const char *clang_getDeclSpelling(CXDecl);
|
||||
unsigned clang_getDeclLine(CXDecl);
|
||||
unsigned clang_getDeclColumn(CXDecl);
|
||||
const char *clang_getDeclSource(CXDecl);
|
||||
|
||||
/*
|
||||
* CXCursor Operations.
|
||||
*/
|
||||
CXCursor clang_getCursor(CXTranslationUnit, const char *source_name,
|
||||
unsigned line, unsigned column);
|
||||
|
||||
enum CXCursorKind clang_getCursorKind(CXCursor);
|
||||
unsigned clang_isDeclaration(enum CXCursorKind);
|
||||
unsigned clang_isReference(enum CXCursorKind);
|
||||
unsigned clang_isDefinition(enum CXCursorKind);
|
||||
unsigned clang_isInvalid(enum CXCursorKind);
|
||||
|
||||
unsigned clang_getCursorLine(CXCursor);
|
||||
unsigned clang_getCursorColumn(CXCursor);
|
||||
const char *clang_getCursorSource(CXCursor);
|
||||
const char *clang_getCursorSpelling(CXCursor);
|
||||
|
||||
/* for debug/testing */
|
||||
const char *clang_getCursorKindSpelling(enum CXCursorKind Kind);
|
||||
void clang_getDefinitionSpellingAndExtent(CXCursor,
|
||||
const char **startBuf,
|
||||
const char **endBuf,
|
||||
unsigned *startLine,
|
||||
unsigned *startColumn,
|
||||
unsigned *endLine,
|
||||
unsigned *endColumn);
|
||||
|
||||
/*
|
||||
* If CXCursorKind == Cursor_Reference, then this will return the referenced
|
||||
* declaration.
|
||||
* If CXCursorKind == Cursor_Declaration, then this will return the declaration.
|
||||
*/
|
||||
CXDecl clang_getCursorDecl(CXCursor);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
@ -37,16 +37,16 @@ public:
|
|||
};
|
||||
private:
|
||||
ValueKind Kind;
|
||||
|
||||
struct ComplexAPSInt {
|
||||
APSInt Real, Imag;
|
||||
|
||||
struct ComplexAPSInt {
|
||||
APSInt Real, Imag;
|
||||
ComplexAPSInt() : Real(1), Imag(1) {}
|
||||
};
|
||||
struct ComplexAPFloat {
|
||||
APFloat Real, Imag;
|
||||
ComplexAPFloat() : Real(0.0), Imag(0.0) {}
|
||||
};
|
||||
|
||||
|
||||
struct LV {
|
||||
Expr* Base;
|
||||
uint64_t Offset;
|
||||
|
|
@ -57,16 +57,17 @@ private:
|
|||
Vec() : Elts(0), NumElts(0) {}
|
||||
~Vec() { delete[] Elts; }
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ?
|
||||
MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ?
|
||||
sizeof(ComplexAPSInt) : sizeof(ComplexAPFloat))
|
||||
};
|
||||
|
||||
/// Data - space for the largest member in units of void*. This is an effort
|
||||
/// to ensure that the APSInt/APFloat values have proper alignment.
|
||||
void *Data[(MaxSize+sizeof(void*)-1)/sizeof(void*)];
|
||||
|
||||
|
||||
union {
|
||||
void *Aligner;
|
||||
char Data[MaxSize];
|
||||
};
|
||||
|
||||
public:
|
||||
APValue() : Kind(Uninitialized) {}
|
||||
explicit APValue(const APSInt &I) : Kind(Uninitialized) {
|
||||
|
|
@ -93,7 +94,7 @@ public:
|
|||
~APValue() {
|
||||
MakeUninit();
|
||||
}
|
||||
|
||||
|
||||
ValueKind getKind() const { return Kind; }
|
||||
bool isUninit() const { return Kind == Uninitialized; }
|
||||
bool isInt() const { return Kind == Int; }
|
||||
|
|
@ -102,54 +103,54 @@ public:
|
|||
bool isComplexFloat() const { return Kind == ComplexFloat; }
|
||||
bool isLValue() const { return Kind == LValue; }
|
||||
bool isVector() const { return Kind == Vector; }
|
||||
|
||||
|
||||
void print(llvm::raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
|
||||
|
||||
APSInt &getInt() {
|
||||
assert(isInt() && "Invalid accessor");
|
||||
return *(APSInt*)(void*)Data;
|
||||
return *(APSInt*)(char*)Data;
|
||||
}
|
||||
const APSInt &getInt() const {
|
||||
return const_cast<APValue*>(this)->getInt();
|
||||
}
|
||||
|
||||
|
||||
APFloat &getFloat() {
|
||||
assert(isFloat() && "Invalid accessor");
|
||||
return *(APFloat*)(void*)Data;
|
||||
return *(APFloat*)(char*)Data;
|
||||
}
|
||||
const APFloat &getFloat() const {
|
||||
return const_cast<APValue*>(this)->getFloat();
|
||||
}
|
||||
|
||||
|
||||
APValue &getVectorElt(unsigned i) const {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
return ((Vec*)(void*)Data)->Elts[i];
|
||||
return ((Vec*)(char*)Data)->Elts[i];
|
||||
}
|
||||
unsigned getVectorLength() const {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
return ((Vec*)(void *)Data)->NumElts;
|
||||
}
|
||||
|
||||
|
||||
APSInt &getComplexIntReal() {
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
return ((ComplexAPSInt*)(void*)Data)->Real;
|
||||
return ((ComplexAPSInt*)(char*)Data)->Real;
|
||||
}
|
||||
const APSInt &getComplexIntReal() const {
|
||||
return const_cast<APValue*>(this)->getComplexIntReal();
|
||||
}
|
||||
|
||||
|
||||
APSInt &getComplexIntImag() {
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
return ((ComplexAPSInt*)(void*)Data)->Imag;
|
||||
return ((ComplexAPSInt*)(char*)Data)->Imag;
|
||||
}
|
||||
const APSInt &getComplexIntImag() const {
|
||||
return const_cast<APValue*>(this)->getComplexIntImag();
|
||||
}
|
||||
|
||||
|
||||
APFloat &getComplexFloatReal() {
|
||||
assert(isComplexFloat() && "Invalid accessor");
|
||||
return ((ComplexAPFloat*)(void*)Data)->Real;
|
||||
return ((ComplexAPFloat*)(char*)Data)->Real;
|
||||
}
|
||||
const APFloat &getComplexFloatReal() const {
|
||||
return const_cast<APValue*>(this)->getComplexFloatReal();
|
||||
|
|
@ -157,7 +158,7 @@ public:
|
|||
|
||||
APFloat &getComplexFloatImag() {
|
||||
assert(isComplexFloat() && "Invalid accessor");
|
||||
return ((ComplexAPFloat*)(void*)Data)->Imag;
|
||||
return ((ComplexAPFloat*)(char*)Data)->Imag;
|
||||
}
|
||||
const APFloat &getComplexFloatImag() const {
|
||||
return const_cast<APValue*>(this)->getComplexFloatImag();
|
||||
|
|
@ -171,44 +172,44 @@ public:
|
|||
assert(isLValue() && "Invalid accessor");
|
||||
return ((const LV*)(const void*)Data)->Offset;
|
||||
}
|
||||
|
||||
|
||||
void setInt(const APSInt &I) {
|
||||
assert(isInt() && "Invalid accessor");
|
||||
*(APSInt*)(void*)Data = I;
|
||||
*(APSInt*)(char*)Data = I;
|
||||
}
|
||||
void setFloat(const APFloat &F) {
|
||||
assert(isFloat() && "Invalid accessor");
|
||||
*(APFloat*)(void*)Data = F;
|
||||
*(APFloat*)(char*)Data = F;
|
||||
}
|
||||
void setVector(const APValue *E, unsigned N) {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
((Vec*)(void*)Data)->Elts = new APValue[N];
|
||||
((Vec*)(void*)Data)->NumElts = N;
|
||||
((Vec*)(char*)Data)->Elts = new APValue[N];
|
||||
((Vec*)(char*)Data)->NumElts = N;
|
||||
for (unsigned i = 0; i != N; ++i)
|
||||
((Vec*)(void*)Data)->Elts[i] = E[i];
|
||||
((Vec*)(char*)Data)->Elts[i] = E[i];
|
||||
}
|
||||
void setComplexInt(const APSInt &R, const APSInt &I) {
|
||||
assert(R.getBitWidth() == I.getBitWidth() &&
|
||||
assert(R.getBitWidth() == I.getBitWidth() &&
|
||||
"Invalid complex int (type mismatch).");
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
((ComplexAPSInt*)(void*)Data)->Real = R;
|
||||
((ComplexAPSInt*)(void*)Data)->Imag = I;
|
||||
((ComplexAPSInt*)(char*)Data)->Real = R;
|
||||
((ComplexAPSInt*)(char*)Data)->Imag = I;
|
||||
}
|
||||
void setComplexFloat(const APFloat &R, const APFloat &I) {
|
||||
assert(&R.getSemantics() == &I.getSemantics() &&
|
||||
assert(&R.getSemantics() == &I.getSemantics() &&
|
||||
"Invalid complex float (type mismatch).");
|
||||
assert(isComplexFloat() && "Invalid accessor");
|
||||
((ComplexAPFloat*)(void*)Data)->Real = R;
|
||||
((ComplexAPFloat*)(void*)Data)->Imag = I;
|
||||
((ComplexAPFloat*)(char*)Data)->Real = R;
|
||||
((ComplexAPFloat*)(char*)Data)->Imag = I;
|
||||
}
|
||||
void setLValue(Expr *B, uint64_t O) {
|
||||
assert(isLValue() && "Invalid accessor");
|
||||
((LV*)(void*)Data)->Base = B;
|
||||
((LV*)(void*)Data)->Offset = O;
|
||||
((LV*)(char*)Data)->Base = B;
|
||||
((LV*)(char*)Data)->Offset = O;
|
||||
}
|
||||
|
||||
|
||||
const APValue &operator=(const APValue &RHS);
|
||||
|
||||
|
||||
private:
|
||||
void MakeUninit();
|
||||
void MakeInt() {
|
||||
|
|
@ -218,27 +219,27 @@ private:
|
|||
}
|
||||
void MakeFloat() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((APFloat*)(void*)Data) APFloat(0.0);
|
||||
new ((void*)(char*)Data) APFloat(0.0);
|
||||
Kind = Float;
|
||||
}
|
||||
void MakeVector() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((Vec*)(void*)Data) Vec();
|
||||
new ((void*)(char*)Data) Vec();
|
||||
Kind = Vector;
|
||||
}
|
||||
void MakeComplexInt() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((ComplexAPSInt*)(void*)Data) ComplexAPSInt();
|
||||
new ((void*)(char*)Data) ComplexAPSInt();
|
||||
Kind = ComplexInt;
|
||||
}
|
||||
void MakeComplexFloat() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((ComplexAPFloat*)(void*)Data) ComplexAPFloat();
|
||||
new ((void*)(char*)Data) ComplexAPFloat();
|
||||
Kind = ComplexFloat;
|
||||
}
|
||||
void MakeLValue() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((LV*)(void*)Data) LV();
|
||||
new ((void*)(char*)Data) LV();
|
||||
Kind = LValue;
|
||||
}
|
||||
};
|
||||
|
|
@ -247,7 +248,7 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const APValue &V) {
|
|||
V.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace clang.
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -36,27 +36,27 @@ public:
|
|||
ASTConsumer() : SemaConsumer(false) { }
|
||||
|
||||
virtual ~ASTConsumer() {}
|
||||
|
||||
|
||||
/// Initialize - This is called to initialize the consumer, providing the
|
||||
/// ASTContext and the Action.
|
||||
virtual void Initialize(ASTContext &Context) {}
|
||||
|
||||
|
||||
/// HandleTopLevelDecl - Handle the specified top-level declaration. This is
|
||||
/// called by the parser to process every top-level Decl*. Note that D can
|
||||
/// be the head of a chain of Decls (e.g. for `int a, b` the chain will have
|
||||
/// two elements). Use Decl::getNextDeclarator() to walk the chain.
|
||||
virtual void HandleTopLevelDecl(DeclGroupRef D);
|
||||
|
||||
|
||||
/// HandleTranslationUnit - This method is called when the ASTs for entire
|
||||
/// translation unit have been parsed.
|
||||
virtual void HandleTranslationUnit(ASTContext &Ctx) {}
|
||||
|
||||
virtual void HandleTranslationUnit(ASTContext &Ctx) {}
|
||||
|
||||
/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
|
||||
/// (e.g. struct, union, enum, class) is completed. This allows the client to
|
||||
/// hack on the type, which can occur at any point in the file (because these
|
||||
/// can be defined in declspecs).
|
||||
virtual void HandleTagDeclDefinition(TagDecl *D) {}
|
||||
|
||||
|
||||
/// \brief Callback invoked at the end of a translation unit to
|
||||
/// notify the consumer that the given tentative definition should
|
||||
/// be completed.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -13,7 +13,7 @@
|
|||
#include "clang/Basic/Diagnostic.h"
|
||||
|
||||
namespace clang {
|
||||
namespace diag {
|
||||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM,
|
||||
#define ASTSTART
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
#ifndef LLVM_CLANG_AST_ATTR_H
|
||||
#define LLVM_CLANG_AST_ATTR_H
|
||||
|
||||
#include "llvm/Support/Casting.h"
|
||||
using llvm::dyn_cast;
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
|
@ -54,22 +57,24 @@ public:
|
|||
DLLImport,
|
||||
Deprecated,
|
||||
Destructor,
|
||||
FastCall,
|
||||
FastCall,
|
||||
Format,
|
||||
FormatArg,
|
||||
GNUInline,
|
||||
IBOutletKind, // Clang-specific. Use "Kind" suffix to not conflict with
|
||||
Malloc,
|
||||
NoDebug,
|
||||
NoInline,
|
||||
NonNull,
|
||||
NoReturn,
|
||||
NoThrow,
|
||||
Nodebug,
|
||||
Noinline,
|
||||
NonNull,
|
||||
ObjCException,
|
||||
ObjCNSObject,
|
||||
CFReturnsRetained, // Clang/Checker-specific.
|
||||
NSReturnsRetained, // Clang/Checker-specific.
|
||||
Overloadable, // Clang-specific
|
||||
Packed,
|
||||
PragmaPack,
|
||||
Pure,
|
||||
Regparm,
|
||||
ReqdWorkGroupSize, // OpenCL-specific
|
||||
|
|
@ -78,14 +83,14 @@ public:
|
|||
StdCall,
|
||||
TransparentUnion,
|
||||
Unavailable,
|
||||
Unused,
|
||||
Unused,
|
||||
Used,
|
||||
Visibility,
|
||||
WarnUnusedResult,
|
||||
Weak,
|
||||
WeakImport
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
Attr *Next;
|
||||
Kind AttrKind;
|
||||
|
|
@ -99,16 +104,16 @@ protected:
|
|||
void operator delete(void* data) throw() {
|
||||
assert(0 && "Attrs cannot be released with regular 'delete'.");
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
Attr(Kind AK) : Next(0), AttrKind(AK), Inherited(false) {}
|
||||
virtual ~Attr() {
|
||||
assert(Next == 0 && "Destroy didn't work");
|
||||
}
|
||||
public:
|
||||
|
||||
|
||||
void Destroy(ASTContext &C);
|
||||
|
||||
|
||||
/// \brief Whether this attribute should be merged to new
|
||||
/// declarations.
|
||||
virtual bool isMerged() const { return true; }
|
||||
|
|
@ -119,17 +124,24 @@ public:
|
|||
const Attr *getNext() const { return Next; }
|
||||
void setNext(Attr *next) { Next = next; }
|
||||
|
||||
template<typename T> const T *getNext() const {
|
||||
for (const Attr *attr = getNext(); attr; attr = attr->getNext())
|
||||
if (const T *V = dyn_cast<T>(attr))
|
||||
return V;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool isInherited() const { return Inherited; }
|
||||
void setInherited(bool value) { Inherited = value; }
|
||||
|
||||
void addAttr(Attr *attr) {
|
||||
assert((attr != 0) && "addAttr(): attr is null");
|
||||
|
||||
|
||||
// FIXME: This doesn't preserve the order in any way.
|
||||
attr->Next = Next;
|
||||
Next = attr;
|
||||
}
|
||||
|
||||
|
||||
// Clone this attribute.
|
||||
virtual Attr* clone(ASTContext &C) const = 0;
|
||||
|
||||
|
|
@ -146,36 +158,39 @@ public: \
|
|||
static bool classof(const ATTR##Attr *A) { return true; } \
|
||||
}
|
||||
|
||||
class PackedAttr : public Attr {
|
||||
DEF_SIMPLE_ATTR(Packed);
|
||||
|
||||
class PragmaPackAttr : public Attr {
|
||||
unsigned Alignment;
|
||||
|
||||
public:
|
||||
PackedAttr(unsigned alignment) : Attr(Packed), Alignment(alignment) {}
|
||||
PragmaPackAttr(unsigned alignment) : Attr(PragmaPack), Alignment(alignment) {}
|
||||
|
||||
/// getAlignment - The specified alignment in bits.
|
||||
unsigned getAlignment() const { return Alignment; }
|
||||
|
||||
virtual Attr* clone(ASTContext &C) const {
|
||||
return ::new (C) PackedAttr(Alignment);
|
||||
virtual Attr* clone(ASTContext &C) const {
|
||||
return ::new (C) PragmaPackAttr(Alignment);
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == Packed;
|
||||
return A->getKind() == PragmaPack;
|
||||
}
|
||||
static bool classof(const PackedAttr *A) { return true; }
|
||||
static bool classof(const PragmaPackAttr *A) { return true; }
|
||||
};
|
||||
|
||||
|
||||
class AlignedAttr : public Attr {
|
||||
unsigned Alignment;
|
||||
public:
|
||||
AlignedAttr(unsigned alignment) : Attr(Aligned), Alignment(alignment) {}
|
||||
|
||||
// FIXME: Should use addressable units, not bits, to match llvm
|
||||
/// getAlignment - The specified alignment in bits.
|
||||
unsigned getAlignment() const { return Alignment; }
|
||||
|
||||
virtual Attr* clone(ASTContext &C) const { return ::new (C) AlignedAttr(Alignment); }
|
||||
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == Aligned;
|
||||
|
|
@ -187,11 +202,11 @@ class AnnotateAttr : public Attr {
|
|||
std::string Annotation;
|
||||
public:
|
||||
AnnotateAttr(const std::string &ann) : Attr(Annotate), Annotation(ann) {}
|
||||
|
||||
|
||||
const std::string& getAnnotation() const { return Annotation; }
|
||||
|
||||
virtual Attr* clone(ASTContext &C) const { return ::new (C) AnnotateAttr(Annotation); }
|
||||
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == Annotate;
|
||||
|
|
@ -203,11 +218,11 @@ class AsmLabelAttr : public Attr {
|
|||
std::string Label;
|
||||
public:
|
||||
AsmLabelAttr(const std::string &L) : Attr(AsmLabel), Label(L) {}
|
||||
|
||||
|
||||
const std::string& getLabel() const { return Label; }
|
||||
|
||||
|
||||
virtual Attr* clone(ASTContext &C) const { return ::new (C) AsmLabelAttr(Label); }
|
||||
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == AsmLabel;
|
||||
|
|
@ -237,28 +252,28 @@ public:
|
|||
ConstructorAttr(int p) : Attr(Constructor), priority(p) {}
|
||||
|
||||
int getPriority() const { return priority; }
|
||||
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) ConstructorAttr(priority); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Constructor; }
|
||||
static bool classof(const Attr *A) { return A->getKind() == Constructor; }
|
||||
static bool classof(const ConstructorAttr *A) { return true; }
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class DestructorAttr : public Attr {
|
||||
int priority;
|
||||
public:
|
||||
DestructorAttr(int p) : Attr(Destructor), priority(p) {}
|
||||
|
||||
int getPriority() const { return priority; }
|
||||
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) DestructorAttr(priority); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Destructor; }
|
||||
static bool classof(const Attr *A) { return A->getKind() == Destructor; }
|
||||
static bool classof(const DestructorAttr *A) { return true; }
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class GNUInlineAttr : public Attr {
|
||||
public:
|
||||
GNUInlineAttr() : Attr(GNUInline) {}
|
||||
|
|
@ -285,15 +300,16 @@ public:
|
|||
static bool classof(const IBOutletAttr *A) { return true; }
|
||||
};
|
||||
|
||||
DEF_SIMPLE_ATTR(Malloc);
|
||||
DEF_SIMPLE_ATTR(NoReturn);
|
||||
DEF_SIMPLE_ATTR(AnalyzerNoReturn);
|
||||
DEF_SIMPLE_ATTR(AnalyzerNoReturn);
|
||||
DEF_SIMPLE_ATTR(Deprecated);
|
||||
|
||||
class SectionAttr : public Attr {
|
||||
std::string Name;
|
||||
public:
|
||||
SectionAttr(const std::string &N) : Attr(Section), Name(N) {}
|
||||
|
||||
|
||||
const std::string& getName() const { return Name; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) SectionAttr(Name); }
|
||||
|
|
@ -307,8 +323,8 @@ public:
|
|||
|
||||
DEF_SIMPLE_ATTR(Unavailable);
|
||||
DEF_SIMPLE_ATTR(Unused);
|
||||
DEF_SIMPLE_ATTR(Used);
|
||||
DEF_SIMPLE_ATTR(Weak);
|
||||
DEF_SIMPLE_ATTR(Used);
|
||||
DEF_SIMPLE_ATTR(Weak);
|
||||
DEF_SIMPLE_ATTR(WeakImport);
|
||||
DEF_SIMPLE_ATTR(NoThrow);
|
||||
DEF_SIMPLE_ATTR(Const);
|
||||
|
|
@ -320,14 +336,14 @@ class NonNullAttr : public Attr {
|
|||
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);
|
||||
}
|
||||
|
||||
|
||||
virtual ~NonNullAttr() {
|
||||
delete [] ArgNums;
|
||||
}
|
||||
|
|
@ -339,7 +355,7 @@ public:
|
|||
|
||||
bool isNonNull(unsigned arg) const {
|
||||
return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true;
|
||||
}
|
||||
}
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) NonNullAttr(ArgNums, Size); }
|
||||
|
||||
|
|
@ -359,8 +375,8 @@ public:
|
|||
int getFormatIdx() const { return formatIdx; }
|
||||
int getFirstArg() const { return firstArg; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) FormatAttr(Type, formatIdx, firstArg);
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) FormatAttr(Type, formatIdx, firstArg);
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
|
@ -437,8 +453,8 @@ public:
|
|||
|
||||
virtual bool isMerged() const { return false; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) OverloadableAttr;
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) OverloadableAttr;
|
||||
}
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == Overloadable; }
|
||||
|
|
@ -465,15 +481,15 @@ public:
|
|||
};
|
||||
|
||||
class FunctionDecl;
|
||||
|
||||
|
||||
class CleanupAttr : public Attr {
|
||||
FunctionDecl *FD;
|
||||
|
||||
|
||||
public:
|
||||
CleanupAttr(FunctionDecl *fd) : Attr(Cleanup), FD(fd) {}
|
||||
|
||||
const FunctionDecl *getFunctionDecl() const { return FD; }
|
||||
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) CleanupAttr(FD); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
|
@ -481,9 +497,9 @@ public:
|
|||
static bool classof(const CleanupAttr *A) { return true; }
|
||||
};
|
||||
|
||||
DEF_SIMPLE_ATTR(Nodebug);
|
||||
DEF_SIMPLE_ATTR(WarnUnusedResult);
|
||||
DEF_SIMPLE_ATTR(Noinline);
|
||||
DEF_SIMPLE_ATTR(NoDebug);
|
||||
DEF_SIMPLE_ATTR(WarnUnusedResult);
|
||||
DEF_SIMPLE_ATTR(NoInline);
|
||||
|
||||
class RegparmAttr : public Attr {
|
||||
unsigned NumParams;
|
||||
|
|
@ -493,11 +509,11 @@ public:
|
|||
|
||||
unsigned getNumParams() const { return NumParams; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) RegparmAttr(NumParams);
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) RegparmAttr(NumParams);
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Regparm; }
|
||||
static bool classof(const RegparmAttr *A) { return true; }
|
||||
};
|
||||
|
|
@ -512,23 +528,23 @@ public:
|
|||
unsigned getYDim() const { return Y; }
|
||||
unsigned getZDim() const { return Z; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) ReqdWorkGroupSizeAttr(X, Y, Z);
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) ReqdWorkGroupSizeAttr(X, Y, Z);
|
||||
}
|
||||
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == ReqdWorkGroupSize;
|
||||
}
|
||||
static bool classof(const ReqdWorkGroupSizeAttr *A) { return true; }
|
||||
};
|
||||
|
||||
|
||||
// Checker-specific attributes.
|
||||
DEF_SIMPLE_ATTR(CFReturnsRetained);
|
||||
DEF_SIMPLE_ATTR(NSReturnsRetained);
|
||||
|
||||
#undef DEF_SIMPLE_ATTR
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
|
|
|||
212
include/clang/AST/CXXInheritance.h
Normal file
212
include/clang/AST/CXXInheritance.h
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
//===------ CXXInheritance.h - C++ Inheritance ------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides routines that help analyzing C++ inheritance hierarchies.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_CXXINHERITANCE_H
|
||||
#define LLVM_CLANG_AST_CXXINHERITANCE_H
|
||||
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/TypeOrdering.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CXXBaseSpecifier;
|
||||
class CXXMethodDecl;
|
||||
class CXXRecordDecl;
|
||||
class NamedDecl;
|
||||
|
||||
/// \brief Represents an element in a path from a derived class to a
|
||||
/// base class.
|
||||
///
|
||||
/// Each step in the path references the link from a
|
||||
/// derived class to one of its direct base classes, along with a
|
||||
/// base "number" that identifies which base subobject of the
|
||||
/// original derived class we are referencing.
|
||||
struct CXXBasePathElement {
|
||||
/// \brief The base specifier that states the link from a derived
|
||||
/// class to a base class, which will be followed by this base
|
||||
/// path element.
|
||||
const CXXBaseSpecifier *Base;
|
||||
|
||||
/// \brief The record decl of the class that the base is a base of.
|
||||
const CXXRecordDecl *Class;
|
||||
|
||||
/// \brief Identifies which base class subobject (of type
|
||||
/// \c Base->getType()) this base path element refers to.
|
||||
///
|
||||
/// This value is only valid if \c !Base->isVirtual(), because there
|
||||
/// is no base numbering for the zero or one virtual bases of a
|
||||
/// given type.
|
||||
int SubobjectNumber;
|
||||
};
|
||||
|
||||
/// \brief Represents a path from a specific derived class
|
||||
/// (which is not represented as part of the path) to a particular
|
||||
/// (direct or indirect) base class subobject.
|
||||
///
|
||||
/// Individual elements in the path are described by the \c CXXBasePathElement
|
||||
/// structure, which captures both the link from a derived class to one of its
|
||||
/// direct bases and identification describing which base class
|
||||
/// subobject is being used.
|
||||
struct CXXBasePath : public llvm::SmallVector<CXXBasePathElement, 4> {
|
||||
/// \brief The set of declarations found inside this base class
|
||||
/// subobject.
|
||||
DeclContext::lookup_result Decls;
|
||||
};
|
||||
|
||||
/// BasePaths - Represents the set of paths from a derived class to
|
||||
/// one of its (direct or indirect) bases. For example, given the
|
||||
/// following class hierachy:
|
||||
///
|
||||
/// @code
|
||||
/// class A { };
|
||||
/// class B : public A { };
|
||||
/// class C : public A { };
|
||||
/// class D : public B, public C{ };
|
||||
/// @endcode
|
||||
///
|
||||
/// There are two potential BasePaths to represent paths from D to a
|
||||
/// base subobject of type A. One path is (D,0) -> (B,0) -> (A,0)
|
||||
/// and another is (D,0)->(C,0)->(A,1). These two paths actually
|
||||
/// refer to two different base class subobjects of the same type,
|
||||
/// so the BasePaths object refers to an ambiguous path. On the
|
||||
/// other hand, consider the following class hierarchy:
|
||||
///
|
||||
/// @code
|
||||
/// class A { };
|
||||
/// class B : public virtual A { };
|
||||
/// class C : public virtual A { };
|
||||
/// class D : public B, public C{ };
|
||||
/// @endcode
|
||||
///
|
||||
/// Here, there are two potential BasePaths again, (D, 0) -> (B, 0)
|
||||
/// -> (A,v) and (D, 0) -> (C, 0) -> (A, v), but since both of them
|
||||
/// refer to the same base class subobject of type A (the virtual
|
||||
/// one), there is no ambiguity.
|
||||
class CXXBasePaths {
|
||||
/// \brief The type from which this search originated.
|
||||
CXXRecordDecl *Origin;
|
||||
|
||||
/// Paths - The actual set of paths that can be taken from the
|
||||
/// derived class to the same base class.
|
||||
std::list<CXXBasePath> Paths;
|
||||
|
||||
/// ClassSubobjects - Records the class subobjects for each class
|
||||
/// type that we've seen. The first element in the pair says
|
||||
/// whether we found a path to a virtual base for that class type,
|
||||
/// while the element contains the number of non-virtual base
|
||||
/// class subobjects for that class type. The key of the map is
|
||||
/// the cv-unqualified canonical type of the base class subobject.
|
||||
std::map<QualType, std::pair<bool, unsigned>, QualTypeOrdering>
|
||||
ClassSubobjects;
|
||||
|
||||
/// FindAmbiguities - Whether Sema::IsDerivedFrom should try find
|
||||
/// ambiguous paths while it is looking for a path from a derived
|
||||
/// type to a base type.
|
||||
bool FindAmbiguities;
|
||||
|
||||
/// RecordPaths - Whether Sema::IsDerivedFrom should record paths
|
||||
/// while it is determining whether there are paths from a derived
|
||||
/// type to a base type.
|
||||
bool RecordPaths;
|
||||
|
||||
/// DetectVirtual - Whether Sema::IsDerivedFrom should abort the search
|
||||
/// if it finds a path that goes across a virtual base. The virtual class
|
||||
/// is also recorded.
|
||||
bool DetectVirtual;
|
||||
|
||||
/// ScratchPath - A BasePath that is used by Sema::IsDerivedFrom
|
||||
/// to help build the set of paths.
|
||||
CXXBasePath ScratchPath;
|
||||
|
||||
/// DetectedVirtual - The base class that is virtual.
|
||||
const RecordType *DetectedVirtual;
|
||||
|
||||
/// \brief Array of the declarations that have been found. This
|
||||
/// array is constructed only if needed, e.g., to iterate over the
|
||||
/// results within LookupResult.
|
||||
NamedDecl **DeclsFound;
|
||||
unsigned NumDeclsFound;
|
||||
|
||||
friend class CXXRecordDecl;
|
||||
|
||||
void ComputeDeclsFound();
|
||||
|
||||
public:
|
||||
typedef std::list<CXXBasePath>::const_iterator paths_iterator;
|
||||
typedef NamedDecl **decl_iterator;
|
||||
|
||||
/// BasePaths - Construct a new BasePaths structure to record the
|
||||
/// paths for a derived-to-base search.
|
||||
explicit CXXBasePaths(bool FindAmbiguities = true,
|
||||
bool RecordPaths = true,
|
||||
bool DetectVirtual = true)
|
||||
: FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths),
|
||||
DetectVirtual(DetectVirtual), DetectedVirtual(0), DeclsFound(0),
|
||||
NumDeclsFound(0) { }
|
||||
|
||||
~CXXBasePaths() { delete [] DeclsFound; }
|
||||
|
||||
paths_iterator begin() const { return Paths.begin(); }
|
||||
paths_iterator end() const { return Paths.end(); }
|
||||
|
||||
CXXBasePath& front() { return Paths.front(); }
|
||||
const CXXBasePath& front() const { return Paths.front(); }
|
||||
|
||||
decl_iterator found_decls_begin();
|
||||
decl_iterator found_decls_end();
|
||||
|
||||
/// \brief Determine whether the path from the most-derived type to the
|
||||
/// given base type is ambiguous (i.e., it refers to multiple subobjects of
|
||||
/// the same base type).
|
||||
bool isAmbiguous(QualType BaseType);
|
||||
|
||||
/// \brief Whether we are finding multiple paths to detect ambiguities.
|
||||
bool isFindingAmbiguities() const { return FindAmbiguities; }
|
||||
|
||||
/// \brief Whether we are recording paths.
|
||||
bool isRecordingPaths() const { return RecordPaths; }
|
||||
|
||||
/// \brief Specify whether we should be recording paths or not.
|
||||
void setRecordingPaths(bool RP) { RecordPaths = RP; }
|
||||
|
||||
/// \brief Whether we are detecting virtual bases.
|
||||
bool isDetectingVirtual() const { return DetectVirtual; }
|
||||
|
||||
/// \brief The virtual base discovered on the path (if we are merely
|
||||
/// detecting virtuals).
|
||||
const RecordType* getDetectedVirtual() const {
|
||||
return DetectedVirtual;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the type from which this base-paths search
|
||||
/// began
|
||||
CXXRecordDecl *getOrigin() const { return Origin; }
|
||||
void setOrigin(CXXRecordDecl *Rec) { Origin = Rec; }
|
||||
|
||||
/// \brief Clear the base-paths results.
|
||||
void clear();
|
||||
|
||||
/// \brief Swap this data structure's contents with another CXXBasePaths
|
||||
/// object.
|
||||
void swap(CXXBasePaths &Other);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
721
include/clang/AST/CanonicalType.h
Normal file
721
include/clang/AST/CanonicalType.h
Normal file
|
|
@ -0,0 +1,721 @@
|
|||
//===-- CanonicalType.h - C Language Family Type Representation -*- 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 CanQual class template, which provides access to
|
||||
// canonical types.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_CANONICAL_TYPE_H
|
||||
#define LLVM_CLANG_AST_CANONICAL_TYPE_H
|
||||
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include <iterator>
|
||||
|
||||
namespace clang {
|
||||
|
||||
template<typename T> class CanProxy;
|
||||
template<typename T> struct CanProxyAdaptor;
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Canonical, qualified type template
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
/// \brief Represents a canonical, potentially-qualified type.
|
||||
///
|
||||
/// The CanQual template is a lightweight smart pointer that provides access
|
||||
/// to the canonical representation of a type, where all typedefs and other
|
||||
/// syntactic sugar has been eliminated. A CanQualType may also have various
|
||||
/// qualifiers (const, volatile, restrict) attached to it.
|
||||
///
|
||||
/// The template type parameter @p T is one of the Type classes (PointerType,
|
||||
/// BuiltinType, etc.). The type stored within @c CanQual<T> will be of that
|
||||
/// type (or some subclass of that type). The typedef @c CanQualType is just
|
||||
/// a shorthand for @c CanQual<Type>.
|
||||
///
|
||||
/// An instance of @c CanQual<T> can be implicitly converted to a
|
||||
/// @c CanQual<U> when T is derived from U, which essentially provides an
|
||||
/// implicit upcast. For example, @c CanQual<LValueReferenceType> can be
|
||||
/// converted to @c CanQual<ReferenceType>. Note that any @c CanQual type can
|
||||
/// be implicitly converted to a QualType, but the reverse operation requires
|
||||
/// a call to ASTContext::getCanonicalType().
|
||||
///
|
||||
///
|
||||
template<typename T = Type>
|
||||
class CanQual {
|
||||
/// \brief The actual, canonical type.
|
||||
QualType Stored;
|
||||
|
||||
public:
|
||||
/// \brief Constructs a NULL canonical type.
|
||||
CanQual() : Stored() { }
|
||||
|
||||
/// \brief Converting constructor that permits implicit upcasting of
|
||||
/// canonical type pointers.
|
||||
template<typename U>
|
||||
CanQual(const CanQual<U>& Other,
|
||||
typename llvm::enable_if<llvm::is_base_of<T, U>, int>::type = 0);
|
||||
|
||||
/// \brief Implicit conversion to the underlying pointer.
|
||||
///
|
||||
/// Also provides the ability to use canonical types in a boolean context,
|
||||
/// e.g.,
|
||||
/// @code
|
||||
/// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { ... }
|
||||
/// @endcode
|
||||
operator const T*() const { return getTypePtr(); }
|
||||
|
||||
/// \brief Retrieve the underlying type pointer, which refers to a
|
||||
/// canonical type.
|
||||
T *getTypePtr() const { return cast_or_null<T>(Stored.getTypePtr()); }
|
||||
|
||||
/// \brief Implicit conversion to a qualified type.
|
||||
operator QualType() const { return Stored; }
|
||||
|
||||
/// \brief Retrieve a canonical type pointer with a different static type,
|
||||
/// upcasting or downcasting as needed.
|
||||
///
|
||||
/// The getAs() function is typically used to try to downcast to a
|
||||
/// more specific (canonical) type in the type system. For example:
|
||||
///
|
||||
/// @code
|
||||
/// void f(CanQual<Type> T) {
|
||||
/// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) {
|
||||
/// // look at Ptr's pointee type
|
||||
/// }
|
||||
/// }
|
||||
/// @endcode
|
||||
///
|
||||
/// \returns A proxy pointer to the same type, but with the specified
|
||||
/// static type (@p U). If the dynamic type is not the specified static type
|
||||
/// or a derived class thereof, a NULL canonical type.
|
||||
template<typename U> CanProxy<U> getAs() const;
|
||||
|
||||
/// \brief Overloaded arrow operator that produces a canonical type
|
||||
/// proxy.
|
||||
CanProxy<T> operator->() const;
|
||||
|
||||
/// \brief Retrieve all qualifiers.
|
||||
Qualifiers getQualifiers() const { return Stored.getQualifiers(); }
|
||||
|
||||
/// \brief Retrieve the const/volatile/restrict qualifiers.
|
||||
unsigned getCVRQualifiers() const { return Stored.getCVRQualifiers(); }
|
||||
|
||||
/// \brief Determines whether this type has any qualifiers
|
||||
bool hasQualifiers() const { return Stored.hasQualifiers(); }
|
||||
|
||||
bool isConstQualified() const {
|
||||
return Stored.isConstQualified();
|
||||
}
|
||||
bool isVolatileQualified() const {
|
||||
return Stored.isVolatileQualified();
|
||||
}
|
||||
bool isRestrictQualified() const {
|
||||
return Stored.isRestrictQualified();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the unqualified form of this type.
|
||||
CanQual<T> getUnqualifiedType() const;
|
||||
|
||||
CanQual<T> getQualifiedType(unsigned TQs) const {
|
||||
return CanQual<T>::CreateUnsafe(QualType(getTypePtr(), TQs));
|
||||
}
|
||||
|
||||
/// \brief Determines whether this canonical type is more qualified than
|
||||
/// the @p Other canonical type.
|
||||
bool isMoreQualifiedThan(CanQual<T> Other) const {
|
||||
return Stored.isMoreQualifiedThan(Other.Stored);
|
||||
}
|
||||
|
||||
/// \brief Determines whether this canonical type is at least as qualified as
|
||||
/// the @p Other canonical type.
|
||||
bool isAtLeastAsQualifiedAs(CanQual<T> Other) const {
|
||||
return Stored.isAtLeastAsQualifiedAs(Other.Stored);
|
||||
}
|
||||
|
||||
/// \brief If the canonical type is a reference type, returns the type that
|
||||
/// it refers to; otherwise, returns the type itself.
|
||||
CanQual<Type> getNonReferenceType() const;
|
||||
|
||||
/// \brief Retrieve the internal representation of this canonical type.
|
||||
void *getAsOpaquePtr() const { return Stored.getAsOpaquePtr(); }
|
||||
|
||||
/// \brief Construct a canonical type from its internal representation.
|
||||
static CanQual<T> getFromOpaquePtr(void *Ptr);
|
||||
|
||||
/// \brief Builds a canonical type from a QualType.
|
||||
///
|
||||
/// This routine is inherently unsafe, because it requires the user to
|
||||
/// ensure that the given type is a canonical type with the correct
|
||||
// (dynamic) type.
|
||||
static CanQual<T> CreateUnsafe(QualType Other);
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
inline bool operator==(CanQual<T> x, CanQual<U> y) {
|
||||
return x.getAsOpaquePtr() == y.getAsOpaquePtr();
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
inline bool operator!=(CanQual<T> x, CanQual<U> y) {
|
||||
return x.getAsOpaquePtr() != y.getAsOpaquePtr();
|
||||
}
|
||||
|
||||
/// \brief Represents a canonical, potentially-qualified type.
|
||||
typedef CanQual<Type> CanQualType;
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Internal proxy classes used by canonical types
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#define LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(Accessor) \
|
||||
CanQualType Accessor() const { \
|
||||
return CanQualType::CreateUnsafe(this->getTypePtr()->Accessor()); \
|
||||
}
|
||||
|
||||
#define LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Type, Accessor) \
|
||||
Type Accessor() const { return this->getTypePtr()->Accessor(); }
|
||||
|
||||
/// \brief Base class of all canonical proxy types, which is responsible for
|
||||
/// storing the underlying canonical type and providing basic conversions.
|
||||
template<typename T>
|
||||
class CanProxyBase {
|
||||
protected:
|
||||
CanQual<T> Stored;
|
||||
|
||||
public:
|
||||
/// \brief Retrieve the pointer to the underlying Type
|
||||
T* getTypePtr() const { return Stored.getTypePtr(); }
|
||||
|
||||
/// \brief Implicit conversion to the underlying pointer.
|
||||
///
|
||||
/// Also provides the ability to use canonical type proxies in a Boolean
|
||||
// context,e.g.,
|
||||
/// @code
|
||||
/// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { ... }
|
||||
/// @endcode
|
||||
operator const T*() const { return this->Stored.getTypePtr(); }
|
||||
|
||||
/// \brief Try to convert the given canonical type to a specific structural
|
||||
/// type.
|
||||
template<typename U> CanProxy<U> getAs() const {
|
||||
return this->Stored.template getAs<U>();
|
||||
}
|
||||
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Type::TypeClass, getTypeClass)
|
||||
|
||||
// Type predicates
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjectType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteOrObjectType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPODType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariablyModifiedType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegerType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isEnumeralType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBooleanType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isCharType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isWideCharType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegralType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isRealFloatingType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAnyComplexType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isFloatingType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isRealType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isArithmeticType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVoidType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDerivedType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isScalarType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAggregateType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAnyPointerType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVoidPointerType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isFunctionPointerType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isMemberFunctionPointerType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isClassType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnionType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexIntegerType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isNullPtrType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDependentType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isOverloadableType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasPointerRepresentation)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasObjCPointerRepresentation)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPromotableIntegerType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSignedIntegerType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnsignedIntegerType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isConstantSizeType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSpecifierType)
|
||||
|
||||
/// \brief Retrieve the proxy-adaptor type.
|
||||
///
|
||||
/// This arrow operator is used when CanProxyAdaptor has been specialized
|
||||
/// for the given type T. In that case, we reference members of the
|
||||
/// CanProxyAdaptor specialization. Otherwise, this operator will be hidden
|
||||
/// by the arrow operator in the primary CanProxyAdaptor template.
|
||||
const CanProxyAdaptor<T> *operator->() const {
|
||||
return static_cast<const CanProxyAdaptor<T> *>(this);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Replacable canonical proxy adaptor class that provides the link
|
||||
/// between a canonical type and the accessors of the type.
|
||||
///
|
||||
/// The CanProxyAdaptor is a replaceable class template that is instantiated
|
||||
/// as part of each canonical proxy type. The primary template merely provides
|
||||
/// redirection to the underlying type (T), e.g., @c PointerType. One can
|
||||
/// provide specializations of this class template for each underlying type
|
||||
/// that provide accessors returning canonical types (@c CanQualType) rather
|
||||
/// than the more typical @c QualType, to propagate the notion of "canonical"
|
||||
/// through the system.
|
||||
template<typename T>
|
||||
struct CanProxyAdaptor : CanProxyBase<T> { };
|
||||
|
||||
/// \brief Canonical proxy type returned when retrieving the members of a
|
||||
/// canonical type or as the result of the @c CanQual<T>::getAs member
|
||||
/// function.
|
||||
///
|
||||
/// The CanProxy type mainly exists as a proxy through which operator-> will
|
||||
/// look to either map down to a raw T* (e.g., PointerType*) or to a proxy
|
||||
/// type that provides canonical-type access to the fields of the type.
|
||||
template<typename T>
|
||||
class CanProxy : public CanProxyAdaptor<T> {
|
||||
public:
|
||||
/// \brief Build a NULL proxy.
|
||||
CanProxy() { }
|
||||
|
||||
/// \brief Build a proxy to the given canonical type.
|
||||
CanProxy(CanQual<T> Stored) { this->Stored = Stored; }
|
||||
|
||||
/// \brief Implicit conversion to the stored canonical type.
|
||||
operator CanQual<T>() const { return this->Stored; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Implement simplify_type for CanQual<T>, so that we can dyn_cast from
|
||||
/// CanQual<T> to a specific Type class. We're prefer isa/dyn_cast/cast/etc.
|
||||
/// to return smart pointer (proxies?).
|
||||
template<typename T>
|
||||
struct simplify_type<const ::clang::CanQual<T> > {
|
||||
typedef T* SimpleType;
|
||||
static SimpleType getSimplifiedValue(const ::clang::CanQual<T> &Val) {
|
||||
return Val.getTypePtr();
|
||||
}
|
||||
};
|
||||
template<typename T>
|
||||
struct simplify_type< ::clang::CanQual<T> >
|
||||
: public simplify_type<const ::clang::CanQual<T> > {};
|
||||
|
||||
// Teach SmallPtrSet that CanQual<T> is "basically a pointer".
|
||||
template<typename T>
|
||||
class PointerLikeTypeTraits<clang::CanQual<T> > {
|
||||
public:
|
||||
static inline void *getAsVoidPointer(clang::CanQual<T> P) {
|
||||
return P.getAsOpaquePtr();
|
||||
}
|
||||
static inline clang::CanQual<T> getFromVoidPointer(void *P) {
|
||||
return clang::CanQual<T>::getFromOpaquePtr(P);
|
||||
}
|
||||
// qualifier information is encoded in the low bits.
|
||||
enum { NumLowBitsAvailable = 0 };
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
namespace clang {
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Canonical proxy adaptors for canonical type nodes.
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
/// \brief Iterator adaptor that turns an iterator over canonical QualTypes
|
||||
/// into an iterator over CanQualTypes.
|
||||
template<typename InputIterator>
|
||||
class CanTypeIterator {
|
||||
InputIterator Iter;
|
||||
|
||||
public:
|
||||
typedef CanQualType value_type;
|
||||
typedef value_type reference;
|
||||
typedef CanProxy<Type> pointer;
|
||||
typedef typename std::iterator_traits<InputIterator>::difference_type
|
||||
difference_type;
|
||||
typedef typename std::iterator_traits<InputIterator>::iterator_category
|
||||
iterator_category;
|
||||
|
||||
CanTypeIterator() : Iter() { }
|
||||
explicit CanTypeIterator(InputIterator Iter) : Iter(Iter) { }
|
||||
|
||||
// Input iterator
|
||||
reference operator*() const {
|
||||
return CanQualType::CreateUnsafe(*Iter);
|
||||
}
|
||||
|
||||
pointer operator->() const;
|
||||
|
||||
CanTypeIterator &operator++() {
|
||||
++Iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CanTypeIterator operator++(int) {
|
||||
CanTypeIterator Tmp(*this);
|
||||
++Iter;
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
friend bool operator==(const CanTypeIterator& X, const CanTypeIterator &Y) {
|
||||
return X.Iter == Y.Iter;
|
||||
}
|
||||
friend bool operator!=(const CanTypeIterator& X, const CanTypeIterator &Y) {
|
||||
return X.Iter != Y.Iter;
|
||||
}
|
||||
|
||||
// Bidirectional iterator
|
||||
CanTypeIterator &operator--() {
|
||||
--Iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CanTypeIterator operator--(int) {
|
||||
CanTypeIterator Tmp(*this);
|
||||
--Iter;
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
// Random access iterator
|
||||
reference operator[](difference_type n) const {
|
||||
return CanQualType::CreateUnsafe(Iter[n]);
|
||||
}
|
||||
|
||||
CanTypeIterator &operator+=(difference_type n) {
|
||||
Iter += n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CanTypeIterator &operator-=(difference_type n) {
|
||||
Iter -= n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend CanTypeIterator operator+(CanTypeIterator X, difference_type n) {
|
||||
X += n;
|
||||
return X;
|
||||
}
|
||||
|
||||
friend CanTypeIterator operator+(difference_type n, CanTypeIterator X) {
|
||||
X += n;
|
||||
return X;
|
||||
}
|
||||
|
||||
friend CanTypeIterator operator-(CanTypeIterator X, difference_type n) {
|
||||
X -= n;
|
||||
return X;
|
||||
}
|
||||
|
||||
friend difference_type operator-(const CanTypeIterator &X,
|
||||
const CanTypeIterator &Y) {
|
||||
return X - Y;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<ComplexType> : public CanProxyBase<ComplexType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<PointerType> : public CanProxyBase<PointerType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<BlockPointerType>
|
||||
: public CanProxyBase<BlockPointerType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<ReferenceType> : public CanProxyBase<ReferenceType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<LValueReferenceType>
|
||||
: public CanProxyBase<LValueReferenceType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<RValueReferenceType>
|
||||
: public CanProxyBase<RValueReferenceType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<MemberPointerType>
|
||||
: public CanProxyBase<MemberPointerType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Type *, getClass)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<ArrayType> : public CanProxyBase<ArrayType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
|
||||
getSizeModifier)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<ConstantArrayType>
|
||||
: public CanProxyBase<ConstantArrayType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
|
||||
getSizeModifier)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const llvm::APInt &, getSize)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<ConstantArrayWithExprType>
|
||||
: public CanProxyBase<ConstantArrayWithExprType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
|
||||
getSizeModifier)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const llvm::APInt &, getSize)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<ConstantArrayWithoutExprType>
|
||||
: public CanProxyBase<ConstantArrayWithoutExprType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
|
||||
getSizeModifier)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const llvm::APInt &, getSize)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<IncompleteArrayType>
|
||||
: public CanProxyBase<IncompleteArrayType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
|
||||
getSizeModifier)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<VariableArrayType>
|
||||
: public CanProxyBase<VariableArrayType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
|
||||
getSizeModifier)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<DependentSizedArrayType>
|
||||
: public CanProxyBase<DependentSizedArrayType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<DependentSizedExtVectorType>
|
||||
: public CanProxyBase<DependentSizedExtVectorType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Expr *, getSizeExpr)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getAttributeLoc)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<VectorType> : public CanProxyBase<VectorType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumElements)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<ExtVectorType> : public CanProxyBase<ExtVectorType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumElements)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<FunctionType> : public CanProxyBase<FunctionType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<FunctionNoProtoType>
|
||||
: public CanProxyBase<FunctionNoProtoType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<FunctionProtoType>
|
||||
: public CanProxyBase<FunctionProtoType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumArgs);
|
||||
CanQualType getArgType(unsigned i) const {
|
||||
return CanQualType::CreateUnsafe(this->getTypePtr()->getArgType(i));
|
||||
}
|
||||
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariadic)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getTypeQuals)
|
||||
|
||||
typedef CanTypeIterator<FunctionProtoType::arg_type_iterator>
|
||||
arg_type_iterator;
|
||||
|
||||
arg_type_iterator arg_type_begin() const {
|
||||
return arg_type_iterator(this->getTypePtr()->arg_type_begin());
|
||||
}
|
||||
|
||||
arg_type_iterator arg_type_end() const {
|
||||
return arg_type_iterator(this->getTypePtr()->arg_type_end());
|
||||
}
|
||||
|
||||
// Note: canonical function types never have exception specifications
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<TypeOfType> : public CanProxyBase<TypeOfType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<DecltypeType> : public CanProxyBase<DecltypeType> {
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getUnderlyingExpr)
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<TagType> : public CanProxyBase<TagType> {
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getDecl)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<RecordType> : public CanProxyBase<RecordType> {
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(RecordDecl *, getDecl)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasConstFields)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getAddressSpace)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<EnumType> : public CanProxyBase<EnumType> {
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(EnumDecl *, getDecl)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<TemplateTypeParmType>
|
||||
: public CanProxyBase<TemplateTypeParmType> {
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getDepth)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndex)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isParameterPack)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(IdentifierInfo *, getName)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<ObjCObjectPointerType>
|
||||
: public CanProxyBase<ObjCObjectPointerType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const ObjCInterfaceType *,
|
||||
getInterfaceType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCIdType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCClassType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedIdType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedClassType)
|
||||
|
||||
typedef ObjCObjectPointerType::qual_iterator qual_iterator;
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_begin)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_end)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, qual_empty)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumProtocols)
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Method and function definitions
|
||||
//----------------------------------------------------------------------------//
|
||||
template<typename T>
|
||||
inline CanQual<T> CanQual<T>::getUnqualifiedType() const {
|
||||
return CanQual<T>::CreateUnsafe(Stored.getUnqualifiedType());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline CanQual<Type> CanQual<T>::getNonReferenceType() const {
|
||||
if (CanQual<ReferenceType> RefType = getAs<ReferenceType>())
|
||||
return RefType->getPointeeType();
|
||||
else
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CanQual<T> CanQual<T>::getFromOpaquePtr(void *Ptr) {
|
||||
CanQual<T> Result;
|
||||
Result.Stored.setFromOpaqueValue(Ptr);
|
||||
assert((!Result || Result.Stored.isCanonical())
|
||||
&& "Type is not canonical!");
|
||||
return Result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CanQual<T> CanQual<T>::CreateUnsafe(QualType Other) {
|
||||
assert((Other.isNull() || Other->isCanonical()) && "Type is not canonical!");
|
||||
assert((Other.isNull() || isa<T>(Other.getTypePtr())) &&
|
||||
"Dynamic type does not meet the static type's requires");
|
||||
CanQual<T> Result;
|
||||
Result.Stored = Other;
|
||||
return Result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
CanProxy<U> CanQual<T>::getAs() const {
|
||||
if (Stored.isNull())
|
||||
return CanProxy<U>();
|
||||
|
||||
if (isa<U>(Stored.getTypePtr()))
|
||||
return CanQual<U>::CreateUnsafe(Stored);
|
||||
|
||||
return CanProxy<U>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CanProxy<T> CanQual<T>::operator->() const {
|
||||
return CanProxy<T>(*this);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
typename CanTypeIterator<InputIterator>::pointer
|
||||
CanTypeIterator<InputIterator>::operator->() const {
|
||||
return CanProxy<Type>(*this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // LLVM_CLANG_AST_CANONICAL_TYPE_H
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -37,6 +37,7 @@ class ObjCCategoryDecl;
|
|||
class ObjCProtocolDecl;
|
||||
class ObjCImplementationDecl;
|
||||
class ObjCCategoryImplDecl;
|
||||
class ObjCImplDecl;
|
||||
class LinkageSpecDecl;
|
||||
class BlockDecl;
|
||||
class DeclarationName;
|
||||
|
|
@ -59,8 +60,8 @@ public:
|
|||
|
||||
namespace clang {
|
||||
|
||||
/// Decl - This represents one declaration (or definition), e.g. a variable,
|
||||
/// typedef, function, struct, etc.
|
||||
/// Decl - This represents one declaration (or definition), e.g. a variable,
|
||||
/// typedef, function, struct, etc.
|
||||
///
|
||||
class Decl {
|
||||
public:
|
||||
|
|
@ -68,7 +69,7 @@ public:
|
|||
enum Kind {
|
||||
#define DECL(Derived, Base) Derived,
|
||||
#define DECL_RANGE(CommonBase, Start, End) \
|
||||
CommonBase##First = Start, CommonBase##Last = End,
|
||||
CommonBase##First = Start, CommonBase##Last = End,
|
||||
#define LAST_DECL_RANGE(CommonBase, Start, End) \
|
||||
CommonBase##First = Start, CommonBase##Last = End
|
||||
#include "clang/AST/DeclNodes.def"
|
||||
|
|
@ -78,7 +79,9 @@ public:
|
|||
/// namespaces, labels, tags, members and ordinary
|
||||
/// identifiers. These are meant as bitmasks, so that searches in
|
||||
/// C++ can look into the "tag" namespace during ordinary lookup. We
|
||||
/// use additional namespaces for Objective-C entities.
|
||||
/// use additional namespaces for Objective-C entities. We also
|
||||
/// put C++ friend declarations (of previously-undeclared entities) in
|
||||
/// shadow namespaces.
|
||||
enum IdentifierNamespace {
|
||||
IDNS_Label = 0x1,
|
||||
IDNS_Tag = 0x2,
|
||||
|
|
@ -86,9 +89,11 @@ public:
|
|||
IDNS_Ordinary = 0x8,
|
||||
IDNS_ObjCProtocol = 0x10,
|
||||
IDNS_ObjCImplementation = 0x20,
|
||||
IDNS_ObjCCategoryImpl = 0x40
|
||||
IDNS_ObjCCategoryImpl = 0x40,
|
||||
IDNS_OrdinaryFriend = 0x80,
|
||||
IDNS_TagFriend = 0x100
|
||||
};
|
||||
|
||||
|
||||
/// ObjCDeclQualifier - Qualifier used on types in method declarations
|
||||
/// for remote messaging. They are meant for the arguments though and
|
||||
/// applied to the Decls (ObjCMethodDecl and ParmVarDecl).
|
||||
|
|
@ -101,7 +106,7 @@ public:
|
|||
OBJC_TQ_Byref = 0x10,
|
||||
OBJC_TQ_Oneway = 0x20
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
/// NextDeclInContext - The next declaration within the same lexical
|
||||
/// DeclContext. These pointers form the linked list that is
|
||||
|
|
@ -114,8 +119,8 @@ private:
|
|||
DeclContext *SemanticDC;
|
||||
DeclContext *LexicalDC;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/// DeclCtx - Holds either a DeclContext* or a MultipleDC*.
|
||||
/// For declarations that don't contain C++ scope specifiers, it contains
|
||||
/// the DeclContext where the Decl was declared.
|
||||
|
|
@ -139,16 +144,16 @@ private:
|
|||
inline DeclContext *getSemanticDC() const {
|
||||
return DeclCtx.get<DeclContext*>();
|
||||
}
|
||||
|
||||
|
||||
/// Loc - The location that this decl.
|
||||
SourceLocation Loc;
|
||||
|
||||
|
||||
/// DeclKind - This indicates which class this is.
|
||||
Kind DeclKind : 8;
|
||||
|
||||
|
||||
/// InvalidDecl - This indicates a semantic error occurred.
|
||||
unsigned int InvalidDecl : 1;
|
||||
|
||||
|
||||
/// HasAttrs - This indicates whether the decl has attributes or not.
|
||||
unsigned int HasAttrs : 1;
|
||||
|
||||
|
|
@ -162,23 +167,23 @@ private:
|
|||
|
||||
protected:
|
||||
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
|
||||
unsigned IdentifierNamespace : 8;
|
||||
|
||||
unsigned IdentifierNamespace : 16;
|
||||
|
||||
private:
|
||||
#ifndef NDEBUG
|
||||
void CheckAccessDeclContext() const;
|
||||
#else
|
||||
void CheckAccessDeclContext() const { }
|
||||
#endif
|
||||
|
||||
|
||||
protected:
|
||||
/// Access - Used by C++ decls for the access specifier.
|
||||
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
|
||||
unsigned Access : 2;
|
||||
friend class CXXClassMemberWrapper;
|
||||
|
||||
Decl(Kind DK, DeclContext *DC, SourceLocation L)
|
||||
: NextDeclInContext(0), DeclCtx(DC),
|
||||
Decl(Kind DK, DeclContext *DC, SourceLocation L)
|
||||
: NextDeclInContext(0), DeclCtx(DC),
|
||||
Loc(L), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false), Used(false),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)), Access(AS_none) {
|
||||
|
|
@ -201,7 +206,7 @@ public:
|
|||
|
||||
Kind getKind() const { return DeclKind; }
|
||||
const char *getDeclKindName() const;
|
||||
|
||||
|
||||
Decl *getNextDeclInContext() { return NextDeclInContext; }
|
||||
const Decl *getNextDeclInContext() const { return NextDeclInContext; }
|
||||
|
||||
|
|
@ -219,16 +224,18 @@ public:
|
|||
return const_cast<Decl*>(this)->getTranslationUnitDecl();
|
||||
}
|
||||
|
||||
bool isInAnonymousNamespace() const;
|
||||
|
||||
ASTContext &getASTContext() const;
|
||||
|
||||
|
||||
void setAccess(AccessSpecifier AS) {
|
||||
Access = AS;
|
||||
Access = AS;
|
||||
CheckAccessDeclContext();
|
||||
}
|
||||
|
||||
AccessSpecifier getAccess() const {
|
||||
|
||||
AccessSpecifier getAccess() const {
|
||||
CheckAccessDeclContext();
|
||||
return AccessSpecifier(Access);
|
||||
return AccessSpecifier(Access);
|
||||
}
|
||||
|
||||
bool hasAttrs() const { return HasAttrs; }
|
||||
|
|
@ -246,11 +253,11 @@ public:
|
|||
return V;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
template<typename T> bool hasAttr() const {
|
||||
return getAttr<T>() != 0;
|
||||
}
|
||||
|
||||
|
||||
/// setInvalidDecl - Indicates the Decl had a semantic error. This
|
||||
/// allows for graceful error recovery.
|
||||
void setInvalidDecl(bool Invalid = true) { InvalidDecl = Invalid; }
|
||||
|
|
@ -261,12 +268,12 @@ public:
|
|||
/// was written explicitly in the source code.
|
||||
bool isImplicit() const { return Implicit; }
|
||||
void setImplicit(bool I = true) { Implicit = I; }
|
||||
|
||||
|
||||
/// \brief Whether this declaration was used, meaning that a definition
|
||||
/// is required.
|
||||
bool isUsed() const { return Used; }
|
||||
void setUsed(bool U = true) { Used = U; }
|
||||
|
||||
|
||||
unsigned getIdentifierNamespace() const {
|
||||
return IdentifierNamespace;
|
||||
}
|
||||
|
|
@ -275,7 +282,7 @@ public:
|
|||
}
|
||||
static unsigned getIdentifierNamespaceForKind(Kind DK);
|
||||
|
||||
|
||||
|
||||
/// getLexicalDeclContext - The declaration context where this Decl was
|
||||
/// lexically declared (LexicalDC). May be different from
|
||||
/// getDeclContext() (SemanticDC).
|
||||
|
|
@ -298,7 +305,7 @@ public:
|
|||
bool isOutOfLine() const {
|
||||
return getLexicalDeclContext() != getDeclContext();
|
||||
}
|
||||
|
||||
|
||||
/// setDeclContext - Set both the semantic and lexical DeclContext
|
||||
/// to DC.
|
||||
void setDeclContext(DeclContext *DC);
|
||||
|
|
@ -311,6 +318,72 @@ public:
|
|||
// be defined inside or outside a function etc).
|
||||
bool isDefinedOutsideFunctionOrMethod() const;
|
||||
|
||||
/// \brief Retrieves the "canonical" declaration of the given declaration.
|
||||
virtual Decl *getCanonicalDecl() { return this; }
|
||||
const Decl *getCanonicalDecl() const {
|
||||
return const_cast<Decl*>(this)->getCanonicalDecl();
|
||||
}
|
||||
|
||||
/// \brief Whether this particular Decl is a canonical one.
|
||||
bool isCanonicalDecl() const { return getCanonicalDecl() == this; }
|
||||
|
||||
protected:
|
||||
/// \brief Returns the next redeclaration or itself if this is the only decl.
|
||||
///
|
||||
/// Decl subclasses that can be redeclared should override this method so that
|
||||
/// Decl::redecl_iterator can iterate over them.
|
||||
virtual Decl *getNextRedeclaration() { return this; }
|
||||
|
||||
public:
|
||||
/// \brief Iterates through all the redeclarations of the same decl.
|
||||
class redecl_iterator {
|
||||
/// Current - The current declaration.
|
||||
Decl *Current;
|
||||
Decl *Starter;
|
||||
|
||||
public:
|
||||
typedef Decl* value_type;
|
||||
typedef Decl* reference;
|
||||
typedef Decl* pointer;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
redecl_iterator() : Current(0) { }
|
||||
explicit redecl_iterator(Decl *C) : Current(C), Starter(C) { }
|
||||
|
||||
reference operator*() const { return Current; }
|
||||
pointer operator->() const { return Current; }
|
||||
|
||||
redecl_iterator& operator++() {
|
||||
assert(Current && "Advancing while iterator has reached end");
|
||||
// Get either previous decl or latest decl.
|
||||
Decl *Next = Current->getNextRedeclaration();
|
||||
assert(Next && "Should return next redeclaration or itself, never null!");
|
||||
Current = (Next != Starter ? Next : 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
redecl_iterator operator++(int) {
|
||||
redecl_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool operator==(redecl_iterator x, redecl_iterator y) {
|
||||
return x.Current == y.Current;
|
||||
}
|
||||
friend bool operator!=(redecl_iterator x, redecl_iterator y) {
|
||||
return x.Current != y.Current;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Returns iterator for all the redeclarations of the same decl.
|
||||
/// It will iterate at least once (when this decl is the only one).
|
||||
redecl_iterator redecls_begin() const {
|
||||
return redecl_iterator(const_cast<Decl*>(this));
|
||||
}
|
||||
redecl_iterator redecls_end() const { return redecl_iterator(); }
|
||||
|
||||
/// getBody - If this Decl represents a declaration for a body of code,
|
||||
/// such as a function or method definition, this method returns the
|
||||
/// top-level Stmt* of that body. Otherwise this method returns null.
|
||||
|
|
@ -327,33 +400,71 @@ public:
|
|||
static void addDeclKind(Kind k);
|
||||
static bool CollectingStats(bool Enable = false);
|
||||
static void PrintStats();
|
||||
|
||||
|
||||
/// isTemplateParameter - Determines whether this declaration is a
|
||||
/// template parameter.
|
||||
bool isTemplateParameter() const;
|
||||
|
||||
|
||||
/// isTemplateParameter - Determines whether this declaration is a
|
||||
/// template parameter pack.
|
||||
bool isTemplateParameterPack() const;
|
||||
|
||||
/// \brief Whether this declaration is a function or function template.
|
||||
bool isFunctionOrFunctionTemplate() const;
|
||||
|
||||
|
||||
/// \brief Changes the namespace of this declaration to reflect that it's
|
||||
/// the object of a friend declaration.
|
||||
///
|
||||
/// These declarations appear in the lexical context of the friending
|
||||
/// class, but in the semantic context of the actual entity. This property
|
||||
/// applies only to a specific decl object; other redeclarations of the
|
||||
/// same entity may not (and probably don't) share this property.
|
||||
void setObjectOfFriendDecl(bool PreviouslyDeclared) {
|
||||
unsigned OldNS = IdentifierNamespace;
|
||||
assert((OldNS == IDNS_Tag || OldNS == IDNS_Ordinary ||
|
||||
OldNS == (IDNS_Tag | IDNS_Ordinary))
|
||||
&& "unsupported namespace for undeclared friend");
|
||||
if (!PreviouslyDeclared) IdentifierNamespace = 0;
|
||||
|
||||
if (OldNS == IDNS_Tag)
|
||||
IdentifierNamespace |= IDNS_TagFriend;
|
||||
else
|
||||
IdentifierNamespace |= IDNS_OrdinaryFriend;
|
||||
}
|
||||
|
||||
enum FriendObjectKind {
|
||||
FOK_None, // not a friend object
|
||||
FOK_Declared, // a friend of a previously-declared entity
|
||||
FOK_Undeclared // a friend of a previously-undeclared entity
|
||||
};
|
||||
|
||||
/// \brief Determines whether this declaration is the object of a
|
||||
/// friend declaration and, if so, what kind.
|
||||
///
|
||||
/// There is currently no direct way to find the associated FriendDecl.
|
||||
FriendObjectKind getFriendObjectKind() const {
|
||||
unsigned mask
|
||||
= (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend));
|
||||
if (!mask) return FOK_None;
|
||||
return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ?
|
||||
FOK_Declared : FOK_Undeclared);
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *) { return true; }
|
||||
static DeclContext *castToDeclContext(const Decl *);
|
||||
static Decl *castFromDeclContext(const DeclContext *);
|
||||
|
||||
|
||||
/// Destroy - Call destructors and release memory.
|
||||
virtual void Destroy(ASTContext& C);
|
||||
|
||||
void print(llvm::raw_ostream &Out, unsigned Indentation = 0);
|
||||
void print(llvm::raw_ostream &Out, unsigned Indentation = 0) const;
|
||||
void print(llvm::raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0);
|
||||
unsigned Indentation = 0) const;
|
||||
static void printGroup(Decl** Begin, unsigned NumDecls,
|
||||
llvm::raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0);
|
||||
void dump();
|
||||
void dump() const;
|
||||
|
||||
private:
|
||||
const Attr *getAttrsImpl() const;
|
||||
|
|
@ -371,10 +482,10 @@ public:
|
|||
PrettyStackTraceDecl(Decl *theDecl, SourceLocation L,
|
||||
SourceManager &sm, const char *Msg)
|
||||
: TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {}
|
||||
|
||||
|
||||
virtual void print(llvm::raw_ostream &OS) const;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
/// DeclContext - This is used only as base class of specific decl types that
|
||||
/// can act as declaration contexts. These decls are (only the top classes
|
||||
|
|
@ -386,8 +497,6 @@ public:
|
|||
/// TagDecl
|
||||
/// ObjCMethodDecl
|
||||
/// ObjCContainerDecl
|
||||
/// ObjCCategoryImplDecl
|
||||
/// ObjCImplementationDecl
|
||||
/// LinkageSpecDecl
|
||||
/// BlockDecl
|
||||
///
|
||||
|
|
@ -421,9 +530,9 @@ class DeclContext {
|
|||
mutable Decl *LastDecl;
|
||||
|
||||
protected:
|
||||
DeclContext(Decl::Kind K)
|
||||
DeclContext(Decl::Kind K)
|
||||
: DeclKind(K), ExternalLexicalStorage(false),
|
||||
ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0),
|
||||
ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0),
|
||||
LastDecl(0) { }
|
||||
|
||||
void DestroyDecls(ASTContext &C);
|
||||
|
|
@ -443,7 +552,7 @@ public:
|
|||
const DeclContext *getParent() const {
|
||||
return const_cast<DeclContext*>(this)->getParent();
|
||||
}
|
||||
|
||||
|
||||
/// getLexicalParent - Returns the containing lexical DeclContext. May be
|
||||
/// different from getParent, e.g.:
|
||||
///
|
||||
|
|
@ -458,8 +567,14 @@ public:
|
|||
}
|
||||
const DeclContext *getLexicalParent() const {
|
||||
return const_cast<DeclContext*>(this)->getLexicalParent();
|
||||
}
|
||||
}
|
||||
|
||||
DeclContext *getLookupParent();
|
||||
|
||||
const DeclContext *getLookupParent() const {
|
||||
return const_cast<DeclContext*>(this)->getLookupParent();
|
||||
}
|
||||
|
||||
ASTContext &getParentASTContext() const {
|
||||
return cast<Decl>(this)->getASTContext();
|
||||
}
|
||||
|
|
@ -499,10 +614,10 @@ public:
|
|||
/// context are semantically declared in the nearest enclosing
|
||||
/// non-transparent (opaque) context but are lexically declared in
|
||||
/// this context. For example, consider the enumerators of an
|
||||
/// enumeration type:
|
||||
/// enumeration type:
|
||||
/// @code
|
||||
/// enum E {
|
||||
/// Val1
|
||||
/// Val1
|
||||
/// };
|
||||
/// @endcode
|
||||
/// Here, E is a transparent context, so its enumerator (Val1) will
|
||||
|
|
@ -512,13 +627,16 @@ public:
|
|||
/// inline namespaces.
|
||||
bool isTransparentContext() const;
|
||||
|
||||
bool Encloses(DeclContext *DC) const {
|
||||
for (; DC; DC = DC->getParent())
|
||||
if (DC == this)
|
||||
return true;
|
||||
return false;
|
||||
/// \brief Determine whether this declaration context is equivalent
|
||||
/// to the declaration context DC.
|
||||
bool Equals(DeclContext *DC) {
|
||||
return this->getPrimaryContext() == DC->getPrimaryContext();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this declaration context encloses the
|
||||
/// declaration context DC.
|
||||
bool Encloses(DeclContext *DC);
|
||||
|
||||
/// getPrimaryContext - There may be many different
|
||||
/// declarations of the same entity (including forward declarations
|
||||
/// of classes, multiple definitions of namespaces, etc.), each with
|
||||
|
|
@ -535,7 +653,7 @@ public:
|
|||
const DeclContext *getLookupContext() const {
|
||||
return const_cast<DeclContext *>(this)->getLookupContext();
|
||||
}
|
||||
|
||||
|
||||
/// \brief Retrieve the nearest enclosing namespace context.
|
||||
DeclContext *getEnclosingNamespaceContext();
|
||||
const DeclContext *getEnclosingNamespaceContext() const {
|
||||
|
|
@ -591,16 +709,16 @@ public:
|
|||
return tmp;
|
||||
}
|
||||
|
||||
friend bool operator==(decl_iterator x, decl_iterator y) {
|
||||
friend bool operator==(decl_iterator x, decl_iterator y) {
|
||||
return x.Current == y.Current;
|
||||
}
|
||||
friend bool operator!=(decl_iterator x, decl_iterator y) {
|
||||
friend bool operator!=(decl_iterator x, decl_iterator y) {
|
||||
return x.Current != y.Current;
|
||||
}
|
||||
};
|
||||
|
||||
/// decls_begin/decls_end - Iterate over the declarations stored in
|
||||
/// this context.
|
||||
/// this context.
|
||||
decl_iterator decls_begin() const;
|
||||
decl_iterator decls_end() const;
|
||||
bool decls_empty() const;
|
||||
|
|
@ -616,7 +734,7 @@ public:
|
|||
/// will either be NULL or will point to a declaration of
|
||||
/// type SpecificDecl.
|
||||
DeclContext::decl_iterator Current;
|
||||
|
||||
|
||||
/// SkipToNextDecl - Advances the current position up to the next
|
||||
/// declaration of type SpecificDecl that also meets the criteria
|
||||
/// required by Acceptable.
|
||||
|
|
@ -661,13 +779,13 @@ public:
|
|||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
friend bool
|
||||
operator==(const specific_decl_iterator& x, const specific_decl_iterator& y) {
|
||||
return x.Current == y.Current;
|
||||
}
|
||||
|
||||
friend bool
|
||||
|
||||
friend bool
|
||||
operator!=(const specific_decl_iterator& x, const specific_decl_iterator& y) {
|
||||
return x.Current != y.Current;
|
||||
}
|
||||
|
|
@ -688,7 +806,7 @@ public:
|
|||
/// will either be NULL or will point to a declaration of
|
||||
/// type SpecificDecl.
|
||||
DeclContext::decl_iterator Current;
|
||||
|
||||
|
||||
/// SkipToNextDecl - Advances the current position up to the next
|
||||
/// declaration of type SpecificDecl that also meets the criteria
|
||||
/// required by Acceptable.
|
||||
|
|
@ -735,13 +853,13 @@ public:
|
|||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
friend bool
|
||||
operator==(const filtered_decl_iterator& x, const filtered_decl_iterator& y) {
|
||||
return x.Current == y.Current;
|
||||
}
|
||||
|
||||
friend bool
|
||||
|
||||
friend bool
|
||||
operator!=(const filtered_decl_iterator& x, const filtered_decl_iterator& y) {
|
||||
return x.Current != y.Current;
|
||||
}
|
||||
|
|
@ -761,6 +879,14 @@ public:
|
|||
/// semantic context via makeDeclVisibleInContext.
|
||||
void addDecl(Decl *D);
|
||||
|
||||
/// @brief Add the declaration D to this context without modifying
|
||||
/// any lookup tables.
|
||||
///
|
||||
/// This is useful for some operations in dependent contexts where
|
||||
/// the semantic context might not be dependent; this basically
|
||||
/// only happens with friends.
|
||||
void addHiddenDecl(Decl *D);
|
||||
|
||||
/// lookup_iterator - An iterator that provides access to the results
|
||||
/// of looking up a name within this context.
|
||||
typedef NamedDecl **lookup_iterator;
|
||||
|
|
@ -795,12 +921,16 @@ public:
|
|||
/// visible from this context, as determined by
|
||||
/// NamedDecl::declarationReplaces, the previous declaration will be
|
||||
/// replaced with D.
|
||||
void makeDeclVisibleInContext(NamedDecl *D);
|
||||
///
|
||||
/// @param Recoverable true if it's okay to not add this decl to
|
||||
/// the lookup tables because it can be easily recovered by walking
|
||||
/// the declaration chains.
|
||||
void makeDeclVisibleInContext(NamedDecl *D, bool Recoverable = true);
|
||||
|
||||
/// udir_iterator - Iterates through the using-directives stored
|
||||
/// within this context.
|
||||
typedef UsingDirectiveDecl * const * udir_iterator;
|
||||
|
||||
|
||||
typedef std::pair<udir_iterator, udir_iterator> udir_iterator_range;
|
||||
|
||||
udir_iterator_range getUsingDirectives() const;
|
||||
|
|
@ -824,8 +954,8 @@ public:
|
|||
|
||||
/// \brief State whether this DeclContext has external storage for
|
||||
/// declarations lexically in this context.
|
||||
void setHasExternalLexicalStorage(bool ES = true) {
|
||||
ExternalLexicalStorage = ES;
|
||||
void setHasExternalLexicalStorage(bool ES = true) {
|
||||
ExternalLexicalStorage = ES;
|
||||
}
|
||||
|
||||
/// \brief Whether this DeclContext has external storage containing
|
||||
|
|
@ -834,8 +964,8 @@ public:
|
|||
|
||||
/// \brief State whether this DeclContext has external storage for
|
||||
/// declarations visible in this context.
|
||||
void setHasExternalVisibleStorage(bool ES = true) {
|
||||
ExternalVisibleStorage = ES;
|
||||
void setHasExternalVisibleStorage(bool ES = true) {
|
||||
ExternalVisibleStorage = ES;
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -57,13 +57,13 @@ public:
|
|||
Data = reinterpret_cast<uintptr_t>(New) | (Data & 0x03);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
~StoredDeclsList() {
|
||||
// If this is a vector-form, free the vector.
|
||||
if (VectorTy *Vector = getAsVector())
|
||||
delete Vector;
|
||||
}
|
||||
|
||||
|
||||
StoredDeclsList &operator=(const StoredDeclsList &RHS) {
|
||||
if (VectorTy *Vector = getAsVector())
|
||||
delete Vector;
|
||||
|
|
@ -74,9 +74,9 @@ public:
|
|||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool isNull() const { return (Data & ~0x03) == 0; }
|
||||
|
||||
|
||||
NamedDecl *getAsDecl() const {
|
||||
if ((Data & 0x03) != DK_Decl)
|
||||
return 0;
|
||||
|
|
@ -135,27 +135,27 @@ public:
|
|||
DeclContext::lookup_result getLookupResult(ASTContext &Context) {
|
||||
if (isNull())
|
||||
return DeclContext::lookup_result(0, 0);
|
||||
|
||||
|
||||
if (hasDeclarationIDs())
|
||||
materializeDecls(Context);
|
||||
|
||||
// If we have a single NamedDecl, return it.
|
||||
if (getAsDecl()) {
|
||||
assert(!isNull() && "Empty list isn't allowed");
|
||||
|
||||
|
||||
// Data is a raw pointer to a NamedDecl*, return it.
|
||||
void *Ptr = &Data;
|
||||
return DeclContext::lookup_result((NamedDecl**)Ptr, (NamedDecl**)Ptr+1);
|
||||
}
|
||||
|
||||
|
||||
assert(getAsVector() && "Must have a vector at this point");
|
||||
VectorTy &Vector = *getAsVector();
|
||||
|
||||
|
||||
// Otherwise, we have a range result.
|
||||
return DeclContext::lookup_result((NamedDecl **)&Vector[0],
|
||||
return DeclContext::lookup_result((NamedDecl **)&Vector[0],
|
||||
(NamedDecl **)&Vector[0]+Vector.size());
|
||||
}
|
||||
|
||||
|
||||
/// HandleRedeclaration - If this is a redeclaration of an existing decl,
|
||||
/// replace the old one with D and return true. Otherwise return false.
|
||||
bool HandleRedeclaration(ASTContext &Context, NamedDecl *D) {
|
||||
|
|
@ -169,7 +169,7 @@ public:
|
|||
setOnlyValue(D);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Determine if this declaration is actually a redeclaration.
|
||||
VectorTy &Vec = *getAsVector();
|
||||
for (VectorTy::iterator OD = Vec.begin(), ODEnd = Vec.end();
|
||||
|
|
@ -183,10 +183,10 @@ public:
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// AddSubsequentDecl - This is called on the second and later decl when it is
|
||||
/// not a redeclaration to merge it into the appropriate place in our list.
|
||||
///
|
||||
///
|
||||
void AddSubsequentDecl(NamedDecl *D) {
|
||||
assert(!hasDeclarationIDs() && "Must materialize before adding decls");
|
||||
|
||||
|
|
@ -197,7 +197,7 @@ public:
|
|||
VT->push_back(reinterpret_cast<uintptr_t>(OldD));
|
||||
Data = reinterpret_cast<uintptr_t>(VT) | DK_Decl_Vector;
|
||||
}
|
||||
|
||||
|
||||
VectorTy &Vec = *getAsVector();
|
||||
if (isa<UsingDirectiveDecl>(D) ||
|
||||
D->getIdentifierNamespace() == Decl::IDNS_Tag)
|
||||
|
|
@ -217,4 +217,4 @@ typedef llvm::DenseMap<DeclarationName, StoredDeclsList> StoredDeclsMap;
|
|||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
class ASTContext;
|
||||
class Decl;
|
||||
class DeclGroup;
|
||||
|
|
@ -27,7 +27,7 @@ class DeclGroupIterator;
|
|||
class DeclGroup {
|
||||
// FIXME: Include a TypeSpecifier object.
|
||||
unsigned NumDecls;
|
||||
|
||||
|
||||
private:
|
||||
DeclGroup() : NumDecls(0) {}
|
||||
DeclGroup(unsigned numdecls, Decl** decls);
|
||||
|
|
@ -38,34 +38,34 @@ public:
|
|||
|
||||
unsigned size() const { return NumDecls; }
|
||||
|
||||
Decl*& operator[](unsigned i) {
|
||||
Decl*& operator[](unsigned i) {
|
||||
assert (i < NumDecls && "Out-of-bounds access.");
|
||||
return *((Decl**) (this+1));
|
||||
}
|
||||
|
||||
Decl* const& operator[](unsigned i) const {
|
||||
|
||||
Decl* const& operator[](unsigned i) const {
|
||||
assert (i < NumDecls && "Out-of-bounds access.");
|
||||
return *((Decl* const*) (this+1));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class DeclGroupRef {
|
||||
// Note this is not a PointerIntPair because we need the address of the
|
||||
// non-group case to be valid as a Decl** for iteration.
|
||||
enum Kind { SingleDeclKind=0x0, DeclGroupKind=0x1, Mask=0x1 };
|
||||
enum Kind { SingleDeclKind=0x0, DeclGroupKind=0x1, Mask=0x1 };
|
||||
Decl* D;
|
||||
|
||||
Kind getKind() const {
|
||||
return (Kind) (reinterpret_cast<uintptr_t>(D) & Mask);
|
||||
}
|
||||
|
||||
public:
|
||||
}
|
||||
|
||||
public:
|
||||
DeclGroupRef() : D(0) {}
|
||||
|
||||
|
||||
explicit DeclGroupRef(Decl* d) : D(d) {}
|
||||
explicit DeclGroupRef(DeclGroup* dg)
|
||||
: D((Decl*) (reinterpret_cast<uintptr_t>(dg) | DeclGroupKind)) {}
|
||||
|
||||
|
||||
static DeclGroupRef Create(ASTContext &C, Decl **Decls, unsigned NumDecls) {
|
||||
if (NumDecls == 0)
|
||||
return DeclGroupRef();
|
||||
|
|
@ -73,10 +73,10 @@ public:
|
|||
return DeclGroupRef(Decls[0]);
|
||||
return DeclGroupRef(DeclGroup::Create(C, Decls, NumDecls));
|
||||
}
|
||||
|
||||
|
||||
typedef Decl** iterator;
|
||||
typedef Decl* const * const_iterator;
|
||||
|
||||
|
||||
bool isNull() const { return D == 0; }
|
||||
bool isSingleDecl() const { return getKind() == SingleDeclKind; }
|
||||
bool isDeclGroup() const { return getKind() == DeclGroupKind; }
|
||||
|
|
@ -88,7 +88,7 @@ public:
|
|||
const Decl *getSingleDecl() const {
|
||||
return const_cast<DeclGroupRef*>(this)->getSingleDecl();
|
||||
}
|
||||
|
||||
|
||||
DeclGroup &getDeclGroup() {
|
||||
assert(isDeclGroup() && "Isn't a declgroup");
|
||||
return *((DeclGroup*)(reinterpret_cast<uintptr_t>(D) & ~Mask));
|
||||
|
|
@ -96,7 +96,7 @@ public:
|
|||
const DeclGroup &getDeclGroup() const {
|
||||
return const_cast<DeclGroupRef*>(this)->getDeclGroup();
|
||||
}
|
||||
|
||||
|
||||
iterator begin() {
|
||||
if (isSingleDecl())
|
||||
return D ? &D : 0;
|
||||
|
|
@ -109,13 +109,13 @@ public:
|
|||
DeclGroup &G = getDeclGroup();
|
||||
return &G[0] + G.size();
|
||||
}
|
||||
|
||||
|
||||
const_iterator begin() const {
|
||||
if (isSingleDecl())
|
||||
return D ? &D : 0;
|
||||
return &getDeclGroup()[0];
|
||||
}
|
||||
|
||||
|
||||
const_iterator end() const {
|
||||
if (isSingleDecl())
|
||||
return D ? &D+1 : 0;
|
||||
|
|
@ -130,7 +130,7 @@ public:
|
|||
return X;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
namespace llvm {
|
||||
|
|
|
|||
|
|
@ -91,39 +91,43 @@ ABSTRACT_DECL(Named, Decl)
|
|||
DECL(TemplateTypeParm, TypeDecl)
|
||||
ABSTRACT_DECL(Value, NamedDecl)
|
||||
DECL(EnumConstant, ValueDecl)
|
||||
DECL(Function, ValueDecl)
|
||||
DECL(CXXMethod, FunctionDecl)
|
||||
DECL(CXXConstructor, CXXMethodDecl)
|
||||
DECL(CXXDestructor, CXXMethodDecl)
|
||||
DECL(CXXConversion, CXXMethodDecl)
|
||||
DECL(Field, ValueDecl)
|
||||
DECL(ObjCIvar, FieldDecl)
|
||||
DECL(ObjCAtDefsField, FieldDecl)
|
||||
DECL(Var, ValueDecl)
|
||||
DECL(ImplicitParam, VarDecl)
|
||||
DECL(ParmVar, VarDecl)
|
||||
DECL(OriginalParmVar, ParmVarDecl)
|
||||
DECL(NonTypeTemplateParm, VarDecl)
|
||||
ABSTRACT_DECL(Declarator, ValueDecl)
|
||||
DECL(Function, DeclaratorDecl)
|
||||
DECL(CXXMethod, FunctionDecl)
|
||||
DECL(CXXConstructor, CXXMethodDecl)
|
||||
DECL(CXXDestructor, CXXMethodDecl)
|
||||
DECL(CXXConversion, CXXMethodDecl)
|
||||
DECL(Field, DeclaratorDecl)
|
||||
DECL(ObjCIvar, FieldDecl)
|
||||
DECL(ObjCAtDefsField, FieldDecl)
|
||||
DECL(Var, DeclaratorDecl)
|
||||
DECL(ImplicitParam, VarDecl)
|
||||
DECL(ParmVar, VarDecl)
|
||||
DECL(OriginalParmVar, ParmVarDecl)
|
||||
DECL(NonTypeTemplateParm, VarDecl)
|
||||
DECL(Template, NamedDecl)
|
||||
DECL(FunctionTemplate, TemplateDecl)
|
||||
DECL(ClassTemplate, TemplateDecl)
|
||||
DECL(TemplateTemplateParm, TemplateDecl)
|
||||
DECL(Using, NamedDecl)
|
||||
DECL(UnresolvedUsing, NamedDecl)
|
||||
DECL(ObjCMethod, NamedDecl)
|
||||
DECL(ObjCContainer, NamedDecl)
|
||||
DECL(ObjCCategory, ObjCContainerDecl)
|
||||
DECL(ObjCProtocol, ObjCContainerDecl)
|
||||
DECL(ObjCInterface, ObjCContainerDecl)
|
||||
ABSTRACT_DECL(ObjCImpl, ObjCContainerDecl)
|
||||
DECL(ObjCCategoryImpl, ObjCImplDecl)
|
||||
DECL(ObjCImplementation, ObjCImplDecl)
|
||||
DECL(ObjCProperty, NamedDecl)
|
||||
DECL(ObjCCompatibleAlias, NamedDecl)
|
||||
ABSTRACT_DECL(ObjCImpl, NamedDecl)
|
||||
DECL(ObjCCategoryImpl, ObjCImplDecl)
|
||||
DECL(ObjCImplementation, ObjCImplDecl)
|
||||
DECL(LinkageSpec, Decl)
|
||||
DECL(ObjCPropertyImpl, Decl)
|
||||
DECL(ObjCForwardProtocol, Decl)
|
||||
DECL(ObjCClass, Decl)
|
||||
DECL(FileScopeAsm, Decl)
|
||||
DECL(Friend, Decl)
|
||||
DECL(FriendTemplate, Decl)
|
||||
DECL(StaticAssert, Decl)
|
||||
LAST_DECL(Block, Decl)
|
||||
|
||||
|
|
@ -132,21 +136,20 @@ DECL_CONTEXT(TranslationUnit)
|
|||
DECL_CONTEXT(Namespace)
|
||||
DECL_CONTEXT(LinkageSpec)
|
||||
DECL_CONTEXT(ObjCMethod)
|
||||
DECL_CONTEXT(ObjCCategoryImpl)
|
||||
DECL_CONTEXT(ObjCImplementation)
|
||||
DECL_CONTEXT_BASE(Tag)
|
||||
DECL_CONTEXT_BASE(Function)
|
||||
DECL_CONTEXT_BASE(ObjCContainer)
|
||||
LAST_DECL_CONTEXT(Block)
|
||||
|
||||
// Declaration ranges
|
||||
DECL_RANGE(Named, OverloadedFunction, ObjCImplementation)
|
||||
DECL_RANGE(ObjCContainer, ObjCContainer, ObjCInterface)
|
||||
DECL_RANGE(Named, OverloadedFunction, ObjCCompatibleAlias)
|
||||
DECL_RANGE(ObjCContainer, ObjCContainer, ObjCImplementation)
|
||||
DECL_RANGE(Field, Field, ObjCAtDefsField)
|
||||
DECL_RANGE(Type, Typedef, TemplateTypeParm)
|
||||
DECL_RANGE(Tag, Enum, ClassTemplatePartialSpecialization)
|
||||
DECL_RANGE(Record, Record, ClassTemplatePartialSpecialization)
|
||||
DECL_RANGE(Value, EnumConstant, NonTypeTemplateParm)
|
||||
DECL_RANGE(Declarator, Function, NonTypeTemplateParm)
|
||||
DECL_RANGE(Function, Function, CXXConversion)
|
||||
DECL_RANGE(Template, Template, TemplateTemplateParm)
|
||||
DECL_RANGE(ObjCImpl, ObjCCategoryImpl, ObjCImplementation)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/CanonicalType.h"
|
||||
#include "clang/Basic/PartialDiagnostic.h"
|
||||
|
||||
namespace llvm {
|
||||
template <typename T> struct DenseMapInfo;
|
||||
|
|
@ -100,7 +102,7 @@ private:
|
|||
/// CXXSpecialName, returns a pointer to it. Otherwise, returns
|
||||
/// a NULL pointer.
|
||||
CXXSpecialName *getAsCXXSpecialName() const {
|
||||
if (getNameKind() >= CXXConstructorName &&
|
||||
if (getNameKind() >= CXXConstructorName &&
|
||||
getNameKind() <= CXXConversionFunctionName)
|
||||
return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask);
|
||||
return 0;
|
||||
|
|
@ -115,16 +117,16 @@ private:
|
|||
|
||||
// Construct a declaration name from the name of a C++ constructor,
|
||||
// destructor, or conversion function.
|
||||
DeclarationName(CXXSpecialName *Name)
|
||||
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
|
||||
DeclarationName(CXXSpecialName *Name)
|
||||
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
|
||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXSpecialName");
|
||||
Ptr |= StoredDeclarationNameExtra;
|
||||
}
|
||||
|
||||
// Construct a declaration name from the name of a C++ overloaded
|
||||
// operator.
|
||||
DeclarationName(CXXOperatorIdName *Name)
|
||||
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
|
||||
DeclarationName(CXXOperatorIdName *Name)
|
||||
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
|
||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXOperatorId");
|
||||
Ptr |= StoredDeclarationNameExtra;
|
||||
}
|
||||
|
|
@ -144,8 +146,8 @@ public:
|
|||
DeclarationName() : Ptr(0) { }
|
||||
|
||||
// Construct a declaration name from an IdentifierInfo *.
|
||||
DeclarationName(const IdentifierInfo *II)
|
||||
: Ptr(reinterpret_cast<uintptr_t>(II)) {
|
||||
DeclarationName(const IdentifierInfo *II)
|
||||
: Ptr(reinterpret_cast<uintptr_t>(II)) {
|
||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo");
|
||||
}
|
||||
|
||||
|
|
@ -157,8 +159,8 @@ public:
|
|||
|
||||
// operator bool() - Evaluates true when this declaration name is
|
||||
// non-empty.
|
||||
operator bool() const {
|
||||
return ((Ptr & PtrMask) != 0) ||
|
||||
operator bool() const {
|
||||
return ((Ptr & PtrMask) != 0) ||
|
||||
(reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask));
|
||||
}
|
||||
|
||||
|
|
@ -170,10 +172,10 @@ public:
|
|||
bool isObjCOneArgSelector() const {
|
||||
return getStoredNameKind() == StoredObjCOneArgSelector;
|
||||
}
|
||||
|
||||
|
||||
/// getNameKind - Determine what kind of name this is.
|
||||
NameKind getNameKind() const;
|
||||
|
||||
|
||||
|
||||
/// getName - Retrieve the human-readable string for this name.
|
||||
std::string getAsString() const;
|
||||
|
|
@ -181,7 +183,7 @@ public:
|
|||
/// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in
|
||||
/// this declaration name, or NULL if this declaration name isn't a
|
||||
/// simple identifier.
|
||||
IdentifierInfo *getAsIdentifierInfo() const {
|
||||
IdentifierInfo *getAsIdentifierInfo() const {
|
||||
if (isIdentifier())
|
||||
return reinterpret_cast<IdentifierInfo *>(Ptr);
|
||||
return 0;
|
||||
|
|
@ -195,12 +197,18 @@ public:
|
|||
/// an opaque pointer.
|
||||
void *getAsOpaquePtr() const { return reinterpret_cast<void*>(Ptr); }
|
||||
|
||||
static DeclarationName getFromOpaquePtr(void *P) {
|
||||
DeclarationName N;
|
||||
N.Ptr = reinterpret_cast<uintptr_t> (P);
|
||||
return N;
|
||||
}
|
||||
|
||||
static DeclarationName getFromOpaqueInteger(uintptr_t P) {
|
||||
DeclarationName N;
|
||||
N.Ptr = P;
|
||||
return N;
|
||||
}
|
||||
|
||||
|
||||
/// getCXXNameType - If this name is one of the C++ names (of a
|
||||
/// constructor, destructor, or conversion function), return the
|
||||
/// type associated with that name.
|
||||
|
|
@ -290,32 +298,32 @@ public:
|
|||
|
||||
/// getCXXConstructorName - Returns the name of a C++ constructor
|
||||
/// for the given Type.
|
||||
DeclarationName getCXXConstructorName(QualType Ty) {
|
||||
DeclarationName getCXXConstructorName(CanQualType Ty) {
|
||||
return getCXXSpecialName(DeclarationName::CXXConstructorName, Ty);
|
||||
}
|
||||
|
||||
/// getCXXDestructorName - Returns the name of a C++ destructor
|
||||
/// for the given Type.
|
||||
DeclarationName getCXXDestructorName(QualType Ty) {
|
||||
DeclarationName getCXXDestructorName(CanQualType Ty) {
|
||||
return getCXXSpecialName(DeclarationName::CXXDestructorName, Ty);
|
||||
}
|
||||
|
||||
/// getCXXConversionFunctionName - Returns the name of a C++
|
||||
/// conversion function for the given Type.
|
||||
DeclarationName getCXXConversionFunctionName(QualType Ty) {
|
||||
DeclarationName getCXXConversionFunctionName(CanQualType Ty) {
|
||||
return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty);
|
||||
}
|
||||
|
||||
/// getCXXSpecialName - Returns a declaration name for special kind
|
||||
/// of C++ name, e.g., for a constructor, destructor, or conversion
|
||||
/// function.
|
||||
DeclarationName getCXXSpecialName(DeclarationName::NameKind Kind,
|
||||
QualType Ty);
|
||||
DeclarationName getCXXSpecialName(DeclarationName::NameKind Kind,
|
||||
CanQualType Ty);
|
||||
|
||||
/// getCXXOperatorName - Get the name of the overloadable C++
|
||||
/// operator corresponding to Op.
|
||||
DeclarationName getCXXOperatorName(OverloadedOperatorKind Op);
|
||||
};
|
||||
};
|
||||
|
||||
/// Insertion operator for diagnostics. This allows sending DeclarationName's
|
||||
/// into a diagnostic with <<.
|
||||
|
|
@ -325,7 +333,15 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
|||
Diagnostic::ak_declarationname);
|
||||
return DB;
|
||||
}
|
||||
|
||||
|
||||
/// Insertion operator for partial diagnostics. This allows binding
|
||||
/// DeclarationName's into a partial diagnostic with <<.
|
||||
inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
|
||||
DeclarationName N) {
|
||||
PD.AddTaggedVal(N.getAsOpaqueInteger(),
|
||||
Diagnostic::ak_declarationname);
|
||||
return PD;
|
||||
}
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
|
|
@ -344,7 +360,7 @@ struct DenseMapInfo<clang::DeclarationName> {
|
|||
|
||||
static unsigned getHashValue(clang::DeclarationName);
|
||||
|
||||
static inline bool
|
||||
static inline bool
|
||||
isEqual(clang::DeclarationName LHS, clang::DeclarationName RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -22,7 +22,7 @@ namespace clang {
|
|||
class ASTContext;
|
||||
class ObjCMethodDecl;
|
||||
class ObjCPropertyDecl;
|
||||
|
||||
|
||||
/// ObjCStringLiteral, used for Objective-C string literals
|
||||
/// i.e. @"foo".
|
||||
class ObjCStringLiteral : public Expr {
|
||||
|
|
@ -34,8 +34,6 @@ public:
|
|||
explicit ObjCStringLiteral(EmptyShell Empty)
|
||||
: Expr(ObjCStringLiteralClass, Empty) {}
|
||||
|
||||
ObjCStringLiteral* Clone(ASTContext &C) const;
|
||||
|
||||
StringLiteral *getString() { return cast<StringLiteral>(String); }
|
||||
const StringLiteral *getString() const { return cast<StringLiteral>(String); }
|
||||
void setString(StringLiteral *S) { String = S; }
|
||||
|
|
@ -43,20 +41,20 @@ public:
|
|||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, String->getLocEnd());
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCStringLiteralClass;
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCStringLiteralClass;
|
||||
}
|
||||
static bool classof(const ObjCStringLiteral *) { return true; }
|
||||
|
||||
static bool classof(const ObjCStringLiteral *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
|
||||
/// ObjCEncodeExpr, used for @encode in Objective-C. @encode has the same type
|
||||
/// and behavior as StringLiteral except that the string initializer is obtained
|
||||
/// from ASTContext with the encoding type as an argument.
|
||||
|
|
@ -64,32 +62,32 @@ class ObjCEncodeExpr : public Expr {
|
|||
QualType EncType;
|
||||
SourceLocation AtLoc, RParenLoc;
|
||||
public:
|
||||
ObjCEncodeExpr(QualType T, QualType ET,
|
||||
ObjCEncodeExpr(QualType T, QualType ET,
|
||||
SourceLocation at, SourceLocation rp)
|
||||
: Expr(ObjCEncodeExprClass, T, ET->isDependentType(),
|
||||
: Expr(ObjCEncodeExprClass, T, ET->isDependentType(),
|
||||
ET->isDependentType()), EncType(ET), AtLoc(at), RParenLoc(rp) {}
|
||||
|
||||
|
||||
explicit ObjCEncodeExpr(EmptyShell Empty) : Expr(ObjCEncodeExprClass, Empty){}
|
||||
|
||||
|
||||
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
|
||||
QualType getEncodedType() const { return EncType; }
|
||||
void setEncodedType(QualType T) { EncType = T; }
|
||||
|
||||
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, RParenLoc);
|
||||
}
|
||||
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCEncodeExprClass;
|
||||
}
|
||||
static bool classof(const ObjCEncodeExpr *) { return true; }
|
||||
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
|
@ -106,11 +104,9 @@ public:
|
|||
explicit ObjCSelectorExpr(EmptyShell Empty)
|
||||
: Expr(ObjCSelectorExprClass, Empty) {}
|
||||
|
||||
ObjCSelectorExpr *Clone(ASTContext &C) const;
|
||||
|
||||
Selector getSelector() const { return SelName; }
|
||||
void setSelector(Selector S) { SelName = S; }
|
||||
|
||||
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
|
|
@ -119,26 +115,26 @@ public:
|
|||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, RParenLoc);
|
||||
}
|
||||
|
||||
|
||||
/// getNumArgs - Return the number of actual arguments to this call.
|
||||
unsigned getNumArgs() const { return SelName.getNumArgs(); }
|
||||
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCSelectorExprClass;
|
||||
}
|
||||
static bool classof(const ObjCSelectorExpr *) { return true; }
|
||||
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
|
||||
/// ObjCProtocolExpr used for protocol expression in Objective-C. This is used
|
||||
/// as: @protocol(foo), as in:
|
||||
/// obj conformsToProtocol:@protocol(foo)]
|
||||
/// The return type is "Protocol*".
|
||||
class ObjCProtocolExpr : public Expr {
|
||||
ObjCProtocolDecl *TheProtocol;
|
||||
class ObjCProtocolExpr : public Expr {
|
||||
ObjCProtocolDecl *TheProtocol;
|
||||
SourceLocation AtLoc, RParenLoc;
|
||||
public:
|
||||
ObjCProtocolExpr(QualType T, ObjCProtocolDecl *protocol,
|
||||
|
|
@ -148,11 +144,9 @@ public:
|
|||
explicit ObjCProtocolExpr(EmptyShell Empty)
|
||||
: Expr(ObjCProtocolExprClass, Empty) {}
|
||||
|
||||
ObjCProtocolExpr *Clone(ASTContext &C) const;
|
||||
|
||||
ObjCProtocolDecl *getProtocol() const { return TheProtocol; }
|
||||
void setProtocol(ObjCProtocolDecl *P) { TheProtocol = P; }
|
||||
|
||||
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
|
|
@ -161,12 +155,12 @@ public:
|
|||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, RParenLoc);
|
||||
}
|
||||
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCProtocolExprClass;
|
||||
}
|
||||
static bool classof(const ObjCProtocolExpr *) { return true; }
|
||||
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
|
@ -179,44 +173,44 @@ class ObjCIvarRefExpr : public Expr {
|
|||
Stmt *Base;
|
||||
bool IsArrow:1; // True if this is "X->F", false if this is "X.F".
|
||||
bool IsFreeIvar:1; // True if ivar reference has no base (self assumed).
|
||||
|
||||
|
||||
public:
|
||||
ObjCIvarRefExpr(ObjCIvarDecl *d,
|
||||
QualType t, SourceLocation l, Expr *base=0,
|
||||
bool arrow = false, bool freeIvar = false) :
|
||||
QualType t, SourceLocation l, Expr *base=0,
|
||||
bool arrow = false, bool freeIvar = false) :
|
||||
Expr(ObjCIvarRefExprClass, t), D(d),
|
||||
Loc(l), Base(base), IsArrow(arrow),
|
||||
IsFreeIvar(freeIvar) {}
|
||||
|
||||
|
||||
explicit ObjCIvarRefExpr(EmptyShell Empty)
|
||||
: Expr(ObjCIvarRefExprClass, Empty) {}
|
||||
|
||||
ObjCIvarDecl *getDecl() { return D; }
|
||||
const ObjCIvarDecl *getDecl() const { return D; }
|
||||
void setDecl(ObjCIvarDecl *d) { D = d; }
|
||||
|
||||
|
||||
const Expr *getBase() const { return cast<Expr>(Base); }
|
||||
Expr *getBase() { return cast<Expr>(Base); }
|
||||
void setBase(Expr * base) { Base = base; }
|
||||
|
||||
|
||||
bool isArrow() const { return IsArrow; }
|
||||
bool isFreeIvar() const { return IsFreeIvar; }
|
||||
void setIsArrow(bool A) { IsArrow = A; }
|
||||
void setIsFreeIvar(bool A) { IsFreeIvar = A; }
|
||||
|
||||
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
void setLocation(SourceLocation L) { Loc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return isFreeIvar() ? SourceRange(Loc)
|
||||
: SourceRange(getBase()->getLocStart(), Loc);
|
||||
: SourceRange(getBase()->getLocStart(), Loc);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCIvarRefExprClass;
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCIvarRefExprClass;
|
||||
}
|
||||
static bool classof(const ObjCIvarRefExpr *) { return true; }
|
||||
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
|
@ -231,113 +225,129 @@ private:
|
|||
SourceLocation IdLoc;
|
||||
Stmt *Base;
|
||||
public:
|
||||
ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
|
||||
ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
|
||||
SourceLocation l, Expr *base)
|
||||
: Expr(ObjCPropertyRefExprClass, t), AsProperty(PD), IdLoc(l), Base(base) {
|
||||
}
|
||||
|
||||
|
||||
explicit ObjCPropertyRefExpr(EmptyShell Empty)
|
||||
: Expr(ObjCPropertyRefExprClass, Empty) {}
|
||||
|
||||
ObjCPropertyDecl *getProperty() const { return AsProperty; }
|
||||
void setProperty(ObjCPropertyDecl *D) { AsProperty = D; }
|
||||
|
||||
|
||||
const Expr *getBase() const { return cast<Expr>(Base); }
|
||||
Expr *getBase() { return cast<Expr>(Base); }
|
||||
void setBase(Expr *base) { Base = base; }
|
||||
|
||||
|
||||
SourceLocation getLocation() const { return IdLoc; }
|
||||
void setLocation(SourceLocation L) { IdLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(getBase()->getLocStart(), IdLoc);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCPropertyRefExprClass;
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCPropertyRefExprClass;
|
||||
}
|
||||
static bool classof(const ObjCPropertyRefExpr *) { return true; }
|
||||
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// ObjCKVCRefExpr - A dot-syntax expression to access "implicit" properties
|
||||
/// (i.e. methods following the property naming convention). KVC stands for
|
||||
/// Key Value Encoding, a generic concept for accessing or setting a 'Key'
|
||||
/// value for an object.
|
||||
///
|
||||
class ObjCKVCRefExpr : public Expr {
|
||||
/// ObjCImplicitSetterGetterRefExpr - A dot-syntax expression to access two
|
||||
/// methods; one to set a value to an 'ivar' (Setter) and the other to access
|
||||
/// an 'ivar' (Setter).
|
||||
/// An example for use of this AST is:
|
||||
/// @code
|
||||
/// @interface Test { }
|
||||
/// - (Test *)crash;
|
||||
/// - (void)setCrash: (Test*)value;
|
||||
/// @end
|
||||
/// void foo(Test *p1, Test *p2)
|
||||
/// {
|
||||
/// p2.crash = p1.crash; // Uses ObjCImplicitSetterGetterRefExpr AST
|
||||
/// }
|
||||
/// @endcode
|
||||
class ObjCImplicitSetterGetterRefExpr : public Expr {
|
||||
/// Setter - Setter method user declared for setting its 'ivar' to a value
|
||||
ObjCMethodDecl *Setter;
|
||||
/// Getter - Getter method user declared for accessing 'ivar' it controls.
|
||||
ObjCMethodDecl *Getter;
|
||||
SourceLocation Loc;
|
||||
/// Location of the member in the dot syntax notation. This is location
|
||||
/// of the getter method.
|
||||
SourceLocation MemberLoc;
|
||||
// FIXME: Swizzle these into a single pointer.
|
||||
Stmt *Base;
|
||||
ObjCInterfaceDecl *ClassProp;
|
||||
ObjCInterfaceDecl *InterfaceDecl;
|
||||
/// Location of the receiver class in the dot syntax notation
|
||||
/// used to call a class method setter/getter.
|
||||
SourceLocation ClassLoc;
|
||||
|
||||
|
||||
public:
|
||||
ObjCKVCRefExpr(ObjCMethodDecl *getter,
|
||||
QualType t,
|
||||
ObjCImplicitSetterGetterRefExpr(ObjCMethodDecl *getter,
|
||||
QualType t,
|
||||
ObjCMethodDecl *setter,
|
||||
SourceLocation l, Expr *base)
|
||||
: Expr(ObjCKVCRefExprClass, t), Setter(setter),
|
||||
Getter(getter), Loc(l), Base(base), ClassProp(0),
|
||||
: Expr(ObjCImplicitSetterGetterRefExprClass, t), Setter(setter),
|
||||
Getter(getter), MemberLoc(l), Base(base), InterfaceDecl(0),
|
||||
ClassLoc(SourceLocation()) {
|
||||
}
|
||||
ObjCKVCRefExpr(ObjCMethodDecl *getter,
|
||||
QualType t,
|
||||
ObjCImplicitSetterGetterRefExpr(ObjCMethodDecl *getter,
|
||||
QualType t,
|
||||
ObjCMethodDecl *setter,
|
||||
SourceLocation l, ObjCInterfaceDecl *C, SourceLocation CL)
|
||||
: Expr(ObjCKVCRefExprClass, t), Setter(setter),
|
||||
Getter(getter), Loc(l), Base(0), ClassProp(C), ClassLoc(CL) {
|
||||
: Expr(ObjCImplicitSetterGetterRefExprClass, t), Setter(setter),
|
||||
Getter(getter), MemberLoc(l), Base(0), InterfaceDecl(C), ClassLoc(CL) {
|
||||
}
|
||||
explicit ObjCKVCRefExpr(EmptyShell Empty) : Expr(ObjCKVCRefExprClass, Empty){}
|
||||
explicit ObjCImplicitSetterGetterRefExpr(EmptyShell Empty)
|
||||
: Expr(ObjCImplicitSetterGetterRefExprClass, Empty){}
|
||||
|
||||
ObjCMethodDecl *getGetterMethod() const { return Getter; }
|
||||
ObjCMethodDecl *getSetterMethod() const { return Setter; }
|
||||
ObjCInterfaceDecl *getClassProp() const { return ClassProp; }
|
||||
ObjCInterfaceDecl *getInterfaceDecl() const { return InterfaceDecl; }
|
||||
void setGetterMethod(ObjCMethodDecl *D) { Getter = D; }
|
||||
void setSetterMethod(ObjCMethodDecl *D) { Setter = D; }
|
||||
void setClassProp(ObjCInterfaceDecl *D) { ClassProp = D; }
|
||||
|
||||
void setInterfaceDecl(ObjCInterfaceDecl *D) { InterfaceDecl = D; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
if (Base)
|
||||
return SourceRange(getBase()->getLocStart(), Loc);
|
||||
return SourceRange(ClassLoc, Loc);
|
||||
return SourceRange(getBase()->getLocStart(), MemberLoc);
|
||||
return SourceRange(ClassLoc, MemberLoc);
|
||||
}
|
||||
const Expr *getBase() const { return cast_or_null<Expr>(Base); }
|
||||
Expr *getBase() { return cast_or_null<Expr>(Base); }
|
||||
void setBase(Expr *base) { Base = base; }
|
||||
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
void setLocation(SourceLocation L) { Loc = L; }
|
||||
|
||||
SourceLocation getLocation() const { return MemberLoc; }
|
||||
void setLocation(SourceLocation L) { MemberLoc = L; }
|
||||
SourceLocation getClassLoc() const { return ClassLoc; }
|
||||
void setClassLoc(SourceLocation L) { ClassLoc = L; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCKVCRefExprClass;
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCImplicitSetterGetterRefExprClass;
|
||||
}
|
||||
static bool classof(const ObjCKVCRefExpr *) { return true; }
|
||||
|
||||
static bool classof(const ObjCImplicitSetterGetterRefExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
|
||||
class ObjCMessageExpr : public Expr {
|
||||
// SubExprs - The receiver and arguments of the message expression.
|
||||
Stmt **SubExprs;
|
||||
|
||||
|
||||
// NumArgs - The number of arguments (not including the receiver) to the
|
||||
// message expression.
|
||||
unsigned NumArgs;
|
||||
|
||||
|
||||
// A unigue name for this message.
|
||||
Selector SelName;
|
||||
|
||||
// A method prototype for this message (optional).
|
||||
|
||||
// A method prototype for this message (optional).
|
||||
// FIXME: Since method decls contain the selector, and most messages have a
|
||||
// prototype, consider devising a scheme for unifying SelName/MethodProto.
|
||||
ObjCMethodDecl *MethodProto;
|
||||
|
|
@ -350,7 +360,7 @@ class ObjCMessageExpr : public Expr {
|
|||
// Bit-swizzling flags.
|
||||
enum { IsInstMeth=0, IsClsMethDeclUnknown, IsClsMethDeclKnown, Flags=0x3 };
|
||||
unsigned getFlag() const { return (uintptr_t) SubExprs[RECEIVER] & Flags; }
|
||||
|
||||
|
||||
public:
|
||||
/// This constructor is used to represent class messages where the
|
||||
/// ObjCInterfaceDecl* of the receiver is not known.
|
||||
|
|
@ -366,28 +376,28 @@ public:
|
|||
QualType retType, ObjCMethodDecl *methDecl,
|
||||
SourceLocation LBrac, SourceLocation RBrac,
|
||||
Expr **ArgExprs, unsigned NumArgs);
|
||||
|
||||
|
||||
// constructor for instance messages.
|
||||
ObjCMessageExpr(Expr *receiver, Selector selInfo,
|
||||
QualType retType, ObjCMethodDecl *methDecl,
|
||||
SourceLocation LBrac, SourceLocation RBrac,
|
||||
Expr **ArgExprs, unsigned NumArgs);
|
||||
|
||||
|
||||
explicit ObjCMessageExpr(EmptyShell Empty)
|
||||
: Expr(ObjCMessageExprClass, Empty), SubExprs(0), NumArgs(0) {}
|
||||
|
||||
|
||||
~ObjCMessageExpr() {
|
||||
delete [] SubExprs;
|
||||
}
|
||||
|
||||
|
||||
/// getReceiver - Returns the receiver of the message expression.
|
||||
/// This can be NULL if the message is for class methods. For
|
||||
/// class methods, use getClassName.
|
||||
/// FIXME: need to handle/detect 'super' usage within a class method.
|
||||
Expr *getReceiver() {
|
||||
Expr *getReceiver() {
|
||||
uintptr_t x = (uintptr_t) SubExprs[RECEIVER];
|
||||
return (x & Flags) == IsInstMeth ? (Expr*) x : 0;
|
||||
}
|
||||
}
|
||||
const Expr *getReceiver() const {
|
||||
return const_cast<ObjCMessageExpr*>(this)->getReceiver();
|
||||
}
|
||||
|
|
@ -395,36 +405,36 @@ public:
|
|||
void setReceiver(Expr *rec) { SubExprs[RECEIVER] = rec; }
|
||||
Selector getSelector() const { return SelName; }
|
||||
void setSelector(Selector S) { SelName = S; }
|
||||
|
||||
|
||||
const ObjCMethodDecl *getMethodDecl() const { return MethodProto; }
|
||||
ObjCMethodDecl *getMethodDecl() { return MethodProto; }
|
||||
void setMethodDecl(ObjCMethodDecl *MD) { MethodProto = MD; }
|
||||
|
||||
|
||||
typedef std::pair<ObjCInterfaceDecl*, IdentifierInfo*> ClassInfo;
|
||||
|
||||
|
||||
/// getClassInfo - For class methods, this returns both the ObjCInterfaceDecl*
|
||||
/// and IdentifierInfo* of the invoked class. Both can be NULL if this
|
||||
/// is an instance message, and the ObjCInterfaceDecl* can be NULL if none
|
||||
/// was available when this ObjCMessageExpr object was constructed.
|
||||
ClassInfo getClassInfo() const;
|
||||
/// was available when this ObjCMessageExpr object was constructed.
|
||||
ClassInfo getClassInfo() const;
|
||||
void setClassInfo(const ClassInfo &C);
|
||||
|
||||
|
||||
/// getClassName - For class methods, this returns the invoked class,
|
||||
/// and returns NULL otherwise. For instance methods, use getReceiver.
|
||||
/// and returns NULL otherwise. For instance methods, use getReceiver.
|
||||
IdentifierInfo *getClassName() const {
|
||||
return getClassInfo().second;
|
||||
}
|
||||
|
||||
|
||||
/// getNumArgs - Return the number of actual arguments to this call.
|
||||
unsigned getNumArgs() const { return NumArgs; }
|
||||
void setNumArgs(unsigned nArgs) {
|
||||
NumArgs = nArgs;
|
||||
void setNumArgs(unsigned nArgs) {
|
||||
NumArgs = nArgs;
|
||||
// FIXME: should always allocate SubExprs via the ASTContext's
|
||||
// allocator.
|
||||
if (!SubExprs)
|
||||
SubExprs = new Stmt* [NumArgs + 1];
|
||||
}
|
||||
|
||||
|
||||
/// getArg - Return the specified argument.
|
||||
Expr *getArg(unsigned Arg) {
|
||||
assert(Arg < NumArgs && "Arg access out of range!");
|
||||
|
|
@ -439,13 +449,13 @@ public:
|
|||
assert(Arg < NumArgs && "Arg access out of range!");
|
||||
SubExprs[Arg+ARGS_START] = ArgExpr;
|
||||
}
|
||||
|
||||
|
||||
SourceLocation getLeftLoc() const { return LBracloc; }
|
||||
SourceLocation getRightLoc() const { return RBracloc; }
|
||||
|
||||
void setLeftLoc(SourceLocation L) { LBracloc = L; }
|
||||
void setRightLoc(SourceLocation L) { RBracloc = L; }
|
||||
|
||||
|
||||
void setSourceRange(SourceRange R) {
|
||||
LBracloc = R.getBegin();
|
||||
RBracloc = R.getEnd();
|
||||
|
|
@ -458,14 +468,14 @@ public:
|
|||
return T->getStmtClass() == ObjCMessageExprClass;
|
||||
}
|
||||
static bool classof(const ObjCMessageExpr *) { return true; }
|
||||
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
|
||||
typedef ExprIterator arg_iterator;
|
||||
typedef ConstExprIterator const_arg_iterator;
|
||||
|
||||
|
||||
arg_iterator arg_begin() { return &SubExprs[ARGS_START]; }
|
||||
arg_iterator arg_end() { return &SubExprs[ARGS_START] + NumArgs; }
|
||||
const_arg_iterator arg_begin() const { return &SubExprs[ARGS_START]; }
|
||||
|
|
@ -477,16 +487,16 @@ public:
|
|||
class ObjCSuperExpr : public Expr {
|
||||
SourceLocation Loc;
|
||||
public:
|
||||
ObjCSuperExpr(SourceLocation L, QualType Type)
|
||||
ObjCSuperExpr(SourceLocation L, QualType Type)
|
||||
: Expr(ObjCSuperExprClass, Type), Loc(L) { }
|
||||
explicit ObjCSuperExpr(EmptyShell Empty) : Expr(ObjCSuperExprClass, Empty) {}
|
||||
|
||||
SourceLocation getLoc() const { return Loc; }
|
||||
void setLoc(SourceLocation L) { Loc = L; }
|
||||
|
||||
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCSuperExprClass;
|
||||
}
|
||||
static bool classof(const ObjCSuperExpr *) { return true; }
|
||||
|
|
@ -496,6 +506,52 @@ public:
|
|||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// ObjCIsaExpr - Represent X->isa and X.isa when X is an ObjC 'id' type.
|
||||
/// (similiar in spirit to MemberExpr).
|
||||
class ObjCIsaExpr : public Expr {
|
||||
/// Base - the expression for the base object pointer.
|
||||
Stmt *Base;
|
||||
|
||||
/// IsaMemberLoc - This is the location of the 'isa'.
|
||||
SourceLocation IsaMemberLoc;
|
||||
|
||||
/// IsArrow - True if this is "X->F", false if this is "X.F".
|
||||
bool IsArrow;
|
||||
public:
|
||||
ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, QualType ty)
|
||||
: Expr(ObjCIsaExprClass, ty),
|
||||
Base(base), IsaMemberLoc(l), IsArrow(isarrow) {}
|
||||
|
||||
/// \brief Build an empty expression.
|
||||
explicit ObjCIsaExpr(EmptyShell Empty) : Expr(ObjCIsaExprClass, Empty) { }
|
||||
|
||||
void setBase(Expr *E) { Base = E; }
|
||||
Expr *getBase() const { return cast<Expr>(Base); }
|
||||
|
||||
bool isArrow() const { return IsArrow; }
|
||||
void setArrow(bool A) { IsArrow = A; }
|
||||
|
||||
/// getMemberLoc - Return the location of the "member", in X->F, it is the
|
||||
/// location of 'F'.
|
||||
SourceLocation getIsaMemberLoc() const { return IsaMemberLoc; }
|
||||
void setIsaMemberLoc(SourceLocation L) { IsaMemberLoc = L; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(getBase()->getLocStart(), IsaMemberLoc);
|
||||
}
|
||||
|
||||
virtual SourceLocation getExprLoc() const { return IsaMemberLoc; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCIsaExprClass;
|
||||
}
|
||||
static bool classof(const ObjCIsaExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ struct VisibleDeclaration {
|
|||
/// \brief The name of the declarations.
|
||||
DeclarationName Name;
|
||||
|
||||
/// \brief The ID numbers of all of the declarations with this name.
|
||||
/// \brief The ID numbers of all of the declarations with this name.
|
||||
///
|
||||
/// These declarations have not necessarily been de-serialized.
|
||||
llvm::SmallVector<unsigned, 4> Declarations;
|
||||
|
|
@ -65,7 +65,7 @@ public:
|
|||
/// replaced with the sorted set of source ranges corresponding to
|
||||
/// comments in the source code.
|
||||
virtual void ReadComments(std::vector<SourceRange> &Comments) = 0;
|
||||
|
||||
|
||||
/// \brief Resolve a type ID into a type, potentially building a new
|
||||
/// type.
|
||||
virtual QualType GetType(uint32_t ID) = 0;
|
||||
|
|
@ -151,7 +151,7 @@ public:
|
|||
this->Ptr = reinterpret_cast<uint64_t>(Ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
LazyOffsetPtr &operator=(uint64_t Offset) {
|
||||
assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits");
|
||||
if (Offset == 0)
|
||||
|
|
@ -177,7 +177,7 @@ public:
|
|||
/// \returns a pointer to the AST node.
|
||||
T* get(ExternalASTSource *Source) const {
|
||||
if (isOffset()) {
|
||||
assert(Source &&
|
||||
assert(Source &&
|
||||
"Cannot deserialize a lazy pointer without an AST source");
|
||||
Ptr = reinterpret_cast<uint64_t>((Source->*Get)(Ptr >> 1));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
|
||||
#define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
|
||||
|
|
@ -26,7 +27,7 @@ namespace clang {
|
|||
class ASTContext;
|
||||
class NamespaceDecl;
|
||||
class IdentifierInfo;
|
||||
class PrintingPolicy;
|
||||
struct PrintingPolicy;
|
||||
class Type;
|
||||
class LangOptions;
|
||||
|
||||
|
|
@ -80,8 +81,8 @@ private:
|
|||
|
||||
/// \brief Copy constructor used internally to clone nested name
|
||||
/// specifiers.
|
||||
NestedNameSpecifier(const NestedNameSpecifier &Other)
|
||||
: llvm::FoldingSetNode(Other), Prefix(Other.Prefix),
|
||||
NestedNameSpecifier(const NestedNameSpecifier &Other)
|
||||
: llvm::FoldingSetNode(Other), Prefix(Other.Prefix),
|
||||
Specifier(Other.Specifier) {
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +90,7 @@ private:
|
|||
|
||||
/// \brief Either find or insert the given nested name specifier
|
||||
/// mockup in the given context.
|
||||
static NestedNameSpecifier *FindOrInsert(ASTContext &Context,
|
||||
static NestedNameSpecifier *FindOrInsert(ASTContext &Context,
|
||||
const NestedNameSpecifier &Mockup);
|
||||
|
||||
public:
|
||||
|
|
@ -98,20 +99,28 @@ public:
|
|||
/// The prefix must be dependent, since nested name specifiers
|
||||
/// referencing an identifier are only permitted when the identifier
|
||||
/// cannot be resolved.
|
||||
static NestedNameSpecifier *Create(ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
static NestedNameSpecifier *Create(ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
IdentifierInfo *II);
|
||||
|
||||
/// \brief Builds a nested name specifier that names a namespace.
|
||||
static NestedNameSpecifier *Create(ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
static NestedNameSpecifier *Create(ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
NamespaceDecl *NS);
|
||||
|
||||
/// \brief Builds a nested name specifier that names a type.
|
||||
static NestedNameSpecifier *Create(ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
static NestedNameSpecifier *Create(ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
bool Template, Type *T);
|
||||
|
||||
/// \brief Builds a specifier that consists of just an identifier.
|
||||
///
|
||||
/// The nested-name-specifier is assumed to be dependent, but has no
|
||||
/// prefix because the prefix is implied by something outside of the
|
||||
/// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent
|
||||
/// type.
|
||||
static NestedNameSpecifier *Create(ASTContext &Context, IdentifierInfo *II);
|
||||
|
||||
/// \brief Returns the nested name specifier representing the global
|
||||
/// scope.
|
||||
static NestedNameSpecifier *GlobalSpecifier(ASTContext &Context);
|
||||
|
|
@ -126,10 +135,10 @@ public:
|
|||
NestedNameSpecifier *getPrefix() const { return Prefix.getPointer(); }
|
||||
|
||||
/// \brief Determine what kind of nested name specifier is stored.
|
||||
SpecifierKind getKind() const {
|
||||
SpecifierKind getKind() const {
|
||||
if (Specifier == 0)
|
||||
return Global;
|
||||
return (SpecifierKind)Prefix.getInt();
|
||||
return (SpecifierKind)Prefix.getInt();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the identifier stored in this nested name
|
||||
|
|
@ -140,7 +149,7 @@ public:
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Retrieve the namespace stored in this nested name
|
||||
/// specifier.
|
||||
NamespaceDecl *getAsNamespace() const {
|
||||
|
|
@ -152,7 +161,7 @@ public:
|
|||
|
||||
/// \brief Retrieve the type stored in this nested name specifier.
|
||||
Type *getAsType() const {
|
||||
if (Prefix.getInt() == TypeSpec ||
|
||||
if (Prefix.getInt() == TypeSpec ||
|
||||
Prefix.getInt() == TypeSpecWithTemplate)
|
||||
return (Type *)Specifier;
|
||||
|
||||
|
|
@ -179,6 +188,15 @@ public:
|
|||
void dump(const LangOptions &LO);
|
||||
};
|
||||
|
||||
/// Insertion operator for diagnostics. This allows sending NestedNameSpecifiers
|
||||
/// into a diagnostic with <<.
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
NestedNameSpecifier *NNS) {
|
||||
DB.AddTaggedVal(reinterpret_cast<intptr_t>(NNS),
|
||||
Diagnostic::ak_nestednamespec);
|
||||
return DB;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
namespace clang {
|
||||
class Stmt;
|
||||
class Expr;
|
||||
|
||||
|
||||
class ParentMap {
|
||||
void* Impl;
|
||||
public:
|
||||
|
|
@ -30,7 +30,7 @@ public:
|
|||
const Stmt *getParent(const Stmt* S) const {
|
||||
return getParent(const_cast<Stmt*>(S));
|
||||
}
|
||||
|
||||
|
||||
const Stmt *getParentIgnoreParens(const Stmt *S) const {
|
||||
return getParentIgnoreParens(const_cast<Stmt*>(S));
|
||||
}
|
||||
|
|
@ -38,13 +38,13 @@ public:
|
|||
bool hasParent(Stmt* S) const {
|
||||
return getParent(S) != 0;
|
||||
}
|
||||
|
||||
|
||||
bool isConsumedExpr(Expr *E) const;
|
||||
|
||||
|
||||
bool isConsumedExpr(const Expr *E) const {
|
||||
return isConsumedExpr(const_cast<Expr*>(E));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // end clang namespace
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -34,9 +34,10 @@ public:
|
|||
/// declarations should be printed.
|
||||
struct PrintingPolicy {
|
||||
/// \brief Create a default printing policy for C.
|
||||
PrintingPolicy(const LangOptions &LO)
|
||||
PrintingPolicy(const LangOptions &LO)
|
||||
: Indentation(2), LangOpts(LO), SuppressSpecifiers(false),
|
||||
SuppressTag(false), SuppressTagKind(false), Dump(false) { }
|
||||
SuppressTag(false), SuppressTagKind(false), SuppressScope(false),
|
||||
Dump(false), ConstantArraySizeAsWritten(false) { }
|
||||
|
||||
/// \brief The number of spaces to use to indent each line.
|
||||
unsigned Indentation : 8;
|
||||
|
|
@ -74,11 +75,32 @@ struct PrintingPolicy {
|
|||
/// kind of tag, e.g., "struct", "union", "enum".
|
||||
bool SuppressTagKind : 1;
|
||||
|
||||
/// \brief Suppresses printing of scope specifiers.
|
||||
bool SuppressScope : 1;
|
||||
|
||||
/// \brief True when we are "dumping" rather than "pretty-printing",
|
||||
/// where dumping involves printing the internal details of the AST
|
||||
/// and pretty-printing involves printing something similar to
|
||||
/// source code.
|
||||
bool Dump : 1;
|
||||
|
||||
/// \brief Whether we should print the sizes of constant array expressions
|
||||
/// as written in the sources.
|
||||
///
|
||||
/// This flag is determines whether arrays types declared as
|
||||
///
|
||||
/// \code
|
||||
/// int a[4+10*10];
|
||||
/// char a[] = "A string";
|
||||
/// \endcode
|
||||
///
|
||||
/// will be printed as written or as follows:
|
||||
///
|
||||
/// \code
|
||||
/// int a[104];
|
||||
/// char a[9] = "A string";
|
||||
/// \endcode
|
||||
bool ConstantArraySizeAsWritten : 1;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
|||
|
|
@ -18,83 +18,175 @@
|
|||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class FieldDecl;
|
||||
class RecordDecl;
|
||||
class CXXRecordDecl;
|
||||
|
||||
/// ASTRecordLayout -
|
||||
/// ASTRecordLayout -
|
||||
/// This class contains layout information for one RecordDecl,
|
||||
/// which is a struct/union/class. The decl represented must be a definition,
|
||||
/// not a forward declaration.
|
||||
/// This class is also used to contain layout information for one
|
||||
/// not a forward declaration.
|
||||
/// This class is also used to contain layout information for one
|
||||
/// ObjCInterfaceDecl. FIXME - Find appropriate name.
|
||||
/// These objects are managed by ASTContext.
|
||||
class ASTRecordLayout {
|
||||
uint64_t Size; // Size of record in bits.
|
||||
uint64_t NextOffset; // Next available offset
|
||||
uint64_t *FieldOffsets;
|
||||
unsigned Alignment; // Alignment of record in bits.
|
||||
unsigned FieldCount; // Number of fields
|
||||
friend class ASTContext;
|
||||
/// Size - Size of record in bits.
|
||||
uint64_t Size;
|
||||
|
||||
/// DataSize - Size of record in bits without tail padding.
|
||||
uint64_t DataSize;
|
||||
|
||||
/// FieldOffsets - Array of field offsets in bits.
|
||||
uint64_t *FieldOffsets;
|
||||
|
||||
// Alignment - Alignment of record in bits.
|
||||
unsigned Alignment;
|
||||
|
||||
// FieldCount - Number of fields.
|
||||
unsigned FieldCount;
|
||||
|
||||
struct CXXRecordLayoutInfo {
|
||||
/// NonVirtualSize - The non-virtual size (in bits) of an object, which is
|
||||
/// the size of the object without virtual bases.
|
||||
uint64_t NonVirtualSize;
|
||||
|
||||
/// NonVirtualAlign - The non-virtual alignment (in bits) of an object,
|
||||
/// which is the alignment of the object without virtual bases.
|
||||
uint64_t NonVirtualAlign;
|
||||
|
||||
/// PrimaryBase - The primary base for our vtable.
|
||||
const CXXRecordDecl *PrimaryBase;
|
||||
/// PrimaryBase - Wether or not the primary base was a virtual base.
|
||||
bool PrimaryBaseWasVirtual;
|
||||
|
||||
/// BaseOffsets - Contains a map from base classes to their offset.
|
||||
/// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
|
||||
llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsets;
|
||||
|
||||
/// VBaseOffsets - Contains a map from vbase classes to their offset.
|
||||
/// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
|
||||
llvm::DenseMap<const CXXRecordDecl *, uint64_t> VBaseOffsets;
|
||||
};
|
||||
|
||||
/// CXXInfo - If the record layout is for a C++ record, this will have
|
||||
/// C++ specific information about the record.
|
||||
CXXRecordLayoutInfo *CXXInfo;
|
||||
|
||||
friend class ASTContext;
|
||||
friend class ASTRecordLayoutBuilder;
|
||||
|
||||
ASTRecordLayout(uint64_t size, unsigned alignment, unsigned datasize,
|
||||
const uint64_t *fieldoffsets, unsigned fieldcount)
|
||||
: Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment),
|
||||
FieldCount(fieldcount), CXXInfo(0) {
|
||||
if (FieldCount > 0) {
|
||||
FieldOffsets = new uint64_t[FieldCount];
|
||||
for (unsigned i = 0; i < FieldCount; ++i)
|
||||
FieldOffsets[i] = fieldoffsets[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor for C++ records.
|
||||
ASTRecordLayout(uint64_t size, unsigned alignment, uint64_t datasize,
|
||||
const uint64_t *fieldoffsets, unsigned fieldcount,
|
||||
uint64_t nonvirtualsize, unsigned nonvirtualalign,
|
||||
const CXXRecordDecl *PB, bool PBVirtual,
|
||||
const std::pair<const CXXRecordDecl *, uint64_t> *bases,
|
||||
unsigned numbases,
|
||||
const std::pair<const CXXRecordDecl *, uint64_t> *vbases,
|
||||
unsigned numvbases)
|
||||
: Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment),
|
||||
FieldCount(fieldcount), CXXInfo(new CXXRecordLayoutInfo) {
|
||||
if (FieldCount > 0) {
|
||||
FieldOffsets = new uint64_t[FieldCount];
|
||||
for (unsigned i = 0; i < FieldCount; ++i)
|
||||
FieldOffsets[i] = fieldoffsets[i];
|
||||
}
|
||||
|
||||
CXXInfo->PrimaryBase = PB;
|
||||
CXXInfo->PrimaryBaseWasVirtual = PBVirtual;
|
||||
CXXInfo->NonVirtualSize = nonvirtualsize;
|
||||
CXXInfo->NonVirtualAlign = nonvirtualalign;
|
||||
for (unsigned i = 0; i != numbases; ++i)
|
||||
CXXInfo->BaseOffsets[bases[i].first] = bases[i].second;
|
||||
for (unsigned i = 0; i != numvbases; ++i)
|
||||
CXXInfo->VBaseOffsets[vbases[i].first] = vbases[i].second;
|
||||
}
|
||||
|
||||
ASTRecordLayout(uint64_t S = 0, unsigned A = 8)
|
||||
: Size(S), NextOffset(S), Alignment(A), FieldCount(0) {}
|
||||
~ASTRecordLayout() {
|
||||
delete [] FieldOffsets;
|
||||
delete CXXInfo;
|
||||
}
|
||||
|
||||
/// Initialize record layout. N is the number of fields in this record.
|
||||
void InitializeLayout(unsigned N) {
|
||||
FieldCount = N;
|
||||
FieldOffsets = new uint64_t[N];
|
||||
}
|
||||
|
||||
/// Finalize record layout. Adjust record size based on the alignment.
|
||||
void FinalizeLayout(bool ForceNonEmpty = false) {
|
||||
// In C++, records cannot be of size 0.
|
||||
if (ForceNonEmpty && Size == 0)
|
||||
Size = 8;
|
||||
// Finally, round the size of the record up to the alignment of the
|
||||
// record itself.
|
||||
Size = (Size + (Alignment-1)) & ~(Alignment-1);
|
||||
}
|
||||
|
||||
void SetFieldOffset(unsigned FieldNo, uint64_t Offset) {
|
||||
assert (FieldNo < FieldCount && "Invalid Field No");
|
||||
FieldOffsets[FieldNo] = Offset;
|
||||
}
|
||||
|
||||
void SetAlignment(unsigned A) { Alignment = A; }
|
||||
|
||||
/// LayoutField - Field layout. StructPacking is the specified
|
||||
/// packing alignment (maximum alignment) in bits to use for the
|
||||
/// structure, or 0 if no packing alignment is specified.
|
||||
void LayoutField(const FieldDecl *FD, unsigned FieldNo,
|
||||
bool IsUnion, unsigned StructPacking,
|
||||
ASTContext &Context);
|
||||
|
||||
ASTRecordLayout(const ASTRecordLayout&); // DO NOT IMPLEMENT
|
||||
void operator=(const ASTRecordLayout&); // DO NOT IMPLEMENT
|
||||
public:
|
||||
|
||||
|
||||
/// getAlignment - Get the record alignment in bits.
|
||||
unsigned getAlignment() const { return Alignment; }
|
||||
|
||||
/// getSize - Get the record size in bits.
|
||||
uint64_t getSize() const { return Size; }
|
||||
|
||||
|
||||
/// getFieldCount - Get the number of fields in the layout.
|
||||
unsigned getFieldCount() const { return FieldCount; }
|
||||
|
||||
|
||||
/// getFieldOffset - Get the offset of the given field index, in
|
||||
/// bits.
|
||||
uint64_t getFieldOffset(unsigned FieldNo) const {
|
||||
assert (FieldNo < FieldCount && "Invalid Field No");
|
||||
return FieldOffsets[FieldNo];
|
||||
}
|
||||
|
||||
/// getNextOffset - Get the next available (unused) offset in the
|
||||
/// structure, in bits.
|
||||
uint64_t getNextOffset() const {
|
||||
return NextOffset;
|
||||
|
||||
/// getDataSize() - Get the record data size, which is the record size
|
||||
/// without tail padding, in bits.
|
||||
uint64_t getDataSize() const {
|
||||
return DataSize;
|
||||
}
|
||||
|
||||
/// getNonVirtualSize - Get the non-virtual size (in bits) of an object,
|
||||
/// which is the size of the object without virtual bases.
|
||||
uint64_t getNonVirtualSize() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
|
||||
return CXXInfo->NonVirtualSize;
|
||||
}
|
||||
|
||||
/// getNonVirtualSize - Get the non-virtual alignment (in bits) of an object,
|
||||
/// which is the alignment of the object without virtual bases.
|
||||
unsigned getNonVirtualAlign() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
|
||||
return CXXInfo->NonVirtualAlign;
|
||||
}
|
||||
|
||||
/// getPrimaryBase - Get the primary base.
|
||||
const CXXRecordDecl *getPrimaryBase() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
|
||||
return CXXInfo->PrimaryBase;
|
||||
}
|
||||
/// getPrimaryBaseWasVirtual - Indicates if the primary base was virtual.
|
||||
bool getPrimaryBaseWasVirtual() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
|
||||
return CXXInfo->PrimaryBaseWasVirtual;
|
||||
}
|
||||
|
||||
/// getBaseClassOffset - Get the offset, in bits, for the given base class.
|
||||
uint64_t getBaseClassOffset(const CXXRecordDecl *Base) const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!");
|
||||
|
||||
return CXXInfo->BaseOffsets[Base];
|
||||
}
|
||||
|
||||
/// getVBaseClassOffset - Get the offset, in bits, for the given base class.
|
||||
uint64_t getVBaseClassOffset(const CXXRecordDecl *VBase) const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!");
|
||||
|
||||
return CXXInfo->VBaseOffsets[VBase];
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
162
include/clang/AST/Redeclarable.h
Normal file
162
include/clang/AST/Redeclarable.h
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
//===-- Redeclarable.h - Base for Decls that can be redeclared -*- 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 Redeclarable interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_REDECLARABLE_H
|
||||
#define LLVM_CLANG_AST_REDECLARABLE_H
|
||||
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// \brief Provides common interface for the Decls that can be redeclared.
|
||||
template<typename decl_type>
|
||||
class Redeclarable {
|
||||
|
||||
protected:
|
||||
struct DeclLink : public llvm::PointerIntPair<decl_type *, 1, bool> {
|
||||
DeclLink(decl_type *D, bool isLatest)
|
||||
: llvm::PointerIntPair<decl_type *, 1, bool>(D, isLatest) { }
|
||||
|
||||
typedef llvm::PointerIntPair<decl_type *, 1, bool> base_type;
|
||||
|
||||
bool NextIsPrevious() const { return base_type::getInt() == false; }
|
||||
bool NextIsLatest() const { return base_type::getInt() == true; }
|
||||
decl_type *getNext() const { return base_type::getPointer(); }
|
||||
};
|
||||
|
||||
struct PreviousDeclLink : public DeclLink {
|
||||
PreviousDeclLink(decl_type *D) : DeclLink(D, false) { }
|
||||
};
|
||||
|
||||
struct LatestDeclLink : public DeclLink {
|
||||
LatestDeclLink(decl_type *D) : DeclLink(D, true) { }
|
||||
};
|
||||
|
||||
/// \brief Points to the next redeclaration in the chain.
|
||||
///
|
||||
/// If NextIsPrevious() is true, this is a link to the previous declaration
|
||||
/// of this same Decl. If NextIsLatest() is true, this is the first
|
||||
/// declaration and Link points to the latest declaration. For example:
|
||||
///
|
||||
/// #1 int f(int x, int y = 1); // <pointer to #3, true>
|
||||
/// #2 int f(int x = 0, int y); // <pointer to #1, false>
|
||||
/// #3 int f(int x, int y) { return x + y; } // <pointer to #2, false>
|
||||
///
|
||||
/// If there is only one declaration, it is <pointer to self, true>
|
||||
DeclLink RedeclLink;
|
||||
|
||||
public:
|
||||
Redeclarable() : RedeclLink(LatestDeclLink(static_cast<decl_type*>(this))) { }
|
||||
|
||||
/// \brief Return the previous declaration of this declaration or NULL if this
|
||||
/// is the first declaration.
|
||||
decl_type *getPreviousDeclaration() {
|
||||
if (RedeclLink.NextIsPrevious())
|
||||
return RedeclLink.getNext();
|
||||
return 0;
|
||||
}
|
||||
const decl_type *getPreviousDeclaration() const {
|
||||
return const_cast<decl_type *>(
|
||||
static_cast<const decl_type*>(this))->getPreviousDeclaration();
|
||||
}
|
||||
|
||||
/// \brief Return the first declaration of this declaration or itself if this
|
||||
/// is the only declaration.
|
||||
decl_type *getFirstDeclaration() {
|
||||
decl_type *D = static_cast<decl_type*>(this);
|
||||
while (D->getPreviousDeclaration())
|
||||
D = D->getPreviousDeclaration();
|
||||
return D;
|
||||
}
|
||||
|
||||
/// \brief Return the first declaration of this declaration or itself if this
|
||||
/// is the only declaration.
|
||||
const decl_type *getFirstDeclaration() const {
|
||||
const decl_type *D = static_cast<const decl_type*>(this);
|
||||
while (D->getPreviousDeclaration())
|
||||
D = D->getPreviousDeclaration();
|
||||
return D;
|
||||
}
|
||||
|
||||
/// \brief Set the previous declaration. If PrevDecl is NULL, set this as the
|
||||
/// first and only declaration.
|
||||
void setPreviousDeclaration(decl_type *PrevDecl) {
|
||||
decl_type *First;
|
||||
|
||||
if (PrevDecl) {
|
||||
// Point to previous.
|
||||
RedeclLink = PreviousDeclLink(PrevDecl);
|
||||
First = PrevDecl->getFirstDeclaration();
|
||||
assert(First->RedeclLink.NextIsLatest() && "Expected first");
|
||||
} else {
|
||||
// Make this first.
|
||||
First = static_cast<decl_type*>(this);
|
||||
}
|
||||
|
||||
// First one will point to this one as latest.
|
||||
First->RedeclLink = LatestDeclLink(static_cast<decl_type*>(this));
|
||||
}
|
||||
|
||||
/// \brief Iterates through all the redeclarations of the same decl.
|
||||
class redecl_iterator {
|
||||
/// Current - The current declaration.
|
||||
decl_type *Current;
|
||||
decl_type *Starter;
|
||||
|
||||
public:
|
||||
typedef decl_type* value_type;
|
||||
typedef decl_type* reference;
|
||||
typedef decl_type* pointer;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
redecl_iterator() : Current(0) { }
|
||||
explicit redecl_iterator(decl_type *C) : Current(C), Starter(C) { }
|
||||
|
||||
reference operator*() const { return Current; }
|
||||
pointer operator->() const { return Current; }
|
||||
|
||||
redecl_iterator& operator++() {
|
||||
assert(Current && "Advancing while iterator has reached end");
|
||||
// Get either previous decl or latest decl.
|
||||
decl_type *Next = Current->RedeclLink.getNext();
|
||||
Current = (Next != Starter ? Next : 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
redecl_iterator operator++(int) {
|
||||
redecl_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool operator==(redecl_iterator x, redecl_iterator y) {
|
||||
return x.Current == y.Current;
|
||||
}
|
||||
friend bool operator!=(redecl_iterator x, redecl_iterator y) {
|
||||
return x.Current != y.Current;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Returns iterator for all the redeclarations of the same decl.
|
||||
/// It will iterate at least once (when this decl is the only one).
|
||||
redecl_iterator redecls_begin() const {
|
||||
return redecl_iterator(const_cast<decl_type*>(
|
||||
static_cast<const decl_type*>(this)));
|
||||
}
|
||||
redecl_iterator redecls_end() const { return redecl_iterator(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -29,13 +29,14 @@ class CXXCatchStmt : public Stmt {
|
|||
/// The handler block.
|
||||
Stmt *HandlerBlock;
|
||||
|
||||
protected:
|
||||
virtual void DoDestroy(ASTContext& Ctx);
|
||||
|
||||
public:
|
||||
CXXCatchStmt(SourceLocation catchLoc, VarDecl *exDecl, Stmt *handlerBlock)
|
||||
: Stmt(CXXCatchStmtClass), CatchLoc(catchLoc), ExceptionDecl(exDecl),
|
||||
HandlerBlock(handlerBlock) {}
|
||||
|
||||
virtual void Destroy(ASTContext& Ctx);
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(CatchLoc, HandlerBlock->getLocEnd());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a template specialization of llvm::GraphTraits to
|
||||
// This file defines a template specialization of llvm::GraphTraits to
|
||||
// treat ASTs (Stmt*) as graphs
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
|
||||
//template <typename T> struct GraphTraits;
|
||||
|
||||
|
||||
|
|
@ -28,23 +28,23 @@ template <> struct GraphTraits<clang::Stmt*> {
|
|||
typedef clang::Stmt NodeType;
|
||||
typedef clang::Stmt::child_iterator ChildIteratorType;
|
||||
typedef llvm::df_iterator<clang::Stmt*> nodes_iterator;
|
||||
|
||||
|
||||
static NodeType* getEntryNode(clang::Stmt* S) { return S; }
|
||||
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N) {
|
||||
if (N) return N->child_begin();
|
||||
else return ChildIteratorType();
|
||||
}
|
||||
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N) {
|
||||
if (N) return N->child_end();
|
||||
else return ChildIteratorType();
|
||||
}
|
||||
|
||||
|
||||
static nodes_iterator nodes_begin(clang::Stmt* S) {
|
||||
return df_begin(S);
|
||||
}
|
||||
|
||||
|
||||
static nodes_iterator nodes_end(clang::Stmt* S) {
|
||||
return df_end(S);
|
||||
}
|
||||
|
|
@ -55,29 +55,29 @@ template <> struct GraphTraits<const clang::Stmt*> {
|
|||
typedef const clang::Stmt NodeType;
|
||||
typedef clang::Stmt::const_child_iterator ChildIteratorType;
|
||||
typedef llvm::df_iterator<const clang::Stmt*> nodes_iterator;
|
||||
|
||||
|
||||
static NodeType* getEntryNode(const clang::Stmt* S) { return S; }
|
||||
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N) {
|
||||
if (N) return N->child_begin();
|
||||
else return ChildIteratorType();
|
||||
else return ChildIteratorType();
|
||||
}
|
||||
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N) {
|
||||
if (N) return N->child_end();
|
||||
else return ChildIteratorType();
|
||||
}
|
||||
|
||||
|
||||
static nodes_iterator nodes_begin(const clang::Stmt* S) {
|
||||
return df_begin(S);
|
||||
}
|
||||
|
||||
|
||||
static nodes_iterator nodes_end(const clang::Stmt* S) {
|
||||
return df_end(S);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -14,54 +14,54 @@
|
|||
#ifndef LLVM_CLANG_AST_STMT_ITR_H
|
||||
#define LLVM_CLANG_AST_STMT_ITR_H
|
||||
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Stmt;
|
||||
class Decl;
|
||||
class VariableArrayType;
|
||||
|
||||
|
||||
class StmtIteratorBase {
|
||||
protected:
|
||||
enum { DeclMode = 0x1, SizeOfTypeVAMode = 0x2, DeclGroupMode = 0x3,
|
||||
Flags = 0x3 };
|
||||
|
||||
|
||||
union { Stmt** stmt; Decl* decl; Decl** DGI; };
|
||||
uintptr_t RawVAPtr;
|
||||
uintptr_t RawVAPtr;
|
||||
Decl** DGE;
|
||||
|
||||
bool inDecl() const {
|
||||
return (RawVAPtr & Flags) == DeclMode;
|
||||
}
|
||||
|
||||
|
||||
bool inDeclGroup() const {
|
||||
return (RawVAPtr & Flags) == DeclGroupMode;
|
||||
}
|
||||
|
||||
bool inSizeOfTypeVA() const {
|
||||
|
||||
bool inSizeOfTypeVA() const {
|
||||
return (RawVAPtr & Flags) == SizeOfTypeVAMode;
|
||||
}
|
||||
|
||||
|
||||
bool inStmt() const {
|
||||
return (RawVAPtr & Flags) == 0;
|
||||
}
|
||||
|
||||
|
||||
VariableArrayType* getVAPtr() const {
|
||||
return reinterpret_cast<VariableArrayType*>(RawVAPtr & ~Flags);
|
||||
}
|
||||
|
||||
|
||||
void setVAPtr(VariableArrayType* P) {
|
||||
assert (inDecl() || inDeclGroup() || inSizeOfTypeVA());
|
||||
assert (inDecl() || inDeclGroup() || inSizeOfTypeVA());
|
||||
RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags);
|
||||
}
|
||||
|
||||
|
||||
void NextDecl(bool ImmediateAdvance = true);
|
||||
bool HandleDecl(Decl* D);
|
||||
void NextVA();
|
||||
|
||||
|
||||
Stmt*& GetDeclExpr() const;
|
||||
|
||||
StmtIteratorBase(Stmt** s) : stmt(s), RawVAPtr(0) {}
|
||||
|
|
@ -70,22 +70,22 @@ protected:
|
|||
StmtIteratorBase(Decl** dgi, Decl** dge);
|
||||
StmtIteratorBase() : stmt(NULL), RawVAPtr(0) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename DERIVED, typename REFERENCE>
|
||||
class StmtIteratorImpl : public StmtIteratorBase,
|
||||
class StmtIteratorImpl : public StmtIteratorBase,
|
||||
public std::iterator<std::forward_iterator_tag,
|
||||
REFERENCE, ptrdiff_t,
|
||||
REFERENCE, REFERENCE> {
|
||||
REFERENCE, ptrdiff_t,
|
||||
REFERENCE, REFERENCE> {
|
||||
protected:
|
||||
StmtIteratorImpl(const StmtIteratorBase& RHS) : StmtIteratorBase(RHS) {}
|
||||
public:
|
||||
StmtIteratorImpl() {}
|
||||
StmtIteratorImpl() {}
|
||||
StmtIteratorImpl(Stmt** s) : StmtIteratorBase(s) {}
|
||||
StmtIteratorImpl(Decl** dgi, Decl** dge) : StmtIteratorBase(dgi, dge) {}
|
||||
StmtIteratorImpl(Decl* d) : StmtIteratorBase(d) {}
|
||||
StmtIteratorImpl(VariableArrayType* t) : StmtIteratorBase(t) {}
|
||||
|
||||
|
||||
DERIVED& operator++() {
|
||||
if (inDecl() || inDeclGroup()) {
|
||||
if (getVAPtr()) NextVA();
|
||||
|
|
@ -95,36 +95,36 @@ public:
|
|||
NextVA();
|
||||
else
|
||||
++stmt;
|
||||
|
||||
|
||||
return static_cast<DERIVED&>(*this);
|
||||
}
|
||||
|
||||
|
||||
DERIVED operator++(int) {
|
||||
DERIVED tmp = static_cast<DERIVED&>(*this);
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
bool operator==(const DERIVED& RHS) const {
|
||||
return stmt == RHS.stmt && RawVAPtr == RHS.RawVAPtr;
|
||||
}
|
||||
|
||||
|
||||
bool operator!=(const DERIVED& RHS) const {
|
||||
return stmt != RHS.stmt || RawVAPtr != RHS.RawVAPtr;
|
||||
}
|
||||
|
||||
REFERENCE operator*() const {
|
||||
|
||||
REFERENCE operator*() const {
|
||||
return (REFERENCE) (inStmt() ? *stmt : GetDeclExpr());
|
||||
}
|
||||
|
||||
REFERENCE operator->() const { return operator*(); }
|
||||
|
||||
REFERENCE operator->() const { return operator*(); }
|
||||
};
|
||||
|
||||
struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
|
||||
explicit StmtIterator() : StmtIteratorImpl<StmtIterator,Stmt*&>() {}
|
||||
|
||||
StmtIterator(Stmt** S) : StmtIteratorImpl<StmtIterator,Stmt*&>(S) {}
|
||||
StmtIterator(Decl** dgi, Decl** dge)
|
||||
StmtIterator(Decl** dgi, Decl** dge)
|
||||
: StmtIteratorImpl<StmtIterator,Stmt*&>(dgi, dge) {}
|
||||
|
||||
StmtIterator(VariableArrayType* t):StmtIteratorImpl<StmtIterator,Stmt*&>(t) {}
|
||||
|
|
@ -133,10 +133,10 @@ struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
|
|||
|
||||
struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
|
||||
const Stmt*> {
|
||||
explicit ConstStmtIterator() :
|
||||
explicit ConstStmtIterator() :
|
||||
StmtIteratorImpl<ConstStmtIterator,const Stmt*>() {}
|
||||
|
||||
ConstStmtIterator(const StmtIterator& RHS) :
|
||||
|
||||
ConstStmtIterator(const StmtIterator& RHS) :
|
||||
StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@
|
|||
# define EXPR(Type, Base) STMT(Type, Base)
|
||||
#endif
|
||||
|
||||
#ifndef ABSTRACT_EXPR
|
||||
# define ABSTRACT_EXPR(Type, Base) EXPR(Type, Base)
|
||||
#endif
|
||||
|
||||
// Normal Statements.
|
||||
STMT(NullStmt , Stmt)
|
||||
FIRST_STMT(NullStmt)
|
||||
|
|
@ -64,7 +68,7 @@ STMT(CXXTryStmt , Stmt)
|
|||
LAST_STMT(CXXTryStmt)
|
||||
|
||||
// Expressions.
|
||||
EXPR(Expr , Stmt)
|
||||
ABSTRACT_EXPR(Expr , Stmt)
|
||||
FIRST_EXPR(Expr)
|
||||
EXPR(PredefinedExpr , Expr)
|
||||
EXPR(DeclRefExpr , Expr)
|
||||
|
|
@ -91,6 +95,7 @@ EXPR(ExtVectorElementExpr , Expr)
|
|||
EXPR(InitListExpr , Expr)
|
||||
EXPR(DesignatedInitExpr , Expr)
|
||||
EXPR(ImplicitValueInitExpr , Expr)
|
||||
EXPR(ParenListExpr , Expr)
|
||||
EXPR(VAArgExpr , Expr)
|
||||
|
||||
// GNU Extensions.
|
||||
|
|
@ -119,6 +124,7 @@ EXPR(CXXZeroInitValueExpr , Expr)
|
|||
EXPR(CXXConditionDeclExpr , DeclRefExpr)
|
||||
EXPR(CXXNewExpr , Expr)
|
||||
EXPR(CXXDeleteExpr , Expr)
|
||||
EXPR(CXXPseudoDestructorExpr, Expr)
|
||||
EXPR(UnresolvedFunctionNameExpr , Expr)
|
||||
EXPR(UnaryTypeTraitExpr , Expr)
|
||||
EXPR(QualifiedDeclRefExpr , DeclRefExpr)
|
||||
|
|
@ -139,8 +145,9 @@ EXPR(ObjCSelectorExpr , Expr)
|
|||
EXPR(ObjCProtocolExpr , Expr)
|
||||
EXPR(ObjCIvarRefExpr , Expr)
|
||||
EXPR(ObjCPropertyRefExpr , Expr)
|
||||
EXPR(ObjCKVCRefExpr , Expr)
|
||||
EXPR(ObjCImplicitSetterGetterRefExpr , Expr)
|
||||
EXPR(ObjCSuperExpr , Expr)
|
||||
EXPR(ObjCIsaExpr , Expr)
|
||||
|
||||
// Clang Extensions.
|
||||
EXPR(ShuffleVectorExpr , Expr)
|
||||
|
|
@ -149,8 +156,9 @@ EXPR(BlockDeclRefExpr , Expr)
|
|||
|
||||
LAST_EXPR(BlockDeclRefExpr)
|
||||
|
||||
#undef STMT
|
||||
#undef ABSTRACT_EXPR
|
||||
#undef EXPR
|
||||
#undef STMT
|
||||
#undef FIRST_STMT
|
||||
#undef LAST_STMT
|
||||
#undef FIRST_EXPR
|
||||
|
|
|
|||
|
|
@ -27,47 +27,47 @@ class ObjCForCollectionStmt : public Stmt {
|
|||
SourceLocation ForLoc;
|
||||
SourceLocation RParenLoc;
|
||||
public:
|
||||
ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, Stmt *Body,
|
||||
ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, Stmt *Body,
|
||||
SourceLocation FCL, SourceLocation RPL);
|
||||
explicit ObjCForCollectionStmt(EmptyShell Empty) :
|
||||
explicit ObjCForCollectionStmt(EmptyShell Empty) :
|
||||
Stmt(ObjCForCollectionStmtClass, Empty) { }
|
||||
|
||||
|
||||
Stmt *getElement() { return SubExprs[ELEM]; }
|
||||
Expr *getCollection() {
|
||||
return reinterpret_cast<Expr*>(SubExprs[COLLECTION]);
|
||||
Expr *getCollection() {
|
||||
return reinterpret_cast<Expr*>(SubExprs[COLLECTION]);
|
||||
}
|
||||
Stmt *getBody() { return SubExprs[BODY]; }
|
||||
|
||||
|
||||
const Stmt *getElement() const { return SubExprs[ELEM]; }
|
||||
const Expr *getCollection() const {
|
||||
const Expr *getCollection() const {
|
||||
return reinterpret_cast<Expr*>(SubExprs[COLLECTION]);
|
||||
}
|
||||
const Stmt *getBody() const { return SubExprs[BODY]; }
|
||||
|
||||
|
||||
void setElement(Stmt *S) { SubExprs[ELEM] = S; }
|
||||
void setCollection(Expr *E) {
|
||||
void setCollection(Expr *E) {
|
||||
SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(E);
|
||||
}
|
||||
void setBody(Stmt *S) { SubExprs[BODY] = S; }
|
||||
|
||||
|
||||
SourceLocation getForLoc() const { return ForLoc; }
|
||||
void setForLoc(SourceLocation Loc) { ForLoc = Loc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCForCollectionStmtClass;
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCForCollectionStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCForCollectionStmt *) { return true; }
|
||||
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
/// ObjCAtCatchStmt - This represents objective-c's @catch statement.
|
||||
class ObjCAtCatchStmt : public Stmt {
|
||||
private:
|
||||
|
|
@ -78,95 +78,95 @@ private:
|
|||
|
||||
public:
|
||||
ObjCAtCatchStmt(SourceLocation atCatchLoc, SourceLocation rparenloc,
|
||||
ParmVarDecl *catchVarDecl,
|
||||
ParmVarDecl *catchVarDecl,
|
||||
Stmt *atCatchStmt, Stmt *atCatchList);
|
||||
|
||||
explicit ObjCAtCatchStmt(EmptyShell Empty) :
|
||||
explicit ObjCAtCatchStmt(EmptyShell Empty) :
|
||||
Stmt(ObjCAtCatchStmtClass, Empty) { }
|
||||
|
||||
|
||||
const Stmt *getCatchBody() const { return SubExprs[BODY]; }
|
||||
Stmt *getCatchBody() { return SubExprs[BODY]; }
|
||||
void setCatchBody(Stmt *S) { SubExprs[BODY] = S; }
|
||||
|
||||
|
||||
const ObjCAtCatchStmt *getNextCatchStmt() const {
|
||||
return static_cast<const ObjCAtCatchStmt*>(SubExprs[NEXT_CATCH]);
|
||||
}
|
||||
ObjCAtCatchStmt *getNextCatchStmt() {
|
||||
ObjCAtCatchStmt *getNextCatchStmt() {
|
||||
return static_cast<ObjCAtCatchStmt*>(SubExprs[NEXT_CATCH]);
|
||||
}
|
||||
void setNextCatchStmt(Stmt *S) { SubExprs[NEXT_CATCH] = S; }
|
||||
|
||||
const ParmVarDecl *getCatchParamDecl() const {
|
||||
return ExceptionDecl;
|
||||
|
||||
const ParmVarDecl *getCatchParamDecl() const {
|
||||
return ExceptionDecl;
|
||||
}
|
||||
ParmVarDecl *getCatchParamDecl() {
|
||||
return ExceptionDecl;
|
||||
ParmVarDecl *getCatchParamDecl() {
|
||||
return ExceptionDecl;
|
||||
}
|
||||
void setCatchParamDecl(ParmVarDecl *D) { ExceptionDecl = D; }
|
||||
|
||||
|
||||
SourceLocation getAtCatchLoc() const { return AtCatchLoc; }
|
||||
void setAtCatchLoc(SourceLocation Loc) { AtCatchLoc = Loc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtCatchLoc, SubExprs[BODY]->getLocEnd());
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtCatchLoc, SubExprs[BODY]->getLocEnd());
|
||||
}
|
||||
|
||||
bool hasEllipsis() const { return getCatchParamDecl() == 0; }
|
||||
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtCatchStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCAtCatchStmt *) { return true; }
|
||||
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// ObjCAtFinallyStmt - This represent objective-c's @finally Statement
|
||||
|
||||
/// ObjCAtFinallyStmt - This represent objective-c's @finally Statement
|
||||
class ObjCAtFinallyStmt : public Stmt {
|
||||
Stmt *AtFinallyStmt;
|
||||
SourceLocation AtFinallyLoc;
|
||||
SourceLocation AtFinallyLoc;
|
||||
public:
|
||||
ObjCAtFinallyStmt(SourceLocation atFinallyLoc, Stmt *atFinallyStmt)
|
||||
: Stmt(ObjCAtFinallyStmtClass),
|
||||
: Stmt(ObjCAtFinallyStmtClass),
|
||||
AtFinallyStmt(atFinallyStmt), AtFinallyLoc(atFinallyLoc) {}
|
||||
|
||||
explicit ObjCAtFinallyStmt(EmptyShell Empty) :
|
||||
explicit ObjCAtFinallyStmt(EmptyShell Empty) :
|
||||
Stmt(ObjCAtFinallyStmtClass, Empty) { }
|
||||
|
||||
|
||||
const Stmt *getFinallyBody() const { return AtFinallyStmt; }
|
||||
Stmt *getFinallyBody() { return AtFinallyStmt; }
|
||||
void setFinallyBody(Stmt *S) { AtFinallyStmt = S; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtFinallyLoc, AtFinallyStmt->getLocEnd());
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtFinallyLoc, AtFinallyStmt->getLocEnd());
|
||||
}
|
||||
|
||||
|
||||
SourceLocation getAtFinallyLoc() const { return AtFinallyLoc; }
|
||||
void setAtFinallyLoc(SourceLocation Loc) { AtFinallyLoc = Loc; }
|
||||
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtFinallyStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCAtFinallyStmt *) { return true; }
|
||||
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// ObjCAtTryStmt - This represent objective-c's over-all
|
||||
|
||||
/// ObjCAtTryStmt - This represent objective-c's over-all
|
||||
/// @try ... @catch ... @finally statement.
|
||||
class ObjCAtTryStmt : public Stmt {
|
||||
private:
|
||||
enum { TRY, CATCH, FINALLY, END_EXPR };
|
||||
Stmt* SubStmts[END_EXPR];
|
||||
|
||||
SourceLocation AtTryLoc;
|
||||
Stmt* SubStmts[END_EXPR];
|
||||
|
||||
SourceLocation AtTryLoc;
|
||||
public:
|
||||
ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
|
||||
Stmt *atCatchStmt,
|
||||
ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
|
||||
Stmt *atCatchStmt,
|
||||
Stmt *atFinallyStmt)
|
||||
: Stmt(ObjCAtTryStmtClass) {
|
||||
SubStmts[TRY] = atTryStmt;
|
||||
|
|
@ -174,41 +174,41 @@ public:
|
|||
SubStmts[FINALLY] = atFinallyStmt;
|
||||
AtTryLoc = atTryLoc;
|
||||
}
|
||||
explicit ObjCAtTryStmt(EmptyShell Empty) :
|
||||
explicit ObjCAtTryStmt(EmptyShell Empty) :
|
||||
Stmt(ObjCAtTryStmtClass, Empty) { }
|
||||
|
||||
|
||||
SourceLocation getAtTryLoc() const { return AtTryLoc; }
|
||||
void setAtTryLoc(SourceLocation Loc) { AtTryLoc = Loc; }
|
||||
|
||||
|
||||
const Stmt *getTryBody() const { return SubStmts[TRY]; }
|
||||
Stmt *getTryBody() { return SubStmts[TRY]; }
|
||||
void setTryBody(Stmt *S) { SubStmts[TRY] = S; }
|
||||
|
||||
const ObjCAtCatchStmt *getCatchStmts() const {
|
||||
return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]);
|
||||
|
||||
const ObjCAtCatchStmt *getCatchStmts() const {
|
||||
return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]);
|
||||
}
|
||||
ObjCAtCatchStmt *getCatchStmts() {
|
||||
return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]);
|
||||
ObjCAtCatchStmt *getCatchStmts() {
|
||||
return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]);
|
||||
}
|
||||
void setCatchStmts(Stmt *S) { SubStmts[CATCH] = S; }
|
||||
|
||||
const ObjCAtFinallyStmt *getFinallyStmt() const {
|
||||
return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]);
|
||||
|
||||
const ObjCAtFinallyStmt *getFinallyStmt() const {
|
||||
return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]);
|
||||
}
|
||||
ObjCAtFinallyStmt *getFinallyStmt() {
|
||||
return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]);
|
||||
ObjCAtFinallyStmt *getFinallyStmt() {
|
||||
return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]);
|
||||
}
|
||||
void setFinallyStmt(Stmt *S) { SubStmts[FINALLY] = S; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtTryLoc, SubStmts[TRY]->getLocEnd());
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtTryLoc, SubStmts[TRY]->getLocEnd());
|
||||
}
|
||||
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtTryStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCAtTryStmt *) { return true; }
|
||||
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
|
@ -223,7 +223,7 @@ private:
|
|||
enum { SYNC_EXPR, SYNC_BODY, END_EXPR };
|
||||
Stmt* SubStmts[END_EXPR];
|
||||
SourceLocation AtSynchronizedLoc;
|
||||
|
||||
|
||||
public:
|
||||
ObjCAtSynchronizedStmt(SourceLocation atSynchronizedLoc, Stmt *synchExpr,
|
||||
Stmt *synchBody)
|
||||
|
|
@ -232,41 +232,41 @@ public:
|
|||
SubStmts[SYNC_BODY] = synchBody;
|
||||
AtSynchronizedLoc = atSynchronizedLoc;
|
||||
}
|
||||
explicit ObjCAtSynchronizedStmt(EmptyShell Empty) :
|
||||
explicit ObjCAtSynchronizedStmt(EmptyShell Empty) :
|
||||
Stmt(ObjCAtSynchronizedStmtClass, Empty) { }
|
||||
|
||||
|
||||
SourceLocation getAtSynchronizedLoc() const { return AtSynchronizedLoc; }
|
||||
void setAtSynchronizedLoc(SourceLocation Loc) { AtSynchronizedLoc = Loc; }
|
||||
|
||||
|
||||
const CompoundStmt *getSynchBody() const {
|
||||
return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]);
|
||||
}
|
||||
CompoundStmt *getSynchBody() {
|
||||
return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]);
|
||||
CompoundStmt *getSynchBody() {
|
||||
return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]);
|
||||
}
|
||||
void setSynchBody(Stmt *S) { SubStmts[SYNC_BODY] = S; }
|
||||
|
||||
const Expr *getSynchExpr() const {
|
||||
return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]);
|
||||
|
||||
const Expr *getSynchExpr() const {
|
||||
return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]);
|
||||
}
|
||||
Expr *getSynchExpr() {
|
||||
return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]);
|
||||
Expr *getSynchExpr() {
|
||||
return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]);
|
||||
}
|
||||
void setSynchExpr(Stmt *S) { SubStmts[SYNC_EXPR] = S; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtSynchronizedLoc, getSynchBody()->getLocEnd());
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtSynchronizedLoc, getSynchBody()->getLocEnd());
|
||||
}
|
||||
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtSynchronizedStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCAtSynchronizedStmt *) { return true; }
|
||||
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
|
||||
/// ObjCAtThrowStmt - This represents objective-c's @throw statement.
|
||||
class ObjCAtThrowStmt : public Stmt {
|
||||
Stmt *Throw;
|
||||
|
|
@ -276,28 +276,28 @@ public:
|
|||
: Stmt(ObjCAtThrowStmtClass), Throw(throwExpr) {
|
||||
AtThrowLoc = atThrowLoc;
|
||||
}
|
||||
explicit ObjCAtThrowStmt(EmptyShell Empty) :
|
||||
explicit ObjCAtThrowStmt(EmptyShell Empty) :
|
||||
Stmt(ObjCAtThrowStmtClass, Empty) { }
|
||||
|
||||
|
||||
const Expr *getThrowExpr() const { return reinterpret_cast<Expr*>(Throw); }
|
||||
Expr *getThrowExpr() { return reinterpret_cast<Expr*>(Throw); }
|
||||
void setThrowExpr(Stmt *S) { Throw = S; }
|
||||
|
||||
|
||||
SourceLocation getThrowLoc() { return AtThrowLoc; }
|
||||
void setThrowLoc(SourceLocation Loc) { AtThrowLoc = Loc; }
|
||||
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
if (Throw)
|
||||
return SourceRange(AtThrowLoc, Throw->getLocEnd());
|
||||
else
|
||||
return SourceRange(AtThrowLoc, Throw->getLocEnd());
|
||||
else
|
||||
return SourceRange(AtThrowLoc);
|
||||
}
|
||||
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtThrowStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCAtThrowStmt *) { return true; }
|
||||
|
||||
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,17 +20,17 @@
|
|||
#include "clang/AST/StmtObjC.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
#define DISPATCH(NAME, CLASS) \
|
||||
return static_cast<ImplClass*>(this)->Visit ## NAME(static_cast<CLASS*>(S))
|
||||
|
||||
|
||||
/// StmtVisitor - This class implements a simple visitor for Stmt subclasses.
|
||||
/// Since Expr derives from Stmt, this also includes support for visiting Exprs.
|
||||
template<typename ImplClass, typename RetTy=void>
|
||||
class StmtVisitor {
|
||||
public:
|
||||
RetTy Visit(Stmt *S) {
|
||||
|
||||
|
||||
// If we have a binary expr, dispatch to the subcode of the binop. A smart
|
||||
// optimizer (e.g. LLVM) will fold this comparison into the switch stmt
|
||||
// below.
|
||||
|
|
@ -53,7 +53,7 @@ public:
|
|||
case BinaryOperator::GE: DISPATCH(BinGE, BinaryOperator);
|
||||
case BinaryOperator::EQ: DISPATCH(BinEQ, BinaryOperator);
|
||||
case BinaryOperator::NE: DISPATCH(BinNE, BinaryOperator);
|
||||
|
||||
|
||||
case BinaryOperator::And: DISPATCH(BinAnd, BinaryOperator);
|
||||
case BinaryOperator::Xor: DISPATCH(BinXor, BinaryOperator);
|
||||
case BinaryOperator::Or : DISPATCH(BinOr, BinaryOperator);
|
||||
|
|
@ -101,7 +101,7 @@ public:
|
|||
case UnaryOperator::OffsetOf: DISPATCH(UnaryOffsetOf, UnaryOperator);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Top switch stmt: dispatch to VisitFooStmt for each FooStmt.
|
||||
switch (S->getStmtClass()) {
|
||||
default: assert(0 && "Unknown stmt kind!");
|
||||
|
|
@ -110,7 +110,7 @@ public:
|
|||
#include "clang/AST/StmtNodes.def"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If the implementation chooses not to implement a certain visit method, fall
|
||||
// back on VisitExpr or whatever else is the superclass.
|
||||
#define STMT(CLASS, PARENT) \
|
||||
|
|
@ -127,7 +127,7 @@ public:
|
|||
BINOP_FALLBACK(Mul) BINOP_FALLBACK(Div) BINOP_FALLBACK(Rem)
|
||||
BINOP_FALLBACK(Add) BINOP_FALLBACK(Sub) BINOP_FALLBACK(Shl)
|
||||
BINOP_FALLBACK(Shr)
|
||||
|
||||
|
||||
BINOP_FALLBACK(LT) BINOP_FALLBACK(GT) BINOP_FALLBACK(LE)
|
||||
BINOP_FALLBACK(GE) BINOP_FALLBACK(EQ) BINOP_FALLBACK(NE)
|
||||
BINOP_FALLBACK(And) BINOP_FALLBACK(Xor) BINOP_FALLBACK(Or)
|
||||
|
|
@ -148,7 +148,7 @@ public:
|
|||
CAO_FALLBACK(ShrAssign) CAO_FALLBACK(AndAssign) CAO_FALLBACK(OrAssign)
|
||||
CAO_FALLBACK(XorAssign)
|
||||
#undef CAO_FALLBACK
|
||||
|
||||
|
||||
// If the implementation doesn't implement unary operator methods, fall back
|
||||
// on VisitUnaryOperator.
|
||||
#define UNARYOP_FALLBACK(NAME) \
|
||||
|
|
@ -158,13 +158,13 @@ public:
|
|||
UNARYOP_FALLBACK(PostInc) UNARYOP_FALLBACK(PostDec)
|
||||
UNARYOP_FALLBACK(PreInc) UNARYOP_FALLBACK(PreDec)
|
||||
UNARYOP_FALLBACK(AddrOf) UNARYOP_FALLBACK(Deref)
|
||||
|
||||
|
||||
UNARYOP_FALLBACK(Plus) UNARYOP_FALLBACK(Minus)
|
||||
UNARYOP_FALLBACK(Not) UNARYOP_FALLBACK(LNot)
|
||||
UNARYOP_FALLBACK(Real) UNARYOP_FALLBACK(Imag)
|
||||
UNARYOP_FALLBACK(Extension) UNARYOP_FALLBACK(OffsetOf)
|
||||
#undef UNARYOP_FALLBACK
|
||||
|
||||
|
||||
// Base case, ignore it. :)
|
||||
RetTy VisitStmt(Stmt *Node) { return RetTy(); }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,9 +26,11 @@ namespace clang {
|
|||
class DependentTemplateName;
|
||||
class IdentifierInfo;
|
||||
class NestedNameSpecifier;
|
||||
class PrintingPolicy;
|
||||
struct PrintingPolicy;
|
||||
class QualifiedTemplateName;
|
||||
class NamedDecl;
|
||||
class TemplateDecl;
|
||||
class OverloadedFunctionDecl;
|
||||
|
||||
/// \brief Represents a C++ template name within the type system.
|
||||
///
|
||||
|
|
@ -58,7 +60,8 @@ class TemplateDecl;
|
|||
/// specifier in the typedef. "apply" is a nested template, and can
|
||||
/// only be understood in the context of
|
||||
class TemplateName {
|
||||
typedef llvm::PointerUnion3<TemplateDecl *, QualifiedTemplateName *,
|
||||
typedef llvm::PointerUnion4<TemplateDecl *, OverloadedFunctionDecl *,
|
||||
QualifiedTemplateName *,
|
||||
DependentTemplateName *> StorageType;
|
||||
|
||||
StorageType Storage;
|
||||
|
|
@ -70,17 +73,32 @@ class TemplateName {
|
|||
public:
|
||||
TemplateName() : Storage() { }
|
||||
explicit TemplateName(TemplateDecl *Template) : Storage(Template) { }
|
||||
explicit TemplateName(OverloadedFunctionDecl *FunctionTemplates)
|
||||
: Storage(FunctionTemplates) { }
|
||||
explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { }
|
||||
explicit TemplateName(DependentTemplateName *Dep) : Storage(Dep) { }
|
||||
|
||||
/// \brief Determine whether this template name is NULL.
|
||||
bool isNull() const { return Storage.isNull(); }
|
||||
|
||||
/// \brief Retrieve the the underlying template declaration that
|
||||
/// this template name refers to, if known.
|
||||
///
|
||||
/// \returns The template declaration that this template name refers
|
||||
/// to, if any. If the template name does not refer to a specific
|
||||
/// declaration because it is a dependent name, returns NULL.
|
||||
/// declaration because it is a dependent name, or if it refers to a
|
||||
/// set of function templates, returns NULL.
|
||||
TemplateDecl *getAsTemplateDecl() const;
|
||||
|
||||
/// \brief Retrieve the the underlying, overloaded function template
|
||||
// declarations that this template name refers to, if known.
|
||||
///
|
||||
/// \returns The set of overloaded function templates that this template
|
||||
/// name refers to, if known. If the template name does not refer to a
|
||||
/// specific set of function templates because it is a dependent name or
|
||||
/// refers to a single template, returns NULL.
|
||||
OverloadedFunctionDecl *getAsOverloadedFunctionDecl() const;
|
||||
|
||||
/// \brief Retrieve the underlying qualified template name
|
||||
/// structure, if any.
|
||||
QualifiedTemplateName *getAsQualifiedTemplateName() const {
|
||||
|
|
@ -119,8 +137,8 @@ public:
|
|||
void *getAsVoidPointer() const { return Storage.getOpaqueValue(); }
|
||||
|
||||
/// \brief Build a template name from a void pointer.
|
||||
static TemplateName getFromVoidPointer(void *Ptr) {
|
||||
return TemplateName(Ptr);
|
||||
static TemplateName getFromVoidPointer(void *Ptr) {
|
||||
return TemplateName(Ptr);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -145,15 +163,21 @@ class QualifiedTemplateName : public llvm::FoldingSetNode {
|
|||
/// this name with DependentTemplateName).
|
||||
llvm::PointerIntPair<NestedNameSpecifier *, 1> Qualifier;
|
||||
|
||||
/// \brief The template declaration that this qualified name refers
|
||||
/// to.
|
||||
TemplateDecl *Template;
|
||||
/// \brief The template declaration or set of overloaded function templates
|
||||
/// that this qualified name refers to.
|
||||
NamedDecl *Template;
|
||||
|
||||
friend class ASTContext;
|
||||
|
||||
QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword,
|
||||
TemplateDecl *Template)
|
||||
: Qualifier(NNS, TemplateKeyword? 1 : 0), Template(Template) { }
|
||||
: Qualifier(NNS, TemplateKeyword? 1 : 0),
|
||||
Template(reinterpret_cast<NamedDecl *>(Template)) { }
|
||||
|
||||
QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword,
|
||||
OverloadedFunctionDecl *Template)
|
||||
: Qualifier(NNS, TemplateKeyword? 1 : 0),
|
||||
Template(reinterpret_cast<NamedDecl *>(Template)) { }
|
||||
|
||||
public:
|
||||
/// \brief Return the nested name specifier that qualifies this name.
|
||||
|
|
@ -163,16 +187,26 @@ public:
|
|||
/// keyword.
|
||||
bool hasTemplateKeyword() const { return Qualifier.getInt(); }
|
||||
|
||||
/// \brief The template declaration or set of overloaded functions that
|
||||
/// that qualified name refers to.
|
||||
NamedDecl *getDecl() const { return Template; }
|
||||
|
||||
/// \brief The template declaration to which this qualified name
|
||||
/// refers.
|
||||
TemplateDecl *getTemplateDecl() const { return Template; }
|
||||
/// refers, or NULL if this qualified name refers to a set of overloaded
|
||||
/// function templates.
|
||||
TemplateDecl *getTemplateDecl() const;
|
||||
|
||||
/// \brief The set of overloaded function tempaltes to which this qualified
|
||||
/// name refers, or NULL if this qualified name refers to a single
|
||||
/// template declaration.
|
||||
OverloadedFunctionDecl *getOverloadedFunctionDecl() const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getQualifier(), hasTemplateKeyword(), getTemplateDecl());
|
||||
Profile(ID, getQualifier(), hasTemplateKeyword(), getDecl());
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
|
||||
bool TemplateKeyword, TemplateDecl *Template) {
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
|
||||
bool TemplateKeyword, NamedDecl *Template) {
|
||||
ID.AddPointer(NNS);
|
||||
ID.AddBoolean(TemplateKeyword);
|
||||
ID.AddPointer(Template);
|
||||
|
|
@ -183,7 +217,7 @@ public:
|
|||
/// resolved prior to template instantiation.
|
||||
///
|
||||
/// This kind of template name refers to a dependent template name,
|
||||
/// including its nested name specifier. For example,
|
||||
/// including its nested name specifier (if any). For example,
|
||||
/// DependentTemplateName can refer to "MetaFun::template apply",
|
||||
/// where "MetaFun::" is the nested name specifier and "apply" is the
|
||||
/// template name referenced. The "template" keyword is implied.
|
||||
|
|
@ -205,11 +239,11 @@ class DependentTemplateName : public llvm::FoldingSetNode {
|
|||
|
||||
friend class ASTContext;
|
||||
|
||||
DependentTemplateName(NestedNameSpecifier *Qualifier,
|
||||
DependentTemplateName(NestedNameSpecifier *Qualifier,
|
||||
const IdentifierInfo *Name)
|
||||
: Qualifier(Qualifier), Name(Name), CanonicalTemplateName(this) { }
|
||||
|
||||
DependentTemplateName(NestedNameSpecifier *Qualifier,
|
||||
DependentTemplateName(NestedNameSpecifier *Qualifier,
|
||||
const IdentifierInfo *Name,
|
||||
TemplateName Canon)
|
||||
: Qualifier(Qualifier), Name(Name), CanonicalTemplateName(Canon) { }
|
||||
|
|
@ -226,7 +260,7 @@ public:
|
|||
Profile(ID, getQualifier(), getName());
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
|
||||
const IdentifierInfo *Name) {
|
||||
ID.AddPointer(NNS);
|
||||
ID.AddPointer(Name);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
538
include/clang/AST/TypeLoc.h
Normal file
538
include/clang/AST/TypeLoc.h
Normal file
|
|
@ -0,0 +1,538 @@
|
|||
//===--- TypeLoc.h - Type Source Info Wrapper -------------------*- 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 TypeLoc interface and subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_TYPELOC_H
|
||||
#define LLVM_CLANG_AST_TYPELOC_H
|
||||
|
||||
#include "clang/AST/Type.h"
|
||||
|
||||
namespace clang {
|
||||
class ParmVarDecl;
|
||||
class TypeSpecLoc;
|
||||
class DeclaratorInfo;
|
||||
|
||||
/// \brief Base wrapper for a particular "section" of type source info.
|
||||
///
|
||||
/// A client should use the TypeLoc subclasses through cast/dyn_cast in order to
|
||||
/// get at the actual information.
|
||||
class TypeLoc {
|
||||
protected:
|
||||
QualType Ty;
|
||||
void *Data;
|
||||
|
||||
public:
|
||||
TypeLoc() : Data(0) { }
|
||||
TypeLoc(QualType ty, void *opaqueData) : Ty(ty), Data(opaqueData) { }
|
||||
|
||||
bool isNull() const { return Ty.isNull(); }
|
||||
operator bool() const { return !isNull(); }
|
||||
|
||||
/// \brief Returns the size of type source info data block for the given type.
|
||||
static unsigned getFullDataSizeForType(QualType Ty);
|
||||
|
||||
/// \brief Get the type for which this source info wrapper provides
|
||||
/// information.
|
||||
QualType getSourceType() const { return Ty; }
|
||||
|
||||
/// \brief Get the pointer where source information is stored.
|
||||
void *getOpaqueData() const { return Data; }
|
||||
|
||||
SourceRange getSourceRange() const;
|
||||
|
||||
/// \brief Find the TypeSpecLoc that is part of this TypeLoc.
|
||||
TypeSpecLoc getTypeSpecLoc() const;
|
||||
|
||||
/// \brief Find the TypeSpecLoc that is part of this TypeLoc and return its
|
||||
/// SourceRange.
|
||||
SourceRange getTypeSpecRange() const;
|
||||
|
||||
/// \brief Returns the size of the type source info data block.
|
||||
unsigned getFullDataSize() const;
|
||||
|
||||
/// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the
|
||||
/// TypeLoc is a PointerLoc and next TypeLoc is for "int".
|
||||
TypeLoc getNextTypeLoc() const;
|
||||
|
||||
friend bool operator==(const TypeLoc &LHS, const TypeLoc &RHS) {
|
||||
return LHS.Ty == RHS.Ty && LHS.Data == RHS.Data;
|
||||
}
|
||||
|
||||
friend bool operator!=(const TypeLoc &LHS, const TypeLoc &RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
|
||||
static bool classof(const TypeLoc *TL) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Base wrapper of type source info data for type-spec types.
|
||||
class TypeSpecLoc : public TypeLoc {
|
||||
public:
|
||||
static bool classof(const TypeLoc *TL);
|
||||
static bool classof(const TypeSpecLoc *TL) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Base wrapper of type source info data for types part of a declarator,
|
||||
/// excluding type-spec types.
|
||||
class DeclaratorLoc : public TypeLoc {
|
||||
public:
|
||||
/// \brief Find the TypeSpecLoc that is part of this DeclaratorLoc.
|
||||
TypeSpecLoc getTypeSpecLoc() const;
|
||||
|
||||
static bool classof(const TypeLoc *TL);
|
||||
static bool classof(const DeclaratorLoc *TL) { return true; }
|
||||
};
|
||||
|
||||
/// \brief The default wrapper for type-spec types that are not handled by
|
||||
/// another specific wrapper.
|
||||
class DefaultTypeSpecLoc : public TypeSpecLoc {
|
||||
struct Info {
|
||||
SourceLocation StartLoc;
|
||||
};
|
||||
|
||||
public:
|
||||
SourceLocation getStartLoc() const {
|
||||
return static_cast<Info*>(Data)->StartLoc;
|
||||
}
|
||||
void setStartLoc(SourceLocation Loc) {
|
||||
static_cast<Info*>(Data)->StartLoc = Loc;
|
||||
}
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getStartLoc(), getStartLoc());
|
||||
}
|
||||
|
||||
/// \brief Returns the size of the type source info data block that is
|
||||
/// specific to this type.
|
||||
unsigned getLocalDataSize() const { return sizeof(Info); }
|
||||
|
||||
/// \brief Returns the size of the type source info data block.
|
||||
unsigned getFullDataSize() const { return getLocalDataSize(); }
|
||||
|
||||
static bool classof(const TypeLoc *TL);
|
||||
static bool classof(const DefaultTypeSpecLoc *TL) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for typedefs.
|
||||
class TypedefLoc : public TypeSpecLoc {
|
||||
struct Info {
|
||||
SourceLocation NameLoc;
|
||||
};
|
||||
|
||||
public:
|
||||
SourceLocation getNameLoc() const {
|
||||
return static_cast<Info*>(Data)->NameLoc;
|
||||
}
|
||||
void setNameLoc(SourceLocation Loc) {
|
||||
static_cast<Info*>(Data)->NameLoc = Loc;
|
||||
}
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getNameLoc(), getNameLoc());
|
||||
}
|
||||
|
||||
TypedefDecl *getTypedefDecl() const {
|
||||
return cast<TypedefType>(Ty)->getDecl();
|
||||
}
|
||||
|
||||
/// \brief Returns the size of the type source info data block that is
|
||||
/// specific to this type.
|
||||
unsigned getLocalDataSize() const { return sizeof(Info); }
|
||||
|
||||
/// \brief Returns the size of the type source info data block.
|
||||
unsigned getFullDataSize() const { return getLocalDataSize(); }
|
||||
|
||||
static bool classof(const TypeLoc *TL);
|
||||
static bool classof(const TypedefLoc *TL) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for ObjC interfaces.
|
||||
class ObjCInterfaceLoc : public TypeSpecLoc {
|
||||
struct Info {
|
||||
SourceLocation NameLoc;
|
||||
};
|
||||
|
||||
public:
|
||||
SourceLocation getNameLoc() const {
|
||||
return static_cast<Info*>(Data)->NameLoc;
|
||||
}
|
||||
void setNameLoc(SourceLocation Loc) {
|
||||
static_cast<Info*>(Data)->NameLoc = Loc;
|
||||
}
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getNameLoc(), getNameLoc());
|
||||
}
|
||||
|
||||
ObjCInterfaceDecl *getIFaceDecl() const {
|
||||
return cast<ObjCInterfaceType>(Ty)->getDecl();
|
||||
}
|
||||
|
||||
/// \brief Returns the size of the type source info data block that is
|
||||
/// specific to this type.
|
||||
unsigned getLocalDataSize() const { return sizeof(Info); }
|
||||
|
||||
/// \brief Returns the size of the type source info data block.
|
||||
unsigned getFullDataSize() const { return getLocalDataSize(); }
|
||||
|
||||
static bool classof(const TypeLoc *TL);
|
||||
static bool classof(const TypedefLoc *TL) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for ObjC protocol lists.
|
||||
class ObjCProtocolListLoc : public TypeSpecLoc {
|
||||
struct Info {
|
||||
SourceLocation LAngleLoc, RAngleLoc;
|
||||
};
|
||||
// SourceLocations are stored after Info, one for each Protocol.
|
||||
SourceLocation *getProtocolLocArray() const {
|
||||
return reinterpret_cast<SourceLocation*>(static_cast<Info*>(Data) + 1);
|
||||
}
|
||||
|
||||
public:
|
||||
SourceLocation getLAngleLoc() const {
|
||||
return static_cast<Info*>(Data)->LAngleLoc;
|
||||
}
|
||||
void setLAngleLoc(SourceLocation Loc) {
|
||||
static_cast<Info*>(Data)->LAngleLoc = Loc;
|
||||
}
|
||||
|
||||
SourceLocation getRAngleLoc() const {
|
||||
return static_cast<Info*>(Data)->RAngleLoc;
|
||||
}
|
||||
void setRAngleLoc(SourceLocation Loc) {
|
||||
static_cast<Info*>(Data)->RAngleLoc = Loc;
|
||||
}
|
||||
|
||||
unsigned getNumProtocols() const {
|
||||
return cast<ObjCProtocolListType>(Ty)->getNumProtocols();
|
||||
}
|
||||
|
||||
SourceLocation getProtocolLoc(unsigned i) const {
|
||||
assert(i < getNumProtocols() && "Index is out of bounds!");
|
||||
return getProtocolLocArray()[i];
|
||||
}
|
||||
void setProtocolLoc(unsigned i, SourceLocation Loc) {
|
||||
assert(i < getNumProtocols() && "Index is out of bounds!");
|
||||
getProtocolLocArray()[i] = Loc;
|
||||
}
|
||||
|
||||
ObjCProtocolDecl *getProtocol(unsigned i) const {
|
||||
assert(i < getNumProtocols() && "Index is out of bounds!");
|
||||
return *(cast<ObjCProtocolListType>(Ty)->qual_begin() + i);
|
||||
}
|
||||
|
||||
TypeLoc getBaseTypeLoc() const {
|
||||
void *Next = static_cast<char*>(Data) + getLocalDataSize();
|
||||
return TypeLoc(cast<ObjCProtocolListType>(Ty)->getBaseType(), Next);
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getLAngleLoc(), getRAngleLoc());
|
||||
}
|
||||
|
||||
/// \brief Returns the size of the type source info data block that is
|
||||
/// specific to this type.
|
||||
unsigned getLocalDataSize() const {
|
||||
return sizeof(Info) + getNumProtocols() * sizeof(SourceLocation);
|
||||
}
|
||||
|
||||
/// \brief Returns the size of the type source info data block.
|
||||
unsigned getFullDataSize() const {
|
||||
return getLocalDataSize() + getBaseTypeLoc().getFullDataSize();
|
||||
}
|
||||
|
||||
static bool classof(const TypeLoc *TL);
|
||||
static bool classof(const ObjCProtocolListLoc *TL) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for pointers.
|
||||
class PointerLoc : public DeclaratorLoc {
|
||||
struct Info {
|
||||
SourceLocation StarLoc;
|
||||
};
|
||||
|
||||
public:
|
||||
SourceLocation getStarLoc() const {
|
||||
return static_cast<Info*>(Data)->StarLoc;
|
||||
}
|
||||
void setStarLoc(SourceLocation Loc) {
|
||||
static_cast<Info*>(Data)->StarLoc = Loc;
|
||||
}
|
||||
|
||||
TypeLoc getPointeeLoc() const {
|
||||
void *Next = static_cast<char*>(Data) + getLocalDataSize();
|
||||
return TypeLoc(cast<PointerType>(Ty)->getPointeeType(), Next);
|
||||
}
|
||||
|
||||
/// \brief Find the TypeSpecLoc that is part of this PointerLoc.
|
||||
TypeSpecLoc getTypeSpecLoc() const {
|
||||
return getPointeeLoc().getTypeSpecLoc();
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getStarLoc(), getStarLoc());
|
||||
}
|
||||
|
||||
/// \brief Returns the size of the type source info data block that is
|
||||
/// specific to this type.
|
||||
unsigned getLocalDataSize() const { return sizeof(Info); }
|
||||
|
||||
/// \brief Returns the size of the type source info data block.
|
||||
unsigned getFullDataSize() const {
|
||||
return getLocalDataSize() + getPointeeLoc().getFullDataSize();
|
||||
}
|
||||
|
||||
static bool classof(const TypeLoc *TL);
|
||||
static bool classof(const PointerLoc *TL) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for block pointers.
|
||||
class BlockPointerLoc : public DeclaratorLoc {
|
||||
struct Info {
|
||||
SourceLocation CaretLoc;
|
||||
};
|
||||
|
||||
public:
|
||||
SourceLocation getCaretLoc() const {
|
||||
return static_cast<Info*>(Data)->CaretLoc;
|
||||
}
|
||||
void setCaretLoc(SourceLocation Loc) {
|
||||
static_cast<Info*>(Data)->CaretLoc = Loc;
|
||||
}
|
||||
|
||||
TypeLoc getPointeeLoc() const {
|
||||
void *Next = static_cast<char*>(Data) + getLocalDataSize();
|
||||
return TypeLoc(cast<BlockPointerType>(Ty)->getPointeeType(), Next);
|
||||
}
|
||||
|
||||
/// \brief Find the TypeSpecLoc that is part of this BlockPointerLoc.
|
||||
TypeSpecLoc getTypeSpecLoc() const {
|
||||
return getPointeeLoc().getTypeSpecLoc();
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getCaretLoc(), getCaretLoc());
|
||||
}
|
||||
|
||||
/// \brief Returns the size of the type source info data block that is
|
||||
/// specific to this type.
|
||||
unsigned getLocalDataSize() const { return sizeof(Info); }
|
||||
|
||||
/// \brief Returns the size of the type source info data block.
|
||||
unsigned getFullDataSize() const {
|
||||
return getLocalDataSize() + getPointeeLoc().getFullDataSize();
|
||||
}
|
||||
|
||||
static bool classof(const TypeLoc *TL);
|
||||
static bool classof(const BlockPointerLoc *TL) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for member pointers.
|
||||
class MemberPointerLoc : public DeclaratorLoc {
|
||||
struct Info {
|
||||
SourceLocation StarLoc;
|
||||
};
|
||||
|
||||
public:
|
||||
SourceLocation getStarLoc() const {
|
||||
return static_cast<Info*>(Data)->StarLoc;
|
||||
}
|
||||
void setStarLoc(SourceLocation Loc) {
|
||||
static_cast<Info*>(Data)->StarLoc = Loc;
|
||||
}
|
||||
|
||||
TypeLoc getPointeeLoc() const {
|
||||
void *Next = static_cast<char*>(Data) + getLocalDataSize();
|
||||
return TypeLoc(cast<MemberPointerType>(Ty)->getPointeeType(), Next);
|
||||
}
|
||||
|
||||
/// \brief Find the TypeSpecLoc that is part of this MemberPointerLoc.
|
||||
TypeSpecLoc getTypeSpecLoc() const {
|
||||
return getPointeeLoc().getTypeSpecLoc();
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getStarLoc(), getStarLoc());
|
||||
}
|
||||
|
||||
/// \brief Returns the size of the type source info data block that is
|
||||
/// specific to this type.
|
||||
unsigned getLocalDataSize() const { return sizeof(Info); }
|
||||
|
||||
/// \brief Returns the size of the type source info data block.
|
||||
unsigned getFullDataSize() const {
|
||||
return getLocalDataSize() + getPointeeLoc().getFullDataSize();
|
||||
}
|
||||
|
||||
static bool classof(const TypeLoc *TL);
|
||||
static bool classof(const MemberPointerLoc *TL) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for references.
|
||||
class ReferenceLoc : public DeclaratorLoc {
|
||||
struct Info {
|
||||
SourceLocation AmpLoc;
|
||||
};
|
||||
|
||||
public:
|
||||
SourceLocation getAmpLoc() const {
|
||||
return static_cast<Info*>(Data)->AmpLoc;
|
||||
}
|
||||
void setAmpLoc(SourceLocation Loc) {
|
||||
static_cast<Info*>(Data)->AmpLoc = Loc;
|
||||
}
|
||||
|
||||
TypeLoc getPointeeLoc() const {
|
||||
void *Next = static_cast<char*>(Data) + getLocalDataSize();
|
||||
return TypeLoc(cast<ReferenceType>(Ty)->getPointeeType(), Next);
|
||||
}
|
||||
|
||||
/// \brief Find the TypeSpecLoc that is part of this ReferenceLoc.
|
||||
TypeSpecLoc getTypeSpecLoc() const {
|
||||
return getPointeeLoc().getTypeSpecLoc();
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getAmpLoc(), getAmpLoc());
|
||||
}
|
||||
|
||||
/// \brief Returns the size of the type source info data block that is
|
||||
/// specific to this type.
|
||||
unsigned getLocalDataSize() const { return sizeof(Info); }
|
||||
|
||||
/// \brief Returns the size of the type source info data block.
|
||||
unsigned getFullDataSize() const {
|
||||
return getLocalDataSize() + getPointeeLoc().getFullDataSize();
|
||||
}
|
||||
|
||||
static bool classof(const TypeLoc *TL);
|
||||
static bool classof(const ReferenceLoc *TL) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for functions.
|
||||
class FunctionLoc : public DeclaratorLoc {
|
||||
struct Info {
|
||||
SourceLocation LParenLoc, RParenLoc;
|
||||
};
|
||||
// ParmVarDecls* are stored after Info, one for each argument.
|
||||
ParmVarDecl **getParmArray() const {
|
||||
return reinterpret_cast<ParmVarDecl**>(static_cast<Info*>(Data) + 1);
|
||||
}
|
||||
|
||||
public:
|
||||
SourceLocation getLParenLoc() const {
|
||||
return static_cast<Info*>(Data)->LParenLoc;
|
||||
}
|
||||
void setLParenLoc(SourceLocation Loc) {
|
||||
static_cast<Info*>(Data)->LParenLoc = Loc;
|
||||
}
|
||||
|
||||
SourceLocation getRParenLoc() const {
|
||||
return static_cast<Info*>(Data)->RParenLoc;
|
||||
}
|
||||
void setRParenLoc(SourceLocation Loc) {
|
||||
static_cast<Info*>(Data)->RParenLoc = Loc;
|
||||
}
|
||||
|
||||
unsigned getNumArgs() const {
|
||||
if (isa<FunctionNoProtoType>(Ty))
|
||||
return 0;
|
||||
return cast<FunctionProtoType>(Ty)->getNumArgs();
|
||||
}
|
||||
ParmVarDecl *getArg(unsigned i) const { return getParmArray()[i]; }
|
||||
void setArg(unsigned i, ParmVarDecl *VD) { getParmArray()[i] = VD; }
|
||||
|
||||
TypeLoc getArgLoc(unsigned i) const;
|
||||
|
||||
TypeLoc getResultLoc() const {
|
||||
void *Next = static_cast<char*>(Data) + getLocalDataSize();
|
||||
return TypeLoc(cast<FunctionType>(Ty)->getResultType(), Next);
|
||||
}
|
||||
|
||||
/// \brief Find the TypeSpecLoc that is part of this FunctionLoc.
|
||||
TypeSpecLoc getTypeSpecLoc() const {
|
||||
return getResultLoc().getTypeSpecLoc();
|
||||
}
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getLParenLoc(), getRParenLoc());
|
||||
}
|
||||
|
||||
/// \brief Returns the size of the type source info data block that is
|
||||
/// specific to this type.
|
||||
unsigned getLocalDataSize() const {
|
||||
return sizeof(Info) + getNumArgs() * sizeof(ParmVarDecl*);
|
||||
}
|
||||
|
||||
/// \brief Returns the size of the type source info data block.
|
||||
unsigned getFullDataSize() const {
|
||||
return getLocalDataSize() + getResultLoc().getFullDataSize();
|
||||
}
|
||||
|
||||
static bool classof(const TypeLoc *TL);
|
||||
static bool classof(const FunctionLoc *TL) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for arrays.
|
||||
class ArrayLoc : public DeclaratorLoc {
|
||||
struct Info {
|
||||
SourceLocation LBracketLoc, RBracketLoc;
|
||||
Expr *Size;
|
||||
};
|
||||
public:
|
||||
SourceLocation getLBracketLoc() const {
|
||||
return static_cast<Info*>(Data)->LBracketLoc;
|
||||
}
|
||||
void setLBracketLoc(SourceLocation Loc) {
|
||||
static_cast<Info*>(Data)->LBracketLoc = Loc;
|
||||
}
|
||||
|
||||
SourceLocation getRBracketLoc() const {
|
||||
return static_cast<Info*>(Data)->RBracketLoc;
|
||||
}
|
||||
void setRBracketLoc(SourceLocation Loc) {
|
||||
static_cast<Info*>(Data)->RBracketLoc = Loc;
|
||||
}
|
||||
|
||||
Expr *getSizeExpr() const {
|
||||
return static_cast<Info*>(Data)->Size;
|
||||
}
|
||||
void setSizeExpr(Expr *Size) {
|
||||
static_cast<Info*>(Data)->Size = Size;
|
||||
}
|
||||
|
||||
TypeLoc getElementLoc() const {
|
||||
void *Next = static_cast<char*>(Data) + getLocalDataSize();
|
||||
return TypeLoc(cast<ArrayType>(Ty)->getElementType(), Next);
|
||||
}
|
||||
|
||||
/// \brief Find the TypeSpecLoc that is part of this ArrayLoc.
|
||||
TypeSpecLoc getTypeSpecLoc() const {
|
||||
return getElementLoc().getTypeSpecLoc();
|
||||
}
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getLBracketLoc(), getRBracketLoc());
|
||||
}
|
||||
|
||||
/// \brief Returns the size of the type source info data block that is
|
||||
/// specific to this type.
|
||||
unsigned getLocalDataSize() const { return sizeof(Info); }
|
||||
|
||||
/// \brief Returns the size of the type source info data block.
|
||||
unsigned getFullDataSize() const {
|
||||
return getLocalDataSize() + getElementLoc().getFullDataSize();
|
||||
}
|
||||
|
||||
static bool classof(const TypeLoc *TL);
|
||||
static bool classof(const ArrayLoc *TL) { return true; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
55
include/clang/AST/TypeLocNodes.def
Normal file
55
include/clang/AST/TypeLocNodes.def
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
//===-- TypeLocNodes.def - Metadata about TypeLoc wrappers ------*- 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 TypeLoc info database. Each node is
|
||||
// enumerated by providing its name (e.g., "PointerLoc" or "ArrayLoc"),
|
||||
// base class (e.g., "TypeSpecLoc" or "DeclaratorLoc"), and the Type subclass
|
||||
// that the TypeLoc is associated with.
|
||||
//
|
||||
// TYPELOC(Class, Base, Type) - Description of the TypeLoc subclass.
|
||||
//
|
||||
// ABSTRACT_TYPELOC(Class) - Refers to TypeSpecLoc and DeclaratorLoc.
|
||||
//
|
||||
// TYPESPEC_TYPELOC(Class, Type) - A TypeLoc referring to a type-spec type.
|
||||
//
|
||||
// DECLARATOR_TYPELOC(Class, Type) - A TypeLoc referring to a type part of
|
||||
// a declarator, excluding type-spec types.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ABSTRACT_TYPELOC
|
||||
# define ABSTRACT_TYPELOC(Class) TYPELOC(Class, TypeLoc, Type)
|
||||
#endif
|
||||
|
||||
#ifndef TYPESPEC_TYPELOC
|
||||
# define TYPESPEC_TYPELOC(Class, Type) TYPELOC(Class, TypeSpecLoc, Type)
|
||||
#endif
|
||||
|
||||
#ifndef DECLARATOR_TYPELOC
|
||||
# define DECLARATOR_TYPELOC(Class, Type) TYPELOC(Class, DeclaratorLoc, Type)
|
||||
#endif
|
||||
|
||||
TYPESPEC_TYPELOC(DefaultTypeSpecLoc, Type)
|
||||
TYPESPEC_TYPELOC(TypedefLoc, TypedefType)
|
||||
TYPESPEC_TYPELOC(ObjCInterfaceLoc, ObjCInterfaceType)
|
||||
TYPESPEC_TYPELOC(ObjCProtocolListLoc, ObjCProtocolListType)
|
||||
DECLARATOR_TYPELOC(PointerLoc, PointerType)
|
||||
DECLARATOR_TYPELOC(BlockPointerLoc, BlockPointerType)
|
||||
DECLARATOR_TYPELOC(MemberPointerLoc, MemberPointerType)
|
||||
DECLARATOR_TYPELOC(ReferenceLoc, ReferenceType)
|
||||
DECLARATOR_TYPELOC(FunctionLoc, FunctionType)
|
||||
DECLARATOR_TYPELOC(ArrayLoc, ArrayType)
|
||||
ABSTRACT_TYPELOC(DeclaratorLoc)
|
||||
ABSTRACT_TYPELOC(TypeSpecLoc)
|
||||
|
||||
|
||||
#undef DECLARATOR_TYPELOC
|
||||
#undef TYPESPEC_TYPELOC
|
||||
#undef ABSTRACT_TYPELOC
|
||||
#undef TYPELOC
|
||||
58
include/clang/AST/TypeLocVisitor.h
Normal file
58
include/clang/AST/TypeLocVisitor.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
//===--- TypeLocVisitor.h - Visitor for TypeLoc subclasses ------*- 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 TypeLocVisitor interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_AST_TYPELOCVISITOR_H
|
||||
#define LLVM_CLANG_AST_TYPELOCVISITOR_H
|
||||
|
||||
#include "clang/AST/TypeLoc.h"
|
||||
#include "clang/AST/TypeVisitor.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
#define DISPATCH(CLASS) \
|
||||
return static_cast<ImplClass*>(this)->Visit ## CLASS(cast<CLASS>(TyLoc))
|
||||
|
||||
template<typename ImplClass, typename RetTy=void>
|
||||
class TypeLocVisitor {
|
||||
class TypeDispatch : public TypeVisitor<TypeDispatch, RetTy> {
|
||||
ImplClass *Impl;
|
||||
TypeLoc TyLoc;
|
||||
|
||||
public:
|
||||
TypeDispatch(ImplClass *impl, TypeLoc &tyLoc) : Impl(impl), TyLoc(tyLoc) { }
|
||||
#define ABSTRACT_TYPELOC(CLASS)
|
||||
#define TYPELOC(CLASS, PARENT, TYPE) \
|
||||
RetTy Visit##TYPE(TYPE *) { \
|
||||
return Impl->Visit##CLASS(reinterpret_cast<CLASS&>(TyLoc)); \
|
||||
}
|
||||
#include "clang/AST/TypeLocNodes.def"
|
||||
};
|
||||
|
||||
public:
|
||||
RetTy Visit(TypeLoc TyLoc) {
|
||||
TypeDispatch TD(static_cast<ImplClass*>(this), TyLoc);
|
||||
return TD.Visit(TyLoc.getSourceType().getTypePtr());
|
||||
}
|
||||
|
||||
#define TYPELOC(CLASS, PARENT, TYPE) RetTy Visit##CLASS(CLASS TyLoc) { \
|
||||
DISPATCH(PARENT); \
|
||||
}
|
||||
#include "clang/AST/TypeLocNodes.def"
|
||||
|
||||
RetTy VisitTypeLoc(TypeLoc TyLoc) { return RetTy(); }
|
||||
};
|
||||
|
||||
#undef DISPATCH
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_AST_TYPELOCVISITOR_H
|
||||
|
|
@ -31,6 +31,12 @@
|
|||
// type that is always dependent. Clients that do not need to deal
|
||||
// with uninstantiated C++ templates can ignore these types.
|
||||
//
|
||||
// There is a fifth macro, independent of the others. Most clients
|
||||
// will not need to use it.
|
||||
//
|
||||
// LEAF_TYPE(Class) - A type that never has inner types. Clients
|
||||
// which can operate on such types more efficiently may wish to do so.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ABSTRACT_TYPE
|
||||
|
|
@ -45,7 +51,6 @@
|
|||
# define DEPENDENT_TYPE(Class, Base) TYPE(Class, Base)
|
||||
#endif
|
||||
|
||||
TYPE(ExtQual, Type)
|
||||
TYPE(Builtin, Type)
|
||||
TYPE(FixedWidthInt, Type)
|
||||
TYPE(Complex, Type)
|
||||
|
|
@ -57,6 +62,8 @@ TYPE(RValueReference, ReferenceType)
|
|||
TYPE(MemberPointer, Type)
|
||||
ABSTRACT_TYPE(Array, Type)
|
||||
TYPE(ConstantArray, ArrayType)
|
||||
NON_CANONICAL_TYPE(ConstantArrayWithExpr, ConstantArrayType)
|
||||
NON_CANONICAL_TYPE(ConstantArrayWithoutExpr, ConstantArrayType)
|
||||
TYPE(IncompleteArray, ArrayType)
|
||||
TYPE(VariableArray, ArrayType)
|
||||
DEPENDENT_TYPE(DependentSizedArray, ArrayType)
|
||||
|
|
@ -73,13 +80,25 @@ NON_CANONICAL_TYPE(Decltype, Type)
|
|||
ABSTRACT_TYPE(Tag, Type)
|
||||
TYPE(Record, TagType)
|
||||
TYPE(Enum, TagType)
|
||||
NON_CANONICAL_TYPE(Elaborated, Type)
|
||||
DEPENDENT_TYPE(TemplateTypeParm, Type)
|
||||
TYPE(TemplateSpecialization, Type)
|
||||
NON_CANONICAL_TYPE(QualifiedName, Type)
|
||||
DEPENDENT_TYPE(Typename, Type)
|
||||
TYPE(ObjCInterface, Type)
|
||||
TYPE(ObjCObjectPointer, Type)
|
||||
TYPE(ObjCQualifiedInterface, ObjCInterfaceType)
|
||||
NON_CANONICAL_TYPE(ObjCProtocolList, Type)
|
||||
|
||||
// These types are always leaves in the type hierarchy.
|
||||
#ifdef LEAF_TYPE
|
||||
LEAF_TYPE(Enum)
|
||||
LEAF_TYPE(Builtin)
|
||||
LEAF_TYPE(FixedWidthInt)
|
||||
LEAF_TYPE(ObjCInterface)
|
||||
LEAF_TYPE(ObjCObjectPointer)
|
||||
LEAF_TYPE(TemplateTypeParm)
|
||||
#undef LEAF_TYPE
|
||||
#endif
|
||||
|
||||
#undef DEPENDENT_TYPE
|
||||
#undef NON_CANONICAL_TYPE
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ namespace llvm {
|
|||
template<> struct DenseMapInfo<clang::QualType> {
|
||||
static inline clang::QualType getEmptyKey() { return clang::QualType(); }
|
||||
|
||||
static inline clang::QualType getTombstoneKey() {
|
||||
static inline clang::QualType getTombstoneKey() {
|
||||
using clang::QualType;
|
||||
return QualType::getFromOpaquePtr(reinterpret_cast<clang::Type *>(-1));
|
||||
}
|
||||
|
|
@ -51,11 +51,11 @@ namespace llvm {
|
|||
return LHS == RHS;
|
||||
}
|
||||
|
||||
static bool isPod() {
|
||||
static bool isPod() {
|
||||
// QualType isn't *technically* a POD type. However, we can get
|
||||
// away with calling it a POD type since its copy constructor,
|
||||
// copy assignment operator, and destructor are all trivial.
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@
|
|||
#include "clang/AST/Type.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
#define DISPATCH(CLASS) \
|
||||
return static_cast<ImplClass*>(this)->Visit ## CLASS(static_cast<CLASS*>(T))
|
||||
|
||||
|
||||
template<typename ImplClass, typename RetTy=void>
|
||||
class TypeVisitor {
|
||||
public:
|
||||
|
|
@ -28,15 +28,17 @@ public:
|
|||
// Top switch stmt: dispatch to VisitFooStmt for each FooStmt.
|
||||
switch (T->getTypeClass()) {
|
||||
default: assert(0 && "Unknown type class!");
|
||||
#define ABSTRACT_TYPE(CLASS, PARENT)
|
||||
#define ABSTRACT_TYPE(CLASS, PARENT)
|
||||
#define TYPE(CLASS, PARENT) case Type::CLASS: DISPATCH(CLASS##Type);
|
||||
#include "clang/AST/TypeNodes.def"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If the implementation chooses not to implement a certain visit method, fall
|
||||
// back on superclass.
|
||||
#define TYPE(CLASS, PARENT) RetTy Visit##CLASS##Type(CLASS##Type *T) { DISPATCH(PARENT); }
|
||||
#define TYPE(CLASS, PARENT) RetTy Visit##CLASS##Type(CLASS##Type *T) { \
|
||||
DISPATCH(PARENT); \
|
||||
}
|
||||
#include "clang/AST/TypeNodes.def"
|
||||
|
||||
// Base case, ignore it. :)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace clang {
|
|||
class Stmt;
|
||||
class DeclRefExpr;
|
||||
class SourceManager;
|
||||
|
||||
|
||||
struct LiveVariables_ValueTypes {
|
||||
|
||||
struct ObserverTy;
|
||||
|
|
@ -35,77 +35,77 @@ struct LiveVariables_ValueTypes {
|
|||
// (so that we don't explore such expressions twice). We also want
|
||||
// to compute liveness information for block-level expressions, since these
|
||||
// act as "temporary" values.
|
||||
|
||||
|
||||
struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy {
|
||||
ObserverTy* Observer;
|
||||
ValTy AlwaysLive;
|
||||
|
||||
|
||||
AnalysisDataTy() : Observer(NULL) {}
|
||||
};
|
||||
|
||||
|
||||
//===-----------------------------------------------------===//
|
||||
// ObserverTy - Observer for uninitialized values queries.
|
||||
//===-----------------------------------------------------===//
|
||||
|
||||
struct ObserverTy {
|
||||
virtual ~ObserverTy() {}
|
||||
|
||||
|
||||
/// ObserveStmt - A callback invoked right before invoking the
|
||||
/// liveness transfer function on the given statement.
|
||||
virtual void ObserveStmt(Stmt* S, const AnalysisDataTy& AD,
|
||||
virtual void ObserveStmt(Stmt* S, const AnalysisDataTy& AD,
|
||||
const ValTy& V) {}
|
||||
|
||||
|
||||
virtual void ObserverKill(DeclRefExpr* DR) {}
|
||||
};
|
||||
};
|
||||
|
||||
class LiveVariables : public DataflowValues<LiveVariables_ValueTypes,
|
||||
dataflow::backward_analysis_tag> {
|
||||
|
||||
|
||||
|
||||
|
||||
public:
|
||||
typedef LiveVariables_ValueTypes::ObserverTy ObserverTy;
|
||||
|
||||
|
||||
LiveVariables(ASTContext& Ctx, CFG& cfg);
|
||||
|
||||
|
||||
/// IsLive - Return true if a variable is live at beginning of a
|
||||
/// specified block.
|
||||
bool isLive(const CFGBlock* B, const VarDecl* D) const;
|
||||
|
||||
|
||||
/// IsLive - Returns true if a variable is live at the beginning of the
|
||||
/// the statement. This query only works if liveness information
|
||||
/// has been recorded at the statement level (see runOnAllBlocks), and
|
||||
/// only returns liveness information for block-level expressions.
|
||||
bool isLive(const Stmt* S, const VarDecl* D) const;
|
||||
|
||||
|
||||
/// IsLive - Returns true the block-level expression "value" is live
|
||||
/// before the given block-level expression (see runOnAllBlocks).
|
||||
bool isLive(const Stmt* Loc, const Stmt* StmtVal) const;
|
||||
|
||||
|
||||
/// IsLive - Return true if a variable is live according to the
|
||||
/// provided livness bitvector.
|
||||
bool isLive(const ValTy& V, const VarDecl* D) const;
|
||||
|
||||
|
||||
/// dumpLiveness - Print to stderr the liveness information encoded
|
||||
/// by a specified bitvector.
|
||||
void dumpLiveness(const ValTy& V, SourceManager& M) const;
|
||||
|
||||
|
||||
/// dumpBlockLiveness - Print to stderr the liveness information
|
||||
/// associated with each basic block.
|
||||
void dumpBlockLiveness(SourceManager& M) const;
|
||||
|
||||
|
||||
/// getNumDecls - Return the number of variables (declarations) that
|
||||
/// whose liveness status is being tracked by the dataflow
|
||||
/// analysis.
|
||||
unsigned getNumDecls() const { return getAnalysisData().getNumDecls(); }
|
||||
|
||||
|
||||
/// IntializeValues - This routine can perform extra initialization, but
|
||||
/// for LiveVariables this does nothing since all that logic is in
|
||||
/// the constructor.
|
||||
/// the constructor.
|
||||
void InitializeValues(const CFG& cfg) {}
|
||||
|
||||
|
||||
void runOnCFG(CFG& cfg);
|
||||
|
||||
|
||||
/// runOnAllBlocks - Propagate the dataflow values once for each block,
|
||||
/// starting from the current dataflow values. 'recordStmtValues' indicates
|
||||
/// whether the method should store dataflow values per each individual
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace clang {
|
|||
class Expr;
|
||||
class DeclRefExpr;
|
||||
class VarDecl;
|
||||
|
||||
|
||||
/// UninitializedValues_ValueTypes - Utility class to wrap type declarations
|
||||
/// for dataflow values and dataflow analysis state for the
|
||||
/// Unitialized Values analysis.
|
||||
|
|
@ -32,39 +32,39 @@ class UninitializedValues_ValueTypes {
|
|||
public:
|
||||
|
||||
struct ObserverTy;
|
||||
|
||||
struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy {
|
||||
|
||||
struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy {
|
||||
AnalysisDataTy() : Observer(NULL), FullUninitTaint(true) {}
|
||||
virtual ~AnalysisDataTy() {};
|
||||
|
||||
|
||||
ObserverTy* Observer;
|
||||
bool FullUninitTaint;
|
||||
};
|
||||
|
||||
|
||||
typedef StmtDeclBitVector_Types::ValTy ValTy;
|
||||
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// ObserverTy - Observer for querying DeclRefExprs that use an uninitalized
|
||||
// value.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
|
||||
struct ObserverTy {
|
||||
virtual ~ObserverTy();
|
||||
virtual void ObserveDeclRefExpr(ValTy& Val, AnalysisDataTy& AD,
|
||||
virtual void ObserveDeclRefExpr(ValTy& Val, AnalysisDataTy& AD,
|
||||
DeclRefExpr* DR, VarDecl* VD) = 0;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/// UninitializedValues - Objects of this class encapsulate dataflow analysis
|
||||
/// information regarding what variable declarations in a function are
|
||||
/// potentially unintialized.
|
||||
class UninitializedValues :
|
||||
public DataflowValues<UninitializedValues_ValueTypes> {
|
||||
class UninitializedValues :
|
||||
public DataflowValues<UninitializedValues_ValueTypes> {
|
||||
public:
|
||||
typedef UninitializedValues_ValueTypes::ObserverTy ObserverTy;
|
||||
|
||||
UninitializedValues(CFG &cfg) { getAnalysisData().setCFG(cfg); }
|
||||
|
||||
|
||||
/// IntializeValues - Create initial dataflow values and meta data for
|
||||
/// a given CFG. This is intended to be called by the dataflow solver.
|
||||
void InitializeValues(const CFG& cfg);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
#include "clang/Basic/Diagnostic.h"
|
||||
|
||||
namespace clang {
|
||||
namespace diag {
|
||||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM,
|
||||
#define ANALYSISSTART
|
||||
|
|
|
|||
451
include/clang/Analysis/CFG.h
Normal file
451
include/clang/Analysis/CFG.h
Normal file
|
|
@ -0,0 +1,451 @@
|
|||
//===--- CFG.h - Classes for representing and building CFGs------*- 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 CFG and CFGBuilder classes for representing and
|
||||
// building Control-Flow Graphs (CFGs) from ASTs.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_CFG_H
|
||||
#define LLVM_CLANG_CFG_H
|
||||
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "clang/Analysis/Support/BumpVector.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
}
|
||||
namespace clang {
|
||||
class Stmt;
|
||||
class Expr;
|
||||
class CFG;
|
||||
class PrinterHelper;
|
||||
class LangOptions;
|
||||
class ASTContext;
|
||||
|
||||
/// CFGBlock - Represents a single basic block in a source-level CFG.
|
||||
/// It consists of:
|
||||
///
|
||||
/// (1) A set of statements/expressions (which may contain subexpressions).
|
||||
/// (2) A "terminator" statement (not in the set of statements).
|
||||
/// (3) A list of successors and predecessors.
|
||||
///
|
||||
/// Terminator: The terminator represents the type of control-flow that occurs
|
||||
/// at the end of the basic block. The terminator is a Stmt* referring to an
|
||||
/// AST node that has control-flow: if-statements, breaks, loops, etc.
|
||||
/// If the control-flow is conditional, the condition expression will appear
|
||||
/// within the set of statements in the block (usually the last statement).
|
||||
///
|
||||
/// Predecessors: the order in the set of predecessors is arbitrary.
|
||||
///
|
||||
/// Successors: the order in the set of successors is NOT arbitrary. We
|
||||
/// currently have the following orderings based on the terminator:
|
||||
///
|
||||
/// Terminator Successor Ordering
|
||||
/// -----------------------------------------------------
|
||||
/// if Then Block; Else Block
|
||||
/// ? operator LHS expression; RHS expression
|
||||
/// &&, || expression that uses result of && or ||, RHS
|
||||
///
|
||||
class CFGBlock {
|
||||
class StatementList {
|
||||
typedef BumpVector<Stmt*> ImplTy;
|
||||
ImplTy Impl;
|
||||
public:
|
||||
StatementList(BumpVectorContext &C) : Impl(C, 4) {}
|
||||
|
||||
typedef std::reverse_iterator<ImplTy::iterator> iterator;
|
||||
typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator;
|
||||
typedef ImplTy::iterator reverse_iterator;
|
||||
typedef ImplTy::const_iterator const_reverse_iterator;
|
||||
|
||||
void push_back(Stmt *s, BumpVectorContext &C) { Impl.push_back(s, C); }
|
||||
Stmt *front() const { return Impl.back(); }
|
||||
Stmt *back() const { return Impl.front(); }
|
||||
|
||||
iterator begin() { return Impl.rbegin(); }
|
||||
iterator end() { return Impl.rend(); }
|
||||
const_iterator begin() const { return Impl.rbegin(); }
|
||||
const_iterator end() const { return Impl.rend(); }
|
||||
reverse_iterator rbegin() { return Impl.begin(); }
|
||||
reverse_iterator rend() { return Impl.end(); }
|
||||
const_reverse_iterator rbegin() const { return Impl.begin(); }
|
||||
const_reverse_iterator rend() const { return Impl.end(); }
|
||||
|
||||
Stmt* operator[](size_t i) const {
|
||||
assert(i < Impl.size());
|
||||
return Impl[Impl.size() - 1 - i];
|
||||
}
|
||||
|
||||
size_t size() const { return Impl.size(); }
|
||||
bool empty() const { return Impl.empty(); }
|
||||
};
|
||||
|
||||
/// Stmts - The set of statements in the basic block.
|
||||
StatementList Stmts;
|
||||
|
||||
/// Label - An (optional) label that prefixes the executable
|
||||
/// statements in the block. When this variable is non-NULL, it is
|
||||
/// either an instance of LabelStmt or SwitchCase.
|
||||
Stmt *Label;
|
||||
|
||||
/// Terminator - The terminator for a basic block that
|
||||
/// indicates the type of control-flow that occurs between a block
|
||||
/// and its successors.
|
||||
Stmt *Terminator;
|
||||
|
||||
/// LoopTarget - Some blocks are used to represent the "loop edge" to
|
||||
/// the start of a loop from within the loop body. This Stmt* will be
|
||||
/// refer to the loop statement for such blocks (and be null otherwise).
|
||||
const Stmt *LoopTarget;
|
||||
|
||||
/// BlockID - A numerical ID assigned to a CFGBlock during construction
|
||||
/// of the CFG.
|
||||
unsigned BlockID;
|
||||
|
||||
/// Predecessors/Successors - Keep track of the predecessor / successor
|
||||
/// CFG blocks.
|
||||
typedef BumpVector<CFGBlock*> AdjacentBlocks;
|
||||
AdjacentBlocks Preds;
|
||||
AdjacentBlocks Succs;
|
||||
|
||||
public:
|
||||
explicit CFGBlock(unsigned blockid, BumpVectorContext &C)
|
||||
: Stmts(C), Label(NULL), Terminator(NULL), LoopTarget(NULL),
|
||||
BlockID(blockid), Preds(C, 1), Succs(C, 1) {}
|
||||
~CFGBlock() {};
|
||||
|
||||
// Statement iterators
|
||||
typedef StatementList::iterator iterator;
|
||||
typedef StatementList::const_iterator const_iterator;
|
||||
typedef StatementList::reverse_iterator reverse_iterator;
|
||||
typedef StatementList::const_reverse_iterator const_reverse_iterator;
|
||||
|
||||
Stmt* front() const { return Stmts.front(); }
|
||||
Stmt* back() const { return Stmts.back(); }
|
||||
|
||||
iterator begin() { return Stmts.begin(); }
|
||||
iterator end() { return Stmts.end(); }
|
||||
const_iterator begin() const { return Stmts.begin(); }
|
||||
const_iterator end() const { return Stmts.end(); }
|
||||
|
||||
reverse_iterator rbegin() { return Stmts.rbegin(); }
|
||||
reverse_iterator rend() { return Stmts.rend(); }
|
||||
const_reverse_iterator rbegin() const { return Stmts.rbegin(); }
|
||||
const_reverse_iterator rend() const { return Stmts.rend(); }
|
||||
|
||||
unsigned size() const { return Stmts.size(); }
|
||||
bool empty() const { return Stmts.empty(); }
|
||||
|
||||
Stmt* operator[](size_t i) const { return Stmts[i]; }
|
||||
|
||||
|
||||
// CFG iterators
|
||||
typedef AdjacentBlocks::iterator pred_iterator;
|
||||
typedef AdjacentBlocks::const_iterator const_pred_iterator;
|
||||
typedef AdjacentBlocks::reverse_iterator pred_reverse_iterator;
|
||||
typedef AdjacentBlocks::const_reverse_iterator const_pred_reverse_iterator;
|
||||
|
||||
typedef AdjacentBlocks::iterator succ_iterator;
|
||||
typedef AdjacentBlocks::const_iterator const_succ_iterator;
|
||||
typedef AdjacentBlocks::reverse_iterator succ_reverse_iterator;
|
||||
typedef AdjacentBlocks::const_reverse_iterator const_succ_reverse_iterator;
|
||||
|
||||
pred_iterator pred_begin() { return Preds.begin(); }
|
||||
pred_iterator pred_end() { return Preds.end(); }
|
||||
const_pred_iterator pred_begin() const { return Preds.begin(); }
|
||||
const_pred_iterator pred_end() const { return Preds.end(); }
|
||||
|
||||
pred_reverse_iterator pred_rbegin() { return Preds.rbegin(); }
|
||||
pred_reverse_iterator pred_rend() { return Preds.rend(); }
|
||||
const_pred_reverse_iterator pred_rbegin() const { return Preds.rbegin(); }
|
||||
const_pred_reverse_iterator pred_rend() const { return Preds.rend(); }
|
||||
|
||||
succ_iterator succ_begin() { return Succs.begin(); }
|
||||
succ_iterator succ_end() { return Succs.end(); }
|
||||
const_succ_iterator succ_begin() const { return Succs.begin(); }
|
||||
const_succ_iterator succ_end() const { return Succs.end(); }
|
||||
|
||||
succ_reverse_iterator succ_rbegin() { return Succs.rbegin(); }
|
||||
succ_reverse_iterator succ_rend() { return Succs.rend(); }
|
||||
const_succ_reverse_iterator succ_rbegin() const { return Succs.rbegin(); }
|
||||
const_succ_reverse_iterator succ_rend() const { return Succs.rend(); }
|
||||
|
||||
unsigned succ_size() const { return Succs.size(); }
|
||||
bool succ_empty() const { return Succs.empty(); }
|
||||
|
||||
unsigned pred_size() const { return Preds.size(); }
|
||||
bool pred_empty() const { return Preds.empty(); }
|
||||
|
||||
// Manipulation of block contents
|
||||
|
||||
void setTerminator(Stmt* Statement) { Terminator = Statement; }
|
||||
void setLabel(Stmt* Statement) { Label = Statement; }
|
||||
void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; }
|
||||
|
||||
Stmt* getTerminator() { return Terminator; }
|
||||
const Stmt* getTerminator() const { return Terminator; }
|
||||
|
||||
Stmt* getTerminatorCondition();
|
||||
|
||||
const Stmt* getTerminatorCondition() const {
|
||||
return const_cast<CFGBlock*>(this)->getTerminatorCondition();
|
||||
}
|
||||
|
||||
const Stmt *getLoopTarget() const { return LoopTarget; }
|
||||
|
||||
bool hasBinaryBranchTerminator() const;
|
||||
|
||||
Stmt* getLabel() { return Label; }
|
||||
const Stmt* getLabel() const { return Label; }
|
||||
|
||||
void reverseStmts();
|
||||
|
||||
unsigned getBlockID() const { return BlockID; }
|
||||
|
||||
void dump(const CFG *cfg, const LangOptions &LO) const;
|
||||
void print(llvm::raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const;
|
||||
void printTerminator(llvm::raw_ostream &OS, const LangOptions &LO) const;
|
||||
|
||||
void addSuccessor(CFGBlock* Block, BumpVectorContext &C) {
|
||||
if (Block)
|
||||
Block->Preds.push_back(this, C);
|
||||
Succs.push_back(Block, C);
|
||||
}
|
||||
|
||||
void appendStmt(Stmt* Statement, BumpVectorContext &C) {
|
||||
Stmts.push_back(Statement, C);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// CFG - Represents a source-level, intra-procedural CFG that represents the
|
||||
/// control-flow of a Stmt. The Stmt can represent an entire function body,
|
||||
/// or a single expression. A CFG will always contain one empty block that
|
||||
/// represents the Exit point of the CFG. A CFG will also contain a designated
|
||||
/// Entry block. The CFG solely represents control-flow; it consists of
|
||||
/// CFGBlocks which are simply containers of Stmt*'s in the AST the CFG
|
||||
/// was constructed from.
|
||||
class CFG {
|
||||
public:
|
||||
//===--------------------------------------------------------------------===//
|
||||
// CFG Construction & Manipulation.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// buildCFG - Builds a CFG from an AST. The responsibility to free the
|
||||
/// constructed CFG belongs to the caller.
|
||||
static CFG* buildCFG(Stmt* AST, ASTContext *C);
|
||||
|
||||
/// createBlock - Create a new block in the CFG. The CFG owns the block;
|
||||
/// the caller should not directly free it.
|
||||
CFGBlock* createBlock();
|
||||
|
||||
/// setEntry - Set the entry block of the CFG. This is typically used
|
||||
/// only during CFG construction. Most CFG clients expect that the
|
||||
/// entry block has no predecessors and contains no statements.
|
||||
void setEntry(CFGBlock *B) { Entry = B; }
|
||||
|
||||
/// setIndirectGotoBlock - Set the block used for indirect goto jumps.
|
||||
/// This is typically used only during CFG construction.
|
||||
void setIndirectGotoBlock(CFGBlock* B) { IndirectGotoBlock = B; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Block Iterators
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
typedef BumpVector<CFGBlock*> CFGBlockListTy;
|
||||
typedef CFGBlockListTy::iterator iterator;
|
||||
typedef CFGBlockListTy::const_iterator const_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
CFGBlock& front() { return *Blocks.front(); }
|
||||
CFGBlock& back() { return *Blocks.back(); }
|
||||
|
||||
iterator begin() { return Blocks.begin(); }
|
||||
iterator end() { return Blocks.end(); }
|
||||
const_iterator begin() const { return Blocks.begin(); }
|
||||
const_iterator end() const { return Blocks.end(); }
|
||||
|
||||
reverse_iterator rbegin() { return Blocks.rbegin(); }
|
||||
reverse_iterator rend() { return Blocks.rend(); }
|
||||
const_reverse_iterator rbegin() const { return Blocks.rbegin(); }
|
||||
const_reverse_iterator rend() const { return Blocks.rend(); }
|
||||
|
||||
CFGBlock& getEntry() { return *Entry; }
|
||||
const CFGBlock& getEntry() const { return *Entry; }
|
||||
CFGBlock& getExit() { return *Exit; }
|
||||
const CFGBlock& getExit() const { return *Exit; }
|
||||
|
||||
CFGBlock* getIndirectGotoBlock() { return IndirectGotoBlock; }
|
||||
const CFGBlock* getIndirectGotoBlock() const { return IndirectGotoBlock; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Member templates useful for various batch operations over CFGs.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
template <typename CALLBACK>
|
||||
void VisitBlockStmts(CALLBACK& O) const {
|
||||
for (const_iterator I=begin(), E=end(); I != E; ++I)
|
||||
for (CFGBlock::const_iterator BI=(*I)->begin(), BE=(*I)->end();
|
||||
BI != BE; ++BI)
|
||||
O(*BI);
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// CFG Introspection.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
struct BlkExprNumTy {
|
||||
const signed Idx;
|
||||
explicit BlkExprNumTy(signed idx) : Idx(idx) {}
|
||||
explicit BlkExprNumTy() : Idx(-1) {}
|
||||
operator bool() const { return Idx >= 0; }
|
||||
operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; }
|
||||
};
|
||||
|
||||
bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); }
|
||||
BlkExprNumTy getBlkExprNum(const Stmt* S);
|
||||
unsigned getNumBlkExprs();
|
||||
|
||||
/// getNumBlockIDs - Returns the total number of BlockIDs allocated (which
|
||||
/// start at 0).
|
||||
unsigned getNumBlockIDs() const { return NumBlockIDs; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// CFG Debugging: Pretty-Printing and Visualization.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
void viewCFG(const LangOptions &LO) const;
|
||||
void print(llvm::raw_ostream& OS, const LangOptions &LO) const;
|
||||
void dump(const LangOptions &LO) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Internal: constructors and data.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0),
|
||||
BlkExprMap(NULL), Blocks(BlkBVC, 10) {};
|
||||
|
||||
~CFG();
|
||||
|
||||
llvm::BumpPtrAllocator& getAllocator() {
|
||||
return BlkBVC.getAllocator();
|
||||
}
|
||||
|
||||
BumpVectorContext &getBumpVectorContext() {
|
||||
return BlkBVC;
|
||||
}
|
||||
|
||||
private:
|
||||
CFGBlock* Entry;
|
||||
CFGBlock* Exit;
|
||||
CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch
|
||||
// for indirect gotos
|
||||
unsigned NumBlockIDs;
|
||||
|
||||
// BlkExprMap - An opaque pointer to prevent inclusion of DenseMap.h.
|
||||
// It represents a map from Expr* to integers to record the set of
|
||||
// block-level expressions and their "statement number" in the CFG.
|
||||
void* BlkExprMap;
|
||||
|
||||
BumpVectorContext BlkBVC;
|
||||
|
||||
CFGBlockListTy Blocks;
|
||||
|
||||
};
|
||||
} // end namespace clang
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GraphTraits specializations for CFG basic block graphs (source-level CFGs)
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Traits for: CFGBlock
|
||||
|
||||
template <> struct GraphTraits<clang::CFGBlock* > {
|
||||
typedef clang::CFGBlock NodeType;
|
||||
typedef clang::CFGBlock::succ_iterator ChildIteratorType;
|
||||
|
||||
static NodeType* getEntryNode(clang::CFGBlock* BB)
|
||||
{ return BB; }
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N)
|
||||
{ return N->succ_begin(); }
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N)
|
||||
{ return N->succ_end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<const clang::CFGBlock* > {
|
||||
typedef const clang::CFGBlock NodeType;
|
||||
typedef clang::CFGBlock::const_succ_iterator ChildIteratorType;
|
||||
|
||||
static NodeType* getEntryNode(const clang::CFGBlock* BB)
|
||||
{ return BB; }
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N)
|
||||
{ return N->succ_begin(); }
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N)
|
||||
{ return N->succ_end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<Inverse<const clang::CFGBlock*> > {
|
||||
typedef const clang::CFGBlock NodeType;
|
||||
typedef clang::CFGBlock::const_pred_iterator ChildIteratorType;
|
||||
|
||||
static NodeType *getEntryNode(Inverse<const clang::CFGBlock*> G)
|
||||
{ return G.Graph; }
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N)
|
||||
{ return N->pred_begin(); }
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N)
|
||||
{ return N->pred_end(); }
|
||||
};
|
||||
|
||||
// Traits for: CFG
|
||||
|
||||
template <> struct GraphTraits<clang::CFG* >
|
||||
: public GraphTraits<clang::CFGBlock* > {
|
||||
|
||||
typedef clang::CFG::iterator nodes_iterator;
|
||||
|
||||
static NodeType *getEntryNode(clang::CFG* F) { return &F->getEntry(); }
|
||||
static nodes_iterator nodes_begin(clang::CFG* F) { return F->begin(); }
|
||||
static nodes_iterator nodes_end(clang::CFG* F) { return F->end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits< const clang::CFG* >
|
||||
: public GraphTraits< const clang::CFGBlock* > {
|
||||
|
||||
typedef clang::CFG::const_iterator nodes_iterator;
|
||||
|
||||
static NodeType *getEntryNode( const clang::CFG* F) { return &F->getEntry(); }
|
||||
static nodes_iterator nodes_begin( const clang::CFG* F) { return F->begin(); }
|
||||
static nodes_iterator nodes_end( const clang::CFG* F) { return F->end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<Inverse<const clang::CFG*> >
|
||||
: public GraphTraits<Inverse<const clang::CFGBlock*> > {
|
||||
|
||||
typedef clang::CFG::const_iterator nodes_iterator;
|
||||
|
||||
static NodeType *getEntryNode(const clang::CFG* F) { return &F->getExit(); }
|
||||
static nodes_iterator nodes_begin(const clang::CFG* F) { return F->begin();}
|
||||
static nodes_iterator nodes_end(const clang::CFG* F) { return F->end(); }
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
||||
147
include/clang/Analysis/CallGraph.h
Normal file
147
include/clang/Analysis/CallGraph.h
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
//== CallGraph.cpp - Call graph building ------------------------*- 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 CallGraph and CallGraphNode classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH
|
||||
#define LLVM_CLANG_ANALYSIS_CALLGRAPH
|
||||
|
||||
#include "clang/Index/ASTLocation.h"
|
||||
#include "clang/Index/Entity.h"
|
||||
#include "clang/Index/Program.h"
|
||||
#include "clang/Frontend/ASTUnit.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CallGraphNode {
|
||||
idx::Entity F;
|
||||
typedef std::pair<idx::ASTLocation, CallGraphNode*> CallRecord;
|
||||
std::vector<CallRecord> CalledFunctions;
|
||||
|
||||
public:
|
||||
CallGraphNode(idx::Entity f) : F(f) {}
|
||||
|
||||
typedef std::vector<CallRecord>::iterator iterator;
|
||||
typedef std::vector<CallRecord>::const_iterator const_iterator;
|
||||
|
||||
iterator begin() { return CalledFunctions.begin(); }
|
||||
iterator end() { return CalledFunctions.end(); }
|
||||
const_iterator begin() const { return CalledFunctions.begin(); }
|
||||
const_iterator end() const { return CalledFunctions.end(); }
|
||||
|
||||
void addCallee(idx::ASTLocation L, CallGraphNode *Node) {
|
||||
CalledFunctions.push_back(std::make_pair(L, Node));
|
||||
}
|
||||
|
||||
bool hasCallee() const { return begin() != end(); }
|
||||
|
||||
std::string getName() const { return F.getPrintableName(); }
|
||||
|
||||
Decl *getDecl(ASTContext &Ctx) const { return F.getDecl(Ctx); }
|
||||
};
|
||||
|
||||
class CallGraph {
|
||||
/// Program manages all Entities.
|
||||
idx::Program Prog;
|
||||
|
||||
typedef std::map<idx::Entity, CallGraphNode *> FunctionMapTy;
|
||||
|
||||
/// FunctionMap owns all CallGraphNodes.
|
||||
FunctionMapTy FunctionMap;
|
||||
|
||||
/// CallerCtx maps a caller to its ASTContext.
|
||||
llvm::DenseMap<CallGraphNode *, ASTContext *> CallerCtx;
|
||||
|
||||
/// Root node is the 'main' function or 0.
|
||||
CallGraphNode *Root;
|
||||
|
||||
/// ExternalCallingNode has edges to all external functions.
|
||||
CallGraphNode *ExternalCallingNode;
|
||||
|
||||
public:
|
||||
CallGraph();
|
||||
~CallGraph();
|
||||
|
||||
typedef FunctionMapTy::iterator iterator;
|
||||
typedef FunctionMapTy::const_iterator const_iterator;
|
||||
|
||||
iterator begin() { return FunctionMap.begin(); }
|
||||
iterator end() { return FunctionMap.end(); }
|
||||
const_iterator begin() const { return FunctionMap.begin(); }
|
||||
const_iterator end() const { return FunctionMap.end(); }
|
||||
|
||||
CallGraphNode *getRoot() { return Root; }
|
||||
|
||||
CallGraphNode *getExternalCallingNode() { return ExternalCallingNode; }
|
||||
|
||||
void addTU(ASTUnit &AST);
|
||||
|
||||
idx::Program &getProgram() { return Prog; }
|
||||
|
||||
CallGraphNode *getOrInsertFunction(idx::Entity F);
|
||||
|
||||
Decl *getDecl(CallGraphNode *Node);
|
||||
|
||||
void print(llvm::raw_ostream &os);
|
||||
void dump();
|
||||
|
||||
void ViewCallGraph() const;
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <> struct GraphTraits<clang::CallGraph> {
|
||||
typedef clang::CallGraph GraphType;
|
||||
typedef clang::CallGraphNode NodeType;
|
||||
|
||||
typedef std::pair<clang::idx::ASTLocation, NodeType*> CGNPairTy;
|
||||
typedef std::pointer_to_unary_function<CGNPairTy, NodeType*> CGNDerefFun;
|
||||
|
||||
typedef mapped_iterator<NodeType::iterator, CGNDerefFun> ChildIteratorType;
|
||||
|
||||
static NodeType *getEntryNode(GraphType *CG) {
|
||||
return CG->getExternalCallingNode();
|
||||
}
|
||||
|
||||
static ChildIteratorType child_begin(NodeType *N) {
|
||||
return map_iterator(N->begin(), CGNDerefFun(CGNDeref));
|
||||
}
|
||||
static ChildIteratorType child_end(NodeType *N) {
|
||||
return map_iterator(N->end(), CGNDerefFun(CGNDeref));
|
||||
}
|
||||
|
||||
typedef std::pair<clang::idx::Entity, NodeType*> PairTy;
|
||||
typedef std::pointer_to_unary_function<PairTy, NodeType*> DerefFun;
|
||||
|
||||
typedef mapped_iterator<GraphType::const_iterator, DerefFun> nodes_iterator;
|
||||
|
||||
static nodes_iterator nodes_begin(const GraphType &CG) {
|
||||
return map_iterator(CG.begin(), DerefFun(CGDeref));
|
||||
}
|
||||
static nodes_iterator nodes_end(const GraphType &CG) {
|
||||
return map_iterator(CG.end(), DerefFun(CGDeref));
|
||||
}
|
||||
|
||||
static NodeType *CGNDeref(CGNPairTy P) { return P.second; }
|
||||
|
||||
static NodeType *CGDeref(PairTy P) { return P.second; }
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
|
||||
#define LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
|
||||
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Analysis/ProgramPoint.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "functional" // STL
|
||||
|
|
@ -24,7 +24,7 @@ namespace clang {
|
|||
//===----------------------------------------------------------------------===//
|
||||
/// DataflowWorkListTy - Data structure representing the worklist used for
|
||||
/// dataflow algorithms.
|
||||
//===----------------------------------------------------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class DataflowWorkListTy {
|
||||
typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet;
|
||||
|
|
@ -33,15 +33,15 @@ public:
|
|||
/// enqueue - Add a block to the worklist. Blocks already on the
|
||||
/// worklist are not added a second time.
|
||||
void enqueue(const CFGBlock* B) { wlist.insert(B); }
|
||||
|
||||
|
||||
/// dequeue - Remove a block from the worklist.
|
||||
const CFGBlock* dequeue() {
|
||||
assert (!wlist.empty());
|
||||
const CFGBlock* B = *wlist.begin();
|
||||
wlist.erase(B);
|
||||
return B;
|
||||
return B;
|
||||
}
|
||||
|
||||
|
||||
/// isEmpty - Return true if the worklist is empty.
|
||||
bool isEmpty() const { return wlist.empty(); }
|
||||
};
|
||||
|
|
@ -59,22 +59,22 @@ template <> struct ItrTraits<forward_analysis_tag> {
|
|||
typedef CFGBlock::const_pred_iterator PrevBItr;
|
||||
typedef CFGBlock::const_succ_iterator NextBItr;
|
||||
typedef CFGBlock::const_iterator StmtItr;
|
||||
|
||||
|
||||
static PrevBItr PrevBegin(const CFGBlock* B) { return B->pred_begin(); }
|
||||
static PrevBItr PrevEnd(const CFGBlock* B) { return B->pred_end(); }
|
||||
|
||||
static NextBItr NextBegin(const CFGBlock* B) { return B->succ_begin(); }
|
||||
|
||||
static NextBItr NextBegin(const CFGBlock* B) { return B->succ_begin(); }
|
||||
static NextBItr NextEnd(const CFGBlock* B) { return B->succ_end(); }
|
||||
|
||||
|
||||
static StmtItr StmtBegin(const CFGBlock* B) { return B->begin(); }
|
||||
static StmtItr StmtEnd(const CFGBlock* B) { return B->end(); }
|
||||
|
||||
|
||||
static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) {
|
||||
return BlockEdge(Prev, B);
|
||||
return BlockEdge(Prev, B, 0);
|
||||
}
|
||||
|
||||
|
||||
static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) {
|
||||
return BlockEdge(B, Next);
|
||||
return BlockEdge(B, Next, 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -82,22 +82,22 @@ template <> struct ItrTraits<backward_analysis_tag> {
|
|||
typedef CFGBlock::const_succ_iterator PrevBItr;
|
||||
typedef CFGBlock::const_pred_iterator NextBItr;
|
||||
typedef CFGBlock::const_reverse_iterator StmtItr;
|
||||
|
||||
static PrevBItr PrevBegin(const CFGBlock* B) { return B->succ_begin(); }
|
||||
|
||||
static PrevBItr PrevBegin(const CFGBlock* B) { return B->succ_begin(); }
|
||||
static PrevBItr PrevEnd(const CFGBlock* B) { return B->succ_end(); }
|
||||
|
||||
static NextBItr NextBegin(const CFGBlock* B) { return B->pred_begin(); }
|
||||
|
||||
static NextBItr NextBegin(const CFGBlock* B) { return B->pred_begin(); }
|
||||
static NextBItr NextEnd(const CFGBlock* B) { return B->pred_end(); }
|
||||
|
||||
|
||||
static StmtItr StmtBegin(const CFGBlock* B) { return B->rbegin(); }
|
||||
static StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); }
|
||||
|
||||
static StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); }
|
||||
|
||||
static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) {
|
||||
return BlockEdge(B, Prev);
|
||||
return BlockEdge(B, Prev, 0);
|
||||
}
|
||||
|
||||
|
||||
static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) {
|
||||
return BlockEdge(Next, B);
|
||||
return BlockEdge(Next, B, 0);
|
||||
}
|
||||
};
|
||||
} // end namespace dataflow
|
||||
|
|
@ -105,7 +105,7 @@ template <> struct ItrTraits<backward_analysis_tag> {
|
|||
//===----------------------------------------------------------------------===//
|
||||
/// DataflowSolverTy - Generic dataflow solver.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
template <typename _DFValuesTy, // Usually a subclass of DataflowValues
|
||||
typename _TransferFuncsTy,
|
||||
typename _MergeOperatorTy,
|
||||
|
|
@ -120,7 +120,7 @@ public:
|
|||
typedef _DFValuesTy DFValuesTy;
|
||||
typedef _TransferFuncsTy TransferFuncsTy;
|
||||
typedef _MergeOperatorTy MergeOperatorTy;
|
||||
|
||||
|
||||
typedef typename _DFValuesTy::AnalysisDirTag AnalysisDirTag;
|
||||
typedef typename _DFValuesTy::ValTy ValTy;
|
||||
typedef typename _DFValuesTy::EdgeDataMapTy EdgeDataMapTy;
|
||||
|
|
@ -130,24 +130,24 @@ public:
|
|||
typedef typename ItrTraits::NextBItr NextBItr;
|
||||
typedef typename ItrTraits::PrevBItr PrevBItr;
|
||||
typedef typename ItrTraits::StmtItr StmtItr;
|
||||
|
||||
|
||||
//===----------------------------------------------------===//
|
||||
// External interface: constructing and running the solver.
|
||||
//===----------------------------------------------------===//
|
||||
|
||||
|
||||
public:
|
||||
DataflowSolver(DFValuesTy& d) : D(d), TF(d.getAnalysisData()) {}
|
||||
~DataflowSolver() {}
|
||||
|
||||
~DataflowSolver() {}
|
||||
|
||||
/// runOnCFG - Computes dataflow values for all blocks in a CFG.
|
||||
void runOnCFG(CFG& cfg, bool recordStmtValues = false) {
|
||||
// Set initial dataflow values and boundary conditions.
|
||||
D.InitializeValues(cfg);
|
||||
D.InitializeValues(cfg);
|
||||
// Solve the dataflow equations. This will populate D.EdgeDataMap
|
||||
// with dataflow values.
|
||||
SolveDataflowEquations(cfg, recordStmtValues);
|
||||
}
|
||||
|
||||
|
||||
/// runOnBlock - Computes dataflow values for a given block. This
|
||||
/// should usually be invoked only after previously computing
|
||||
/// dataflow values using runOnCFG, as runOnBlock is intended to
|
||||
|
|
@ -162,10 +162,10 @@ public:
|
|||
ProcessBlock(B, recordStmtValues, AnalysisDirTag());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void runOnBlock(const CFGBlock& B, bool recordStmtValues) {
|
||||
runOnBlock(&B, recordStmtValues);
|
||||
}
|
||||
}
|
||||
void runOnBlock(CFG::iterator& I, bool recordStmtValues) {
|
||||
runOnBlock(*I, recordStmtValues);
|
||||
}
|
||||
|
|
@ -177,81 +177,87 @@ public:
|
|||
for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
|
||||
runOnBlock(I, recordStmtValues);
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------===//
|
||||
// Internal solver logic.
|
||||
//===----------------------------------------------------===//
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
/// SolveDataflowEquations - Perform the actual worklist algorithm
|
||||
/// to compute dataflow values.
|
||||
void SolveDataflowEquations(CFG& cfg, bool recordStmtValues) {
|
||||
// Enqueue all blocks to ensure the dataflow values are computed
|
||||
// for every block. Not all blocks are guaranteed to reach the exit block.
|
||||
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
|
||||
WorkList.enqueue(&*I);
|
||||
|
||||
WorkList.enqueue(&**I);
|
||||
|
||||
while (!WorkList.isEmpty()) {
|
||||
const CFGBlock* B = WorkList.dequeue();
|
||||
ProcessMerge(cfg,B);
|
||||
ProcessMerge(cfg, B);
|
||||
ProcessBlock(B, recordStmtValues, AnalysisDirTag());
|
||||
UpdateEdges(cfg,B,TF.getVal());
|
||||
UpdateEdges(cfg, B, TF.getVal());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ProcessMerge(CFG& cfg, const CFGBlock* B) {
|
||||
ValTy& V = TF.getVal();
|
||||
ValTy& V = TF.getVal();
|
||||
TF.SetTopValue(V);
|
||||
|
||||
// Merge dataflow values from all predecessors of this block.
|
||||
MergeOperatorTy Merge;
|
||||
|
||||
|
||||
EdgeDataMapTy& M = D.getEdgeDataMap();
|
||||
bool firstMerge = true;
|
||||
|
||||
|
||||
for (PrevBItr I=ItrTraits::PrevBegin(B),E=ItrTraits::PrevEnd(B); I!=E; ++I){
|
||||
|
||||
CFGBlock *PrevBlk = *I;
|
||||
|
||||
if (!PrevBlk)
|
||||
continue;
|
||||
|
||||
typename EdgeDataMapTy::iterator EI =
|
||||
M.find(ItrTraits::PrevEdge(B, *I));
|
||||
M.find(ItrTraits::PrevEdge(B, PrevBlk));
|
||||
|
||||
if (EI != M.end()) {
|
||||
if (firstMerge) {
|
||||
firstMerge = false;
|
||||
V.copyValues(EI->second);
|
||||
}
|
||||
else Merge(V,EI->second);
|
||||
else
|
||||
Merge(V, EI->second);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Set the data for the block.
|
||||
D.getBlockDataMap()[B].copyValues(V);
|
||||
}
|
||||
}
|
||||
|
||||
/// ProcessBlock - Process the transfer functions for a given block.
|
||||
void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
|
||||
dataflow::forward_analysis_tag) {
|
||||
|
||||
|
||||
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I)
|
||||
ProcessStmt(*I, recordStmtValues, AnalysisDirTag());
|
||||
|
||||
TF.VisitTerminator(const_cast<CFGBlock*>(B));
|
||||
|
||||
TF.VisitTerminator(const_cast<CFGBlock*>(B));
|
||||
}
|
||||
|
||||
|
||||
void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
|
||||
dataflow::backward_analysis_tag) {
|
||||
|
||||
|
||||
TF.VisitTerminator(const_cast<CFGBlock*>(B));
|
||||
|
||||
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I)
|
||||
ProcessStmt(*I, recordStmtValues, AnalysisDirTag());
|
||||
}
|
||||
|
||||
|
||||
void ProcessStmt(const Stmt* S, bool record, dataflow::forward_analysis_tag) {
|
||||
if (record) D.getStmtDataMap()[S] = TF.getVal();
|
||||
TF.BlockStmt_Visit(const_cast<Stmt*>(S));
|
||||
TF.BlockStmt_Visit(const_cast<Stmt*>(S));
|
||||
}
|
||||
|
||||
|
||||
void ProcessStmt(const Stmt* S, bool record, dataflow::backward_analysis_tag){
|
||||
TF.BlockStmt_Visit(const_cast<Stmt*>(S));
|
||||
if (record) D.getStmtDataMap()[S] = TF.getVal();
|
||||
|
|
@ -263,14 +269,15 @@ private:
|
|||
// forward/backward analysis respectively)
|
||||
void UpdateEdges(CFG& cfg, const CFGBlock* B, ValTy& V) {
|
||||
for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I)
|
||||
UpdateEdgeValue(ItrTraits::NextEdge(B, *I),V,*I);
|
||||
if (CFGBlock *NextBlk = *I)
|
||||
UpdateEdgeValue(ItrTraits::NextEdge(B, NextBlk),V, NextBlk);
|
||||
}
|
||||
|
||||
|
||||
/// UpdateEdgeValue - Update the value associated with a given edge.
|
||||
void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock* TargetBlock) {
|
||||
EdgeDataMapTy& M = D.getEdgeDataMap();
|
||||
typename EdgeDataMapTy::iterator I = M.find(E);
|
||||
|
||||
|
||||
if (I == M.end()) { // First computed value for this edge?
|
||||
M[E].copyValues(V);
|
||||
WorkList.enqueue(TargetBlock);
|
||||
|
|
@ -280,7 +287,7 @@ private:
|
|||
WorkList.enqueue(TargetBlock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
DFValuesTy& D;
|
||||
DataflowWorkListTy WorkList;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_VALUES
|
||||
#define LLVM_CLANG_ANALYSES_DATAFLOW_VALUES
|
||||
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Analysis/ProgramPoint.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
/// Dataflow Directional Tag Classes. These are used for tag dispatching
|
||||
/// within the dataflow solver/transfer functions to determine what direction
|
||||
/// a dataflow analysis flows.
|
||||
//===----------------------------------------------------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
|
|
@ -34,19 +34,19 @@ namespace dataflow {
|
|||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DataflowValues. Container class to store dataflow values for a CFG.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename ValueTypes,
|
||||
typename _AnalysisDirTag = dataflow::forward_analysis_tag >
|
||||
class DataflowValues {
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type declarations.
|
||||
//===--------------------------------------------------------------------===//
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
public:
|
||||
typedef typename ValueTypes::ValTy ValTy;
|
||||
typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy;
|
||||
typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy;
|
||||
typedef _AnalysisDirTag AnalysisDirTag;
|
||||
typedef llvm::DenseMap<ProgramPoint, ValTy> EdgeDataMapTy;
|
||||
typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy;
|
||||
|
|
@ -60,15 +60,15 @@ public:
|
|||
/// isForwardAnalysis - Returns true if the dataflow values are computed
|
||||
/// from a forward analysis.
|
||||
bool isForwardAnalysis() { return isForwardAnalysis(AnalysisDirTag()); }
|
||||
|
||||
|
||||
/// isBackwardAnalysis - Returns true if the dataflow values are computed
|
||||
/// from a backward analysis.
|
||||
bool isBackwardAnalysis() { return !isForwardAnalysis(); }
|
||||
|
||||
|
||||
private:
|
||||
bool isForwardAnalysis(dataflow::forward_analysis_tag) { return true; }
|
||||
bool isForwardAnalysis(dataflow::backward_analysis_tag) { return false; }
|
||||
|
||||
bool isForwardAnalysis(dataflow::backward_analysis_tag) { return false; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Initialization and accessors methods.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
@ -76,10 +76,10 @@ private:
|
|||
public:
|
||||
DataflowValues() : StmtDataMap(NULL) {}
|
||||
~DataflowValues() { delete StmtDataMap; }
|
||||
|
||||
|
||||
/// InitializeValues - Invoked by the solver to initialize state needed for
|
||||
/// dataflow analysis. This method is usually specialized by subclasses.
|
||||
void InitializeValues(const CFG& cfg) {};
|
||||
void InitializeValues(const CFG& cfg) {};
|
||||
|
||||
|
||||
/// getEdgeData - Retrieves the dataflow values associated with a
|
||||
|
|
@ -89,28 +89,28 @@ public:
|
|||
assert (I != EdgeDataMap.end() && "No data associated with Edge.");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
|
||||
const ValTy& getEdgeData(const BlockEdge& E) const {
|
||||
return reinterpret_cast<DataflowValues*>(this)->getEdgeData(E);
|
||||
}
|
||||
}
|
||||
|
||||
/// getBlockData - Retrieves the dataflow values associated with a
|
||||
/// getBlockData - Retrieves the dataflow values associated with a
|
||||
/// specified CFGBlock. If the dataflow analysis is a forward analysis,
|
||||
/// this data is associated with the END of the block. If the analysis
|
||||
/// is a backwards analysis, it is associated with the ENTRY of the block.
|
||||
/// is a backwards analysis, it is associated with the ENTRY of the block.
|
||||
ValTy& getBlockData(const CFGBlock* B) {
|
||||
typename BlockDataMapTy::iterator I = BlockDataMap.find(B);
|
||||
assert (I != BlockDataMap.end() && "No data associated with block.");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
|
||||
const ValTy& getBlockData(const CFGBlock* B) const {
|
||||
return const_cast<DataflowValues*>(this)->getBlockData(B);
|
||||
}
|
||||
|
||||
/// getStmtData - Retrieves the dataflow values associated with a
|
||||
|
||||
/// getStmtData - Retrieves the dataflow values associated with a
|
||||
/// specified Stmt. If the dataflow analysis is a forward analysis,
|
||||
/// this data corresponds to the point immediately before a Stmt.
|
||||
/// this data corresponds to the point immediately before a Stmt.
|
||||
/// If the analysis is a backwards analysis, it is associated with
|
||||
/// the point after a Stmt. This data is only computed for block-level
|
||||
/// expressions, and only when requested when the analysis is executed.
|
||||
|
|
@ -120,11 +120,11 @@ public:
|
|||
assert (I != StmtDataMap->end() && "No data associated with statement.");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
|
||||
const ValTy& getStmtData(const Stmt* S) const {
|
||||
return const_cast<DataflowValues*>(this)->getStmtData(S);
|
||||
}
|
||||
|
||||
|
||||
/// getEdgeDataMap - Retrieves the internal map between CFG edges and
|
||||
/// dataflow values. Usually used by a dataflow solver to compute
|
||||
/// values for blocks.
|
||||
|
|
@ -138,35 +138,35 @@ public:
|
|||
/// to the dataflow values at the end of the block.
|
||||
BlockDataMapTy& getBlockDataMap() { return BlockDataMap; }
|
||||
const BlockDataMapTy& getBlockDataMap() const { return BlockDataMap; }
|
||||
|
||||
|
||||
/// getStmtDataMap - Retrieves the internal map between Stmts and
|
||||
/// dataflow values.
|
||||
StmtDataMapTy& getStmtDataMap() {
|
||||
if (!StmtDataMap) StmtDataMap = new StmtDataMapTy();
|
||||
return *StmtDataMap;
|
||||
}
|
||||
|
||||
|
||||
const StmtDataMapTy& getStmtDataMap() const {
|
||||
return const_cast<DataflowValues*>(this)->getStmtDataMap();
|
||||
}
|
||||
|
||||
/// getAnalysisData - Retrieves the meta data associated with a
|
||||
/// dataflow analysis for analyzing a particular CFG.
|
||||
/// getAnalysisData - Retrieves the meta data associated with a
|
||||
/// dataflow analysis for analyzing a particular CFG.
|
||||
/// This is typically consumed by transfer function code (via the solver).
|
||||
/// This can also be used by subclasses to interpret the dataflow values.
|
||||
AnalysisDataTy& getAnalysisData() { return AnalysisData; }
|
||||
const AnalysisDataTy& getAnalysisData() const { return AnalysisData; }
|
||||
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Internal data.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
|
||||
protected:
|
||||
EdgeDataMapTy EdgeDataMap;
|
||||
BlockDataMapTy BlockDataMap;
|
||||
StmtDataMapTy* StmtDataMap;
|
||||
AnalysisDataTy AnalysisData;
|
||||
};
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -31,23 +31,29 @@ class BugReporter;
|
|||
class ObjCImplementationDecl;
|
||||
class LangOptions;
|
||||
class GRExprEngine;
|
||||
|
||||
void CheckDeadStores(LiveVariables& L, BugReporter& BR);
|
||||
|
||||
|
||||
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(ObjCImplementationDecl* D, const LangOptions& L,
|
||||
const LangOptions& lopts);
|
||||
|
||||
void CheckObjCDealloc(const ObjCImplementationDecl* D, const LangOptions& L,
|
||||
BugReporter& BR);
|
||||
|
||||
void CheckObjCInstMethSignature(ObjCImplementationDecl* ID, BugReporter& BR);
|
||||
void CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR);
|
||||
|
||||
void RegisterAppleChecks(GRExprEngine& Eng);
|
||||
|
||||
|
||||
void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID,
|
||||
BugReporter& BR);
|
||||
|
||||
void CheckObjCUnusedIvar(const ObjCImplementationDecl *D, BugReporter& BR);
|
||||
|
||||
void RegisterAppleChecks(GRExprEngine& Eng, const Decl &D);
|
||||
|
||||
void CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR);
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
|
|
@ -24,12 +25,17 @@
|
|||
#include <algorithm>
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
class Stmt;
|
||||
class Decl;
|
||||
class Preprocessor;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// High-level interface for handlers of path-sensitive diagnostics.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class PathDiagnostic;
|
||||
|
||||
class Stmt;
|
||||
class Decl;
|
||||
class Preprocessor;
|
||||
|
|
@ -38,21 +44,18 @@ class PathDiagnosticClient : public DiagnosticClient {
|
|||
public:
|
||||
PathDiagnosticClient() {}
|
||||
virtual ~PathDiagnosticClient() {}
|
||||
|
||||
virtual void SetPreprocessor(Preprocessor *PP) {}
|
||||
|
||||
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; }
|
||||
|
||||
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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -60,11 +63,11 @@ public:
|
|||
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;
|
||||
|
|
@ -75,27 +78,27 @@ private:
|
|||
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;
|
||||
|
|
@ -104,27 +107,29 @@ public:
|
|||
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 {
|
||||
|
|
@ -134,19 +139,24 @@ 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:
|
||||
|
|
@ -159,7 +169,7 @@ private:
|
|||
const Kind kind;
|
||||
const DisplayHint Hint;
|
||||
std::vector<SourceRange> ranges;
|
||||
|
||||
|
||||
// Do not implement:
|
||||
PathDiagnosticPiece();
|
||||
PathDiagnosticPiece(const PathDiagnosticPiece &P);
|
||||
|
|
@ -167,42 +177,42 @@ private:
|
|||
|
||||
protected:
|
||||
PathDiagnosticPiece(const std::string& s, Kind k, DisplayHint hint = Below);
|
||||
|
||||
|
||||
PathDiagnosticPiece(const char* 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 {
|
||||
|
||||
range_iterator ranges_end() const {
|
||||
return ranges_begin() + ranges.size();
|
||||
}
|
||||
|
||||
|
|
@ -213,15 +223,17 @@ public:
|
|||
}
|
||||
|
||||
code_modifications_iterator code_modifications_end() const {
|
||||
return CodeModificationHints.empty()? 0
|
||||
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;
|
||||
|
|
@ -234,30 +246,32 @@ public:
|
|||
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,
|
||||
const std::string& s, bool addPosRange = true)
|
||||
: PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
|
||||
|
||||
|
||||
PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, const char* 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<PathDiagnosticLocationPair> LPairs;
|
||||
public:
|
||||
|
|
@ -267,40 +281,40 @@ public:
|
|||
: PathDiagnosticPiece(s, ControlFlow) {
|
||||
LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
|
||||
}
|
||||
|
||||
|
||||
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
|
||||
const PathDiagnosticLocation &endPos,
|
||||
const char* 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<PathDiagnosticLocationPair>::iterator iterator;
|
||||
iterator begin() { return LPairs.begin(); }
|
||||
iterator end() { return LPairs.end(); }
|
||||
|
|
@ -308,7 +322,7 @@ public:
|
|||
virtual void flattenLocations() {
|
||||
for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten();
|
||||
}
|
||||
|
||||
|
||||
typedef std::vector<PathDiagnosticLocationPair>::const_iterator
|
||||
const_iterator;
|
||||
const_iterator begin() const { return LPairs.begin(); }
|
||||
|
|
@ -317,171 +331,177 @@ public:
|
|||
static inline bool classof(const PathDiagnosticPiece* P) {
|
||||
return P->getKind() == ControlFlow;
|
||||
}
|
||||
};
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
|
||||
};
|
||||
|
||||
class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
|
||||
std::vector<PathDiagnosticPiece*> 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<PathDiagnosticPiece*>::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<PathDiagnosticPiece*>::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 {
|
||||
class PathDiagnostic : public llvm::FoldingSetNode {
|
||||
std::deque<PathDiagnosticPiece*> path;
|
||||
unsigned Size;
|
||||
std::string BugType;
|
||||
std::string Desc;
|
||||
std::string Category;
|
||||
std::deque<std::string> OtherDesc;
|
||||
|
||||
public:
|
||||
|
||||
public:
|
||||
PathDiagnostic();
|
||||
|
||||
|
||||
PathDiagnostic(const char* bugtype, const char* desc, const char* category);
|
||||
|
||||
PathDiagnostic(const std::string& bugtype, const std::string& desc,
|
||||
|
||||
PathDiagnostic(const std::string& bugtype, const std::string& desc,
|
||||
const std::string& category);
|
||||
|
||||
|
||||
~PathDiagnostic();
|
||||
|
||||
|
||||
const std::string& getDescription() const { return Desc; }
|
||||
const std::string& getBugType() const { return BugType; }
|
||||
const std::string& getCategory() const { return Category; }
|
||||
|
||||
const std::string& getCategory() const { return Category; }
|
||||
|
||||
typedef std::deque<std::string>::const_iterator meta_iterator;
|
||||
meta_iterator meta_begin() const { return OtherDesc.begin(); }
|
||||
meta_iterator meta_end() const { return OtherDesc.end(); }
|
||||
void addMeta(const std::string& s) { OtherDesc.push_back(s); }
|
||||
void addMeta(const char* 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:
|
||||
public:
|
||||
typedef std::deque<PathDiagnosticPiece*>::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:
|
||||
public:
|
||||
typedef std::deque<PathDiagnosticPiece*>::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<iterator> reverse_iterator;
|
||||
typedef std::reverse_iterator<const_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
|
||||
|
|
|
|||
167
include/clang/Analysis/PathSensitive/AnalysisContext.h
Normal file
167
include/clang/Analysis/PathSensitive/AnalysisContext.h
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
//=== 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 "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Decl;
|
||||
class Stmt;
|
||||
class CFG;
|
||||
class LiveVariables;
|
||||
class ParentMap;
|
||||
class ImplicitParamDecl;
|
||||
|
||||
/// 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;
|
||||
|
||||
public:
|
||||
AnalysisContext(const Decl *d) : D(d), cfg(0), liveness(0), PM(0) {}
|
||||
~AnalysisContext();
|
||||
|
||||
const Decl *getDecl() { return D; }
|
||||
Stmt *getBody();
|
||||
CFG *getCFG();
|
||||
ParentMap &getParentMap();
|
||||
LiveVariables *getLiveVariables();
|
||||
|
||||
/// Return the ImplicitParamDecl* associated with 'self' if this
|
||||
/// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise.
|
||||
const ImplicitParamDecl *getSelfDecl() const;
|
||||
};
|
||||
|
||||
class AnalysisContextManager {
|
||||
typedef llvm::DenseMap<const Decl*, AnalysisContext*> ContextMap;
|
||||
ContextMap Contexts;
|
||||
public:
|
||||
~AnalysisContextManager();
|
||||
|
||||
AnalysisContext *getContext(const Decl *D);
|
||||
};
|
||||
|
||||
class LocationContext : public llvm::FoldingSetNode {
|
||||
public:
|
||||
enum ContextKind { StackFrame, Scope };
|
||||
|
||||
private:
|
||||
ContextKind Kind;
|
||||
AnalysisContext *Ctx;
|
||||
const LocationContext *Parent;
|
||||
|
||||
protected:
|
||||
LocationContext(ContextKind k, AnalysisContext *ctx,
|
||||
const LocationContext *parent)
|
||||
: Kind(k), Ctx(ctx), Parent(parent) {}
|
||||
|
||||
public:
|
||||
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();
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, Kind, Ctx, Parent);
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, ContextKind k,
|
||||
AnalysisContext *ctx, const LocationContext *parent);
|
||||
|
||||
static bool classof(const LocationContext*) { return true; }
|
||||
};
|
||||
|
||||
class StackFrameContext : public LocationContext {
|
||||
const Stmt *CallSite;
|
||||
|
||||
public:
|
||||
StackFrameContext(AnalysisContext *ctx, const LocationContext *parent,
|
||||
const Stmt *s)
|
||||
: LocationContext(StackFrame, ctx, parent), CallSite(s) {}
|
||||
|
||||
Stmt const *getCallSite() const { return CallSite; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getAnalysisContext(), getParent(), CallSite);
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
|
||||
const LocationContext *parent, const Stmt *s);
|
||||
|
||||
static bool classof(const LocationContext* Ctx) {
|
||||
return Ctx->getKind() == StackFrame;
|
||||
}
|
||||
};
|
||||
|
||||
class ScopeContext : public LocationContext {
|
||||
const Stmt *Enter;
|
||||
|
||||
public:
|
||||
ScopeContext(AnalysisContext *ctx, const LocationContext *parent,
|
||||
const Stmt *s)
|
||||
: LocationContext(Scope, ctx, parent), Enter(s) {}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getAnalysisContext(), getParent(), Enter);
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
|
||||
const LocationContext *parent, const Stmt *s);
|
||||
|
||||
static bool classof(const LocationContext* Ctx) {
|
||||
return Ctx->getKind() == Scope;
|
||||
}
|
||||
};
|
||||
|
||||
class LocationContextManager {
|
||||
llvm::FoldingSet<LocationContext> Contexts;
|
||||
|
||||
public:
|
||||
StackFrameContext *getStackFrame(AnalysisContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const Stmt *s);
|
||||
|
||||
ScopeContext *getScope(AnalysisContext *ctx, const LocationContext *parent,
|
||||
const Stmt *s);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
#endif
|
||||
140
include/clang/Analysis/PathSensitive/AnalysisManager.h
Normal file
140
include/clang/Analysis/PathSensitive/AnalysisManager.h
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
//== 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<PathDiagnosticClient> PD;
|
||||
|
||||
// Configurable components creators.
|
||||
StoreManagerCreator CreateStoreMgr;
|
||||
ConstraintManagerCreator CreateConstraintMgr;
|
||||
|
||||
enum AnalysisScope { ScopeTU, ScopeDecl } AScope;
|
||||
|
||||
bool DisplayedFunction;
|
||||
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 displayProgress, bool vizdot, bool vizubi,
|
||||
bool purge, bool eager, bool trim)
|
||||
|
||||
: Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd),
|
||||
CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),
|
||||
AScope(ScopeDecl), DisplayedFunction(!displayProgress),
|
||||
VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge),
|
||||
EagerlyAssume(eager), TrimGraph(trim) {}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
void DisplayFunction(Decl *D);
|
||||
|
||||
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.
|
||||
StackFrameContext *getStackFrame(Decl const *D) {
|
||||
return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), 0, 0);
|
||||
}
|
||||
|
||||
// Get a stack frame with parent.
|
||||
StackFrameContext const *getStackFrame(Decl const *D,
|
||||
LocationContext const *Parent,
|
||||
Stmt const *S) {
|
||||
return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), Parent, S);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines BasicValueFactory, a class that manages the lifetime
|
||||
// of APSInt objects and symbolic constraints used by GRExprEngine
|
||||
// of APSInt objects and symbolic constraints used by GRExprEngine
|
||||
// and related classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -24,25 +24,43 @@
|
|||
#include "llvm/ADT/ImmutableList.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
class GRState;
|
||||
|
||||
class CompoundValData : public llvm::FoldingSetNode {
|
||||
QualType T;
|
||||
llvm::ImmutableList<SVal> L;
|
||||
|
||||
public:
|
||||
CompoundValData(QualType t, llvm::ImmutableList<SVal> l)
|
||||
CompoundValData(QualType t, llvm::ImmutableList<SVal> l)
|
||||
: T(t), L(l) {}
|
||||
|
||||
typedef llvm::ImmutableList<SVal>::iterator iterator;
|
||||
iterator begin() const { return L.begin(); }
|
||||
iterator end() const { return L.end(); }
|
||||
|
||||
iterator end() const { return L.end(); }
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID& ID, QualType T,
|
||||
llvm::ImmutableList<SVal> 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<llvm::FoldingSetNodeWrapper<llvm::APSInt> >
|
||||
APSIntSetTy;
|
||||
|
|
@ -56,44 +74,54 @@ class BasicValueFactory {
|
|||
|
||||
llvm::ImmutableList<SVal>::Factory SValListFactory;
|
||||
llvm::FoldingSet<CompoundValData> CompoundValDataSet;
|
||||
llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet;
|
||||
|
||||
public:
|
||||
BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc)
|
||||
BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc)
|
||||
: Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0),
|
||||
SValListFactory(Alloc) {}
|
||||
|
||||
~BasicValueFactory();
|
||||
|
||||
ASTContext& getContext() const { return Ctx; }
|
||||
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 &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);
|
||||
|
||||
return getValue(From.getSExtValue(),
|
||||
To.getBitWidth(),
|
||||
To.isUnsigned());
|
||||
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()));
|
||||
}
|
||||
|
|
@ -103,44 +131,51 @@ public:
|
|||
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,
|
||||
|
||||
const CompoundValData *getCompoundValData(QualType T,
|
||||
llvm::ImmutableList<SVal> Vals);
|
||||
|
||||
|
||||
const LazyCompoundValData *getLazyCompoundValData(const GRState *state,
|
||||
const TypedRegion *region);
|
||||
|
||||
llvm::ImmutableList<SVal> getEmptySValList() {
|
||||
return SValListFactory.GetEmptyList();
|
||||
}
|
||||
|
||||
|
||||
llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) {
|
||||
return SValListFactory.Add(X, L);
|
||||
}
|
||||
|
|
@ -148,13 +183,13 @@ public:
|
|||
const llvm::APSInt* EvaluateAPSInt(BinaryOperator::Opcode Op,
|
||||
const llvm::APSInt& V1,
|
||||
const llvm::APSInt& V2);
|
||||
|
||||
|
||||
const std::pair<SVal, uintptr_t>&
|
||||
getPersistentSValWithData(const SVal& V, uintptr_t Data);
|
||||
|
||||
|
||||
const std::pair<SVal, SVal>&
|
||||
getPersistentSValPair(const SVal& V1, const SVal& V2);
|
||||
|
||||
getPersistentSValPair(const SVal& V1, const SVal& V2);
|
||||
|
||||
const SVal* getPersistentSVal(SVal X);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
#include <list>
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
class PathDiagnostic;
|
||||
class PathDiagnosticPiece;
|
||||
class PathDiagnosticClient;
|
||||
|
|
@ -40,7 +40,7 @@ class GRState;
|
|||
class Stmt;
|
||||
class BugType;
|
||||
class ParentMap;
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Interface for individual bug reports.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -48,22 +48,22 @@ class ParentMap;
|
|||
class BugReporterVisitor {
|
||||
public:
|
||||
virtual ~BugReporterVisitor();
|
||||
virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N,
|
||||
const ExplodedNode<GRState>* PrevN,
|
||||
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<GRState> *EndNode;
|
||||
const ExplodedNode *EndNode;
|
||||
SourceRange R;
|
||||
|
||||
|
||||
protected:
|
||||
friend class BugReporter;
|
||||
friend class BugReportEquivClass;
|
||||
|
|
@ -71,79 +71,78 @@ protected:
|
|||
virtual void Profile(llvm::FoldingSetNodeID& hash) const {
|
||||
hash.AddInteger(getLocation().getRawEncoding());
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
class NodeResolver {
|
||||
public:
|
||||
virtual ~NodeResolver() {}
|
||||
virtual const ExplodedNode<GRState>*
|
||||
getOriginalNode(const ExplodedNode<GRState>* N) = 0;
|
||||
virtual const ExplodedNode*
|
||||
getOriginalNode(const ExplodedNode* N) = 0;
|
||||
};
|
||||
|
||||
BugReport(BugType& bt, const char* desc, const ExplodedNode<GRState> *n)
|
||||
|
||||
BugReport(BugType& bt, const char* desc, const ExplodedNode *n)
|
||||
: BT(bt), Description(desc), EndNode(n) {}
|
||||
|
||||
|
||||
BugReport(BugType& bt, const char* shortDesc, const char* desc,
|
||||
const ExplodedNode<GRState> *n)
|
||||
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<GRState>* getEndNode() const { return EndNode; }
|
||||
|
||||
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.
|
||||
Stmt* getStmt(BugReporter& BR) const;
|
||||
|
||||
const Stmt* getStmt() const;
|
||||
|
||||
const std::string& getDescription() const { return Description; }
|
||||
|
||||
const std::string& getShortDescription() const {
|
||||
return ShortDescription.empty() ? Description : ShortDescription;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: Is this needed?
|
||||
virtual std::pair<const char**,const char**> 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<GRState>* N);
|
||||
|
||||
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(BugReporter& BR,const SourceRange*& beg,
|
||||
const SourceRange*& end);
|
||||
|
||||
virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N,
|
||||
const ExplodedNode<GRState>* PrevN,
|
||||
/// 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<GRState>* N) {}
|
||||
const ExplodedNode* N) {}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// BugTypes (collections of related reports).
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
class BugReportEquivClass : public llvm::FoldingSetNode {
|
||||
// List of *owned* BugReport objects.
|
||||
std::list<BugReport*> Reports;
|
||||
|
||||
|
||||
friend class BugReporter;
|
||||
void AddReport(BugReport* R) { Reports.push_back(R); }
|
||||
public:
|
||||
|
|
@ -165,7 +164,7 @@ public:
|
|||
BugReport* operator*() const { return *impl; }
|
||||
BugReport* operator->() const { return *impl; }
|
||||
};
|
||||
|
||||
|
||||
class const_iterator {
|
||||
std::list<BugReport*>::const_iterator impl;
|
||||
public:
|
||||
|
|
@ -176,64 +175,70 @@ public:
|
|||
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()); }
|
||||
};
|
||||
|
||||
|
||||
class BugType {
|
||||
private:
|
||||
const std::string Name;
|
||||
const std::string Category;
|
||||
llvm::FoldingSet<BugReportEquivClass> EQClasses;
|
||||
friend class BugReporter;
|
||||
bool SuppressonSink;
|
||||
public:
|
||||
BugType(const char *name, const char* cat) : Name(name), Category(cat) {}
|
||||
BugType(const char *name, const char* cat)
|
||||
: Name(name), Category(cat), SuppressonSink(false) {}
|
||||
virtual ~BugType();
|
||||
|
||||
|
||||
// FIXME: Should these be made strings as well?
|
||||
const std::string& getName() const { return Name; }
|
||||
const std::string& getCategory() const { return Category; }
|
||||
|
||||
virtual void FlushReports(BugReporter& BR);
|
||||
void AddReport(BugReport* BR);
|
||||
|
||||
/// 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<BugReportEquivClass>::iterator iterator;
|
||||
iterator begin() { return EQClasses.begin(); }
|
||||
iterator end() { return EQClasses.end(); }
|
||||
|
||||
|
||||
typedef llvm::FoldingSet<BugReportEquivClass>::const_iterator const_iterator;
|
||||
const_iterator begin() const { return EQClasses.begin(); }
|
||||
const_iterator end() const { return EQClasses.end(); }
|
||||
};
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Specialized subclasses of BugReport.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
// FIXME: Collapse this with the default BugReport class.
|
||||
class RangedBugReport : public BugReport {
|
||||
std::vector<SourceRange> Ranges;
|
||||
public:
|
||||
RangedBugReport(BugType& D, const char* description, ExplodedNode<GRState> *n)
|
||||
RangedBugReport(BugType& D, const char* description, ExplodedNode *n)
|
||||
: BugReport(D, description, n) {}
|
||||
|
||||
|
||||
RangedBugReport(BugType& D, const char *shortDescription,
|
||||
const char *description, ExplodedNode<GRState> *n)
|
||||
const char *description, ExplodedNode *n)
|
||||
: BugReport(D, shortDescription, description, n) {}
|
||||
|
||||
|
||||
~RangedBugReport();
|
||||
|
||||
// FIXME: Move this out of line.
|
||||
void addRange(SourceRange R) { Ranges.push_back(R); }
|
||||
|
||||
|
||||
// FIXME: Move this out of line.
|
||||
void getRanges(BugReporter& BR,const SourceRange*& beg,
|
||||
const SourceRange*& end) {
|
||||
|
||||
void getRanges(const SourceRange*& beg, const SourceRange*& end) {
|
||||
|
||||
if (Ranges.empty()) {
|
||||
beg = NULL;
|
||||
end = NULL;
|
||||
|
|
@ -244,7 +249,36 @@ public:
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class EnhancedBugReport : public RangedBugReport {
|
||||
public:
|
||||
typedef void (*VisitorCreator)(BugReporterContext &BRcC, const void *data,
|
||||
const ExplodedNode *N);
|
||||
|
||||
private:
|
||||
typedef std::vector<std::pair<VisitorCreator, const void*> > Creators;
|
||||
Creators creators;
|
||||
|
||||
public:
|
||||
EnhancedBugReport(BugType& D, const char* description, ExplodedNode *n)
|
||||
: RangedBugReport(D, description, n) {}
|
||||
|
||||
EnhancedBugReport(BugType& D, const char *shortDescription,
|
||||
const char *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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -252,15 +286,12 @@ public:
|
|||
class BugReporterData {
|
||||
public:
|
||||
virtual ~BugReporterData();
|
||||
virtual Diagnostic& getDiagnostic() = 0;
|
||||
virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
|
||||
virtual ASTContext& getContext() = 0;
|
||||
virtual Diagnostic& getDiagnostic() = 0;
|
||||
virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
|
||||
virtual ASTContext& getASTContext() = 0;
|
||||
virtual SourceManager& getSourceManager() = 0;
|
||||
virtual CFG* getCFG() = 0;
|
||||
virtual ParentMap& getParentMap() = 0;
|
||||
virtual LiveVariables* getLiveVariables() = 0;
|
||||
};
|
||||
|
||||
|
||||
class BugReporter {
|
||||
public:
|
||||
enum Kind { BaseBRKind, GRBugReporterKind };
|
||||
|
|
@ -270,9 +301,9 @@ private:
|
|||
BugTypesTy::Factory F;
|
||||
BugTypesTy BugTypes;
|
||||
|
||||
const Kind kind;
|
||||
const Kind kind;
|
||||
BugReporterData& D;
|
||||
|
||||
|
||||
void FlushReport(BugReportEquivClass& EQ);
|
||||
|
||||
protected:
|
||||
|
|
@ -281,40 +312,34 @@ protected:
|
|||
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.getContext(); }
|
||||
|
||||
|
||||
ASTContext& getContext() { return D.getASTContext(); }
|
||||
|
||||
SourceManager& getSourceManager() { return D.getSourceManager(); }
|
||||
|
||||
CFG* getCFG() { return D.getCFG(); }
|
||||
|
||||
ParentMap& getParentMap() { return D.getParentMap(); }
|
||||
|
||||
LiveVariables* getLiveVariables() { return D.getLiveVariables(); }
|
||||
|
||||
|
||||
virtual void GeneratePathDiagnostic(PathDiagnostic& PD,
|
||||
BugReportEquivClass& EQ) {}
|
||||
|
||||
void Register(BugType *BT);
|
||||
|
||||
|
||||
void EmitReport(BugReport *R);
|
||||
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* BugStr,
|
||||
SourceLocation Loc,
|
||||
SourceRange* RangeBeg, unsigned NumRanges);
|
||||
|
|
@ -322,28 +347,28 @@ public:
|
|||
void EmitBasicReport(const char* BugName, const char* BugCategory,
|
||||
const char* BugStr, SourceLocation Loc,
|
||||
SourceRange* RangeBeg, unsigned NumRanges);
|
||||
|
||||
|
||||
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* BugStr,
|
||||
SourceLocation Loc) {
|
||||
EmitBasicReport(BugName, BugStr, Loc, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* BugCategory,
|
||||
const char* BugStr, SourceLocation Loc) {
|
||||
EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* BugStr,
|
||||
SourceLocation Loc, SourceRange R) {
|
||||
EmitBasicReport(BugName, BugStr, Loc, &R, 1);
|
||||
}
|
||||
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* Category,
|
||||
const char* BugStr, SourceLocation Loc, SourceRange R) {
|
||||
EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1);
|
||||
}
|
||||
|
||||
|
||||
static bool classof(const BugReporter* R) { return true; }
|
||||
};
|
||||
|
||||
|
|
@ -351,95 +376,87 @@ public:
|
|||
class GRBugReporter : public BugReporter {
|
||||
GRExprEngine& Eng;
|
||||
llvm::SmallSet<SymbolRef, 10> NotableSymbols;
|
||||
public:
|
||||
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; }
|
||||
GRExprEngine &getEngine() { return Eng; }
|
||||
|
||||
/// getGraph - Get the exploded graph created by the analysis engine
|
||||
/// for the analyzed method or function.
|
||||
ExplodedGraph<GRState>& getGraph();
|
||||
|
||||
ExplodedGraph &getGraph();
|
||||
|
||||
/// getStateManager - Return the state manager used by the analysis
|
||||
/// engine.
|
||||
GRStateManager& getStateManager();
|
||||
|
||||
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<BugReporterVisitor*> Callbacks;
|
||||
public:
|
||||
BugReporterContext(GRBugReporter& br) : BR(br) {}
|
||||
virtual ~BugReporterContext();
|
||||
|
||||
|
||||
void addVisitor(BugReporterVisitor* visitor) {
|
||||
if (visitor) Callbacks.push_back(visitor);
|
||||
}
|
||||
|
||||
|
||||
typedef std::vector<BugReporterVisitor*>::iterator visitor_iterator;
|
||||
visitor_iterator visitor_begin() { return Callbacks.begin(); }
|
||||
visitor_iterator visitor_end() { return Callbacks.end(); }
|
||||
|
||||
GRBugReporter& getBugReporter() { return BR; }
|
||||
|
||||
ExplodedGraph<GRState>& getGraph() { return BR.getGraph(); }
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
const Decl& getCodeDecl() {
|
||||
return getStateManager().getCodeDecl();
|
||||
}
|
||||
|
||||
const CFG& getCFG() {
|
||||
return *BR.getCFG();
|
||||
}
|
||||
|
||||
virtual BugReport::NodeResolver& getNodeResolver() = 0;
|
||||
|
||||
virtual BugReport::NodeResolver& getNodeResolver() = 0;
|
||||
};
|
||||
|
||||
class DiagBugReport : public RangedBugReport {
|
||||
|
|
@ -448,19 +465,37 @@ class DiagBugReport : public RangedBugReport {
|
|||
public:
|
||||
DiagBugReport(BugType& D, const char* 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(const std::string& s) { Strs.push_back(s); }
|
||||
|
||||
|
||||
void addString(const std::string& s) { Strs.push_back(s); }
|
||||
|
||||
typedef std::list<std::string>::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
|
||||
|
|
|
|||
122
include/clang/Analysis/PathSensitive/Checker.h
Normal file
122
include/clang/Analysis/PathSensitive/Checker.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
//== 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<bool> OldSink;
|
||||
SaveAndRestore<const void*> OldTag;
|
||||
SaveAndRestore<ProgramPoint::Kind> OldPointKind;
|
||||
SaveOr OldHasGen;
|
||||
|
||||
public:
|
||||
CheckerContext(ExplodedNodeSet &dst,
|
||||
GRStmtNodeBuilder &builder,
|
||||
GRExprEngine &eng,
|
||||
ExplodedNode *pred,
|
||||
const void *tag, bool preVisit)
|
||||
: Dst(dst), B(builder), Eng(eng), Pred(pred),
|
||||
OldSink(B.BuildSinks), OldTag(B.Tag),
|
||||
OldPointKind(B.PointKind), OldHasGen(B.HasGeneratedNode) {
|
||||
//assert(Dst.empty()); // This is a fake assertion.
|
||||
// See GRExprEngine::CheckerVisit(), CurrSet is repeatedly used.
|
||||
B.Tag = tag;
|
||||
if (preVisit)
|
||||
B.PointKind = ProgramPoint::PreStmtKind;
|
||||
}
|
||||
|
||||
~CheckerContext() {
|
||||
if (!B.BuildSinks && !B.HasGeneratedNode)
|
||||
Dst.Add(Pred);
|
||||
}
|
||||
|
||||
ConstraintManager &getConstraintManager() {
|
||||
return Eng.getConstraintManager();
|
||||
}
|
||||
ExplodedNodeSet &getNodeSet() { return Dst; }
|
||||
GRStmtNodeBuilder &getNodeBuilder() { return B; }
|
||||
ExplodedNode *&getPredecessor() { return Pred; }
|
||||
const GRState *getState() { return B.GetState(Pred); }
|
||||
|
||||
ASTContext &getASTContext() {
|
||||
return Eng.getContext();
|
||||
}
|
||||
|
||||
ExplodedNode *GenerateNode(const Stmt *S, bool markAsSink = false) {
|
||||
return GenerateNode(S, getState(), markAsSink);
|
||||
}
|
||||
|
||||
ExplodedNode *GenerateNode(const Stmt* S, const GRState *state,
|
||||
bool markAsSink = false) {
|
||||
ExplodedNode *node = B.generateNode(S, state, Pred);
|
||||
|
||||
if (markAsSink && node)
|
||||
node->markAsSink();
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void addTransition(ExplodedNode *node) {
|
||||
Dst.Add(node);
|
||||
}
|
||||
|
||||
void EmitReport(BugReport *R) {
|
||||
Eng.getBugReporter().EmitReport(R);
|
||||
}
|
||||
};
|
||||
|
||||
class Checker {
|
||||
private:
|
||||
friend class GRExprEngine;
|
||||
|
||||
void GR_Visit(ExplodedNodeSet &Dst,
|
||||
GRStmtNodeBuilder &Builder,
|
||||
GRExprEngine &Eng,
|
||||
const Stmt *stmt,
|
||||
ExplodedNode *Pred, bool isPrevisit) {
|
||||
CheckerContext C(Dst, Builder, Eng, Pred, getTag(), isPrevisit);
|
||||
assert(isPrevisit && "Only previsit supported for now.");
|
||||
_PreVisit(C, stmt);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~Checker() {}
|
||||
virtual void _PreVisit(CheckerContext &C, const Stmt *stmt) = 0;
|
||||
virtual const void *getTag() = 0;
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
|
||||
18
include/clang/Analysis/PathSensitive/CheckerVisitor.def
Normal file
18
include/clang/Analysis/PathSensitive/CheckerVisitor.def
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
//===-- 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.
|
||||
//
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
PREVISIT(CallExpr)
|
||||
PREVISIT(ObjCMessageExpr)
|
||||
PREVISIT(BinaryOperator)
|
||||
|
||||
#undef PREVISIT
|
||||
59
include/clang/Analysis/PathSensitive/CheckerVisitor.h
Normal file
59
include/clang/Analysis/PathSensitive/CheckerVisitor.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
//== 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<typename ImplClass>
|
||||
class CheckerVisitor : public Checker {
|
||||
public:
|
||||
virtual void _PreVisit(CheckerContext &C, const Stmt *stmt) {
|
||||
PreVisit(C, stmt);
|
||||
}
|
||||
|
||||
void PreVisit(CheckerContext &C, const Stmt *S) {
|
||||
switch (S->getStmtClass()) {
|
||||
default:
|
||||
assert(false && "Unsupport statement.");
|
||||
return;
|
||||
case Stmt::CompoundAssignOperatorClass:
|
||||
static_cast<ImplClass*>(this)->PreVisitBinaryOperator(C,
|
||||
static_cast<const BinaryOperator*>(S));
|
||||
break;
|
||||
#define PREVISIT(NAME) \
|
||||
case Stmt::NAME ## Class:\
|
||||
static_cast<ImplClass*>(this)->PreVisit ## NAME(C,static_cast<const NAME*>(S));\
|
||||
break;
|
||||
#include "clang/Analysis/PathSensitive/CheckerVisitor.def"
|
||||
}
|
||||
}
|
||||
|
||||
#define PREVISIT(NAME) \
|
||||
void PreVisit ## NAME(CheckerContext &C, const NAME* S) {}
|
||||
#include "clang/Analysis/PathSensitive/CheckerVisitor.def"
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -30,26 +30,32 @@ class SVal;
|
|||
class ConstraintManager {
|
||||
public:
|
||||
virtual ~ConstraintManager();
|
||||
virtual const GRState *Assume(const GRState *state, SVal Cond,
|
||||
virtual const GRState *Assume(const GRState *state, DefinedSVal Cond,
|
||||
bool Assumption) = 0;
|
||||
|
||||
virtual const GRState *AssumeInBound(const GRState *state, SVal Idx,
|
||||
SVal UpperBound, bool Assumption) = 0;
|
||||
virtual const GRState *AssumeInBound(const GRState *state, DefinedSVal Idx,
|
||||
DefinedSVal UpperBound, bool Assumption) = 0;
|
||||
|
||||
std::pair<const GRState*, const GRState*> 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,
|
||||
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,
|
||||
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
|
||||
|
|
|
|||
|
|
@ -26,125 +26,78 @@
|
|||
|
||||
namespace clang {
|
||||
|
||||
class AnalysisContext;
|
||||
class EnvironmentManager;
|
||||
class ValueManager;
|
||||
class LiveVariables;
|
||||
|
||||
|
||||
class Environment {
|
||||
private:
|
||||
friend class EnvironmentManager;
|
||||
|
||||
|
||||
// Type definitions.
|
||||
typedef llvm::ImmutableMap<const Stmt*,SVal> BindingsTy;
|
||||
|
||||
// Data.
|
||||
BindingsTy SubExprBindings;
|
||||
BindingsTy BlkExprBindings;
|
||||
|
||||
Environment(BindingsTy seb, BindingsTy beb)
|
||||
: SubExprBindings(seb), BlkExprBindings(beb) {}
|
||||
|
||||
BindingsTy ExprBindings;
|
||||
AnalysisContext *ACtx;
|
||||
|
||||
Environment(BindingsTy eb, AnalysisContext *aCtx)
|
||||
: ExprBindings(eb), ACtx(aCtx) {}
|
||||
|
||||
public:
|
||||
|
||||
typedef BindingsTy::iterator seb_iterator;
|
||||
seb_iterator seb_begin() const { return SubExprBindings.begin(); }
|
||||
seb_iterator seb_end() const { return SubExprBindings.end(); }
|
||||
|
||||
typedef BindingsTy::iterator beb_iterator;
|
||||
beb_iterator beb_begin() const { return BlkExprBindings.begin(); }
|
||||
beb_iterator beb_end() const { return BlkExprBindings.end(); }
|
||||
|
||||
SVal LookupSubExpr(const Stmt* E) const {
|
||||
const SVal* X = SubExprBindings.lookup(cast<Expr>(E));
|
||||
return X ? *X : UnknownVal();
|
||||
}
|
||||
|
||||
SVal LookupBlkExpr(const Stmt* E) const {
|
||||
const SVal* X = BlkExprBindings.lookup(E);
|
||||
return X ? *X : UnknownVal();
|
||||
}
|
||||
|
||||
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 = SubExprBindings.lookup(E);
|
||||
if (X) return *X;
|
||||
X = BlkExprBindings.lookup(E);
|
||||
const SVal* X = ExprBindings.lookup(E);
|
||||
return X ? *X : UnknownVal();
|
||||
}
|
||||
|
||||
|
||||
SVal GetSVal(const Stmt* Ex, ValueManager& ValMgr) const;
|
||||
SVal GetBlkExprSVal(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->SubExprBindings.Profile(ID);
|
||||
E->BlkExprBindings.Profile(ID);
|
||||
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 SubExprBindings == RHS.SubExprBindings &&
|
||||
BlkExprBindings == RHS.BlkExprBindings;
|
||||
return ExprBindings == RHS.ExprBindings;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class EnvironmentManager {
|
||||
private:
|
||||
typedef Environment::BindingsTy::Factory FactoryTy;
|
||||
FactoryTy F;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
EnvironmentManager(llvm::BumpPtrAllocator& Allocator) : F(Allocator) {}
|
||||
~EnvironmentManager() {}
|
||||
|
||||
/// RemoveBlkExpr - Return a new environment object with the same bindings as
|
||||
/// the provided environment except with any bindings for the provided Stmt*
|
||||
/// removed. This method only removes bindings for block-level expressions.
|
||||
/// Using this method on a non-block level expression will return the
|
||||
/// same environment object.
|
||||
Environment RemoveBlkExpr(const Environment& Env, const Stmt* E) {
|
||||
return Environment(Env.SubExprBindings, F.Remove(Env.BlkExprBindings, E));
|
||||
Environment getInitialEnvironment(AnalysisContext *ACtx) {
|
||||
return Environment(F.GetEmptyMap(), ACtx);
|
||||
}
|
||||
|
||||
Environment RemoveSubExpr(const Environment& Env, const Stmt* E) {
|
||||
return Environment(F.Remove(Env.SubExprBindings, E), Env.BlkExprBindings);
|
||||
}
|
||||
|
||||
Environment AddBlkExpr(const Environment& Env, const Stmt *E, SVal V) {
|
||||
return Environment(Env.SubExprBindings, F.Add(Env.BlkExprBindings, E, V));
|
||||
}
|
||||
|
||||
Environment AddSubExpr(const Environment& Env, const Stmt *E, SVal V) {
|
||||
return Environment(F.Add(Env.SubExprBindings, E, V), Env.BlkExprBindings);
|
||||
}
|
||||
|
||||
/// RemoveSubExprBindings - Return a new environment object with
|
||||
/// the same bindings as the provided environment except with all the
|
||||
/// subexpression bindings removed.
|
||||
Environment RemoveSubExprBindings(const Environment& Env) {
|
||||
return Environment(F.GetEmptyMap(), Env.BlkExprBindings);
|
||||
}
|
||||
|
||||
Environment getInitialEnvironment() {
|
||||
return Environment(F.GetEmptyMap(), F.GetEmptyMap());
|
||||
}
|
||||
|
||||
Environment BindExpr(const Environment& Env, const Stmt* E, SVal V,
|
||||
bool isBlkExpr, bool Invalidate);
|
||||
|
||||
Environment
|
||||
RemoveDeadBindings(Environment Env, Stmt* Loc, SymbolReaper& SymReaper,
|
||||
GRStateManager& StateMgr, const GRState *state,
|
||||
llvm::SmallVectorImpl<const MemRegion*>& DRoots);
|
||||
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<const MemRegion*>& RegionRoots);
|
||||
};
|
||||
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#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"
|
||||
|
|
@ -25,193 +26,158 @@
|
|||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "clang/Analysis/Support/BumpVector.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRCoreEngineImpl;
|
||||
class ExplodedNodeImpl;
|
||||
class GRState;
|
||||
class CFG;
|
||||
class ASTContext;
|
||||
|
||||
class GRStmtNodeBuilderImpl;
|
||||
class GRBranchNodeBuilderImpl;
|
||||
class GRIndirectGotoNodeBuilderImpl;
|
||||
class GRSwitchNodeBuilderImpl;
|
||||
class GREndPathNodebuilderImpl;
|
||||
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 ExplodedNodeImpl : public llvm::FoldingSetNode {
|
||||
protected:
|
||||
friend class ExplodedGraphImpl;
|
||||
friend class GRCoreEngineImpl;
|
||||
friend class GRStmtNodeBuilderImpl;
|
||||
friend class GRBranchNodeBuilderImpl;
|
||||
friend class GRIndirectGotoNodeBuilderImpl;
|
||||
friend class GRSwitchNodeBuilderImpl;
|
||||
friend class GREndPathNodeBuilderImpl;
|
||||
|
||||
|
||||
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<void*>(P & ~Mask);
|
||||
}
|
||||
|
||||
ExplodedNodeImpl* getNode() const {
|
||||
return reinterpret_cast<ExplodedNodeImpl*>(getPtr());
|
||||
ExplodedNode *getNode() const {
|
||||
return reinterpret_cast<ExplodedNode*>(getPtr());
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
NodeGroup() : P(0) {}
|
||||
|
||||
~NodeGroup();
|
||||
|
||||
ExplodedNodeImpl** begin() const;
|
||||
|
||||
ExplodedNodeImpl** end() const;
|
||||
|
||||
|
||||
ExplodedNode **begin() const;
|
||||
|
||||
ExplodedNode **end() const;
|
||||
|
||||
unsigned size() const;
|
||||
|
||||
bool empty() const { return size() == 0; }
|
||||
|
||||
void addNode(ExplodedNodeImpl* N);
|
||||
|
||||
|
||||
bool empty() const { return (P & ~Mask) == 0; }
|
||||
|
||||
void addNode(ExplodedNode* N, ExplodedGraph &G);
|
||||
|
||||
void setFlag() {
|
||||
assert (P == 0);
|
||||
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 void* State;
|
||||
|
||||
const GRState* State;
|
||||
|
||||
/// Preds - The predecessors of this node.
|
||||
NodeGroup Preds;
|
||||
|
||||
|
||||
/// Succs - The successors of this node.
|
||||
NodeGroup Succs;
|
||||
|
||||
/// Construct a ExplodedNodeImpl with the provided location and state.
|
||||
explicit ExplodedNodeImpl(const ProgramPoint& loc, const void* state)
|
||||
: Location(loc), State(state) {}
|
||||
|
||||
/// addPredeccessor - Adds a predecessor to the current node, and
|
||||
/// in tandem add this node as a successor of the other node.
|
||||
void addPredecessor(ExplodedNodeImpl* V);
|
||||
|
||||
|
||||
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 <typename T>
|
||||
const T* getLocationAs() const { return llvm::dyn_cast<T>(&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(); }
|
||||
|
||||
// For debugging.
|
||||
|
||||
public:
|
||||
|
||||
class Auditor {
|
||||
public:
|
||||
virtual ~Auditor();
|
||||
virtual void AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst) = 0;
|
||||
};
|
||||
|
||||
static void SetAuditor(Auditor* A);
|
||||
};
|
||||
void markAsSink() { Succs.setFlag(); }
|
||||
|
||||
|
||||
template <typename StateTy>
|
||||
struct GRTrait {
|
||||
static inline void Profile(llvm::FoldingSetNodeID& ID, const StateTy* St) {
|
||||
St->Profile(ID);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename StateTy>
|
||||
class ExplodedNode : public ExplodedNodeImpl {
|
||||
public:
|
||||
/// Construct a ExplodedNodeImpl with the given node ID, program edge,
|
||||
/// and state.
|
||||
explicit ExplodedNode(const ProgramPoint& loc, const StateTy* St)
|
||||
: ExplodedNodeImpl(loc, St) {}
|
||||
|
||||
/// getState - Returns the state associated with the node.
|
||||
inline const StateTy* getState() const {
|
||||
return static_cast<const StateTy*>(State);
|
||||
}
|
||||
|
||||
// Profiling (for FoldingSet).
|
||||
|
||||
static inline void Profile(llvm::FoldingSetNodeID& ID,
|
||||
const ProgramPoint& Loc,
|
||||
const StateTy* state) {
|
||||
ID.Add(Loc);
|
||||
GRTrait<StateTy>::Profile(ID, state);
|
||||
}
|
||||
|
||||
inline void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
Profile(ID, getLocation(), getState());
|
||||
}
|
||||
|
||||
void addPredecessor(ExplodedNode* V) {
|
||||
ExplodedNodeImpl::addPredecessor(V);
|
||||
}
|
||||
|
||||
ExplodedNode* getFirstPred() {
|
||||
return pred_empty() ? NULL : *(pred_begin());
|
||||
}
|
||||
|
||||
|
||||
const ExplodedNode* getFirstPred() const {
|
||||
return const_cast<ExplodedNode*>(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 (ExplodedNode**) Preds.begin(); }
|
||||
pred_iterator pred_end() { return (ExplodedNode**) Preds.end(); }
|
||||
pred_iterator pred_begin() { return Preds.begin(); }
|
||||
pred_iterator pred_end() { return Preds.end(); }
|
||||
|
||||
const_pred_iterator pred_begin() const {
|
||||
return const_cast<ExplodedNode*>(this)->pred_begin();
|
||||
}
|
||||
}
|
||||
const_pred_iterator pred_end() const {
|
||||
return const_cast<ExplodedNode*>(this)->pred_end();
|
||||
}
|
||||
|
||||
succ_iterator succ_begin() { return (ExplodedNode**) Succs.begin(); }
|
||||
succ_iterator succ_end() { return (ExplodedNode**) Succs.end(); }
|
||||
succ_iterator succ_begin() { return Succs.begin(); }
|
||||
succ_iterator succ_end() { return Succs.end(); }
|
||||
|
||||
const_succ_iterator succ_begin() const {
|
||||
return const_cast<ExplodedNode*>(this)->succ_begin();
|
||||
|
|
@ -219,23 +185,40 @@ public:
|
|||
const_succ_iterator succ_end() const {
|
||||
return const_cast<ExplodedNode*>(this)->succ_end();
|
||||
}
|
||||
|
||||
// For debugging.
|
||||
|
||||
public:
|
||||
|
||||
class Auditor {
|
||||
public:
|
||||
virtual ~Auditor();
|
||||
virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst) = 0;
|
||||
};
|
||||
|
||||
static void SetAuditor(Auditor* A);
|
||||
};
|
||||
|
||||
class InterExplodedGraphMapImpl;
|
||||
// FIXME: Is this class necessary?
|
||||
class InterExplodedGraphMap {
|
||||
llvm::DenseMap<const ExplodedNode*, ExplodedNode*> M;
|
||||
friend class ExplodedGraph;
|
||||
|
||||
class ExplodedGraphImpl {
|
||||
public:
|
||||
ExplodedNode* getMappedNode(const ExplodedNode* N) const;
|
||||
|
||||
InterExplodedGraphMap() {};
|
||||
virtual ~InterExplodedGraphMap() {}
|
||||
};
|
||||
|
||||
class ExplodedGraph {
|
||||
protected:
|
||||
friend class GRCoreEngineImpl;
|
||||
friend class GRStmtNodeBuilderImpl;
|
||||
friend class GRBranchNodeBuilderImpl;
|
||||
friend class GRIndirectGotoNodeBuilderImpl;
|
||||
friend class GRSwitchNodeBuilderImpl;
|
||||
friend class GREndPathNodeBuilderImpl;
|
||||
|
||||
friend class GRCoreEngine;
|
||||
|
||||
// Type definitions.
|
||||
typedef llvm::SmallVector<ExplodedNodeImpl*,2> RootsTy;
|
||||
typedef llvm::SmallVector<ExplodedNodeImpl*,10> EndNodesTy;
|
||||
|
||||
typedef llvm::SmallVector<ExplodedNode*,2> RootsTy;
|
||||
typedef llvm::SmallVector<ExplodedNode*,10> 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
|
||||
|
|
@ -245,338 +228,199 @@ protected:
|
|||
/// EndNodes - The nodes in the simulation graph which have been
|
||||
/// specially marked as the endpoint of an abstract simulation path.
|
||||
EndNodesTy EndNodes;
|
||||
|
||||
/// Allocator - BumpPtrAllocator to create nodes.
|
||||
llvm::BumpPtrAllocator Allocator;
|
||||
|
||||
/// cfg - The CFG associated with this analysis graph.
|
||||
CFG& cfg;
|
||||
|
||||
/// CodeDecl - The declaration containing the code being analyzed. This
|
||||
/// can be a FunctionDecl or and ObjCMethodDecl.
|
||||
Decl& CodeDecl;
|
||||
|
||||
|
||||
/// Nodes - The nodes in the graph.
|
||||
llvm::FoldingSet<ExplodedNode> 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;
|
||||
|
||||
/// getNodeImpl - Retrieve the node associated with a (Location,State)
|
||||
/// pair, where 'State' is represented as an opaque void*. This method
|
||||
/// is intended to be used only by GRCoreEngineImpl.
|
||||
virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L,
|
||||
const void* State,
|
||||
bool* IsNew) = 0;
|
||||
|
||||
virtual ExplodedGraphImpl* MakeEmptyGraph() const = 0;
|
||||
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.
|
||||
ExplodedNodeImpl* addRoot(ExplodedNodeImpl* V) {
|
||||
ExplodedNode* addRoot(ExplodedNode* V) {
|
||||
Roots.push_back(V);
|
||||
return V;
|
||||
}
|
||||
|
||||
/// addEndOfPath - Add an untyped node to the set of EOP nodes.
|
||||
ExplodedNodeImpl* addEndOfPath(ExplodedNodeImpl* V) {
|
||||
ExplodedNode* addEndOfPath(ExplodedNode* V) {
|
||||
EndNodes.push_back(V);
|
||||
return V;
|
||||
}
|
||||
|
||||
// ctor.
|
||||
ExplodedGraphImpl(CFG& c, Decl& cd, ASTContext& ctx)
|
||||
: cfg(c), CodeDecl(cd), Ctx(ctx), NumNodes(0) {}
|
||||
|
||||
public:
|
||||
virtual ~ExplodedGraphImpl() {}
|
||||
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; }
|
||||
|
||||
llvm::BumpPtrAllocator& getAllocator() { return Allocator; }
|
||||
CFG& getCFG() { return cfg; }
|
||||
|
||||
// Iterators.
|
||||
typedef ExplodedNode NodeTy;
|
||||
typedef llvm::FoldingSet<ExplodedNode> 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; }
|
||||
|
||||
Decl& getCodeDecl() { return CodeDecl; }
|
||||
const Decl& getCodeDecl() const { return CodeDecl; }
|
||||
typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> NodeMap;
|
||||
|
||||
const FunctionDecl* getFunctionDecl() const {
|
||||
return llvm::dyn_cast<FunctionDecl>(&CodeDecl);
|
||||
}
|
||||
|
||||
typedef llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> NodeMap;
|
||||
|
||||
ExplodedGraphImpl* Trim(const ExplodedNodeImpl* const * NBeg,
|
||||
const ExplodedNodeImpl* const * NEnd,
|
||||
InterExplodedGraphMapImpl *M,
|
||||
llvm::DenseMap<const void*, const void*> *InverseMap)
|
||||
const;
|
||||
};
|
||||
|
||||
class InterExplodedGraphMapImpl {
|
||||
llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> M;
|
||||
friend class ExplodedGraphImpl;
|
||||
void add(const ExplodedNodeImpl* From, ExplodedNodeImpl* To);
|
||||
|
||||
protected:
|
||||
ExplodedNodeImpl* getMappedImplNode(const ExplodedNodeImpl* N) const;
|
||||
|
||||
InterExplodedGraphMapImpl();
|
||||
public:
|
||||
virtual ~InterExplodedGraphMapImpl() {}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Type-specialized ExplodedGraph classes.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename STATE>
|
||||
class InterExplodedGraphMap : public InterExplodedGraphMapImpl {
|
||||
public:
|
||||
InterExplodedGraphMap() {};
|
||||
~InterExplodedGraphMap() {};
|
||||
|
||||
ExplodedNode<STATE>* getMappedNode(const ExplodedNode<STATE>* N) const {
|
||||
return static_cast<ExplodedNode<STATE>*>(getMappedImplNode(N));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename STATE>
|
||||
class ExplodedGraph : public ExplodedGraphImpl {
|
||||
public:
|
||||
typedef STATE StateTy;
|
||||
typedef ExplodedNode<StateTy> NodeTy;
|
||||
typedef llvm::FoldingSet<NodeTy> AllNodesTy;
|
||||
|
||||
protected:
|
||||
/// Nodes - The nodes in the graph.
|
||||
AllNodesTy Nodes;
|
||||
|
||||
protected:
|
||||
virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L,
|
||||
const void* State,
|
||||
bool* IsNew) {
|
||||
|
||||
return getNode(L, static_cast<const StateTy*>(State), IsNew);
|
||||
}
|
||||
|
||||
virtual ExplodedGraphImpl* MakeEmptyGraph() const {
|
||||
return new ExplodedGraph(cfg, CodeDecl, Ctx);
|
||||
}
|
||||
|
||||
public:
|
||||
ExplodedGraph(CFG& c, Decl& cd, ASTContext& ctx)
|
||||
: ExplodedGraphImpl(c, cd, ctx) {}
|
||||
|
||||
/// 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.
|
||||
NodeTy* getNode(const ProgramPoint& L, const StateTy* State,
|
||||
bool* IsNew = NULL) {
|
||||
|
||||
// Profile 'State' to determine if we already have an existing node.
|
||||
llvm::FoldingSetNodeID profile;
|
||||
void* InsertPos = 0;
|
||||
|
||||
NodeTy::Profile(profile, L, State);
|
||||
NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos);
|
||||
|
||||
if (!V) {
|
||||
// Allocate a new node.
|
||||
V = (NodeTy*) Allocator.Allocate<NodeTy>();
|
||||
new (V) NodeTy(L, State);
|
||||
|
||||
// Insert the node into the node set and return it.
|
||||
Nodes.InsertNode(V, InsertPos);
|
||||
|
||||
++NumNodes;
|
||||
|
||||
if (IsNew) *IsNew = true;
|
||||
}
|
||||
else
|
||||
if (IsNew) *IsNew = false;
|
||||
|
||||
return V;
|
||||
}
|
||||
|
||||
// Iterators.
|
||||
typedef NodeTy** roots_iterator;
|
||||
typedef const NodeTy** const_roots_iterator;
|
||||
typedef NodeTy** eop_iterator;
|
||||
typedef const NodeTy** const_eop_iterator;
|
||||
typedef typename AllNodesTy::iterator node_iterator;
|
||||
typedef typename 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 reinterpret_cast<roots_iterator>(Roots.begin());
|
||||
}
|
||||
|
||||
roots_iterator roots_end() {
|
||||
return reinterpret_cast<roots_iterator>(Roots.end());
|
||||
}
|
||||
|
||||
const_roots_iterator roots_begin() const {
|
||||
return const_cast<ExplodedGraph>(this)->roots_begin();
|
||||
}
|
||||
|
||||
const_roots_iterator roots_end() const {
|
||||
return const_cast<ExplodedGraph>(this)->roots_end();
|
||||
}
|
||||
|
||||
eop_iterator eop_begin() {
|
||||
return reinterpret_cast<eop_iterator>(EndNodes.begin());
|
||||
}
|
||||
|
||||
eop_iterator eop_end() {
|
||||
return reinterpret_cast<eop_iterator>(EndNodes.end());
|
||||
}
|
||||
|
||||
const_eop_iterator eop_begin() const {
|
||||
return const_cast<ExplodedGraph>(this)->eop_begin();
|
||||
}
|
||||
|
||||
const_eop_iterator eop_end() const {
|
||||
return const_cast<ExplodedGraph>(this)->eop_end();
|
||||
}
|
||||
|
||||
std::pair<ExplodedGraph*, InterExplodedGraphMap<STATE>*>
|
||||
std::pair<ExplodedGraph*, InterExplodedGraphMap*>
|
||||
Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd,
|
||||
llvm::DenseMap<const void*, const void*> *InverseMap = 0) const {
|
||||
|
||||
if (NBeg == NEnd)
|
||||
return std::make_pair((ExplodedGraph*) 0,
|
||||
(InterExplodedGraphMap<STATE>*) 0);
|
||||
|
||||
assert (NBeg < NEnd);
|
||||
|
||||
const ExplodedNodeImpl* const* NBegImpl =
|
||||
(const ExplodedNodeImpl* const*) NBeg;
|
||||
const ExplodedNodeImpl* const* NEndImpl =
|
||||
(const ExplodedNodeImpl* const*) NEnd;
|
||||
|
||||
llvm::OwningPtr<InterExplodedGraphMap<STATE> >
|
||||
M(new InterExplodedGraphMap<STATE>());
|
||||
llvm::DenseMap<const void*, const void*> *InverseMap = 0) const;
|
||||
|
||||
ExplodedGraphImpl* G = ExplodedGraphImpl::Trim(NBegImpl, NEndImpl, M.get(),
|
||||
InverseMap);
|
||||
|
||||
return std::make_pair(static_cast<ExplodedGraph*>(G), M.take());
|
||||
}
|
||||
ExplodedGraph* TrimInternal(const ExplodedNode* const * NBeg,
|
||||
const ExplodedNode* const * NEnd,
|
||||
InterExplodedGraphMap *M,
|
||||
llvm::DenseMap<const void*, const void*> *InverseMap) const;
|
||||
};
|
||||
|
||||
template <typename StateTy>
|
||||
class ExplodedNodeSet {
|
||||
|
||||
typedef ExplodedNode<StateTy> NodeTy;
|
||||
typedef llvm::SmallPtrSet<NodeTy*,5> ImplTy;
|
||||
typedef llvm::SmallPtrSet<ExplodedNode*,5> ImplTy;
|
||||
ImplTy Impl;
|
||||
|
||||
|
||||
public:
|
||||
ExplodedNodeSet(NodeTy* N) {
|
||||
assert (N && !static_cast<ExplodedNodeImpl*>(N)->isSink());
|
||||
ExplodedNodeSet(ExplodedNode* N) {
|
||||
assert (N && !static_cast<ExplodedNode*>(N)->isSink());
|
||||
Impl.insert(N);
|
||||
}
|
||||
|
||||
|
||||
ExplodedNodeSet() {}
|
||||
|
||||
inline void Add(NodeTy* N) {
|
||||
if (N && !static_cast<ExplodedNodeImpl*>(N)->isSink()) Impl.insert(N);
|
||||
|
||||
inline void Add(ExplodedNode* N) {
|
||||
if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N);
|
||||
}
|
||||
|
||||
typedef typename ImplTy::iterator iterator;
|
||||
typedef typename ImplTy::const_iterator const_iterator;
|
||||
|
||||
ExplodedNodeSet& operator=(const ExplodedNodeSet &X) {
|
||||
Impl = X.Impl;
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef ImplTy::iterator iterator;
|
||||
typedef ImplTy::const_iterator const_iterator;
|
||||
|
||||
inline unsigned size() const { return Impl.size(); }
|
||||
inline bool empty() const { return Impl.empty(); }
|
||||
|
||||
inline void clear() { Impl.clear(); }
|
||||
|
||||
|
||||
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<typename StateTy>
|
||||
struct GraphTraits<clang::ExplodedNode<StateTy>*> {
|
||||
typedef clang::ExplodedNode<StateTy> NodeType;
|
||||
typedef typename NodeType::succ_iterator ChildIteratorType;
|
||||
template<> struct GraphTraits<clang::ExplodedNode*> {
|
||||
typedef clang::ExplodedNode NodeType;
|
||||
typedef NodeType::succ_iterator ChildIteratorType;
|
||||
typedef llvm::df_iterator<NodeType*> 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<typename StateTy>
|
||||
struct GraphTraits<const clang::ExplodedNode<StateTy>*> {
|
||||
typedef const clang::ExplodedNode<StateTy> NodeType;
|
||||
typedef typename NodeType::succ_iterator ChildIteratorType;
|
||||
|
||||
template<> struct GraphTraits<const clang::ExplodedNode*> {
|
||||
typedef const clang::ExplodedNode NodeType;
|
||||
typedef NodeType::const_succ_iterator ChildIteratorType;
|
||||
typedef llvm::df_iterator<NodeType*> 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
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//==- GRAuditor.h - Observers of the creation of ExplodedNodes------*- C++ -*-//
|
||||
//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
|
|
@ -18,22 +18,18 @@
|
|||
#ifndef LLVM_CLANG_ANALYSIS_GRAUDITOR
|
||||
#define LLVM_CLANG_ANALYSIS_GRAUDITOR
|
||||
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
template <typename STATE>
|
||||
|
||||
class ExplodedNode;
|
||||
class GRStateManager;
|
||||
|
||||
class GRAuditor {
|
||||
public:
|
||||
typedef ExplodedNode<STATE> NodeTy;
|
||||
typedef typename STATE::ManagerTy ManagerTy;
|
||||
|
||||
virtual ~GRAuditor() {}
|
||||
virtual bool Audit(NodeTy* N, ManagerTy& M) = 0;
|
||||
virtual bool Audit(ExplodedNode* N, GRStateManager& M) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//==- GRBlockCounter.h - ADT for counting block visits -------------*- C++ -*-//
|
||||
//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
|
|
@ -24,27 +24,27 @@ namespace clang {
|
|||
|
||||
class GRBlockCounter {
|
||||
void* Data;
|
||||
|
||||
GRBlockCounter(void* D) : Data(D) {}
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine ------------------*- C++ -*-//
|
||||
//
|
||||
//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine --------------*- C++ -*-//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
|
|
@ -20,647 +20,417 @@
|
|||
#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 {
|
||||
|
||||
class GRStmtNodeBuilderImpl;
|
||||
class GRBranchNodeBuilderImpl;
|
||||
class GRIndirectGotoNodeBuilderImpl;
|
||||
class GRSwitchNodeBuilderImpl;
|
||||
class GREndPathNodeBuilderImpl;
|
||||
class GRWorkList;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// GRCoreEngineImpl - Implements the core logic of the graph-reachability
|
||||
/// 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 GRCoreEngineImpl)
|
||||
/// 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 GRCoreEngineImpl {
|
||||
protected:
|
||||
friend class GRStmtNodeBuilderImpl;
|
||||
friend class GRBranchNodeBuilderImpl;
|
||||
friend class GRIndirectGotoNodeBuilderImpl;
|
||||
friend class GRSwitchNodeBuilderImpl;
|
||||
friend class GREndPathNodeBuilderImpl;
|
||||
|
||||
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<ExplodedGraphImpl> G;
|
||||
|
||||
llvm::OwningPtr<ExplodedGraph> 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 void* State,
|
||||
ExplodedNodeImpl* Pred);
|
||||
|
||||
/// getInitialState - Gets the void* representing the initial 'state'
|
||||
/// of the analysis. This is simply a wrapper (implemented
|
||||
/// in GRCoreEngine) that performs type erasure on the initial
|
||||
/// state returned by the checker object.
|
||||
virtual const void* getInitialState() = 0;
|
||||
|
||||
void HandleBlockEdge(const BlockEdge& E, ExplodedNodeImpl* Pred);
|
||||
void HandleBlockEntrance(const BlockEntrance& E, ExplodedNodeImpl* Pred);
|
||||
void HandleBlockExit(CFGBlock* B, ExplodedNodeImpl* Pred);
|
||||
|
||||
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, ExplodedNodeImpl *Pred);
|
||||
|
||||
unsigned StmtIdx, ExplodedNode *Pred);
|
||||
|
||||
void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B,
|
||||
ExplodedNodeImpl* Pred);
|
||||
|
||||
virtual void ProcessEndPath(GREndPathNodeBuilderImpl& Builder) = 0;
|
||||
|
||||
virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State,
|
||||
GRBlockCounter BC) = 0;
|
||||
ExplodedNode* Pred);
|
||||
|
||||
virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& Builder) = 0;
|
||||
/// Get the initial state from the subengine.
|
||||
const GRState* getInitialState(const LocationContext *InitLoc) {
|
||||
return SubEngine.getInitialState(InitLoc);
|
||||
}
|
||||
|
||||
virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
|
||||
GRBranchNodeBuilderImpl& Builder) = 0;
|
||||
void ProcessEndPath(GREndPathNodeBuilder& Builder);
|
||||
|
||||
virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& Builder) = 0;
|
||||
|
||||
virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& Builder) = 0;
|
||||
void ProcessStmt(Stmt* S, 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:
|
||||
GRCoreEngineImpl(const GRCoreEngineImpl&); // Do not implement.
|
||||
GRCoreEngineImpl& operator=(const GRCoreEngineImpl&);
|
||||
|
||||
protected:
|
||||
GRCoreEngineImpl(ExplodedGraphImpl* g, GRWorkList* wl)
|
||||
: G(g), WList(wl), BCounterFactory(g->getAllocator()) {}
|
||||
|
||||
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(unsigned Steps);
|
||||
|
||||
virtual ~GRCoreEngineImpl();
|
||||
|
||||
CFG& getCFG() { return G->getCFG(); }
|
||||
bool ExecuteWorkList(const LocationContext *L, unsigned Steps);
|
||||
};
|
||||
|
||||
class GRStmtNodeBuilderImpl {
|
||||
GRCoreEngineImpl& Eng;
|
||||
|
||||
class GRStmtNodeBuilder {
|
||||
GRCoreEngine& Eng;
|
||||
CFGBlock& B;
|
||||
const unsigned Idx;
|
||||
ExplodedNodeImpl* Pred;
|
||||
ExplodedNodeImpl* LastNode;
|
||||
|
||||
typedef llvm::SmallPtrSet<ExplodedNodeImpl*,5> DeferredTy;
|
||||
DeferredTy Deferred;
|
||||
|
||||
void GenerateAutoTransition(ExplodedNodeImpl* N);
|
||||
|
||||
public:
|
||||
GRStmtNodeBuilderImpl(CFGBlock* b, unsigned idx,
|
||||
ExplodedNodeImpl* N, GRCoreEngineImpl* e);
|
||||
|
||||
~GRStmtNodeBuilderImpl();
|
||||
|
||||
ExplodedNodeImpl* getBasePredecessor() const { return Pred; }
|
||||
|
||||
ExplodedNodeImpl* getLastNode() const {
|
||||
return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL;
|
||||
}
|
||||
|
||||
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return getBlockCounter().getNumVisited(B.getBlockID());
|
||||
}
|
||||
|
||||
ExplodedNodeImpl*
|
||||
generateNodeImpl(PostStmt PP, const void* State, ExplodedNodeImpl* Pred);
|
||||
|
||||
ExplodedNodeImpl*
|
||||
generateNodeImpl(Stmt* S, const void* State, ExplodedNodeImpl* Pred,
|
||||
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
|
||||
const void *tag = 0);
|
||||
ExplodedNode* Pred;
|
||||
ExplodedNode* LastNode;
|
||||
GRStateManager& Mgr;
|
||||
GRAuditor* Auditor;
|
||||
|
||||
ExplodedNodeImpl*
|
||||
generateNodeImpl(Stmt* S, const void* State,
|
||||
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
|
||||
const void *tag = 0) {
|
||||
ExplodedNodeImpl* N = getLastNode();
|
||||
assert (N && "Predecessor of new node is infeasible.");
|
||||
return generateNodeImpl(S, State, N, K, tag);
|
||||
}
|
||||
|
||||
ExplodedNodeImpl*
|
||||
generateNodeImpl(Stmt* S, const void* State, const void *tag = 0) {
|
||||
ExplodedNodeImpl* N = getLastNode();
|
||||
assert (N && "Predecessor of new node is infeasible.");
|
||||
return generateNodeImpl(S, State, N, ProgramPoint::PostStmtKind, tag);
|
||||
}
|
||||
|
||||
/// 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; }
|
||||
};
|
||||
|
||||
|
||||
template<typename STATE>
|
||||
class GRStmtNodeBuilder {
|
||||
public:
|
||||
typedef STATE StateTy;
|
||||
typedef typename StateTy::ManagerTy StateManagerTy;
|
||||
typedef ExplodedNode<StateTy> NodeTy;
|
||||
|
||||
private:
|
||||
GRStmtNodeBuilderImpl& NB;
|
||||
StateManagerTy& Mgr;
|
||||
const StateTy* CleanedState;
|
||||
GRAuditor<StateTy>* Auditor;
|
||||
|
||||
public:
|
||||
GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb, StateManagerTy& mgr) :
|
||||
NB(nb), Mgr(mgr), Auditor(0), PurgingDeadSymbols(false),
|
||||
BuildSinks(false), HasGeneratedNode(false),
|
||||
PointKind(ProgramPoint::PostStmtKind), Tag(0) {
|
||||
|
||||
CleanedState = getLastNode()->getState();
|
||||
}
|
||||
|
||||
void setAuditor(GRAuditor<StateTy>* A) {
|
||||
Auditor = A;
|
||||
}
|
||||
|
||||
NodeTy* getLastNode() const {
|
||||
return static_cast<NodeTy*>(NB.getLastNode());
|
||||
}
|
||||
|
||||
NodeTy* generateNode(PostStmt PP, const StateTy* St, NodeTy* Pred) {
|
||||
HasGeneratedNode = true;
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(PP, St, Pred));
|
||||
}
|
||||
|
||||
NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred,
|
||||
ProgramPoint::Kind K) {
|
||||
HasGeneratedNode = true;
|
||||
if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind;
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, K, Tag));
|
||||
}
|
||||
|
||||
NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred) {
|
||||
return generateNode(S, St, Pred, PointKind);
|
||||
}
|
||||
|
||||
NodeTy* generateNode(Stmt* S, const StateTy* St, ProgramPoint::Kind K) {
|
||||
HasGeneratedNode = true;
|
||||
if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind;
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, K, Tag));
|
||||
}
|
||||
|
||||
NodeTy* generateNode(Stmt* S, const StateTy* St) {
|
||||
return generateNode(S, St, PointKind);
|
||||
}
|
||||
|
||||
|
||||
GRBlockCounter getBlockCounter() const {
|
||||
return NB.getBlockCounter();
|
||||
}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return NB.getCurrentBlockCount();
|
||||
}
|
||||
|
||||
const StateTy* GetState(NodeTy* Pred) const {
|
||||
if ((ExplodedNodeImpl*) Pred == NB.getBasePredecessor())
|
||||
return CleanedState;
|
||||
else
|
||||
return Pred->getState();
|
||||
}
|
||||
|
||||
void SetCleanedState(const StateTy* St) {
|
||||
CleanedState = St;
|
||||
}
|
||||
|
||||
NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
|
||||
NodeTy* Pred, const StateTy* St) {
|
||||
return MakeNode(Dst, S, Pred, St, PointKind);
|
||||
}
|
||||
|
||||
NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
|
||||
NodeTy* Pred, const StateTy* St, ProgramPoint::Kind K) {
|
||||
|
||||
const StateTy* 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;
|
||||
}
|
||||
|
||||
NodeTy* 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;
|
||||
}
|
||||
|
||||
NodeTy* MakeSinkNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
|
||||
NodeTy* Pred, const StateTy* St) {
|
||||
bool Tmp = BuildSinks;
|
||||
BuildSinks = true;
|
||||
NodeTy* N = MakeNode(Dst, S, Pred, St);
|
||||
BuildSinks = Tmp;
|
||||
return N;
|
||||
}
|
||||
|
||||
bool PurgingDeadSymbols;
|
||||
bool BuildSinks;
|
||||
bool HasGeneratedNode;
|
||||
ProgramPoint::Kind PointKind;
|
||||
const void *Tag;
|
||||
|
||||
const GRState* CleanedState;
|
||||
|
||||
|
||||
typedef llvm::SmallPtrSet<ExplodedNode*,5> 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; }
|
||||
|
||||
void setAuditor(GRAuditor* A) { Auditor = A; }
|
||||
|
||||
const GRState* GetState(ExplodedNode* Pred) const {
|
||||
if ((ExplodedNode*) 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 GRBranchNodeBuilderImpl {
|
||||
GRCoreEngineImpl& Eng;
|
||||
|
||||
class GRBranchNodeBuilder {
|
||||
GRCoreEngine& Eng;
|
||||
CFGBlock* Src;
|
||||
CFGBlock* DstT;
|
||||
CFGBlock* DstF;
|
||||
ExplodedNodeImpl* Pred;
|
||||
ExplodedNode* Pred;
|
||||
|
||||
typedef llvm::SmallVector<ExplodedNodeImpl*,3> DeferredTy;
|
||||
typedef llvm::SmallVector<ExplodedNode*,3> DeferredTy;
|
||||
DeferredTy Deferred;
|
||||
|
||||
|
||||
bool GeneratedTrue;
|
||||
bool GeneratedFalse;
|
||||
|
||||
bool InFeasibleTrue;
|
||||
bool InFeasibleFalse;
|
||||
|
||||
public:
|
||||
GRBranchNodeBuilderImpl(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF,
|
||||
ExplodedNodeImpl* pred, GRCoreEngineImpl* e)
|
||||
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) {}
|
||||
|
||||
~GRBranchNodeBuilderImpl();
|
||||
|
||||
ExplodedNodeImpl* getPredecessor() const { return Pred; }
|
||||
const ExplodedGraphImpl& getGraph() const { return *Eng.G; }
|
||||
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();}
|
||||
|
||||
ExplodedNodeImpl* generateNodeImpl(const void* State, bool branch);
|
||||
|
||||
|
||||
ExplodedNode* generateNode(const GRState* State, bool branch);
|
||||
|
||||
CFGBlock* getTargetBlock(bool branch) const {
|
||||
return branch ? DstT : DstF;
|
||||
}
|
||||
|
||||
void markInfeasible(bool branch) {
|
||||
if (branch) GeneratedTrue = true;
|
||||
else GeneratedFalse = true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename STATE>
|
||||
class GRBranchNodeBuilder {
|
||||
typedef STATE StateTy;
|
||||
typedef ExplodedGraph<StateTy> GraphTy;
|
||||
typedef typename GraphTy::NodeTy NodeTy;
|
||||
|
||||
GRBranchNodeBuilderImpl& NB;
|
||||
|
||||
public:
|
||||
GRBranchNodeBuilder(GRBranchNodeBuilderImpl& nb) : NB(nb) {}
|
||||
|
||||
const GraphTy& getGraph() const {
|
||||
return static_cast<const GraphTy&>(NB.getGraph());
|
||||
void markInfeasible(bool branch) {
|
||||
if (branch)
|
||||
InFeasibleTrue = GeneratedTrue = true;
|
||||
else
|
||||
InFeasibleFalse = GeneratedFalse = true;
|
||||
}
|
||||
|
||||
NodeTy* getPredecessor() const {
|
||||
return static_cast<NodeTy*>(NB.getPredecessor());
|
||||
|
||||
bool isFeasible(bool branch) {
|
||||
return branch ? !InFeasibleTrue : !InFeasibleFalse;
|
||||
}
|
||||
|
||||
const StateTy* getState() const {
|
||||
|
||||
const GRState* getState() const {
|
||||
return getPredecessor()->getState();
|
||||
}
|
||||
|
||||
NodeTy* generateNode(const StateTy* St, bool branch) {
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(St, branch));
|
||||
}
|
||||
|
||||
GRBlockCounter getBlockCounter() const {
|
||||
return NB.getBlockCounter();
|
||||
}
|
||||
|
||||
CFGBlock* getTargetBlock(bool branch) const {
|
||||
return NB.getTargetBlock(branch);
|
||||
}
|
||||
|
||||
void markInfeasible(bool branch) {
|
||||
NB.markInfeasible(branch);
|
||||
}
|
||||
};
|
||||
|
||||
class GRIndirectGotoNodeBuilderImpl {
|
||||
GRCoreEngineImpl& Eng;
|
||||
|
||||
class GRIndirectGotoNodeBuilder {
|
||||
GRCoreEngine& Eng;
|
||||
CFGBlock* Src;
|
||||
CFGBlock& DispatchBlock;
|
||||
Expr* E;
|
||||
ExplodedNodeImpl* Pred;
|
||||
public:
|
||||
GRIndirectGotoNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src,
|
||||
Expr* e, CFGBlock* dispatch,
|
||||
GRCoreEngineImpl* eng)
|
||||
: Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
|
||||
|
||||
ExplodedNode* Pred;
|
||||
|
||||
class Iterator {
|
||||
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 GRIndirectGotoNodeBuilderImpl;
|
||||
Iterator(CFGBlock::succ_iterator i) : I(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; }
|
||||
|
||||
|
||||
iterator& operator++() { ++I; return *this; }
|
||||
bool operator!=(const iterator& X) const { return I != X.I; }
|
||||
|
||||
LabelStmt* getLabel() const {
|
||||
return llvm::cast<LabelStmt>((*I)->getLabel());
|
||||
}
|
||||
|
||||
|
||||
CFGBlock* getBlock() const {
|
||||
return *I;
|
||||
}
|
||||
};
|
||||
|
||||
Iterator begin() { return Iterator(DispatchBlock.succ_begin()); }
|
||||
Iterator end() { return Iterator(DispatchBlock.succ_end()); }
|
||||
|
||||
ExplodedNodeImpl* generateNodeImpl(const Iterator& I, const void* State,
|
||||
bool isSink);
|
||||
|
||||
|
||||
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 void* getState() const { return Pred->State; }
|
||||
|
||||
const GRState* getState() const { return Pred->State; }
|
||||
};
|
||||
|
||||
template<typename STATE>
|
||||
class GRIndirectGotoNodeBuilder {
|
||||
typedef STATE StateTy;
|
||||
typedef ExplodedGraph<StateTy> GraphTy;
|
||||
typedef typename GraphTy::NodeTy NodeTy;
|
||||
|
||||
GRIndirectGotoNodeBuilderImpl& NB;
|
||||
|
||||
public:
|
||||
GRIndirectGotoNodeBuilder(GRIndirectGotoNodeBuilderImpl& nb) : NB(nb) {}
|
||||
|
||||
typedef GRIndirectGotoNodeBuilderImpl::Iterator iterator;
|
||||
|
||||
iterator begin() { return NB.begin(); }
|
||||
iterator end() { return NB.end(); }
|
||||
|
||||
Expr* getTarget() const { return NB.getTarget(); }
|
||||
|
||||
NodeTy* generateNode(const iterator& I, const StateTy* St, bool isSink=false){
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(I, St, isSink));
|
||||
}
|
||||
|
||||
const StateTy* getState() const {
|
||||
return static_cast<const StateTy*>(NB.getState());
|
||||
}
|
||||
};
|
||||
|
||||
class GRSwitchNodeBuilderImpl {
|
||||
GRCoreEngineImpl& Eng;
|
||||
class GRSwitchNodeBuilder {
|
||||
GRCoreEngine& Eng;
|
||||
CFGBlock* Src;
|
||||
Expr* Condition;
|
||||
ExplodedNodeImpl* Pred;
|
||||
ExplodedNode* Pred;
|
||||
|
||||
public:
|
||||
GRSwitchNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src,
|
||||
Expr* condition, GRCoreEngineImpl* eng)
|
||||
GRSwitchNodeBuilder(ExplodedNode* pred, CFGBlock* src,
|
||||
Expr* condition, GRCoreEngine* eng)
|
||||
: Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
|
||||
|
||||
class Iterator {
|
||||
|
||||
class iterator {
|
||||
CFGBlock::succ_reverse_iterator I;
|
||||
|
||||
friend class GRSwitchNodeBuilderImpl;
|
||||
Iterator(CFGBlock::succ_reverse_iterator i) : I(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; }
|
||||
|
||||
iterator& operator++() { ++I; return *this; }
|
||||
bool operator!=(const iterator& X) const { return I != X.I; }
|
||||
|
||||
CaseStmt* getCase() const {
|
||||
return llvm::cast<CaseStmt>((*I)->getLabel());
|
||||
}
|
||||
|
||||
|
||||
CFGBlock* getBlock() const {
|
||||
return *I;
|
||||
}
|
||||
};
|
||||
|
||||
Iterator begin() { return Iterator(Src->succ_rbegin()+1); }
|
||||
Iterator end() { return Iterator(Src->succ_rend()); }
|
||||
|
||||
ExplodedNodeImpl* generateCaseStmtNodeImpl(const Iterator& I,
|
||||
const void* State);
|
||||
|
||||
ExplodedNodeImpl* generateDefaultCaseNodeImpl(const void* State,
|
||||
bool isSink);
|
||||
|
||||
|
||||
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 void* getState() const { return Pred->State; }
|
||||
|
||||
const GRState* getState() const { return Pred->State; }
|
||||
};
|
||||
|
||||
template<typename STATE>
|
||||
class GRSwitchNodeBuilder {
|
||||
typedef STATE StateTy;
|
||||
typedef ExplodedGraph<StateTy> GraphTy;
|
||||
typedef typename GraphTy::NodeTy NodeTy;
|
||||
|
||||
GRSwitchNodeBuilderImpl& NB;
|
||||
|
||||
public:
|
||||
GRSwitchNodeBuilder(GRSwitchNodeBuilderImpl& nb) : NB(nb) {}
|
||||
|
||||
typedef GRSwitchNodeBuilderImpl::Iterator iterator;
|
||||
|
||||
iterator begin() { return NB.begin(); }
|
||||
iterator end() { return NB.end(); }
|
||||
|
||||
Expr* getCondition() const { return NB.getCondition(); }
|
||||
|
||||
NodeTy* generateCaseStmtNode(const iterator& I, const StateTy* St) {
|
||||
return static_cast<NodeTy*>(NB.generateCaseStmtNodeImpl(I, St));
|
||||
}
|
||||
|
||||
NodeTy* generateDefaultCaseNode(const StateTy* St, bool isSink = false) {
|
||||
return static_cast<NodeTy*>(NB.generateDefaultCaseNodeImpl(St, isSink));
|
||||
}
|
||||
|
||||
const StateTy* getState() const {
|
||||
return static_cast<const StateTy*>(NB.getState());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class GREndPathNodeBuilderImpl {
|
||||
GRCoreEngineImpl& Eng;
|
||||
class GREndPathNodeBuilder {
|
||||
GRCoreEngine& Eng;
|
||||
CFGBlock& B;
|
||||
ExplodedNodeImpl* Pred;
|
||||
ExplodedNode* Pred;
|
||||
bool HasGeneratedNode;
|
||||
|
||||
|
||||
public:
|
||||
GREndPathNodeBuilderImpl(CFGBlock* b, ExplodedNodeImpl* N,
|
||||
GRCoreEngineImpl* e)
|
||||
: Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {}
|
||||
|
||||
~GREndPathNodeBuilderImpl();
|
||||
|
||||
ExplodedNodeImpl* getPredecessor() const { return Pred; }
|
||||
|
||||
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
|
||||
|
||||
GREndPathNodeBuilder(CFGBlock* b, ExplodedNode* N, GRCoreEngine* e)
|
||||
: Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {}
|
||||
|
||||
~GREndPathNodeBuilder();
|
||||
|
||||
ExplodedNode* getPredecessor() const { return Pred; }
|
||||
|
||||
GRBlockCounter getBlockCounter() const {
|
||||
return Eng.WList->getBlockCounter();
|
||||
}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return getBlockCounter().getNumVisited(B.getBlockID());
|
||||
}
|
||||
|
||||
ExplodedNodeImpl* generateNodeImpl(const void* State,
|
||||
const void *tag = 0,
|
||||
ExplodedNodeImpl *P = 0);
|
||||
|
||||
}
|
||||
|
||||
ExplodedNode* generateNode(const GRState* State, const void *tag = 0,
|
||||
ExplodedNode *P = 0);
|
||||
|
||||
CFGBlock* getBlock() const { return &B; }
|
||||
};
|
||||
|
||||
|
||||
template<typename STATE>
|
||||
class GREndPathNodeBuilder {
|
||||
typedef STATE StateTy;
|
||||
typedef ExplodedNode<StateTy> NodeTy;
|
||||
|
||||
GREndPathNodeBuilderImpl& NB;
|
||||
|
||||
public:
|
||||
GREndPathNodeBuilder(GREndPathNodeBuilderImpl& nb) : NB(nb) {}
|
||||
|
||||
NodeTy* getPredecessor() const {
|
||||
return static_cast<NodeTy*>(NB.getPredecessor());
|
||||
}
|
||||
|
||||
GRBlockCounter getBlockCounter() const {
|
||||
return NB.getBlockCounter();
|
||||
}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return NB.getCurrentBlockCount();
|
||||
}
|
||||
|
||||
const StateTy* getState() const {
|
||||
const GRState* getState() const {
|
||||
return getPredecessor()->getState();
|
||||
}
|
||||
|
||||
NodeTy* MakeNode(const StateTy* St, const void *tag = 0) {
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag));
|
||||
}
|
||||
|
||||
NodeTy *generateNode(const StateTy *St, NodeTy *Pred, const void *tag = 0) {
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag, Pred));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename SUBENGINE>
|
||||
class GRCoreEngine : public GRCoreEngineImpl {
|
||||
public:
|
||||
typedef SUBENGINE SubEngineTy;
|
||||
typedef typename SubEngineTy::StateTy StateTy;
|
||||
typedef typename StateTy::ManagerTy StateManagerTy;
|
||||
typedef ExplodedGraph<StateTy> GraphTy;
|
||||
typedef typename GraphTy::NodeTy NodeTy;
|
||||
|
||||
protected:
|
||||
SubEngineTy& SubEngine;
|
||||
|
||||
virtual const void* getInitialState() {
|
||||
return SubEngine.getInitialState();
|
||||
}
|
||||
|
||||
virtual void ProcessEndPath(GREndPathNodeBuilderImpl& BuilderImpl) {
|
||||
GREndPathNodeBuilder<StateTy> Builder(BuilderImpl);
|
||||
SubEngine.ProcessEndPath(Builder);
|
||||
}
|
||||
|
||||
virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& BuilderImpl) {
|
||||
GRStmtNodeBuilder<StateTy> Builder(BuilderImpl,SubEngine.getStateManager());
|
||||
SubEngine.ProcessStmt(S, Builder);
|
||||
}
|
||||
|
||||
virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State,
|
||||
GRBlockCounter BC) {
|
||||
return SubEngine.ProcessBlockEntrance(Blk,
|
||||
static_cast<const StateTy*>(State),
|
||||
BC);
|
||||
}
|
||||
|
||||
virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
|
||||
GRBranchNodeBuilderImpl& BuilderImpl) {
|
||||
GRBranchNodeBuilder<StateTy> Builder(BuilderImpl);
|
||||
SubEngine.ProcessBranch(Condition, Terminator, Builder);
|
||||
}
|
||||
|
||||
virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& BuilderImpl) {
|
||||
GRIndirectGotoNodeBuilder<StateTy> Builder(BuilderImpl);
|
||||
SubEngine.ProcessIndirectGoto(Builder);
|
||||
}
|
||||
|
||||
virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& BuilderImpl) {
|
||||
GRSwitchNodeBuilder<StateTy> Builder(BuilderImpl);
|
||||
SubEngine.ProcessSwitch(Builder);
|
||||
}
|
||||
|
||||
public:
|
||||
/// Construct a GRCoreEngine object to analyze the provided CFG using
|
||||
/// a DFS exploration of the exploded graph.
|
||||
GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, SubEngineTy& subengine)
|
||||
: GRCoreEngineImpl(new GraphTy(cfg, cd, ctx),
|
||||
GRWorkList::MakeBFS()),
|
||||
SubEngine(subengine) {}
|
||||
|
||||
/// 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(CFG& cfg, Decl& cd, ASTContext& ctx, GRWorkList* wlist,
|
||||
SubEngineTy& subengine)
|
||||
: GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), wlist),
|
||||
SubEngine(subengine) {}
|
||||
|
||||
virtual ~GRCoreEngine() {}
|
||||
|
||||
/// getGraph - Returns the exploded graph.
|
||||
GraphTy& getGraph() {
|
||||
return *static_cast<GraphTy*>(G.get());
|
||||
}
|
||||
|
||||
/// takeGraph - Returns the exploded graph. Ownership of the graph is
|
||||
/// transfered to the caller.
|
||||
GraphTy* takeGraph() {
|
||||
return static_cast<GraphTy*>(G.take());
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
|
|
|||
|
|
@ -16,111 +16,86 @@
|
|||
#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/SValuator.h"
|
||||
#include "clang/Analysis/PathSensitive/BugReporter.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
namespace clang {
|
||||
|
||||
class PathDiagnosticClient;
|
||||
class Diagnostic;
|
||||
class ObjCForCollectionStmt;
|
||||
class Checker;
|
||||
|
||||
class GRExprEngine : public GRSubEngine {
|
||||
AnalysisManager &AMgr;
|
||||
|
||||
GRCoreEngine CoreEngine;
|
||||
|
||||
class GRExprEngine {
|
||||
public:
|
||||
typedef GRState StateTy;
|
||||
typedef ExplodedGraph<StateTy> GraphTy;
|
||||
typedef GraphTy::NodeTy NodeTy;
|
||||
|
||||
// Builders.
|
||||
typedef GRStmtNodeBuilder<StateTy> StmtNodeBuilder;
|
||||
typedef GRBranchNodeBuilder<StateTy> BranchNodeBuilder;
|
||||
typedef GRIndirectGotoNodeBuilder<StateTy> IndirectGotoNodeBuilder;
|
||||
typedef GRSwitchNodeBuilder<StateTy> SwitchNodeBuilder;
|
||||
typedef GREndPathNodeBuilder<StateTy> EndPathNodeBuilder;
|
||||
typedef ExplodedNodeSet<StateTy> NodeSet;
|
||||
|
||||
protected:
|
||||
GRCoreEngine<GRExprEngine> CoreEngine;
|
||||
|
||||
/// G - the simulation graph.
|
||||
GraphTy& G;
|
||||
|
||||
/// Liveness - live-variables information the ValueDecl* and block-level
|
||||
/// Expr* in the CFG. Used to prune out dead state.
|
||||
LiveVariables& Liveness;
|
||||
ExplodedGraph& G;
|
||||
|
||||
/// Builder - The current GRStmtNodeBuilder which is used when building the
|
||||
/// nodes for a given statement.
|
||||
StmtNodeBuilder* Builder;
|
||||
|
||||
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.
|
||||
llvm::OwningPtr<SValuator> SVator;
|
||||
|
||||
SValuator &SVator;
|
||||
|
||||
/// EntryNode - The immediate predecessor node.
|
||||
NodeTy* EntryNode;
|
||||
ExplodedNode* EntryNode;
|
||||
|
||||
/// CleanedState - The state for EntryNode "cleaned" of all dead
|
||||
/// variables and symbols (as determined by a liveness analysis).
|
||||
const GRState* CleanedState;
|
||||
|
||||
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<GRSimpleAPICheck> BatchAuditor;
|
||||
|
||||
/// PurgeDead - Remove dead bindings before processing a statement.
|
||||
bool PurgeDead;
|
||||
|
||||
llvm::OwningPtr<GRSimpleAPICheck> BatchAuditor;
|
||||
std::vector<Checker*> 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;
|
||||
|
||||
/// 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.
|
||||
const bool EagerlyAssume;
|
||||
|
||||
public:
|
||||
typedef llvm::SmallPtrSet<NodeTy*,2> ErrorNodes;
|
||||
typedef llvm::DenseMap<NodeTy*, Expr*> UndefArgsTy;
|
||||
|
||||
typedef llvm::SmallPtrSet<ExplodedNode*,2> ErrorNodes;
|
||||
typedef llvm::DenseMap<ExplodedNode*, Expr*> UndefArgsTy;
|
||||
|
||||
/// NilReceiverStructRetExplicit - Nodes in the ExplodedGraph that resulted
|
||||
/// from [x ...] with 'x' definitely being nil and the result was a 'struct'
|
||||
// (an undefined value).
|
||||
ErrorNodes NilReceiverStructRetExplicit;
|
||||
|
||||
|
||||
/// NilReceiverStructRetImplicit - Nodes in the ExplodedGraph that resulted
|
||||
/// from [x ...] with 'x' possibly being nil and the result was a 'struct'
|
||||
// (an undefined value).
|
||||
ErrorNodes NilReceiverStructRetImplicit;
|
||||
|
||||
|
||||
/// NilReceiverLargerThanVoidPtrRetExplicit - Nodes in the ExplodedGraph that
|
||||
/// resulted from [x ...] with 'x' definitely being nil and the result's size
|
||||
// was larger than sizeof(void *) (an undefined value).
|
||||
|
|
@ -130,7 +105,7 @@ public:
|
|||
/// resulted from [x ...] with 'x' possibly being nil and the result's size
|
||||
// was larger than sizeof(void *) (an undefined value).
|
||||
ErrorNodes NilReceiverLargerThanVoidPtrRetImplicit;
|
||||
|
||||
|
||||
/// RetsStackAddr - Nodes in the ExplodedGraph that result from returning
|
||||
/// the address of a stack variable.
|
||||
ErrorNodes RetsStackAddr;
|
||||
|
|
@ -138,65 +113,55 @@ public:
|
|||
/// RetsUndef - Nodes in the ExplodedGraph that result from returning
|
||||
/// an undefined value.
|
||||
ErrorNodes RetsUndef;
|
||||
|
||||
|
||||
/// UndefBranches - Nodes in the ExplodedGraph that result from
|
||||
/// taking a branch based on an undefined value.
|
||||
ErrorNodes UndefBranches;
|
||||
|
||||
|
||||
/// UndefStores - Sinks in the ExplodedGraph that result from
|
||||
/// making a store to an undefined lvalue.
|
||||
ErrorNodes UndefStores;
|
||||
|
||||
|
||||
/// NoReturnCalls - Sinks in the ExplodedGraph that result from
|
||||
// calling a function with the attribute "noreturn".
|
||||
ErrorNodes NoReturnCalls;
|
||||
|
||||
|
||||
/// ImplicitNullDeref - Nodes in the ExplodedGraph that result from
|
||||
/// taking a dereference on a symbolic pointer that MAY be NULL.
|
||||
ErrorNodes ImplicitNullDeref;
|
||||
|
||||
|
||||
/// ExplicitNullDeref - Nodes in the ExplodedGraph that result from
|
||||
/// taking a dereference on a symbolic pointer that MUST be NULL.
|
||||
ErrorNodes ExplicitNullDeref;
|
||||
|
||||
/// UnitDeref - Nodes in the ExplodedGraph that result from
|
||||
|
||||
/// UndefDeref - Nodes in the ExplodedGraph that result from
|
||||
/// taking a dereference on an undefined value.
|
||||
ErrorNodes UndefDeref;
|
||||
|
||||
/// ImplicitBadDivides - Nodes in the ExplodedGraph that result from
|
||||
/// evaluating a divide or modulo operation where the denominator
|
||||
/// MAY be zero.
|
||||
ErrorNodes ImplicitBadDivides;
|
||||
|
||||
/// ExplicitBadDivides - Nodes in the ExplodedGraph that result from
|
||||
/// evaluating a divide or modulo operation where the denominator
|
||||
/// MUST be zero or undefined.
|
||||
ErrorNodes ExplicitBadDivides;
|
||||
|
||||
/// ImplicitBadSizedVLA - Nodes in the ExplodedGraph that result from
|
||||
/// ImplicitBadSizedVLA - Nodes in the ExplodedGraph that result from
|
||||
/// constructing a zero-sized VLA where the size may be zero.
|
||||
ErrorNodes ImplicitBadSizedVLA;
|
||||
|
||||
/// ExplicitBadSizedVLA - Nodes in the ExplodedGraph that result from
|
||||
|
||||
/// ExplicitBadSizedVLA - Nodes in the ExplodedGraph that result from
|
||||
/// constructing a zero-sized VLA where the size must be zero.
|
||||
ErrorNodes ExplicitBadSizedVLA;
|
||||
|
||||
|
||||
/// UndefResults - Nodes in the ExplodedGraph where the operands are defined
|
||||
/// by the result is not. Excludes divide-by-zero errors.
|
||||
ErrorNodes UndefResults;
|
||||
|
||||
|
||||
/// BadCalls - Nodes in the ExplodedGraph resulting from calls to function
|
||||
/// pointers that are NULL (or other constants) or Undefined.
|
||||
ErrorNodes BadCalls;
|
||||
|
||||
|
||||
/// UndefReceiver - Nodes in the ExplodedGraph resulting from message
|
||||
/// ObjC message expressions where the receiver is undefined (uninitialized).
|
||||
ErrorNodes UndefReceivers;
|
||||
|
||||
|
||||
/// UndefArg - Nodes in the ExplodedGraph resulting from calls to functions
|
||||
/// where a pass-by-value argument has an undefined value.
|
||||
UndefArgsTy UndefArgs;
|
||||
|
||||
|
||||
/// MsgExprUndefArgs - Nodes in the ExplodedGraph resulting from
|
||||
/// message expressions where a pass-by-value argument has an undefined
|
||||
/// value.
|
||||
|
|
@ -209,136 +174,124 @@ public:
|
|||
/// OutOfBoundMemAccesses - Nodes in the ExplodedGraph resulting from
|
||||
/// out-of-bound memory accesses where the index MUST be out-of-bound.
|
||||
ErrorNodes ExplicitOOBMemAccesses;
|
||||
|
||||
|
||||
public:
|
||||
GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx, LiveVariables& L,
|
||||
BugReporterData& BRD,
|
||||
bool purgeDead, bool eagerlyAssume = true,
|
||||
StoreManagerCreator SMC = CreateBasicStoreManager,
|
||||
ConstraintManagerCreator CMC = CreateBasicConstraintManager);
|
||||
GRExprEngine(AnalysisManager &mgr);
|
||||
|
||||
~GRExprEngine();
|
||||
|
||||
void ExecuteWorkList(unsigned Steps = 150000) {
|
||||
CoreEngine.ExecuteWorkList(Steps);
|
||||
|
||||
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(); }
|
||||
|
||||
/// getCFG - Returns the CFG associated with this analysis.
|
||||
CFG& getCFG() { return G.getCFG(); }
|
||||
|
||||
|
||||
AnalysisManager &getAnalysisManager() const { return AMgr; }
|
||||
|
||||
SValuator &getSValuator() { return SVator; }
|
||||
|
||||
GRTransferFuncs& getTF() { return *StateMgr.TF; }
|
||||
|
||||
|
||||
BugReporter& getBugReporter() { return BR; }
|
||||
|
||||
|
||||
/// setTransferFunctions
|
||||
void setTransferFunctions(GRTransferFuncs* tf);
|
||||
|
||||
void setTransferFunctions(GRTransferFuncs& tf) {
|
||||
setTransferFunctions(&tf);
|
||||
}
|
||||
|
||||
|
||||
/// ViewGraph - Visualize the ExplodedGraph created by executing the
|
||||
/// simulation.
|
||||
void ViewGraph(bool trim = false);
|
||||
|
||||
void ViewGraph(NodeTy** Beg, NodeTy** End);
|
||||
|
||||
/// getLiveness - Returned computed live-variables information for the
|
||||
/// analyzed function.
|
||||
const LiveVariables& getLiveness() const { return Liveness; }
|
||||
LiveVariables& getLiveness() { return Liveness; }
|
||||
|
||||
|
||||
void ViewGraph(ExplodedNode** Beg, ExplodedNode** End);
|
||||
|
||||
/// getInitialState - Return the initial state used for the root vertex
|
||||
/// in the ExplodedGraph.
|
||||
const GRState* getInitialState();
|
||||
|
||||
GraphTy& getGraph() { return G; }
|
||||
const GraphTy& getGraph() const { return G; }
|
||||
const GRState* getInitialState(const LocationContext *InitLoc);
|
||||
|
||||
ExplodedGraph& getGraph() { return G; }
|
||||
const ExplodedGraph& getGraph() const { return G; }
|
||||
|
||||
void RegisterInternalChecks();
|
||||
|
||||
bool isRetStackAddr(const NodeTy* N) const {
|
||||
return N->isSink() && RetsStackAddr.count(const_cast<NodeTy*>(N)) != 0;
|
||||
|
||||
void registerCheck(Checker *check) {
|
||||
Checkers.push_back(check);
|
||||
}
|
||||
|
||||
bool isUndefControlFlow(const NodeTy* N) const {
|
||||
return N->isSink() && UndefBranches.count(const_cast<NodeTy*>(N)) != 0;
|
||||
|
||||
bool isRetStackAddr(const ExplodedNode* N) const {
|
||||
return N->isSink() && RetsStackAddr.count(const_cast<ExplodedNode*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isUndefStore(const NodeTy* N) const {
|
||||
return N->isSink() && UndefStores.count(const_cast<NodeTy*>(N)) != 0;
|
||||
|
||||
bool isUndefControlFlow(const ExplodedNode* N) const {
|
||||
return N->isSink() && UndefBranches.count(const_cast<ExplodedNode*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isImplicitNullDeref(const NodeTy* N) const {
|
||||
return N->isSink() && ImplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0;
|
||||
|
||||
bool isUndefStore(const ExplodedNode* N) const {
|
||||
return N->isSink() && UndefStores.count(const_cast<ExplodedNode*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isExplicitNullDeref(const NodeTy* N) const {
|
||||
return N->isSink() && ExplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0;
|
||||
|
||||
bool isImplicitNullDeref(const ExplodedNode* N) const {
|
||||
return N->isSink() && ImplicitNullDeref.count(const_cast<ExplodedNode*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isUndefDeref(const NodeTy* N) const {
|
||||
return N->isSink() && UndefDeref.count(const_cast<NodeTy*>(N)) != 0;
|
||||
|
||||
bool isExplicitNullDeref(const ExplodedNode* N) const {
|
||||
return N->isSink() && ExplicitNullDeref.count(const_cast<ExplodedNode*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isImplicitBadDivide(const NodeTy* N) const {
|
||||
return N->isSink() && ImplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0;
|
||||
|
||||
bool isUndefDeref(const ExplodedNode* N) const {
|
||||
return N->isSink() && UndefDeref.count(const_cast<ExplodedNode*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isExplicitBadDivide(const NodeTy* N) const {
|
||||
return N->isSink() && ExplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0;
|
||||
|
||||
bool isNoReturnCall(const ExplodedNode* N) const {
|
||||
return N->isSink() && NoReturnCalls.count(const_cast<ExplodedNode*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isNoReturnCall(const NodeTy* N) const {
|
||||
return N->isSink() && NoReturnCalls.count(const_cast<NodeTy*>(N)) != 0;
|
||||
|
||||
bool isUndefResult(const ExplodedNode* N) const {
|
||||
return N->isSink() && UndefResults.count(const_cast<ExplodedNode*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isUndefResult(const NodeTy* N) const {
|
||||
return N->isSink() && UndefResults.count(const_cast<NodeTy*>(N)) != 0;
|
||||
|
||||
bool isBadCall(const ExplodedNode* N) const {
|
||||
return N->isSink() && BadCalls.count(const_cast<ExplodedNode*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isBadCall(const NodeTy* N) const {
|
||||
return N->isSink() && BadCalls.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isUndefArg(const NodeTy* N) const {
|
||||
|
||||
bool isUndefArg(const ExplodedNode* N) const {
|
||||
return N->isSink() &&
|
||||
(UndefArgs.find(const_cast<NodeTy*>(N)) != UndefArgs.end() ||
|
||||
MsgExprUndefArgs.find(const_cast<NodeTy*>(N)) != MsgExprUndefArgs.end());
|
||||
(UndefArgs.find(const_cast<ExplodedNode*>(N)) != UndefArgs.end() ||
|
||||
MsgExprUndefArgs.find(const_cast<ExplodedNode*>(N)) != MsgExprUndefArgs.end());
|
||||
}
|
||||
|
||||
bool isUndefReceiver(const NodeTy* N) const {
|
||||
return N->isSink() && UndefReceivers.count(const_cast<NodeTy*>(N)) != 0;
|
||||
|
||||
bool isUndefReceiver(const ExplodedNode* N) const {
|
||||
return N->isSink() && UndefReceivers.count(const_cast<ExplodedNode*>(N)) != 0;
|
||||
}
|
||||
|
||||
|
||||
typedef ErrorNodes::iterator ret_stackaddr_iterator;
|
||||
ret_stackaddr_iterator ret_stackaddr_begin() { return RetsStackAddr.begin(); }
|
||||
ret_stackaddr_iterator ret_stackaddr_end() { return RetsStackAddr.end(); }
|
||||
|
||||
ret_stackaddr_iterator ret_stackaddr_end() { return RetsStackAddr.end(); }
|
||||
|
||||
typedef ErrorNodes::iterator ret_undef_iterator;
|
||||
ret_undef_iterator ret_undef_begin() { return RetsUndef.begin(); }
|
||||
ret_undef_iterator ret_undef_end() { return RetsUndef.end(); }
|
||||
|
||||
|
||||
typedef ErrorNodes::iterator undef_branch_iterator;
|
||||
undef_branch_iterator undef_branches_begin() { return UndefBranches.begin(); }
|
||||
undef_branch_iterator undef_branches_end() { return UndefBranches.end(); }
|
||||
|
||||
undef_branch_iterator undef_branches_end() { return UndefBranches.end(); }
|
||||
|
||||
typedef ErrorNodes::iterator null_deref_iterator;
|
||||
null_deref_iterator null_derefs_begin() { return ExplicitNullDeref.begin(); }
|
||||
null_deref_iterator null_derefs_end() { return ExplicitNullDeref.end(); }
|
||||
|
||||
|
||||
null_deref_iterator implicit_null_derefs_begin() {
|
||||
return ImplicitNullDeref.begin();
|
||||
}
|
||||
null_deref_iterator implicit_null_derefs_end() {
|
||||
return ImplicitNullDeref.end();
|
||||
}
|
||||
|
||||
|
||||
typedef ErrorNodes::iterator nil_receiver_struct_ret_iterator;
|
||||
|
||||
|
||||
nil_receiver_struct_ret_iterator nil_receiver_struct_ret_begin() {
|
||||
return NilReceiverStructRetExplicit.begin();
|
||||
}
|
||||
|
|
@ -346,9 +299,9 @@ public:
|
|||
nil_receiver_struct_ret_iterator nil_receiver_struct_ret_end() {
|
||||
return NilReceiverStructRetExplicit.end();
|
||||
}
|
||||
|
||||
|
||||
typedef ErrorNodes::iterator nil_receiver_larger_than_voidptr_ret_iterator;
|
||||
|
||||
|
||||
nil_receiver_larger_than_voidptr_ret_iterator
|
||||
nil_receiver_larger_than_voidptr_ret_begin() {
|
||||
return NilReceiverLargerThanVoidPtrRetExplicit.begin();
|
||||
|
|
@ -358,60 +311,42 @@ public:
|
|||
nil_receiver_larger_than_voidptr_ret_end() {
|
||||
return NilReceiverLargerThanVoidPtrRetExplicit.end();
|
||||
}
|
||||
|
||||
|
||||
typedef ErrorNodes::iterator undef_deref_iterator;
|
||||
undef_deref_iterator undef_derefs_begin() { return UndefDeref.begin(); }
|
||||
undef_deref_iterator undef_derefs_end() { return UndefDeref.end(); }
|
||||
|
||||
typedef ErrorNodes::iterator bad_divide_iterator;
|
||||
|
||||
bad_divide_iterator explicit_bad_divides_begin() {
|
||||
return ExplicitBadDivides.begin();
|
||||
}
|
||||
|
||||
bad_divide_iterator explicit_bad_divides_end() {
|
||||
return ExplicitBadDivides.end();
|
||||
}
|
||||
|
||||
bad_divide_iterator implicit_bad_divides_begin() {
|
||||
return ImplicitBadDivides.begin();
|
||||
}
|
||||
|
||||
bad_divide_iterator implicit_bad_divides_end() {
|
||||
return ImplicitBadDivides.end();
|
||||
}
|
||||
|
||||
typedef ErrorNodes::iterator undef_result_iterator;
|
||||
undef_result_iterator undef_results_begin() { return UndefResults.begin(); }
|
||||
undef_result_iterator undef_results_end() { return UndefResults.end(); }
|
||||
|
||||
typedef ErrorNodes::iterator bad_calls_iterator;
|
||||
bad_calls_iterator bad_calls_begin() { return BadCalls.begin(); }
|
||||
bad_calls_iterator bad_calls_end() { return BadCalls.end(); }
|
||||
|
||||
bad_calls_iterator bad_calls_end() { return BadCalls.end(); }
|
||||
|
||||
typedef UndefArgsTy::iterator undef_arg_iterator;
|
||||
undef_arg_iterator undef_arg_begin() { return UndefArgs.begin(); }
|
||||
undef_arg_iterator undef_arg_end() { return UndefArgs.end(); }
|
||||
|
||||
undef_arg_iterator undef_arg_end() { return UndefArgs.end(); }
|
||||
|
||||
undef_arg_iterator msg_expr_undef_arg_begin() {
|
||||
return MsgExprUndefArgs.begin();
|
||||
}
|
||||
undef_arg_iterator msg_expr_undef_arg_end() {
|
||||
return MsgExprUndefArgs.end();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
typedef ErrorNodes::iterator undef_receivers_iterator;
|
||||
|
||||
undef_receivers_iterator undef_receivers_begin() {
|
||||
return UndefReceivers.begin();
|
||||
}
|
||||
|
||||
|
||||
undef_receivers_iterator undef_receivers_end() {
|
||||
return UndefReceivers.end();
|
||||
}
|
||||
|
||||
typedef ErrorNodes::iterator oob_memacc_iterator;
|
||||
oob_memacc_iterator implicit_oob_memacc_begin() {
|
||||
oob_memacc_iterator implicit_oob_memacc_begin() {
|
||||
return ImplicitOOBMemAccesses.begin();
|
||||
}
|
||||
oob_memacc_iterator implicit_oob_memacc_end() {
|
||||
|
|
@ -426,45 +361,45 @@ public:
|
|||
|
||||
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(Stmt* S, StmtNodeBuilder& builder);
|
||||
|
||||
/// nodes by processing the 'effects' of a block-level statement.
|
||||
void ProcessStmt(Stmt* S, 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, BranchNodeBuilder& builder);
|
||||
|
||||
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(IndirectGotoNodeBuilder& builder);
|
||||
|
||||
void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder);
|
||||
|
||||
/// ProcessSwitch - Called by GRCoreEngine. Used to generate successor
|
||||
/// nodes by processing the 'effects' of a switch statement.
|
||||
void ProcessSwitch(SwitchNodeBuilder& builder);
|
||||
|
||||
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(EndPathNodeBuilder& builder) {
|
||||
void ProcessEndPath(GREndPathNodeBuilder& builder) {
|
||||
getTF().EvalEndPath(*this, builder);
|
||||
StateMgr.EndPath(builder.getState());
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
|
|
@ -472,204 +407,198 @@ public:
|
|||
const BasicValueFactory& getBasicVals() const {
|
||||
return StateMgr.getBasicVals();
|
||||
}
|
||||
|
||||
ValueManager &getValueManager() { return ValMgr; }
|
||||
|
||||
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(NodeTy* N) {
|
||||
const GRState* GetState(ExplodedNode* N) {
|
||||
return N == EntryNode ? CleanedState : N->getState();
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
NodeTy* MakeNode(NodeSet& Dst, Stmt* S, NodeTy* Pred, const GRState* St,
|
||||
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);
|
||||
|
||||
/// Visit - Transfer function logic for all statements. Dispatches to
|
||||
/// other functions that handle specific kinds of statements.
|
||||
void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
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, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitLValue(Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst);
|
||||
|
||||
/// VisitArraySubscriptExpr - Transfer function for array accesses.
|
||||
void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, NodeTy* Pred,
|
||||
NodeSet& Dst, bool asLValue);
|
||||
|
||||
void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, ExplodedNode* Pred,
|
||||
ExplodedNodeSet& Dst, bool asLValue);
|
||||
|
||||
/// VisitAsmStmt - Transfer function logic for inline asm.
|
||||
void VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst);
|
||||
|
||||
void VisitAsmStmtHelperOutputs(AsmStmt* A,
|
||||
AsmStmt::outputs_iterator I,
|
||||
AsmStmt::outputs_iterator E,
|
||||
NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
ExplodedNode* Pred, ExplodedNodeSet& Dst);
|
||||
|
||||
void VisitAsmStmtHelperInputs(AsmStmt* A,
|
||||
AsmStmt::inputs_iterator I,
|
||||
AsmStmt::inputs_iterator E,
|
||||
NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
ExplodedNode* Pred, ExplodedNodeSet& Dst);
|
||||
|
||||
/// VisitBinaryOperator - Transfer function logic for binary operators.
|
||||
void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
|
||||
void VisitBinaryOperator(BinaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst);
|
||||
|
||||
|
||||
|
||||
/// VisitCall - Transfer function for function calls.
|
||||
void VisitCall(CallExpr* CE, NodeTy* Pred,
|
||||
void VisitCall(CallExpr* CE, ExplodedNode* Pred,
|
||||
CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
|
||||
NodeSet& Dst);
|
||||
void VisitCallRec(CallExpr* CE, NodeTy* Pred,
|
||||
ExplodedNodeSet& Dst);
|
||||
void VisitCallRec(CallExpr* CE, ExplodedNode* Pred,
|
||||
CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
|
||||
NodeSet& Dst, const FunctionProtoType *,
|
||||
ExplodedNodeSet& Dst, const FunctionProtoType *,
|
||||
unsigned ParamIdx = 0);
|
||||
|
||||
|
||||
/// VisitCast - Transfer function logic for all casts (implicit and explicit).
|
||||
void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst);
|
||||
void VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst);
|
||||
|
||||
/// VisitCastPointerToInteger - Transfer function (called by VisitCast) that
|
||||
/// handles pointer to integer casts and array to integer casts.
|
||||
void VisitCastPointerToInteger(SVal V, const GRState* state, QualType PtrTy,
|
||||
Expr* CastE, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitCompoundLiteralExpr - Transfer function logic for compound literals.
|
||||
void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, NodeTy* Pred,
|
||||
NodeSet& Dst, bool asLValue);
|
||||
|
||||
/// VisitDeclRefExpr - Transfer function logic for DeclRefExprs.
|
||||
void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst,
|
||||
bool asLValue);
|
||||
|
||||
/// VisitDeclStmt - Transfer function logic for DeclStmts.
|
||||
void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
|
||||
void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst);
|
||||
void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, ExplodedNode* Pred,
|
||||
ExplodedNodeSet& Dst, bool asLValue);
|
||||
|
||||
void VisitInitListExpr(InitListExpr* E, NodeTy* Pred, NodeSet& Dst);
|
||||
/// VisitDeclRefExpr - Transfer function logic for DeclRefExprs.
|
||||
void VisitDeclRefExpr(DeclRefExpr* DR, 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);
|
||||
|
||||
void VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, ExplodedNodeSet& Dst);
|
||||
|
||||
/// VisitLogicalExpr - Transfer function logic for '&&', '||'
|
||||
void VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst);
|
||||
|
||||
/// VisitMemberExpr - Transfer function for member expressions.
|
||||
void VisitMemberExpr(MemberExpr* M, NodeTy* Pred, NodeSet& Dst,bool asLValue);
|
||||
|
||||
void VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, ExplodedNodeSet& Dst,bool asLValue);
|
||||
|
||||
/// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs.
|
||||
void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, NodeTy* Pred, NodeSet& Dst,
|
||||
bool asLValue);
|
||||
void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, ExplodedNode* Pred, ExplodedNodeSet& Dst,
|
||||
bool asLValue);
|
||||
|
||||
/// VisitObjCForCollectionStmt - Transfer function logic for
|
||||
/// ObjCForCollectionStmt.
|
||||
void VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, NodeTy* Pred,
|
||||
NodeSet& Dst);
|
||||
|
||||
void VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, NodeTy* Pred,
|
||||
NodeSet& Dst, SVal ElementV);
|
||||
|
||||
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, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, ExplodedNodeSet& Dst);
|
||||
|
||||
void VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
|
||||
ObjCMessageExpr::arg_iterator I,
|
||||
ObjCMessageExpr::arg_iterator E,
|
||||
NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, NodeTy* Pred,
|
||||
NodeSet& Dst);
|
||||
|
||||
ExplodedNode* Pred, ExplodedNodeSet& Dst);
|
||||
|
||||
void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, ExplodedNode* Pred,
|
||||
ExplodedNodeSet& Dst);
|
||||
|
||||
/// VisitReturnStmt - Transfer function logic for return statements.
|
||||
void VisitReturnStmt(ReturnStmt* R, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitReturnStmt(ReturnStmt* R, ExplodedNode* Pred, ExplodedNodeSet& Dst);
|
||||
|
||||
/// VisitSizeOfAlignOfExpr - Transfer function for sizeof.
|
||||
void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, NodeTy* Pred,
|
||||
NodeSet& Dst);
|
||||
|
||||
void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, ExplodedNode* Pred,
|
||||
ExplodedNodeSet& Dst);
|
||||
|
||||
/// VisitUnaryOperator - Transfer function logic for unary operators.
|
||||
void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst,
|
||||
void VisitUnaryOperator(UnaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst,
|
||||
bool asLValue);
|
||||
|
||||
const GRState* CheckDivideZero(Expr* Ex, const GRState* St, NodeTy* Pred,
|
||||
SVal Denom);
|
||||
|
||||
|
||||
const GRState* CheckDivideZero(Expr* Ex, const GRState* St, ExplodedNode* Pred,
|
||||
SVal Denom);
|
||||
|
||||
/// 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(NodeSet& Dst, NodeSet& Src, Expr *Ex);
|
||||
|
||||
SVal EvalCast(SVal X, QualType CastT) {
|
||||
if (X.isUnknownOrUndef())
|
||||
return X;
|
||||
|
||||
if (isa<Loc>(X))
|
||||
return SVator->EvalCast(cast<Loc>(X), CastT);
|
||||
else
|
||||
return SVator->EvalCast(cast<NonLoc>(X), CastT);
|
||||
}
|
||||
|
||||
void EvalEagerlyAssume(ExplodedNodeSet& Dst, ExplodedNodeSet& Src, Expr *Ex);
|
||||
|
||||
SVal EvalMinus(SVal X) {
|
||||
return X.isValid() ? SVator->EvalMinus(cast<NonLoc>(X)) : X;
|
||||
return X.isValid() ? SVator.EvalMinus(cast<NonLoc>(X)) : X;
|
||||
}
|
||||
|
||||
|
||||
SVal EvalComplement(SVal X) {
|
||||
return X.isValid() ? SVator->EvalComplement(cast<NonLoc>(X)) : X;
|
||||
return X.isValid() ? SVator.EvalComplement(cast<NonLoc>(X)) : X;
|
||||
}
|
||||
|
||||
|
||||
bool EvalBuiltinFunction(const FunctionDecl *FD, CallExpr *CE,
|
||||
ExplodedNode *Pred, ExplodedNodeSet &Dst);
|
||||
|
||||
public:
|
||||
|
||||
SVal EvalBinOp(BinaryOperator::Opcode op, NonLoc L, NonLoc R, QualType T) {
|
||||
return SVator->EvalBinOpNN(op, L, R, T);
|
||||
}
|
||||
|
||||
SVal EvalBinOp(BinaryOperator::Opcode op, NonLoc L, SVal R, QualType T) {
|
||||
return R.isValid() ? SVator->EvalBinOpNN(op, L, cast<NonLoc>(R), T) : R;
|
||||
}
|
||||
|
||||
SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op,
|
||||
SVal lhs, SVal rhs, QualType T);
|
||||
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<NonLoc>(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 EvalCall(NodeSet& Dst, CallExpr* CE, SVal L, NodeTy* Pred);
|
||||
|
||||
void EvalObjCMessageExpr(NodeSet& Dst, ObjCMessageExpr* ME, NodeTy* Pred) {
|
||||
void EvalCall(ExplodedNodeSet& Dst, CallExpr* CE, SVal L, ExplodedNode* Pred);
|
||||
|
||||
void EvalObjCMessageExpr(ExplodedNodeSet& Dst, ObjCMessageExpr* ME, ExplodedNode* Pred) {
|
||||
assert (Builder && "GRStmtNodeBuilder must be defined.");
|
||||
getTF().EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred);
|
||||
}
|
||||
|
||||
void EvalReturn(NodeSet& Dst, ReturnStmt* s, NodeTy* Pred);
|
||||
|
||||
const GRState* MarkBranch(const GRState* St, Stmt* Terminator,
|
||||
void EvalReturn(ExplodedNodeSet& Dst, ReturnStmt* s, ExplodedNode* Pred);
|
||||
|
||||
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(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
|
||||
void EvalBind(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred,
|
||||
const GRState* St, SVal location, SVal Val);
|
||||
|
||||
|
||||
public:
|
||||
void EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
|
||||
void EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred,
|
||||
const GRState* St, SVal location, const void *tag = 0);
|
||||
|
||||
NodeTy* EvalLocation(Stmt* Ex, NodeTy* Pred,
|
||||
|
||||
ExplodedNode* EvalLocation(Stmt* Ex, ExplodedNode* Pred,
|
||||
const GRState* St, SVal location,
|
||||
const void *tag = 0);
|
||||
|
||||
|
||||
void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, const GRState* St,
|
||||
|
||||
void EvalStore(ExplodedNodeSet& Dst, Expr* E, ExplodedNode* Pred, const GRState* St,
|
||||
SVal TargetLV, SVal Val, const void *tag = 0);
|
||||
|
||||
void EvalStore(NodeSet& Dst, Expr* E, Expr* StoreE, NodeTy* Pred,
|
||||
|
||||
void EvalStore(ExplodedNodeSet& Dst, Expr* E, Expr* StoreE, ExplodedNode* Pred,
|
||||
const GRState* St, SVal TargetLV, SVal Val,
|
||||
const void *tag = 0);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -15,38 +15,15 @@
|
|||
#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 {
|
||||
|
||||
|
||||
// SaveAndRestore - A utility class that uses RAII to save and restore
|
||||
// the value of a variable.
|
||||
template<typename T>
|
||||
struct SaveAndRestore {
|
||||
SaveAndRestore(T& x) : X(x), old_value(x) {}
|
||||
~SaveAndRestore() { X = old_value; }
|
||||
T get() { return old_value; }
|
||||
private:
|
||||
T& X;
|
||||
T old_value;
|
||||
};
|
||||
|
||||
// SaveOr - Similar to SaveAndRestore. Operates only on bools; the old
|
||||
// value of a variable is saved, and during the dstor the old value is
|
||||
// or'ed with the new value.
|
||||
struct SaveOr {
|
||||
SaveOr(bool& x) : X(x), old_value(x) { x = false; }
|
||||
~SaveOr() { X |= old_value; }
|
||||
private:
|
||||
bool& X;
|
||||
const bool old_value;
|
||||
};
|
||||
|
||||
class GRStmtNodeBuilderRef {
|
||||
GRExprEngine::NodeSet &Dst;
|
||||
GRExprEngine::StmtNodeBuilder &B;
|
||||
ExplodedNodeSet &Dst;
|
||||
GRStmtNodeBuilder &B;
|
||||
GRExprEngine& Eng;
|
||||
GRExprEngine::NodeTy* Pred;
|
||||
ExplodedNode* Pred;
|
||||
const GRState* state;
|
||||
const Stmt* stmt;
|
||||
const unsigned OldSize;
|
||||
|
|
@ -57,25 +34,25 @@ class GRStmtNodeBuilderRef {
|
|||
|
||||
private:
|
||||
friend class GRExprEngine;
|
||||
|
||||
|
||||
GRStmtNodeBuilderRef(); // do not implement
|
||||
void operator=(const GRStmtNodeBuilderRef&); // do not implement
|
||||
|
||||
GRStmtNodeBuilderRef(GRExprEngine::NodeSet &dst,
|
||||
GRExprEngine::StmtNodeBuilder &builder,
|
||||
|
||||
GRStmtNodeBuilderRef(ExplodedNodeSet &dst,
|
||||
GRStmtNodeBuilder &builder,
|
||||
GRExprEngine& eng,
|
||||
GRExprEngine::NodeTy* pred,
|
||||
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.
|
||||
// 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*>(stmt), Pred, state);
|
||||
|
|
@ -85,14 +62,14 @@ public:
|
|||
}
|
||||
|
||||
const GRState *getState() { return state; }
|
||||
|
||||
|
||||
GRStateManager& getStateManager() {
|
||||
return Eng.getStateManager();
|
||||
}
|
||||
|
||||
GRExprEngine::NodeTy* MakeNode(const GRState* state) {
|
||||
return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
|
||||
}
|
||||
|
||||
ExplodedNode* MakeNode(const GRState* state) {
|
||||
return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
|
|
|||
|
|
@ -20,16 +20,16 @@
|
|||
#include "clang/Analysis/PathSensitive/GRState.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
class Diagnostic;
|
||||
class BugReporter;
|
||||
class ASTContext;
|
||||
class GRExprEngine;
|
||||
class PathDiagnosticClient;
|
||||
template <typename T> class ExplodedGraph;
|
||||
|
||||
|
||||
class GRSimpleAPICheck : public GRAuditor<GRState> {
|
||||
class ExplodedGraph;
|
||||
|
||||
|
||||
class GRSimpleAPICheck : public GRAuditor {
|
||||
public:
|
||||
GRSimpleAPICheck() {}
|
||||
virtual ~GRSimpleAPICheck() {}
|
||||
|
|
|
|||
|
|
@ -49,12 +49,12 @@ typedef StoreManager* (*StoreManagerCreator)(GRStateManager&);
|
|||
//===----------------------------------------------------------------------===//
|
||||
// GRStateTrait - Traits used by the Generic Data Map of a GRState.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
template <typename T> struct GRStatePartialTrait;
|
||||
|
||||
template <typename T> struct GRStateTrait {
|
||||
typedef typename T::data_type data_type;
|
||||
static inline void* GDMIndex() { return &T::TagInt; }
|
||||
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;
|
||||
|
|
@ -66,68 +66,78 @@ template <typename T> struct GRStateTrait {
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
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:
|
||||
// Typedefs.
|
||||
public:
|
||||
typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy;
|
||||
typedef llvm::ImmutableMap<void*, void*> GenericDataMap;
|
||||
|
||||
typedef GRStateManager ManagerTy;
|
||||
|
||||
typedef llvm::ImmutableMap<void*, void*> GenericDataMap;
|
||||
|
||||
private:
|
||||
void operator=(const GRState& R) const;
|
||||
|
||||
|
||||
friend class GRStateManager;
|
||||
|
||||
GRStateManager *Mgr;
|
||||
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)
|
||||
: Mgr(mgr),
|
||||
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(),
|
||||
Mgr(RHS.Mgr),
|
||||
StateMgr(RHS.StateMgr),
|
||||
Env(RHS.Env),
|
||||
St(RHS.St),
|
||||
GDM(RHS.GDM) {}
|
||||
|
||||
|
||||
/// getStateManager - Return the GRStateManager associated with this state.
|
||||
GRStateManager &getStateManager() const { return *Mgr; }
|
||||
|
||||
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);
|
||||
|
|
@ -138,28 +148,19 @@ public:
|
|||
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;
|
||||
|
||||
// Iterators.
|
||||
typedef Environment::seb_iterator seb_iterator;
|
||||
seb_iterator seb_begin() const { return Env.seb_begin(); }
|
||||
seb_iterator seb_end() const { return Env.beb_end(); }
|
||||
|
||||
typedef Environment::beb_iterator beb_iterator;
|
||||
beb_iterator beb_begin() const { return Env.beb_begin(); }
|
||||
beb_iterator beb_end() const { return Env.beb_end(); }
|
||||
|
||||
|
||||
BasicValueFactory &getBasicVals() const;
|
||||
SymbolManager &getSymbolManager() const;
|
||||
GRTransferFuncs &getTransferFuncs() const;
|
||||
|
||||
|
||||
//==---------------------------------------------------------------------==//
|
||||
// Constraints on values.
|
||||
//==---------------------------------------------------------------------==//
|
||||
|
|
@ -192,91 +193,85 @@ public:
|
|||
// FIXME: (a) should probably disappear since it is redundant with (b).
|
||||
// (i.e., (b) could just be set to NULL).
|
||||
//
|
||||
|
||||
const GRState *assume(SVal condition, bool assumption) const;
|
||||
|
||||
const GRState *assumeInBound(SVal idx, SVal upperBound,
|
||||
|
||||
const GRState *Assume(DefinedOrUnknownSVal cond, bool assumption) const;
|
||||
|
||||
const GRState *AssumeInBound(DefinedOrUnknownSVal idx,
|
||||
DefinedOrUnknownSVal upperBound,
|
||||
bool assumption) const;
|
||||
|
||||
|
||||
//==---------------------------------------------------------------------==//
|
||||
// Utility methods for getting regions.
|
||||
//==---------------------------------------------------------------------==//
|
||||
|
||||
const VarRegion* getRegion(const VarDecl* D) const;
|
||||
|
||||
const MemRegion* getSelfRegion() const;
|
||||
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,
|
||||
SVal V) const;
|
||||
|
||||
const GRState *bindExpr(const Stmt* Ex, SVal V, bool isBlkExpr,
|
||||
bool Invalidate) const;
|
||||
|
||||
const GRState *bindExpr(const Stmt* Ex, SVal V, bool Invalidate = true) const;
|
||||
|
||||
const GRState *bindBlkExpr(const Stmt *Ex, SVal V) const {
|
||||
return bindExpr(Ex, V, true, false);
|
||||
}
|
||||
|
||||
const GRState *bindDecl(const VarDecl* VD, SVal IVal) const;
|
||||
|
||||
const GRState *bindDeclWithNoInit(const VarDecl* VD) const;
|
||||
|
||||
|
||||
const GRState *BindExpr(const Stmt *S, SVal V, bool Invalidate = true) const;
|
||||
|
||||
const GRState *bindDecl(const VarDecl *VD, const LocationContext *LC,
|
||||
SVal V) const;
|
||||
|
||||
const GRState *bindDeclWithNoInit(const VarDecl *VD,
|
||||
const LocationContext *LC) 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 *decl) const;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
/// Get the lvalue for an ivar reference.
|
||||
SVal getLValue(const ObjCIvarDecl *decl, SVal base) const;
|
||||
|
||||
|
||||
/// Get the lvalue for a field reference.
|
||||
SVal getLValue(SVal Base, const FieldDecl *decl) const;
|
||||
|
||||
SVal getLValue(const FieldDecl *decl, SVal Base) const;
|
||||
|
||||
/// Get the lvalue for an array index.
|
||||
SVal getLValue(QualType ElementType, SVal Base, SVal Idx) const;
|
||||
|
||||
SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const;
|
||||
|
||||
const llvm::APSInt *getSymVal(SymbolRef sym) const;
|
||||
|
||||
SVal getSVal(const Stmt* Ex) const;
|
||||
|
||||
SVal getBlkExprSVal(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;
|
||||
|
||||
template <typename CB> CB scanReachableSymbols(SVal val) const;
|
||||
|
||||
|
||||
//==---------------------------------------------------------------------==//
|
||||
// Accessing the Generic Data Map (GDM).
|
||||
//==---------------------------------------------------------------------==//
|
||||
|
||||
void* const* FindGDM(void* K) const;
|
||||
|
||||
|
||||
template<typename T>
|
||||
const GRState *add(typename GRStateTrait<T>::key_type K) const;
|
||||
|
||||
|
|
@ -285,31 +280,31 @@ public:
|
|||
get() const {
|
||||
return GRStateTrait<T>::MakeData(FindGDM(GRStateTrait<T>::GDMIndex()));
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
typename GRStateTrait<T>::lookup_type
|
||||
get(typename GRStateTrait<T>::key_type key) const {
|
||||
void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
|
||||
return GRStateTrait<T>::Lookup(GRStateTrait<T>::MakeData(d), key);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
typename GRStateTrait<T>::context_type get_context() const;
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
const GRState *remove(typename GRStateTrait<T>::key_type K) const;
|
||||
|
||||
template<typename T>
|
||||
const GRState *remove(typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::context_type C) const;
|
||||
|
||||
|
||||
template<typename T>
|
||||
const GRState *set(typename GRStateTrait<T>::data_type D) const;
|
||||
|
||||
|
||||
template<typename T>
|
||||
const GRState *set(typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::value_type E) const;
|
||||
typename GRStateTrait<T>::value_type E) const;
|
||||
|
||||
template<typename T>
|
||||
const GRState *set(typename GRStateTrait<T>::key_type K,
|
||||
|
|
@ -321,7 +316,7 @@ public:
|
|||
void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
|
||||
return GRStateTrait<T>::Contains(GRStateTrait<T>::MakeData(d), key);
|
||||
}
|
||||
|
||||
|
||||
// State pretty-printing.
|
||||
class Printer {
|
||||
public:
|
||||
|
|
@ -329,66 +324,55 @@ public:
|
|||
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;
|
||||
const char *sep = "") const;
|
||||
|
||||
void printStdErr() const;
|
||||
|
||||
void printDOT(llvm::raw_ostream& Out) const;
|
||||
|
||||
void printStdErr() const;
|
||||
|
||||
void printDOT(llvm::raw_ostream& Out) const;
|
||||
|
||||
// Tags used for the Generic Data Map.
|
||||
struct NullDerefTag {
|
||||
static int TagInt;
|
||||
typedef const SVal* data_type;
|
||||
};
|
||||
};
|
||||
|
||||
template<> struct GRTrait<GRState*> {
|
||||
static inline void* toPtr(GRState* St) { return (void*) St; }
|
||||
static inline GRState* toState(void* P) { return (GRState*) P; }
|
||||
static inline void Profile(llvm::FoldingSetNodeID& profile, GRState* St) {
|
||||
// At this point states have already been uniqued. Just
|
||||
// add the pointer.
|
||||
profile.AddPointer(St);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class GRStateSet {
|
||||
typedef llvm::SmallPtrSet<const GRState*,5> ImplTy;
|
||||
ImplTy Impl;
|
||||
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)
|
||||
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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -396,22 +380,21 @@ public:
|
|||
class GRStateManager {
|
||||
friend class GRExprEngine;
|
||||
friend class GRState;
|
||||
|
||||
|
||||
private:
|
||||
EnvironmentManager EnvMgr;
|
||||
llvm::OwningPtr<StoreManager> StoreMgr;
|
||||
llvm::OwningPtr<ConstraintManager> ConstraintMgr;
|
||||
GRState::IntSetTy::Factory ISetFactory;
|
||||
|
||||
|
||||
GRState::GenericDataMap::Factory GDMFactory;
|
||||
|
||||
|
||||
typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy;
|
||||
GDMContextsTy GDMContexts;
|
||||
|
||||
|
||||
/// Printers - A set of printer objects used for pretty-printing a GRState.
|
||||
/// GRStateManager owns these objects.
|
||||
std::vector<GRState::Printer*> Printers;
|
||||
|
||||
|
||||
/// StateSet - FoldingSet containing all the states created for analyzing
|
||||
/// a particular function. This is used to unique states.
|
||||
llvm::FoldingSet<GRState> StateSet;
|
||||
|
|
@ -421,52 +404,36 @@ private:
|
|||
|
||||
/// Alloc - A BumpPtrAllocator to allocate states.
|
||||
llvm::BumpPtrAllocator& Alloc;
|
||||
|
||||
|
||||
/// CurrentStmt - The block-level statement currently being visited. This
|
||||
/// is set by GRExprEngine.
|
||||
Stmt* CurrentStmt;
|
||||
|
||||
/// cfg - The CFG for the analyzed function/method.
|
||||
CFG& cfg;
|
||||
|
||||
/// codedecl - The Decl representing the function/method being analyzed.
|
||||
const Decl& codedecl;
|
||||
|
||||
|
||||
/// TF - Object that represents a bundle of transfer functions
|
||||
/// for manipulating and creating SVals.
|
||||
GRTransferFuncs* TF;
|
||||
|
||||
/// Liveness - live-variables information of the ValueDecl* and block-level
|
||||
/// Expr* in the CFG. Used to get initial store and prune out dead state.
|
||||
LiveVariables& Liveness;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
GRStateManager(ASTContext& Ctx,
|
||||
StoreManagerCreator CreateStoreManager,
|
||||
ConstraintManagerCreator CreateConstraintManager,
|
||||
llvm::BumpPtrAllocator& alloc, CFG& c,
|
||||
const Decl& cd, LiveVariables& L)
|
||||
: EnvMgr(alloc),
|
||||
ISetFactory(alloc),
|
||||
GDMFactory(alloc),
|
||||
ValueMgr(alloc, Ctx),
|
||||
Alloc(alloc),
|
||||
cfg(c),
|
||||
codedecl(cd),
|
||||
Liveness(L) {
|
||||
StoreMgr.reset((*CreateStoreManager)(*this));
|
||||
ConstraintMgr.reset((*CreateConstraintManager)(*this));
|
||||
llvm::BumpPtrAllocator& alloc)
|
||||
: EnvMgr(alloc),
|
||||
GDMFactory(alloc),
|
||||
ValueMgr(alloc, Ctx, *this),
|
||||
Alloc(alloc) {
|
||||
StoreMgr.reset((*CreateStoreManager)(*this));
|
||||
ConstraintMgr.reset((*CreateConstraintManager)(*this));
|
||||
}
|
||||
|
||||
|
||||
~GRStateManager();
|
||||
|
||||
const GRState *getInitialState();
|
||||
|
||||
const GRState *getInitialState(const LocationContext *InitLoc);
|
||||
|
||||
ASTContext &getContext() { return ValueMgr.getContext(); }
|
||||
const ASTContext &getContext() const { return ValueMgr.getContext(); }
|
||||
|
||||
const Decl &getCodeDecl() { return codedecl; }
|
||||
const ASTContext &getContext() const { return ValueMgr.getContext(); }
|
||||
|
||||
GRTransferFuncs& getTransferFuncs() { return *TF; }
|
||||
|
||||
BasicValueFactory &getBasicVals() {
|
||||
|
|
@ -475,18 +442,17 @@ public:
|
|||
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; }
|
||||
|
||||
LiveVariables& getLiveVariables() { return Liveness; }
|
||||
|
||||
llvm::BumpPtrAllocator& getAllocator() { return Alloc; }
|
||||
|
||||
MemRegionManager& getRegionManager() {
|
||||
|
|
@ -495,28 +461,22 @@ public:
|
|||
const MemRegionManager& getRegionManager() const {
|
||||
return ValueMgr.getRegionManager();
|
||||
}
|
||||
|
||||
|
||||
StoreManager& getStoreManager() { return *StoreMgr; }
|
||||
ConstraintManager& getConstraintManager() { return *ConstraintMgr; }
|
||||
|
||||
const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc,
|
||||
const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc,
|
||||
SymbolReaper& SymReaper);
|
||||
|
||||
const GRState* RemoveSubExprBindings(const GRState* St) {
|
||||
GRState NewSt = *St;
|
||||
NewSt.Env = EnvMgr.RemoveSubExprBindings(NewSt.Env);
|
||||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
@ -525,9 +485,9 @@ public:
|
|||
|
||||
const GRState* getPersistentState(GRState& Impl);
|
||||
|
||||
bool isEqual(const GRState* state, Expr* Ex, const llvm::APSInt& V);
|
||||
bool isEqual(const GRState* state, Expr* Ex, uint64_t);
|
||||
|
||||
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.
|
||||
//==---------------------------------------------------------------------==//
|
||||
|
|
@ -545,21 +505,21 @@ public:
|
|||
// The templated methods below use the GRStateTrait<T> class
|
||||
// to resolve keys into the GDM and to return data values to clients.
|
||||
//
|
||||
|
||||
// Trait based GDM dispatch.
|
||||
|
||||
// Trait based GDM dispatch.
|
||||
template <typename T>
|
||||
const GRState* set(const GRState* st, typename GRStateTrait<T>::data_type D) {
|
||||
return addGDM(st, GRStateTrait<T>::GDMIndex(),
|
||||
GRStateTrait<T>::MakeVoidPtr(D));
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
const GRState* set(const GRState* st,
|
||||
typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::value_type V,
|
||||
typename GRStateTrait<T>::context_type C) {
|
||||
|
||||
return addGDM(st, GRStateTrait<T>::GDMIndex(),
|
||||
|
||||
return addGDM(st, GRStateTrait<T>::GDMIndex(),
|
||||
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Set(st->get<T>(), K, V, C)));
|
||||
}
|
||||
|
||||
|
|
@ -575,22 +535,22 @@ public:
|
|||
const GRState* remove(const GRState* st,
|
||||
typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::context_type C) {
|
||||
|
||||
return addGDM(st, GRStateTrait<T>::GDMIndex(),
|
||||
|
||||
return addGDM(st, GRStateTrait<T>::GDMIndex(),
|
||||
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Remove(st->get<T>(), K, C)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void* FindGDMContext(void* index,
|
||||
void* (*CreateContext)(llvm::BumpPtrAllocator&),
|
||||
void (*DeleteContext)(void*));
|
||||
|
||||
|
||||
template <typename T>
|
||||
typename GRStateTrait<T>::context_type get_context() {
|
||||
void* p = FindGDMContext(GRStateTrait<T>::GDMIndex(),
|
||||
GRStateTrait<T>::CreateContext,
|
||||
GRStateTrait<T>::DeleteContext);
|
||||
|
||||
|
||||
return GRStateTrait<T>::MakeContext(p);
|
||||
}
|
||||
|
||||
|
|
@ -602,84 +562,96 @@ public:
|
|||
ConstraintMgr->EndPath(St);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Out-of-line method definitions for GRState.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
inline const VarRegion* GRState::getRegion(const VarDecl* D) const {
|
||||
return Mgr->getRegionManager().getVarRegion(D);
|
||||
}
|
||||
|
||||
inline const MemRegion* GRState::getSelfRegion() const {
|
||||
return Mgr->StoreMgr->getSelfRegion(getStore());
|
||||
inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) {
|
||||
return getStateManager().getSymVal(this, sym);
|
||||
}
|
||||
|
||||
inline const GRState *GRState::assume(SVal Cond, bool Assumption) const {
|
||||
return Mgr->ConstraintMgr->Assume(this, Cond, Assumption);
|
||||
inline const VarRegion* GRState::getRegion(const VarDecl *D,
|
||||
const LocationContext *LC) const {
|
||||
return getStateManager().getRegionManager().getVarRegion(D, LC);
|
||||
}
|
||||
|
||||
inline const GRState *GRState::assumeInBound(SVal Idx, SVal UpperBound,
|
||||
inline const GRState *GRState::Assume(DefinedOrUnknownSVal Cond,
|
||||
bool Assumption) const {
|
||||
if (Cond.isUnknown())
|
||||
return this;
|
||||
|
||||
return getStateManager().ConstraintMgr->Assume(this, cast<DefinedSVal>(Cond),
|
||||
Assumption);
|
||||
}
|
||||
|
||||
inline const GRState *GRState::AssumeInBound(DefinedOrUnknownSVal Idx,
|
||||
DefinedOrUnknownSVal UpperBound,
|
||||
bool Assumption) const {
|
||||
return Mgr->ConstraintMgr->AssumeInBound(this, Idx, UpperBound, Assumption);
|
||||
}
|
||||
if (Idx.isUnknown() || UpperBound.isUnknown())
|
||||
return this;
|
||||
|
||||
ConstraintManager &CM = *getStateManager().ConstraintMgr;
|
||||
return CM.AssumeInBound(this, cast<DefinedSVal>(Idx),
|
||||
cast<DefinedSVal>(UpperBound), Assumption);
|
||||
}
|
||||
|
||||
inline const GRState *GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL,
|
||||
SVal V) const {
|
||||
return Mgr->StoreMgr->BindCompoundLiteral(this, CL, V);
|
||||
}
|
||||
|
||||
inline const GRState *GRState::bindDecl(const VarDecl* VD, SVal IVal) const {
|
||||
return Mgr->StoreMgr->BindDecl(this, VD, IVal);
|
||||
return getStateManager().StoreMgr->BindCompoundLiteral(this, CL, V);
|
||||
}
|
||||
|
||||
inline const GRState *GRState::bindDeclWithNoInit(const VarDecl* VD) const {
|
||||
return Mgr->StoreMgr->BindDeclWithNoInit(this, VD);
|
||||
inline const GRState *GRState::bindDecl(const VarDecl* VD,
|
||||
const LocationContext *LC,
|
||||
SVal IVal) const {
|
||||
return getStateManager().StoreMgr->BindDecl(this, VD, LC, IVal);
|
||||
}
|
||||
|
||||
|
||||
inline const GRState *GRState::bindDeclWithNoInit(const VarDecl* VD,
|
||||
const LocationContext *LC) const {
|
||||
return getStateManager().StoreMgr->BindDeclWithNoInit(this, VD, LC);
|
||||
}
|
||||
|
||||
inline const GRState *GRState::bindLoc(Loc LV, SVal V) const {
|
||||
return Mgr->StoreMgr->Bind(this, LV, V);
|
||||
return getStateManager().StoreMgr->Bind(this, LV, V);
|
||||
}
|
||||
|
||||
inline const GRState *GRState::bindLoc(SVal LV, SVal V) const {
|
||||
return !isa<Loc>(LV) ? this : bindLoc(cast<Loc>(LV), V);
|
||||
}
|
||||
|
||||
inline SVal GRState::getLValue(const VarDecl* VD) const {
|
||||
return Mgr->StoreMgr->getLValueVar(this, VD);
|
||||
|
||||
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 Mgr->StoreMgr->getLValueString(this, literal);
|
||||
return getStateManager().StoreMgr->getLValueString(literal);
|
||||
}
|
||||
|
||||
|
||||
inline SVal GRState::getLValue(const CompoundLiteralExpr *literal) const {
|
||||
return Mgr->StoreMgr->getLValueCompoundLiteral(this, literal);
|
||||
return getStateManager().StoreMgr->getLValueCompoundLiteral(literal);
|
||||
}
|
||||
|
||||
inline SVal GRState::getLValue(const ObjCIvarDecl *D, SVal Base) const {
|
||||
return Mgr->StoreMgr->getLValueIvar(this, D, Base);
|
||||
}
|
||||
|
||||
inline SVal GRState::getLValue(SVal Base, const FieldDecl* D) const {
|
||||
return Mgr->StoreMgr->getLValueField(this, Base, D);
|
||||
}
|
||||
|
||||
inline SVal GRState::getLValue(QualType ElementType, SVal Base, SVal Idx) const{
|
||||
return Mgr->StoreMgr->getLValueElement(this, ElementType, Base, Idx);
|
||||
}
|
||||
|
||||
inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) const {
|
||||
return Mgr->getSymVal(this, sym);
|
||||
}
|
||||
|
||||
inline SVal GRState::getSVal(const Stmt* Ex) const {
|
||||
return Env.GetSVal(Ex, Mgr->ValueMgr);
|
||||
return getStateManager().StoreMgr->getLValueIvar(D, Base);
|
||||
}
|
||||
|
||||
inline SVal GRState::getBlkExprSVal(const Stmt* Ex) const {
|
||||
return Env.GetBlkExprSVal(Ex, Mgr->ValueMgr);
|
||||
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 {
|
||||
|
|
@ -688,69 +660,69 @@ inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const {
|
|||
if (Loc::IsLocType(T) || T->isIntegerType())
|
||||
return getSVal(S);
|
||||
}
|
||||
|
||||
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
inline SVal GRState::getSVal(Loc LV, QualType T) const {
|
||||
return Mgr->StoreMgr->Retrieve(this, LV, T);
|
||||
return getStateManager().StoreMgr->Retrieve(this, LV, T).getSVal();
|
||||
}
|
||||
|
||||
inline SVal GRState::getSVal(const MemRegion* R) const {
|
||||
return Mgr->StoreMgr->Retrieve(this, loc::MemRegionVal(R));
|
||||
return getStateManager().StoreMgr->Retrieve(this, loc::MemRegionVal(R)).getSVal();
|
||||
}
|
||||
|
||||
|
||||
inline BasicValueFactory &GRState::getBasicVals() const {
|
||||
return Mgr->getBasicVals();
|
||||
return getStateManager().getBasicVals();
|
||||
}
|
||||
|
||||
inline SymbolManager &GRState::getSymbolManager() const {
|
||||
return Mgr->getSymbolManager();
|
||||
return getStateManager().getSymbolManager();
|
||||
}
|
||||
|
||||
|
||||
inline GRTransferFuncs &GRState::getTransferFuncs() const {
|
||||
return Mgr->getTransferFuncs();
|
||||
return getStateManager().getTransferFuncs();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const GRState *GRState::add(typename GRStateTrait<T>::key_type K) const {
|
||||
return Mgr->add<T>(this, K, get_context<T>());
|
||||
return getStateManager().add<T>(this, K, get_context<T>());
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
typename GRStateTrait<T>::context_type GRState::get_context() const {
|
||||
return Mgr->get_context<T>();
|
||||
return getStateManager().get_context<T>();
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
const GRState *GRState::remove(typename GRStateTrait<T>::key_type K) const {
|
||||
return Mgr->remove<T>(this, K, get_context<T>());
|
||||
return getStateManager().remove<T>(this, K, get_context<T>());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const GRState *GRState::remove(typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::context_type C) const {
|
||||
return Mgr->remove<T>(this, K, C);
|
||||
return getStateManager().remove<T>(this, K, C);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
const GRState *GRState::set(typename GRStateTrait<T>::data_type D) const {
|
||||
return Mgr->set<T>(this, D);
|
||||
return getStateManager().set<T>(this, D);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
const GRState *GRState::set(typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::value_type E) const {
|
||||
return Mgr->set<T>(this, K, E, get_context<T>());
|
||||
return getStateManager().set<T>(this, K, E, get_context<T>());
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
const GRState *GRState::set(typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::value_type E,
|
||||
typename GRStateTrait<T>::context_type C) const {
|
||||
return Mgr->set<T>(this, K, E, C);
|
||||
return getStateManager().set<T>(this, K, E, C);
|
||||
}
|
||||
|
||||
|
||||
template <typename CB>
|
||||
CB GRState::scanReachableSymbols(SVal val) const {
|
||||
CB cb(this);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//==- GRStateTrait.h - Partial implementations of GRStateTrait -----*- C++ -*-//
|
||||
//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
|
|
@ -27,59 +27,59 @@ namespace llvm {
|
|||
|
||||
namespace clang {
|
||||
template <typename T> struct GRStatePartialTrait;
|
||||
|
||||
|
||||
// Partial-specialization for ImmutableMap.
|
||||
|
||||
|
||||
template <typename Key, typename Data, typename Info>
|
||||
struct GRStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > {
|
||||
typedef llvm::ImmutableMap<Key,Data,Info> data_type;
|
||||
typedef typename data_type::Factory& context_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);
|
||||
return new typename data_type::Factory(Alloc);
|
||||
}
|
||||
|
||||
|
||||
static void DeleteContext(void* Ctx) {
|
||||
delete (typename data_type::Factory*) Ctx;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Partial-specialization for ImmutableSet.
|
||||
|
||||
|
||||
template <typename Key, typename Info>
|
||||
struct GRStatePartialTrait< llvm::ImmutableSet<Key,Info> > {
|
||||
typedef llvm::ImmutableSet<Key,Info> data_type;
|
||||
typedef typename data_type::Factory& context_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();
|
||||
|
|
@ -88,60 +88,60 @@ namespace clang {
|
|||
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);
|
||||
return new typename data_type::Factory(Alloc);
|
||||
}
|
||||
|
||||
|
||||
static void DeleteContext(void* Ctx) {
|
||||
delete (typename data_type::Factory*) Ctx;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Partial-specialization for ImmutableList.
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct GRStatePartialTrait< llvm::ImmutableList<T> > {
|
||||
typedef llvm::ImmutableList<T> data_type;
|
||||
typedef T key_type;
|
||||
typedef typename data_type::Factory& context_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<T>*) *p)
|
||||
return p ? data_type((const llvm::ImmutableListImpl<T>*) *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);
|
||||
return new typename data_type::Factory(Alloc);
|
||||
}
|
||||
|
||||
|
||||
static void DeleteContext(void* Ctx) {
|
||||
delete (typename data_type::Factory*) Ctx;
|
||||
}
|
||||
}
|
||||
};
|
||||
} // end clang namespace
|
||||
|
||||
|
|
|
|||
68
include/clang/Analysis/PathSensitive/GRSubEngine.h
Normal file
68
include/clang/Analysis/PathSensitive/GRSubEngine.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
//== 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
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Stmt;
|
||||
class CFGBlock;
|
||||
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(Stmt* S, 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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -21,66 +21,68 @@
|
|||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
class GRExprEngine;
|
||||
class BugReporter;
|
||||
class ObjCMessageExpr;
|
||||
class GRStmtNodeBuilderRef;
|
||||
|
||||
|
||||
class GRTransferFuncs {
|
||||
public:
|
||||
GRTransferFuncs() {}
|
||||
virtual ~GRTransferFuncs() {}
|
||||
|
||||
|
||||
virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {}
|
||||
virtual void RegisterChecks(BugReporter& BR) {}
|
||||
|
||||
|
||||
|
||||
// Calls.
|
||||
|
||||
virtual void EvalCall(ExplodedNodeSet<GRState>& Dst,
|
||||
|
||||
virtual void EvalCall(ExplodedNodeSet& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
GRStmtNodeBuilder& Builder,
|
||||
CallExpr* CE, SVal L,
|
||||
ExplodedNode<GRState>* Pred) {}
|
||||
|
||||
virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
|
||||
ExplodedNode* Pred) {}
|
||||
|
||||
virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
GRStmtNodeBuilder& Builder,
|
||||
ObjCMessageExpr* ME,
|
||||
ExplodedNode<GRState>* Pred) {}
|
||||
|
||||
ExplodedNode* Pred) {}
|
||||
|
||||
// Stores.
|
||||
|
||||
|
||||
virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) {}
|
||||
|
||||
|
||||
// End-of-path and dead symbol notification.
|
||||
|
||||
|
||||
virtual void EvalEndPath(GRExprEngine& Engine,
|
||||
GREndPathNodeBuilder<GRState>& Builder) {}
|
||||
|
||||
|
||||
virtual void EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst,
|
||||
GREndPathNodeBuilder& Builder) {}
|
||||
|
||||
|
||||
virtual void EvalDeadSymbols(ExplodedNodeSet& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
ExplodedNode<GRState>* Pred,
|
||||
GRStmtNodeBuilder& Builder,
|
||||
ExplodedNode* Pred,
|
||||
Stmt* S, const GRState* state,
|
||||
SymbolReaper& SymReaper) {}
|
||||
|
||||
// Return statements.
|
||||
virtual void EvalReturn(ExplodedNodeSet<GRState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
ReturnStmt* S,
|
||||
ExplodedNode<GRState>* Pred) {}
|
||||
|
||||
// Assumptions.
|
||||
// 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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
GRTransferFuncs *CreateCallInliner(ASTContext &ctx);
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//==- GRWorkList.h - Worklist class used by GRCoreEngine -----------*- C++ -*-//
|
||||
//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
|
|
@ -17,31 +17,31 @@
|
|||
|
||||
#include "clang/Analysis/PathSensitive/GRBlockCounter.h"
|
||||
|
||||
namespace clang {
|
||||
namespace clang {
|
||||
|
||||
class ExplodedNodeImpl;
|
||||
|
||||
|
||||
class GRWorkListUnit {
|
||||
ExplodedNodeImpl* Node;
|
||||
ExplodedNode* Node;
|
||||
GRBlockCounter Counter;
|
||||
CFGBlock* Block;
|
||||
unsigned BlockIdx;
|
||||
|
||||
|
||||
public:
|
||||
GRWorkListUnit(ExplodedNodeImpl* N, GRBlockCounter C,
|
||||
GRWorkListUnit(ExplodedNode* N, GRBlockCounter C,
|
||||
CFGBlock* B, unsigned idx)
|
||||
: Node(N),
|
||||
Counter(C),
|
||||
Block(B),
|
||||
BlockIdx(idx) {}
|
||||
|
||||
explicit GRWorkListUnit(ExplodedNodeImpl* N, GRBlockCounter C)
|
||||
|
||||
explicit GRWorkListUnit(ExplodedNode* N, GRBlockCounter C)
|
||||
: Node(N),
|
||||
Counter(C),
|
||||
Block(NULL),
|
||||
BlockIdx(0) {}
|
||||
|
||||
ExplodedNodeImpl* getNode() const { return Node; }
|
||||
|
||||
ExplodedNode* getNode() const { return Node; }
|
||||
GRBlockCounter getBlockCounter() const { return Counter; }
|
||||
CFGBlock* getBlock() const { return Block; }
|
||||
unsigned getIndex() const { return BlockIdx; }
|
||||
|
|
@ -52,25 +52,25 @@ class GRWorkList {
|
|||
public:
|
||||
virtual ~GRWorkList();
|
||||
virtual bool hasWork() const = 0;
|
||||
|
||||
|
||||
virtual void Enqueue(const GRWorkListUnit& U) = 0;
|
||||
|
||||
void Enqueue(ExplodedNodeImpl* N, CFGBlock& B, unsigned idx) {
|
||||
void Enqueue(ExplodedNode* N, CFGBlock& B, unsigned idx) {
|
||||
Enqueue(GRWorkListUnit(N, CurrentCounter, &B, idx));
|
||||
}
|
||||
|
||||
void Enqueue(ExplodedNodeImpl* N) {
|
||||
|
||||
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
|
||||
} // end clang namespace
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -31,10 +31,15 @@
|
|||
namespace llvm { class raw_ostream; }
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
class MemRegionManager;
|
||||
class MemSpaceRegion;
|
||||
|
||||
class MemSpaceRegion;
|
||||
class LocationContext;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Base region classes.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// MemRegion - The root abstract class for all memory regions.
|
||||
class MemRegion : public llvm::FoldingSetNode {
|
||||
public:
|
||||
|
|
@ -46,55 +51,57 @@ public:
|
|||
CodeTextRegionKind,
|
||||
CompoundLiteralRegionKind,
|
||||
StringRegionKind, ElementRegionKind,
|
||||
TypedViewRegionKind,
|
||||
// Decl Regions.
|
||||
BEG_DECL_REGIONS,
|
||||
VarRegionKind, FieldRegionKind,
|
||||
ObjCIvarRegionKind, ObjCObjectRegionKind,
|
||||
END_DECL_REGIONS,
|
||||
END_TYPED_REGIONS };
|
||||
END_TYPED_REGIONS };
|
||||
private:
|
||||
const Kind kind;
|
||||
|
||||
|
||||
protected:
|
||||
MemRegion(Kind k) : kind(k) {}
|
||||
virtual ~MemRegion();
|
||||
ASTContext &getContext() const;
|
||||
|
||||
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;
|
||||
|
||||
bool hasStackStorage() const;
|
||||
|
||||
|
||||
bool hasParametersStorage() const;
|
||||
|
||||
|
||||
bool hasGlobalsStorage() const;
|
||||
|
||||
|
||||
bool hasGlobalsOrParametersStorage() const;
|
||||
|
||||
|
||||
bool hasHeapStorage() const;
|
||||
|
||||
|
||||
bool hasHeapOrStackStorage() const;
|
||||
|
||||
virtual void print(llvm::raw_ostream& os) const;
|
||||
virtual void dumpToStream(llvm::raw_ostream& os) const;
|
||||
|
||||
void dump() const;
|
||||
|
||||
Kind getKind() const { return kind; }
|
||||
|
||||
void printStdErr() const;
|
||||
|
||||
Kind getKind() const { return kind; }
|
||||
|
||||
template<typename RegionTy> 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 {
|
||||
|
|
@ -105,7 +112,7 @@ protected:
|
|||
|
||||
MemSpaceRegion(MemRegionManager *mgr) : MemRegion(MemSpaceRegionKind),
|
||||
Mgr(mgr) {}
|
||||
|
||||
|
||||
MemRegionManager* getMemRegionManager() const {
|
||||
return Mgr;
|
||||
}
|
||||
|
|
@ -124,13 +131,13 @@ public:
|
|||
/// are subclasses of SubRegion.
|
||||
class SubRegion : public MemRegion {
|
||||
protected:
|
||||
const MemRegion* superRegion;
|
||||
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;
|
||||
|
|
@ -140,6 +147,32 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Auxillary data classes for use with MemRegions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class ElementRegion;
|
||||
|
||||
class RegionRawOffset : public std::pair<const MemRegion*, int64_t> {
|
||||
private:
|
||||
friend class ElementRegion;
|
||||
|
||||
RegionRawOffset(const MemRegion* reg, int64_t offset = 0)
|
||||
: std::pair<const MemRegion*, int64_t>(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 {
|
||||
|
|
@ -151,43 +184,45 @@ protected:
|
|||
|
||||
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 print(llvm::raw_ostream& os) const;
|
||||
|
||||
|
||||
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;
|
||||
return T.getTypePtr() ? T.getDesugaredType() : T;
|
||||
}
|
||||
|
||||
|
||||
QualType getDesugaredLocationType(ASTContext& C) const {
|
||||
return getLocationType(C)->getDesugaredType();
|
||||
return getLocationType(C).getDesugaredType();
|
||||
}
|
||||
|
||||
bool isBoundable() const {
|
||||
|
|
@ -205,32 +240,12 @@ public:
|
|||
/// is a function declared in the program. Symbolic function is a function
|
||||
/// pointer that we don't know which function it points to.
|
||||
class CodeTextRegion : public TypedRegion {
|
||||
public:
|
||||
enum CodeKind { Declared, Symbolic };
|
||||
|
||||
private:
|
||||
// The function pointer kind that this CodeTextRegion represents.
|
||||
CodeKind codekind;
|
||||
|
||||
// Data may be a SymbolRef or FunctionDecl*.
|
||||
const void* Data;
|
||||
|
||||
// Cached function pointer type.
|
||||
QualType LocationType;
|
||||
const FunctionDecl *FD;
|
||||
|
||||
public:
|
||||
|
||||
CodeTextRegion(const FunctionDecl* fd, QualType t, const MemRegion* sreg)
|
||||
: TypedRegion(sreg, CodeTextRegionKind),
|
||||
codekind(Declared),
|
||||
Data(fd),
|
||||
LocationType(t) {}
|
||||
|
||||
CodeTextRegion(SymbolRef sym, QualType t, const MemRegion* sreg)
|
||||
: TypedRegion(sreg, CodeTextRegionKind),
|
||||
codekind(Symbolic),
|
||||
Data(sym),
|
||||
LocationType(t) {}
|
||||
CodeTextRegion(const FunctionDecl* fd, const MemRegion* sreg)
|
||||
: TypedRegion(sreg, CodeTextRegionKind), FD(fd) {}
|
||||
|
||||
QualType getValueType(ASTContext &C) const {
|
||||
// Do not get the object type of a CodeTextRegion.
|
||||
|
|
@ -239,30 +254,21 @@ public:
|
|||
}
|
||||
|
||||
QualType getLocationType(ASTContext &C) const {
|
||||
return LocationType;
|
||||
return C.getPointerType(FD->getType());
|
||||
}
|
||||
|
||||
bool isDeclared() const { return codekind == Declared; }
|
||||
bool isSymbolic() const { return codekind == Symbolic; }
|
||||
const FunctionDecl *getDecl() const {
|
||||
return FD;
|
||||
}
|
||||
|
||||
const FunctionDecl* getDecl() const {
|
||||
assert(codekind == Declared);
|
||||
return static_cast<const FunctionDecl*>(Data);
|
||||
}
|
||||
|
||||
SymbolRef getSymbol() const {
|
||||
assert(codekind == Symbolic);
|
||||
return const_cast<SymbolRef>(static_cast<const SymbolRef>(Data));
|
||||
}
|
||||
|
||||
bool isBoundable() const { return false; }
|
||||
|
||||
virtual void print(llvm::raw_ostream& os) const;
|
||||
|
||||
virtual void dumpToStream(llvm::raw_ostream& os) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
|
||||
const void* data, QualType t, const MemRegion*);
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FunctionDecl *FD,
|
||||
const MemRegion*);
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == CodeTextRegionKind;
|
||||
|
|
@ -279,25 +285,27 @@ protected:
|
|||
const SymbolRef sym;
|
||||
|
||||
public:
|
||||
SymbolicRegion(const SymbolRef s, const MemRegion* sreg)
|
||||
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 print(llvm::raw_ostream& os) const;
|
||||
|
||||
|
||||
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 {
|
||||
|
|
@ -315,7 +323,7 @@ protected:
|
|||
public:
|
||||
|
||||
const StringLiteral* getStringLiteral() const { return Str; }
|
||||
|
||||
|
||||
QualType getValueType(ASTContext& C) const {
|
||||
return Str->getType();
|
||||
}
|
||||
|
|
@ -326,53 +334,13 @@ public:
|
|||
ProfileRegion(ID, Str, superRegion);
|
||||
}
|
||||
|
||||
void print(llvm::raw_ostream& os) const;
|
||||
void dumpToStream(llvm::raw_ostream& os) const;
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == StringRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
class TypedViewRegion : public TypedRegion {
|
||||
friend class MemRegionManager;
|
||||
QualType LValueType;
|
||||
|
||||
TypedViewRegion(QualType lvalueType, const MemRegion* sreg)
|
||||
: TypedRegion(sreg, TypedViewRegionKind), LValueType(lvalueType) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType T,
|
||||
const MemRegion* superRegion);
|
||||
|
||||
public:
|
||||
|
||||
void print(llvm::raw_ostream& os) const;
|
||||
|
||||
QualType getLocationType(ASTContext&) const {
|
||||
return LValueType;
|
||||
}
|
||||
|
||||
QualType getValueType(ASTContext&) const {
|
||||
const PointerType* PTy = LValueType->getAsPointerType();
|
||||
assert(PTy);
|
||||
return PTy->getPointeeType();
|
||||
}
|
||||
|
||||
bool isBoundable() const {
|
||||
return isa<PointerType>(LValueType);
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
ProfileRegion(ID, LValueType, superRegion);
|
||||
}
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == TypedViewRegionKind;
|
||||
}
|
||||
|
||||
const MemRegion *removeViews() const;
|
||||
};
|
||||
|
||||
|
||||
/// CompoundLiteralRegion - A memory region representing a compound literal.
|
||||
/// Compound literals are essentially temporaries that are stack allocated
|
||||
/// or in the global constant pool.
|
||||
|
|
@ -383,7 +351,7 @@ private:
|
|||
|
||||
CompoundLiteralRegion(const CompoundLiteralExpr* cl, const MemRegion* sReg)
|
||||
: TypedRegion(sReg, CompoundLiteralRegionKind), CL(cl) {}
|
||||
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
|
||||
const CompoundLiteralExpr* CL,
|
||||
const MemRegion* superRegion);
|
||||
|
|
@ -395,11 +363,11 @@ public:
|
|||
bool isBoundable() const { return !CL->isFileScope(); }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
|
||||
void print(llvm::raw_ostream& os) const;
|
||||
|
||||
void dumpToStream(llvm::raw_ostream& os) const;
|
||||
|
||||
const CompoundLiteralExpr* getLiteralExpr() const { return CL; }
|
||||
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == CompoundLiteralRegionKind;
|
||||
}
|
||||
|
|
@ -414,41 +382,51 @@ protected:
|
|||
|
||||
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;
|
||||
|
||||
VarRegion(const VarDecl* vd, const MemRegion* sReg)
|
||||
: DeclRegion(vd, sReg, VarRegionKind) {}
|
||||
|
||||
// Data.
|
||||
const LocationContext *LC;
|
||||
|
||||
// Constructors and private methods.
|
||||
VarRegion(const VarDecl* vd, const LocationContext *lC, const MemRegion* sReg)
|
||||
: DeclRegion(vd, sReg, VarRegionKind), LC(lC) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl* VD,
|
||||
const MemRegion* superRegion) {
|
||||
const LocationContext *LC,
|
||||
const MemRegion *superRegion) {
|
||||
DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
|
||||
ID.AddPointer(LC);
|
||||
}
|
||||
|
||||
public:
|
||||
const VarDecl* getDecl() const { return cast<VarDecl>(D); }
|
||||
|
||||
QualType getValueType(ASTContext& C) const {
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
|
||||
public:
|
||||
const VarDecl *getDecl() const { return cast<VarDecl>(D); }
|
||||
|
||||
const LocationContext *getLocationContext() const { return LC; }
|
||||
|
||||
QualType getValueType(ASTContext& C) const {
|
||||
// FIXME: We can cache this if needed.
|
||||
return C.getCanonicalType(getDecl()->getType());
|
||||
}
|
||||
|
||||
void print(llvm::raw_ostream& os) const;
|
||||
|
||||
}
|
||||
|
||||
void dumpToStream(llvm::raw_ostream& os) const;
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == VarRegionKind;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class FieldRegion : public DeclRegion {
|
||||
|
|
@ -458,57 +436,57 @@ class FieldRegion : public DeclRegion {
|
|||
: DeclRegion(fd, sReg, FieldRegionKind) {}
|
||||
|
||||
public:
|
||||
|
||||
void print(llvm::raw_ostream& os) const;
|
||||
|
||||
|
||||
void dumpToStream(llvm::raw_ostream& os) const;
|
||||
|
||||
const FieldDecl* getDecl() const { return cast<FieldDecl>(D); }
|
||||
|
||||
QualType getValueType(ASTContext& C) const {
|
||||
|
||||
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 ObjCObjectRegion : public DeclRegion {
|
||||
|
||||
|
||||
friend class MemRegionManager;
|
||||
|
||||
|
||||
ObjCObjectRegion(const ObjCInterfaceDecl* ivd, const MemRegion* sReg)
|
||||
: DeclRegion(ivd, sReg, ObjCObjectRegionKind) {}
|
||||
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
|
||||
const ObjCInterfaceDecl* ivd,
|
||||
const MemRegion* superRegion) {
|
||||
DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCObjectRegionKind);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
const ObjCInterfaceDecl* getInterface() const {
|
||||
return cast<ObjCInterfaceDecl>(D);
|
||||
}
|
||||
|
||||
|
||||
QualType getValueType(ASTContext& C) const {
|
||||
return C.getObjCInterfaceType(getInterface());
|
||||
}
|
||||
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == ObjCObjectRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class ObjCIvarRegion : public DeclRegion {
|
||||
|
||||
|
||||
friend class MemRegionManager;
|
||||
|
||||
|
||||
ObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* sReg)
|
||||
: DeclRegion(ivd, sReg, ObjCIvarRegionKind) {}
|
||||
|
||||
|
|
@ -516,11 +494,13 @@ class ObjCIvarRegion : public DeclRegion {
|
|||
const MemRegion* superRegion) {
|
||||
DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
const ObjCIvarDecl* getDecl() const { return cast<ObjCIvarDecl>(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;
|
||||
}
|
||||
|
|
@ -539,7 +519,7 @@ class ElementRegion : public TypedRegion {
|
|||
cast<nonloc::ConcreteInt>(&Idx)->getValue().isSigned()) &&
|
||||
"The index must be signed");
|
||||
}
|
||||
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType,
|
||||
SVal Idx, const MemRegion* superRegion);
|
||||
|
||||
|
|
@ -550,12 +530,14 @@ public:
|
|||
QualType getValueType(ASTContext&) const {
|
||||
return ElementType;
|
||||
}
|
||||
|
||||
|
||||
QualType getElementType() const {
|
||||
return ElementType;
|
||||
}
|
||||
|
||||
void print(llvm::raw_ostream& os) const;
|
||||
|
||||
RegionRawOffset getAsRawOffset() const;
|
||||
|
||||
void dumpToStream(llvm::raw_ostream& os) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
|
||||
|
|
@ -563,25 +545,13 @@ public:
|
|||
return R->getKind() == ElementRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename RegionTy>
|
||||
const RegionTy* MemRegion::getAs() const {
|
||||
const MemRegion *R = this;
|
||||
|
||||
do {
|
||||
if (const RegionTy* RT = dyn_cast<RegionTy>(R))
|
||||
return RT;
|
||||
|
||||
if (const TypedViewRegion *TR = dyn_cast<TypedViewRegion>(R)) {
|
||||
R = TR->getSuperRegion();
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
while (R);
|
||||
|
||||
return 0;
|
||||
if (const RegionTy* RT = dyn_cast<RegionTy>(this))
|
||||
return RT;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -592,7 +562,7 @@ class MemRegionManager {
|
|||
ASTContext &C;
|
||||
llvm::BumpPtrAllocator& A;
|
||||
llvm::FoldingSet<MemRegion> Regions;
|
||||
|
||||
|
||||
MemSpaceRegion *globals;
|
||||
MemSpaceRegion *stack;
|
||||
MemSpaceRegion *stackArguments;
|
||||
|
|
@ -604,11 +574,11 @@ public:
|
|||
MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator& a)
|
||||
: C(c), A(a), globals(0), stack(0), stackArguments(0), heap(0),
|
||||
unknown(0), code(0) {}
|
||||
|
||||
|
||||
~MemRegionManager() {}
|
||||
|
||||
|
||||
ASTContext &getContext() { return C; }
|
||||
|
||||
|
||||
/// getStackRegion - Retrieve the memory region associated with the
|
||||
/// current stack frame.
|
||||
MemSpaceRegion *getStackRegion();
|
||||
|
|
@ -616,11 +586,11 @@ public:
|
|||
/// getStackArgumentsRegion - Retrieve the memory region associated with
|
||||
/// function/method arguments of the current stack frame.
|
||||
MemSpaceRegion *getStackArgumentsRegion();
|
||||
|
||||
|
||||
/// getGlobalsRegion - Retrieve the memory region associated with
|
||||
/// all global variables.
|
||||
MemSpaceRegion *getGlobalsRegion();
|
||||
|
||||
|
||||
/// getHeapRegion - Retrieve the memory region associated with the
|
||||
/// generic "heap".
|
||||
MemSpaceRegion *getHeapRegion();
|
||||
|
|
@ -633,69 +603,77 @@ public:
|
|||
|
||||
/// getAllocaRegion - Retrieve a region associated with a call to alloca().
|
||||
AllocaRegion *getAllocaRegion(const Expr* Ex, unsigned Cnt);
|
||||
|
||||
|
||||
/// getCompoundLiteralRegion - Retrieve the region associated with a
|
||||
/// given CompoundLiteral.
|
||||
CompoundLiteralRegion*
|
||||
getCompoundLiteralRegion(const CompoundLiteralExpr* CL);
|
||||
|
||||
getCompoundLiteralRegion(const CompoundLiteralExpr* CL);
|
||||
|
||||
/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
|
||||
SymbolicRegion* getSymbolicRegion(SymbolRef sym);
|
||||
|
||||
StringRegion* getStringRegion(const StringLiteral* Str);
|
||||
|
||||
/// getVarRegion - Retrieve or create the memory region associated with
|
||||
/// a specified VarDecl.
|
||||
VarRegion* getVarRegion(const VarDecl* vd);
|
||||
|
||||
/// a specified VarDecl and LocationContext.
|
||||
VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC);
|
||||
|
||||
/// getElementRegion - Retrieve the memory region associated with the
|
||||
/// associated element type, index, and super region.
|
||||
ElementRegion* getElementRegion(QualType elementType, SVal Idx,
|
||||
const MemRegion* superRegion,ASTContext &Ctx);
|
||||
ElementRegion *getElementRegion(QualType elementType, SVal Idx,
|
||||
const MemRegion *superRegion,
|
||||
ASTContext &Ctx);
|
||||
|
||||
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).
|
||||
FieldRegion* getFieldRegion(const FieldDecl* fd,
|
||||
FieldRegion *getFieldRegion(const FieldDecl* fd,
|
||||
const MemRegion* superRegion);
|
||||
|
||||
|
||||
FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR,
|
||||
const MemRegion *superRegion) {
|
||||
return getFieldRegion(FR->getDecl(), superRegion);
|
||||
}
|
||||
|
||||
/// getObjCObjectRegion - Retrieve or create the memory region associated with
|
||||
/// the instance of a specified Objective-C class.
|
||||
ObjCObjectRegion* getObjCObjectRegion(const ObjCInterfaceDecl* ID,
|
||||
const MemRegion* 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).
|
||||
ObjCIvarRegion* getObjCIvarRegion(const ObjCIvarDecl* ivd,
|
||||
ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd,
|
||||
const MemRegion* superRegion);
|
||||
|
||||
TypedViewRegion* getTypedViewRegion(QualType LValueType,
|
||||
const MemRegion* superRegion);
|
||||
CodeTextRegion *getCodeTextRegion(const FunctionDecl *FD);
|
||||
|
||||
CodeTextRegion* getCodeTextRegion(SymbolRef sym, QualType t);
|
||||
CodeTextRegion* getCodeTextRegion(const FunctionDecl* fd, QualType t);
|
||||
|
||||
template <typename RegionTy, typename A1>
|
||||
RegionTy* getRegion(const A1 a1);
|
||||
|
||||
|
||||
template <typename RegionTy, typename A1>
|
||||
RegionTy* getRegion(const A1 a1, const MemRegion* superRegion);
|
||||
|
||||
RegionTy* getSubRegion(const A1 a1, const MemRegion* superRegion);
|
||||
|
||||
template <typename RegionTy, typename A1, typename A2>
|
||||
RegionTy* getRegion(const A1 a1, const A2 a2);
|
||||
|
||||
bool isGlobalsRegion(const MemRegion* R) {
|
||||
bool isGlobalsRegion(const MemRegion* R) {
|
||||
assert(R);
|
||||
return R == globals;
|
||||
return R == globals;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
MemSpaceRegion* LazyAllocate(MemSpaceRegion*& region);
|
||||
};
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Out-of-line member definitions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -703,69 +681,69 @@ private:
|
|||
inline ASTContext& MemRegion::getContext() const {
|
||||
return getMemRegionManager()->getContext();
|
||||
}
|
||||
|
||||
|
||||
template<typename RegionTy> struct MemRegionManagerTrait;
|
||||
|
||||
|
||||
template <typename RegionTy, typename A1>
|
||||
RegionTy* MemRegionManager::getRegion(const A1 a1) {
|
||||
|
||||
const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion =
|
||||
MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1);
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
RegionTy::ProfileRegion(ID, a1, superRegion);
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
RegionTy::ProfileRegion(ID, a1, superRegion);
|
||||
void* InsertPos;
|
||||
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
|
||||
InsertPos));
|
||||
|
||||
|
||||
if (!R) {
|
||||
R = (RegionTy*) A.Allocate<RegionTy>();
|
||||
new (R) RegionTy(a1, superRegion);
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
|
||||
return R;
|
||||
}
|
||||
|
||||
template <typename RegionTy, typename A1>
|
||||
RegionTy* MemRegionManager::getRegion(const A1 a1, const MemRegion *superRegion)
|
||||
{
|
||||
llvm::FoldingSetNodeID ID;
|
||||
RegionTy::ProfileRegion(ID, a1, superRegion);
|
||||
RegionTy* MemRegionManager::getSubRegion(const A1 a1,
|
||||
const MemRegion *superRegion) {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
RegionTy::ProfileRegion(ID, a1, superRegion);
|
||||
void* InsertPos;
|
||||
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
|
||||
InsertPos));
|
||||
|
||||
|
||||
if (!R) {
|
||||
R = (RegionTy*) A.Allocate<RegionTy>();
|
||||
new (R) RegionTy(a1, superRegion);
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
|
||||
return R;
|
||||
}
|
||||
|
||||
|
||||
template <typename RegionTy, typename A1, typename A2>
|
||||
RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) {
|
||||
|
||||
|
||||
const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion =
|
||||
MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1, a2);
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
RegionTy::ProfileRegion(ID, a1, a2, superRegion);
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
RegionTy::ProfileRegion(ID, a1, a2, superRegion);
|
||||
void* InsertPos;
|
||||
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
|
||||
InsertPos));
|
||||
|
||||
|
||||
if (!R) {
|
||||
R = (RegionTy*) A.Allocate<RegionTy>();
|
||||
new (R) RegionTy(a1, a2, superRegion);
|
||||
Regions.InsertNode(R, InsertPos);
|
||||
}
|
||||
|
||||
|
||||
return R;
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Traits for constructing regions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -776,18 +754,18 @@ template <> struct MemRegionManagerTrait<AllocaRegion> {
|
|||
const Expr *, unsigned) {
|
||||
return MRMgr.getStackRegion();
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <> struct MemRegionManagerTrait<CompoundLiteralRegion> {
|
||||
typedef MemRegion SuperRegionTy;
|
||||
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
|
||||
const CompoundLiteralExpr *CL) {
|
||||
|
||||
return CL->isFileScope() ? MRMgr.getGlobalsRegion()
|
||||
|
||||
return CL->isFileScope() ? MRMgr.getGlobalsRegion()
|
||||
: MRMgr.getStackRegion();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <> struct MemRegionManagerTrait<StringRegion> {
|
||||
typedef MemSpaceRegion SuperRegionTy;
|
||||
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
|
||||
|
|
@ -795,20 +773,24 @@ template <> struct MemRegionManagerTrait<StringRegion> {
|
|||
return MRMgr.getGlobalsRegion();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <> struct MemRegionManagerTrait<VarRegion> {
|
||||
typedef MemRegion SuperRegionTy;
|
||||
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
|
||||
const VarDecl *d) {
|
||||
if (d->hasLocalStorage()) {
|
||||
return isa<ParmVarDecl>(d) || isa<ImplicitParamDecl>(d)
|
||||
static const SuperRegionTy* getSuperRegion(MemRegionManager &MRMgr,
|
||||
const VarDecl *D,
|
||||
const LocationContext *LC) {
|
||||
|
||||
// FIXME: Make stack regions have a location context?
|
||||
|
||||
if (D->hasLocalStorage()) {
|
||||
return isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)
|
||||
? MRMgr.getStackArgumentsRegion() : MRMgr.getStackRegion();
|
||||
}
|
||||
|
||||
|
||||
return MRMgr.getGlobalsRegion();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <> struct MemRegionManagerTrait<SymbolicRegion> {
|
||||
typedef MemRegion SuperRegionTy;
|
||||
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
|
||||
|
|
@ -820,7 +802,7 @@ template <> struct MemRegionManagerTrait<SymbolicRegion> {
|
|||
template<> struct MemRegionManagerTrait<CodeTextRegion> {
|
||||
typedef MemSpaceRegion SuperRegionTy;
|
||||
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
|
||||
const FunctionDecl*, QualType) {
|
||||
const FunctionDecl*) {
|
||||
return MRMgr.getCodeRegion();
|
||||
}
|
||||
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
|
||||
|
|
@ -828,7 +810,7 @@ template<> struct MemRegionManagerTrait<CodeTextRegion> {
|
|||
return MRMgr.getCodeRegion();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -836,10 +818,10 @@ template<> struct MemRegionManagerTrait<CodeTextRegion> {
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace llvm {
|
||||
static inline raw_ostream& operator<<(raw_ostream& O,
|
||||
const clang::MemRegion* R) {
|
||||
R->print(O);
|
||||
return O;
|
||||
static inline raw_ostream& operator<<(raw_ostream& os,
|
||||
const clang::MemRegion* R) {
|
||||
R->dumpToStream(os);
|
||||
return os;
|
||||
}
|
||||
} // end llvm namespace
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,11 @@
|
|||
#include "clang/Analysis/PathSensitive/SymbolManager.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/ADT/ImmutableList.h"
|
||||
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
//==------------------------------------------------------------------------==//
|
||||
// Base SVal types.
|
||||
//==------------------------------------------------------------------------==//
|
||||
|
|
@ -26,40 +30,43 @@
|
|||
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<void*>(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<SVal,5> 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<void*>(Data));
|
||||
|
|
@ -68,7 +75,7 @@ public:
|
|||
inline bool operator==(const SVal& R) const {
|
||||
return getRawKind() == R.getRawKind() && Data == R.Data;
|
||||
}
|
||||
|
||||
|
||||
inline bool operator!=(const SVal& R) const {
|
||||
return !(*this == R);
|
||||
}
|
||||
|
|
@ -84,25 +91,25 @@ public:
|
|||
inline bool isUnknownOrUndef() const {
|
||||
return getRawKind() <= UnknownKind;
|
||||
}
|
||||
|
||||
|
||||
inline bool isValid() const {
|
||||
return getRawKind() > UnknownKind;
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
/// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl.
|
||||
/// Otherwise return 0.
|
||||
const FunctionDecl* getAsFunctionDecl() const;
|
||||
|
||||
/// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
|
||||
|
||||
/// 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;
|
||||
|
|
@ -112,9 +119,9 @@ public:
|
|||
const SymExpr *getAsSymbolicExpression() const;
|
||||
|
||||
const MemRegion *getAsRegion() const;
|
||||
|
||||
void print(llvm::raw_ostream& OS) const;
|
||||
void printStdErr() const;
|
||||
|
||||
void dumpToStream(llvm::raw_ostream& OS) const;
|
||||
void dump() const;
|
||||
|
||||
// Iterators.
|
||||
class symbol_iterator {
|
||||
|
|
@ -123,14 +130,14 @@ public:
|
|||
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)
|
||||
|
|
@ -138,97 +145,135 @@ public:
|
|||
else
|
||||
return symbol_iterator();
|
||||
}
|
||||
|
||||
|
||||
symbol_iterator symbol_end() const { return symbol_iterator(); }
|
||||
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SVal*) { return true; }
|
||||
};
|
||||
|
||||
class UnknownVal : public SVal {
|
||||
public:
|
||||
UnknownVal() : SVal(UnknownKind) {}
|
||||
|
||||
static inline bool classof(const SVal* V) {
|
||||
return V->getBaseKind() == UnknownKind;
|
||||
}
|
||||
};
|
||||
|
||||
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; }
|
||||
|
||||
void* getData() const { return Data; }
|
||||
};
|
||||
|
||||
class NonLoc : public SVal {
|
||||
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:
|
||||
NonLoc(unsigned SubKind, const void* d) : SVal(d, false, SubKind) {}
|
||||
explicit DefinedOrUnknownSVal(const void* d, bool isLoc, unsigned ValKind)
|
||||
: SVal(d, isLoc, ValKind) {}
|
||||
|
||||
explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL)
|
||||
: SVal(k, D) {}
|
||||
|
||||
public:
|
||||
void print(llvm::raw_ostream& Out) const;
|
||||
// Implement isa<T> 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<T> 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<T> support.
|
||||
static inline bool classof(const SVal* V) {
|
||||
return V->getBaseKind() == NonLocKind;
|
||||
}
|
||||
};
|
||||
|
||||
class Loc : public SVal {
|
||||
class Loc : public DefinedSVal {
|
||||
protected:
|
||||
Loc(unsigned SubKind, const void* D)
|
||||
: SVal(const_cast<void*>(D), true, SubKind) {}
|
||||
: DefinedSVal(const_cast<void*>(D), true, SubKind) {}
|
||||
|
||||
public:
|
||||
void print(llvm::raw_ostream& Out) const;
|
||||
void dumpToStream(llvm::raw_ostream& Out) const;
|
||||
|
||||
Loc(const Loc& X) : SVal(X.Data, true, X.getSubKind()) {}
|
||||
Loc(const Loc& X) : DefinedSVal(X.Data, true, X.getSubKind()) {}
|
||||
Loc& operator=(const Loc& X) { memcpy(this, &X, sizeof(Loc)); return *this; }
|
||||
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SVal* V) {
|
||||
return V->getBaseKind() == LocKind;
|
||||
}
|
||||
|
||||
|
||||
static inline bool IsLocType(QualType T) {
|
||||
return T->isPointerType() || T->isObjCQualifiedIdType()
|
||||
|| T->isBlockPointerType();
|
||||
return T->isAnyPointerType() || T->isBlockPointerType();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//==------------------------------------------------------------------------==//
|
||||
// Subclasses of NonLoc.
|
||||
//==------------------------------------------------------------------------==//
|
||||
|
||||
namespace nonloc {
|
||||
|
||||
|
||||
enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind,
|
||||
LocAsIntegerKind, CompoundValKind };
|
||||
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 &&
|
||||
return V->getBaseKind() == NonLocKind &&
|
||||
V->getSubKind() == SymbolValKind;
|
||||
}
|
||||
|
||||
|
||||
static inline bool classof(const NonLoc* V) {
|
||||
return V->getSubKind() == SymbolValKind;
|
||||
}
|
||||
};
|
||||
|
||||
class SymExprVal : public NonLoc {
|
||||
class SymExprVal : public NonLoc {
|
||||
public:
|
||||
SymExprVal(const SymExpr *SE)
|
||||
: NonLoc(SymExprValKind, reinterpret_cast<const void*>(SE)) {}
|
||||
|
|
@ -236,12 +281,12 @@ public:
|
|||
const SymExpr *getSymbolicExpression() const {
|
||||
return reinterpret_cast<SymExpr*>(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;
|
||||
}
|
||||
|
|
@ -250,30 +295,30 @@ public:
|
|||
class ConcreteInt : public NonLoc {
|
||||
public:
|
||||
ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {}
|
||||
|
||||
|
||||
const llvm::APSInt& getValue() const {
|
||||
return *static_cast<llvm::APSInt*>(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<T> 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;
|
||||
|
||||
|
|
@ -281,28 +326,28 @@ class LocAsInteger : public NonLoc {
|
|||
NonLoc(LocAsIntegerKind, &data) {
|
||||
assert (isa<Loc>(data.first));
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
Loc getLoc() const {
|
||||
return cast<Loc>(((std::pair<SVal, uintptr_t>*) Data)->first);
|
||||
}
|
||||
|
||||
|
||||
const Loc& getPersistentLoc() const {
|
||||
const SVal& V = ((std::pair<SVal, uintptr_t>*) Data)->first;
|
||||
return cast<Loc>(V);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
unsigned getNumBits() const {
|
||||
return ((std::pair<SVal, unsigned>*) Data)->second;
|
||||
}
|
||||
|
||||
|
||||
// Implement isa<T> 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;
|
||||
}
|
||||
|
|
@ -317,10 +362,10 @@ public:
|
|||
const CompoundValData* getValue() const {
|
||||
return static_cast<CompoundValData*>(Data);
|
||||
}
|
||||
|
||||
|
||||
typedef llvm::ImmutableList<SVal>::iterator iterator;
|
||||
iterator begin() const;
|
||||
iterator end() const;
|
||||
iterator end() const;
|
||||
|
||||
static bool classof(const SVal* V) {
|
||||
return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind;
|
||||
|
|
@ -330,7 +375,28 @@ public:
|
|||
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<const LazyCompoundValData*>(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
|
||||
|
||||
//==------------------------------------------------------------------------==//
|
||||
|
|
@ -338,27 +404,27 @@ public:
|
|||
//==------------------------------------------------------------------------==//
|
||||
|
||||
namespace loc {
|
||||
|
||||
|
||||
enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind };
|
||||
|
||||
class GotoLabel : public Loc {
|
||||
public:
|
||||
GotoLabel(LabelStmt* Label) : Loc(GotoLabelKind, Label) {}
|
||||
|
||||
|
||||
LabelStmt* getLabel() const {
|
||||
return static_cast<LabelStmt*>(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:
|
||||
|
|
@ -367,35 +433,37 @@ public:
|
|||
const MemRegion* getRegion() const {
|
||||
return static_cast<MemRegion*>(Data);
|
||||
}
|
||||
|
||||
|
||||
const MemRegion* getBaseRegion() const;
|
||||
|
||||
template <typename REGION>
|
||||
const REGION* getRegionAs() const {
|
||||
return llvm::dyn_cast<REGION>(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<T> 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<llvm::APSInt*>(Data);
|
||||
}
|
||||
|
|
@ -403,19 +471,26 @@ public:
|
|||
// Transfer functions for binary/unary operations on ConcreteInts.
|
||||
SVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
|
||||
const ConcreteInt& R) const;
|
||||
|
||||
|
||||
// Implement isa<T> 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
|
||||
|
||||
} // 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
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
//
|
||||
// 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
|
||||
|
|
@ -24,32 +24,66 @@ class GRState;
|
|||
class ValueManager;
|
||||
|
||||
class SValuator {
|
||||
friend class ValueManager;
|
||||
protected:
|
||||
ValueManager &ValMgr;
|
||||
|
||||
|
||||
virtual SVal EvalCastNL(NonLoc val, QualType castTy) = 0;
|
||||
|
||||
virtual SVal EvalCastL(Loc val, QualType castTy) = 0;
|
||||
|
||||
public:
|
||||
SValuator(ValueManager &valMgr) : ValMgr(valMgr) {}
|
||||
virtual ~SValuator() {}
|
||||
|
||||
virtual SVal EvalCast(NonLoc val, QualType castTy) = 0;
|
||||
|
||||
virtual SVal EvalCast(Loc val, QualType castTy) = 0;
|
||||
template <typename T>
|
||||
class GenericCastResult : public std::pair<const GRState *, T> {
|
||||
public:
|
||||
const GRState *getState() const { return this->first; }
|
||||
T getSVal() const { return this->second; }
|
||||
GenericCastResult(const GRState *s, T v)
|
||||
: std::pair<const GRState*,T>(s, v) {}
|
||||
};
|
||||
|
||||
class CastResult : public GenericCastResult<SVal> {
|
||||
public:
|
||||
CastResult(const GRState *s, SVal v) : GenericCastResult<SVal>(s, v) {}
|
||||
};
|
||||
|
||||
class DefinedOrUnknownCastResult :
|
||||
public GenericCastResult<DefinedOrUnknownSVal> {
|
||||
public:
|
||||
DefinedOrUnknownCastResult(const GRState *s, DefinedOrUnknownSVal v)
|
||||
: GenericCastResult<DefinedOrUnknownSVal>(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(BinaryOperator::Opcode Op, NonLoc lhs,
|
||||
NonLoc rhs, QualType resultTy) = 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;
|
||||
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
|
||||
|
|
|
|||
|
|
@ -23,16 +23,17 @@
|
|||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
typedef const void* Store;
|
||||
|
||||
class GRState;
|
||||
class GRState;
|
||||
class GRStateManager;
|
||||
class Stmt;
|
||||
class Expr;
|
||||
class ObjCIvarDecl;
|
||||
class SubRegionMap;
|
||||
|
||||
class StackFrameContext;
|
||||
|
||||
class StoreManager {
|
||||
protected:
|
||||
ValueManager &ValMgr;
|
||||
|
|
@ -43,37 +44,30 @@ protected:
|
|||
|
||||
StoreManager(GRStateManager &stateMgr);
|
||||
|
||||
protected:
|
||||
virtual const GRState *AddRegionView(const GRState *state,
|
||||
const MemRegion *view,
|
||||
const MemRegion *base) {
|
||||
return state;
|
||||
}
|
||||
|
||||
public:
|
||||
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
|
||||
/// \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(const GRState *state, Loc loc,
|
||||
QualType T = QualType()) = 0;
|
||||
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
|
||||
/// \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
|
||||
|
|
@ -81,36 +75,31 @@ public:
|
|||
virtual const GRState *BindCompoundLiteral(const GRState *state,
|
||||
const CompoundLiteralExpr* cl,
|
||||
SVal v) = 0;
|
||||
|
||||
|
||||
/// getInitialStore - Returns the initial "empty" store representing the
|
||||
/// value bindings upon entry to an analyzed function.
|
||||
virtual Store getInitialStore() = 0;
|
||||
|
||||
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 GRState *state, const VarDecl *vd) = 0;
|
||||
virtual SVal getLValueVar(const VarDecl *VD, const LocationContext *LC) = 0;
|
||||
|
||||
virtual SVal getLValueString(const GRState *state,
|
||||
const StringLiteral* sl) = 0;
|
||||
virtual SVal getLValueString(const StringLiteral* sl) = 0;
|
||||
|
||||
virtual SVal getLValueCompoundLiteral(const GRState *state,
|
||||
const CompoundLiteralExpr* cl) = 0;
|
||||
|
||||
virtual SVal getLValueIvar(const GRState *state, const ObjCIvarDecl* decl,
|
||||
SVal base) = 0;
|
||||
|
||||
virtual SVal getLValueField(const GRState *state, SVal base,
|
||||
const FieldDecl* D) = 0;
|
||||
|
||||
virtual SVal getLValueElement(const GRState *state, QualType elementType,
|
||||
SVal base, SVal offset) = 0;
|
||||
virtual SVal getLValueCompoundLiteral(const CompoundLiteralExpr* cl) = 0;
|
||||
|
||||
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 SVal getSizeInElements(const GRState *state, const MemRegion *region){
|
||||
|
|
@ -120,7 +109,7 @@ public:
|
|||
/// 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;
|
||||
|
|
@ -129,33 +118,32 @@ public:
|
|||
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.
|
||||
virtual CastResult CastRegion(const GRState *state, const MemRegion *region,
|
||||
QualType CastToTy);
|
||||
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();
|
||||
}
|
||||
|
||||
/// getSelfRegion - Returns the region for the 'self' (Objective-C) or
|
||||
/// 'this' object (C++). When used when analyzing a normal function this
|
||||
/// method returns NULL.
|
||||
virtual const MemRegion* getSelfRegion(Store store) = 0;
|
||||
|
||||
virtual Store RemoveDeadBindings(const GRState *state,
|
||||
Stmt* Loc, SymbolReaper& SymReaper,
|
||||
virtual void RemoveDeadBindings(GRState &state, Stmt* Loc,
|
||||
SymbolReaper& SymReaper,
|
||||
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0;
|
||||
|
||||
virtual const GRState *BindDecl(const GRState *state, const VarDecl *vd,
|
||||
SVal initVal) = 0;
|
||||
virtual const GRState *BindDecl(const GRState *ST, const VarDecl *VD,
|
||||
const LocationContext *LC, SVal initVal) = 0;
|
||||
|
||||
virtual const GRState *BindDeclWithNoInit(const GRState *state,
|
||||
const VarDecl *vd) = 0;
|
||||
virtual const GRState *BindDeclWithNoInit(const GRState *ST,
|
||||
const VarDecl *VD,
|
||||
const LocationContext *LC) = 0;
|
||||
|
||||
virtual const GRState *InvalidateRegion(const GRState *state,
|
||||
const MemRegion *R,
|
||||
const Expr *E, unsigned Count) = 0;
|
||||
|
||||
// FIXME: Make out-of-line.
|
||||
virtual const GRState *setExtent(const GRState *state,
|
||||
|
|
@ -163,25 +151,35 @@ public:
|
|||
return state;
|
||||
}
|
||||
|
||||
// FIXME: Make out-of-line.
|
||||
virtual const GRState *setDefaultValue(const GRState *state,
|
||||
const MemRegion *region,
|
||||
SVal val) {
|
||||
/// 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:
|
||||
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;
|
||||
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.
|
||||
SValuator::CastResult CastRetrievedVal(SVal val, const GRState *state,
|
||||
const TypedRegion *R, QualType castTy);
|
||||
};
|
||||
|
||||
// FIXME: Do we still need this?
|
||||
|
|
@ -190,14 +188,14 @@ public:
|
|||
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;
|
||||
|
||||
virtual bool iterSubRegions(const MemRegion *region, Visitor& V) const = 0;
|
||||
};
|
||||
|
||||
// FIXME: Do we need to pass GRStateManager anymore?
|
||||
|
|
|
|||
|
|
@ -21,66 +21,72 @@
|
|||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/ImmutableSet.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
namespace clang {
|
||||
class MemRegion;
|
||||
class TypedRegion;
|
||||
class ASTContext;
|
||||
class BasicValueFactory;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
class SymExpr : public llvm::FoldingSetNode {
|
||||
public:
|
||||
enum Kind { BEGIN_SYMBOLS, RegionValueKind, ConjuredKind, END_SYMBOLS,
|
||||
enum Kind { BEGIN_SYMBOLS,
|
||||
RegionValueKind, ConjuredKind, DerivedKind,
|
||||
END_SYMBOLS,
|
||||
SymIntKind, SymSymKind };
|
||||
private:
|
||||
Kind K;
|
||||
|
||||
protected:
|
||||
SymExpr(Kind k) : K(k) {}
|
||||
|
||||
SymExpr(Kind k) : K(k) {}
|
||||
|
||||
public:
|
||||
virtual ~SymExpr() {}
|
||||
|
||||
Kind getKind() const { return K; }
|
||||
|
||||
virtual QualType getType(ASTContext&) const = 0;
|
||||
|
||||
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<T> 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) {}
|
||||
SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {}
|
||||
|
||||
public:
|
||||
virtual ~SymbolData() {}
|
||||
|
||||
|
||||
SymbolID getSymbolID() const { return Sym; }
|
||||
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SymExpr* SE) {
|
||||
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
|
||||
|
|
@ -90,7 +96,7 @@ class SymbolRegionValue : public SymbolData {
|
|||
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,
|
||||
|
|
@ -99,11 +105,13 @@ public:
|
|||
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<T> support.
|
||||
|
|
@ -123,15 +131,17 @@ public:
|
|||
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) {
|
||||
QualType T, unsigned Count, const void* SymbolTag) {
|
||||
profile.AddInteger((unsigned) ConjuredKind);
|
||||
profile.AddPointer(S);
|
||||
profile.Add(T);
|
||||
|
|
@ -146,7 +156,39 @@ public:
|
|||
// Implement isa<T> 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<T> support.
|
||||
static inline bool classof(const SymExpr* SE) {
|
||||
return SE->getKind() == DerivedKind;
|
||||
}
|
||||
};
|
||||
|
||||
// SymIntExpr - Represents symbolic expression like 'x' + 3.
|
||||
|
|
@ -163,14 +205,16 @@ public:
|
|||
|
||||
// FIXME: We probably need to make this out-of-line to avoid redundant
|
||||
// generation of virtual functions.
|
||||
QualType getType(ASTContext& C) const { return T; }
|
||||
|
||||
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,
|
||||
static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
|
||||
BinaryOperator::Opcode op, const llvm::APSInt& rhs,
|
||||
QualType t) {
|
||||
ID.AddInteger((unsigned) SymIntKind);
|
||||
|
|
@ -183,11 +227,11 @@ public:
|
|||
void Profile(llvm::FoldingSetNodeID& ID) {
|
||||
Profile(ID, LHS, Op, RHS, T);
|
||||
}
|
||||
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SymExpr* SE) {
|
||||
return SE->getKind() == SymIntKind;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// SymSymExpr - Represents symbolic expression like 'x' + 'y'.
|
||||
|
|
@ -204,11 +248,13 @@ public:
|
|||
|
||||
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);
|
||||
|
|
@ -221,45 +267,48 @@ public:
|
|||
void Profile(llvm::FoldingSetNodeID& ID) {
|
||||
Profile(ID, LHS, Op, RHS, T);
|
||||
}
|
||||
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SymExpr* SE) {
|
||||
return SE->getKind() == SymSymKind;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class SymbolManager {
|
||||
typedef llvm::FoldingSet<SymExpr> DataSetTy;
|
||||
DataSetTy DataSet;
|
||||
DataSetTy DataSet;
|
||||
unsigned SymbolCounter;
|
||||
llvm::BumpPtrAllocator& BPAlloc;
|
||||
BasicValueFactory &BV;
|
||||
ASTContext& Ctx;
|
||||
|
||||
|
||||
public:
|
||||
SymbolManager(ASTContext& ctx, BasicValueFactory &bv,
|
||||
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,
|
||||
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) {
|
||||
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);
|
||||
|
|
@ -267,29 +316,28 @@ public:
|
|||
|
||||
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::ImmutableSet<SymbolRef> SetTy;
|
||||
typedef SetTy::Factory FactoryTy;
|
||||
|
||||
FactoryTy F;
|
||||
typedef llvm::DenseSet<SymbolRef> SetTy;
|
||||
|
||||
SetTy TheLiving;
|
||||
SetTy TheDead;
|
||||
LiveVariables& Liveness;
|
||||
SymbolManager& SymMgr;
|
||||
|
||||
|
||||
public:
|
||||
SymbolReaper(LiveVariables& liveness, SymbolManager& symmgr)
|
||||
: TheLiving(F.GetEmptySet()), TheDead(F.GetEmptySet()),
|
||||
Liveness(liveness), SymMgr(symmgr) {}
|
||||
: Liveness(liveness), SymMgr(symmgr) {}
|
||||
|
||||
~SymbolReaper() {}
|
||||
|
||||
bool isLive(SymbolRef sym);
|
||||
|
||||
|
|
@ -300,19 +348,19 @@ public:
|
|||
bool isLive(const Stmt* Loc, const VarDecl* VD) const {
|
||||
return Liveness.isLive(Loc, VD);
|
||||
}
|
||||
|
||||
|
||||
void markLive(SymbolRef sym);
|
||||
bool maybeDead(SymbolRef sym);
|
||||
|
||||
typedef SetTy::iterator dead_iterator;
|
||||
|
||||
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.isEmpty();
|
||||
return !TheDead.empty();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class SymbolVisitor {
|
||||
public:
|
||||
// VisitSymbol - A visitor method invoked by
|
||||
|
|
@ -321,11 +369,14 @@ public:
|
|||
virtual bool VisitSymbol(SymbolRef sym) = 0;
|
||||
virtual ~SymbolVisitor();
|
||||
};
|
||||
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
namespace llvm {
|
||||
llvm::raw_ostream& operator<<(llvm::raw_ostream& Out,
|
||||
const clang::SymExpr *SE);
|
||||
static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os,
|
||||
const clang::SymExpr *SE) {
|
||||
SE->dumpToStream(os);
|
||||
return os;
|
||||
}
|
||||
} // end llvm namespace
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,82 +16,123 @@
|
|||
#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 {
|
||||
namespace clang {
|
||||
|
||||
class GRStateManager;
|
||||
|
||||
class ValueManager {
|
||||
|
||||
ASTContext &Context;
|
||||
ASTContext &Context;
|
||||
BasicValueFactory BasicVals;
|
||||
|
||||
|
||||
/// SymMgr - Object that manages the symbol information.
|
||||
SymbolManager SymMgr;
|
||||
|
||||
/// SVator - SValuator object that creates SVals from expressions.
|
||||
llvm::OwningPtr<SValuator> SVator;
|
||||
|
||||
MemRegionManager MemMgr;
|
||||
|
||||
|
||||
GRStateManager &StateMgr;
|
||||
|
||||
const QualType ArrayIndexTy;
|
||||
const unsigned ArrayIndexWidth;
|
||||
|
||||
public:
|
||||
ValueManager(llvm::BumpPtrAllocator &alloc, ASTContext &context)
|
||||
: Context(context), BasicVals(Context, alloc),
|
||||
SymMgr(Context, BasicVals, alloc),
|
||||
MemMgr(Context, alloc) {}
|
||||
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) {
|
||||
const void* SymbolTag = 0) {
|
||||
return SymMgr.getConjuredSymbol(E, VisitCount, SymbolTag);
|
||||
}
|
||||
|
||||
/// makeZeroVal - Construct an SVal representing '0' for the specified type.
|
||||
SVal makeZeroVal(QualType T);
|
||||
DefinedOrUnknownSVal makeZeroVal(QualType T);
|
||||
|
||||
/// getRegionValueSymbolVal - make a unique symbol for value of R.
|
||||
SVal getRegionValueSymbolVal(const MemRegion *R, QualType T = QualType());
|
||||
|
||||
SVal getRegionValueSymbolValOrUnknown(const MemRegion *R, QualType T) {
|
||||
return SymMgr.canSymbolicate(T) ? getRegionValueSymbolVal(R, T)
|
||||
: UnknownVal();
|
||||
}
|
||||
|
||||
SVal getConjuredSymbolVal(const Expr *E, unsigned Count);
|
||||
SVal getConjuredSymbolVal(const Expr* E, QualType T, unsigned Count);
|
||||
DefinedOrUnknownSVal getRegionValueSymbolVal(const MemRegion *R,
|
||||
QualType T = QualType());
|
||||
|
||||
SVal getFunctionPointer(const FunctionDecl* FD);
|
||||
DefinedOrUnknownSVal getRegionValueSymbolValOrUnknown(const MemRegion *R,
|
||||
QualType T) {
|
||||
if (SymMgr.canSymbolicate(T))
|
||||
return getRegionValueSymbolVal(R, T);
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
NonLoc makeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals) {
|
||||
return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals));
|
||||
}
|
||||
|
||||
NonLoc makeZeroArrayIndex() {
|
||||
return nonloc::ConcreteInt(BasicVals.getZeroWithPtrWidth(false));
|
||||
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()));
|
||||
|
|
@ -100,7 +141,7 @@ public:
|
|||
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));
|
||||
}
|
||||
|
|
@ -109,7 +150,10 @@ public:
|
|||
return nonloc::ConcreteInt(BasicVals.getValue(V, isUnsigned));
|
||||
}
|
||||
|
||||
NonLoc makeIntVal(uint64_t X, QualType T) {
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
@ -117,6 +161,10 @@ public:
|
|||
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));
|
||||
}
|
||||
|
|
@ -127,10 +175,10 @@ public:
|
|||
|
||||
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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
#ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT
|
||||
#define LLVM_CLANG_ANALYSIS_PROGRAM_POINT
|
||||
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
|
|
@ -24,123 +24,95 @@
|
|||
#include <utility>
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
class LocationContext;
|
||||
|
||||
class ProgramPoint {
|
||||
public:
|
||||
enum Kind { BlockEdgeKind = 0x0,
|
||||
BlockEntranceKind = 0x1,
|
||||
BlockExitKind = 0x2,
|
||||
// Keep the following four together and in this order.
|
||||
PostStmtKind = 0x3,
|
||||
PostLocationChecksSucceedKind = 0x4,
|
||||
PostOutOfBoundsCheckFailedKind = 0x5,
|
||||
PostNullCheckFailedKind = 0x6,
|
||||
PostUndefLocationCheckFailedKind = 0x7,
|
||||
PostLoadKind = 0x8,
|
||||
PostStoreKind = 0x9,
|
||||
PostPurgeDeadSymbolsKind = 0x10,
|
||||
PostStmtCustomKind = 0x11,
|
||||
PostLValueKind = 0x12,
|
||||
enum Kind { BlockEdgeKind,
|
||||
BlockEntranceKind,
|
||||
BlockExitKind,
|
||||
PreStmtKind,
|
||||
// Keep the following together and in this order.
|
||||
PostStmtKind,
|
||||
PostLocationChecksSucceedKind,
|
||||
PostOutOfBoundsCheckFailedKind,
|
||||
PostNullCheckFailedKind,
|
||||
PostUndefLocationCheckFailedKind,
|
||||
PostLoadKind,
|
||||
PostStoreKind,
|
||||
PostPurgeDeadSymbolsKind,
|
||||
PostStmtCustomKind,
|
||||
PostLValueKind,
|
||||
MinPostStmtKind = PostStmtKind,
|
||||
MaxPostStmtKind = PostLValueKind };
|
||||
|
||||
private:
|
||||
enum { TwoPointers = 0x1, Custom = 0x2, Mask = 0x3 };
|
||||
|
||||
std::pair<uintptr_t,uintptr_t> Data;
|
||||
std::pair<const void *, const void *> Data;
|
||||
Kind K;
|
||||
|
||||
// The LocationContext could be NULL to allow ProgramPoint to be used in
|
||||
// context insensitive analysis.
|
||||
const LocationContext *L;
|
||||
const void *Tag;
|
||||
|
||||
protected:
|
||||
ProgramPoint(const void* P, Kind k, const void *tag = 0)
|
||||
: Data(reinterpret_cast<uintptr_t>(P),
|
||||
(uintptr_t) k), Tag(tag) {}
|
||||
|
||||
ProgramPoint(const void* P1, const void* P2, const void *tag = 0)
|
||||
: Data(reinterpret_cast<uintptr_t>(P1) | TwoPointers,
|
||||
reinterpret_cast<uintptr_t>(P2)), Tag(tag) {}
|
||||
|
||||
ProgramPoint(const void* P1, const void* P2, bool, const void *tag = 0)
|
||||
: Data(reinterpret_cast<uintptr_t>(P1) | Custom,
|
||||
reinterpret_cast<uintptr_t>(P2)), Tag(tag) {}
|
||||
|
||||
protected:
|
||||
void* getData1NoMask() const {
|
||||
Kind k = getKind(); k = k;
|
||||
assert(k == BlockEntranceKind || k == BlockExitKind);
|
||||
return reinterpret_cast<void*>(Data.first);
|
||||
}
|
||||
|
||||
void* getData1() const {
|
||||
Kind k = getKind(); k = k;
|
||||
assert(k == BlockEdgeKind ||(k >= MinPostStmtKind && k <= MaxPostStmtKind));
|
||||
return reinterpret_cast<void*>(Data.first & ~Mask);
|
||||
}
|
||||
ProgramPoint(const void* P, Kind k, const LocationContext *l,
|
||||
const void *tag = 0)
|
||||
: Data(P, NULL), K(k), L(l), Tag(tag) {}
|
||||
|
||||
void* getData2() const {
|
||||
Kind k = getKind(); k = k;
|
||||
assert(k == BlockEdgeKind || k == PostStmtCustomKind);
|
||||
return reinterpret_cast<void*>(Data.second);
|
||||
}
|
||||
|
||||
ProgramPoint(const void* P1, const void* P2, Kind k, const LocationContext *l,
|
||||
const void *tag = 0)
|
||||
: Data(P1, P2), K(k), L(l), Tag(tag) {}
|
||||
|
||||
protected:
|
||||
const void* getData1() const { return Data.first; }
|
||||
const void* getData2() const { return Data.second; }
|
||||
const void *getTag() const { return Tag; }
|
||||
|
||||
public:
|
||||
Kind getKind() const {
|
||||
switch (Data.first & Mask) {
|
||||
case TwoPointers: return BlockEdgeKind;
|
||||
case Custom: return PostStmtCustomKind;
|
||||
default: return (Kind) Data.second;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
Kind getKind() const { return K; }
|
||||
|
||||
const LocationContext *getLocationContext() const { return L; }
|
||||
|
||||
// For use with DenseMap. This hash is probably slow.
|
||||
unsigned getHashValue() const {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
ID.AddPointer(reinterpret_cast<void*>(Data.first));
|
||||
ID.AddPointer(reinterpret_cast<void*>(Data.second));
|
||||
ID.AddPointer(Tag);
|
||||
Profile(ID);
|
||||
return ID.ComputeHash();
|
||||
}
|
||||
|
||||
|
||||
static bool classof(const ProgramPoint*) { return true; }
|
||||
|
||||
bool operator==(const ProgramPoint & RHS) const {
|
||||
return Data == RHS.Data && Tag == RHS.Tag;
|
||||
return K == RHS.K && Data == RHS.Data && L == RHS.L && Tag == RHS.Tag;
|
||||
}
|
||||
|
||||
bool operator!=(const ProgramPoint& RHS) const {
|
||||
return Data != RHS.Data || Tag != RHS.Tag;
|
||||
return K != RHS.K || Data != RHS.Data || L != RHS.L || Tag != RHS.Tag;
|
||||
}
|
||||
|
||||
bool operator<(const ProgramPoint& RHS) const {
|
||||
return Data < RHS.Data && Tag < RHS.Tag;
|
||||
}
|
||||
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
ID.AddPointer(reinterpret_cast<void*>(Data.first));
|
||||
if (getKind() != PostStmtCustomKind)
|
||||
ID.AddPointer(reinterpret_cast<void*>(Data.second));
|
||||
else {
|
||||
const std::pair<const void*, const void*> *P =
|
||||
reinterpret_cast<std::pair<const void*, const void*>*>(Data.second);
|
||||
ID.AddPointer(P->first);
|
||||
ID.AddPointer(P->second);
|
||||
}
|
||||
ID.AddInteger((unsigned) K);
|
||||
ID.AddPointer(Data.first);
|
||||
ID.AddPointer(Data.second);
|
||||
ID.AddPointer(L);
|
||||
ID.AddPointer(Tag);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class BlockEntrance : public ProgramPoint {
|
||||
public:
|
||||
BlockEntrance(const CFGBlock* B, const void *tag = 0)
|
||||
: ProgramPoint(B, BlockEntranceKind, tag) {}
|
||||
|
||||
BlockEntrance(const CFGBlock* B, const LocationContext *L,
|
||||
const void *tag = 0)
|
||||
: ProgramPoint(B, BlockEntranceKind, L, tag) {}
|
||||
|
||||
CFGBlock* getBlock() const {
|
||||
return reinterpret_cast<CFGBlock*>(getData1NoMask());
|
||||
return const_cast<CFGBlock*>(reinterpret_cast<const CFGBlock*>(getData1()));
|
||||
}
|
||||
|
||||
|
||||
Stmt* getFirstStmt() const {
|
||||
CFGBlock* B = getBlock();
|
||||
const CFGBlock* B = getBlock();
|
||||
return B->empty() ? NULL : B->front();
|
||||
}
|
||||
|
||||
|
|
@ -151,42 +123,70 @@ public:
|
|||
|
||||
class BlockExit : public ProgramPoint {
|
||||
public:
|
||||
BlockExit(const CFGBlock* B) : ProgramPoint(B, BlockExitKind) {}
|
||||
|
||||
BlockExit(const CFGBlock* B, const LocationContext *L)
|
||||
: ProgramPoint(B, BlockExitKind, L) {}
|
||||
|
||||
CFGBlock* getBlock() const {
|
||||
return reinterpret_cast<CFGBlock*>(getData1NoMask());
|
||||
return const_cast<CFGBlock*>(reinterpret_cast<const CFGBlock*>(getData1()));
|
||||
}
|
||||
|
||||
Stmt* getLastStmt() const {
|
||||
CFGBlock* B = getBlock();
|
||||
const CFGBlock* B = getBlock();
|
||||
return B->empty() ? NULL : B->back();
|
||||
}
|
||||
|
||||
|
||||
Stmt* getTerminator() const {
|
||||
return getBlock()->getTerminator();
|
||||
}
|
||||
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == BlockExitKind;
|
||||
}
|
||||
};
|
||||
|
||||
class PostStmt : public ProgramPoint {
|
||||
protected:
|
||||
PostStmt(const Stmt* S, Kind k,const void *tag = 0)
|
||||
: ProgramPoint(S, k, tag) {}
|
||||
|
||||
PostStmt(const Stmt* S, const void* data, bool, const void *tag =0)
|
||||
: ProgramPoint(S, data, true, tag) {}
|
||||
|
||||
class StmtPoint : public ProgramPoint {
|
||||
public:
|
||||
PostStmt(const Stmt* S, const void *tag = 0)
|
||||
: ProgramPoint(S, PostStmtKind, tag) {}
|
||||
StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L,
|
||||
const void *tag)
|
||||
: ProgramPoint(S, p2, k, L, tag) {}
|
||||
|
||||
Stmt* getStmt() const { return (Stmt*) getData1(); }
|
||||
|
||||
template<typename T>
|
||||
T* getStmtAs() const { return llvm::dyn_cast<T>(getStmt()); }
|
||||
const Stmt *getStmt() const { return (const Stmt*) getData1(); }
|
||||
|
||||
template <typename T>
|
||||
const T* getStmtAs() const { return llvm::dyn_cast<T>(getStmt()); }
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
unsigned k = Location->getKind();
|
||||
return k >= PreStmtKind && k <= MaxPostStmtKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class PreStmt : public StmtPoint {
|
||||
public:
|
||||
PreStmt(const Stmt *S, const LocationContext *L, const void *tag,
|
||||
const Stmt *SubStmt = 0)
|
||||
: StmtPoint(S, SubStmt, PreStmtKind, L, tag) {}
|
||||
|
||||
const Stmt *getSubStmt() const { return (const Stmt*) getData2(); }
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PreStmtKind;
|
||||
}
|
||||
};
|
||||
|
||||
class PostStmt : public StmtPoint {
|
||||
protected:
|
||||
PostStmt(const Stmt* S, Kind k, const LocationContext *L, const void *tag = 0)
|
||||
: StmtPoint(S, NULL, k, L, tag) {}
|
||||
|
||||
PostStmt(const Stmt* S, const void* data, Kind k, const LocationContext *L,
|
||||
const void *tag =0)
|
||||
: StmtPoint(S, data, k, L, tag) {}
|
||||
|
||||
public:
|
||||
explicit PostStmt(const Stmt* S, const LocationContext *L,const void *tag = 0)
|
||||
: StmtPoint(S, NULL, PostStmtKind, L, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
unsigned k = Location->getKind();
|
||||
|
|
@ -196,40 +196,42 @@ public:
|
|||
|
||||
class PostLocationChecksSucceed : public PostStmt {
|
||||
public:
|
||||
PostLocationChecksSucceed(const Stmt* S, const void *tag = 0)
|
||||
: PostStmt(S, PostLocationChecksSucceedKind, tag) {}
|
||||
|
||||
PostLocationChecksSucceed(const Stmt* S, const LocationContext *L,
|
||||
const void *tag = 0)
|
||||
: PostStmt(S, PostLocationChecksSucceedKind, L, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostLocationChecksSucceedKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class PostStmtCustom : public PostStmt {
|
||||
public:
|
||||
PostStmtCustom(const Stmt* S,
|
||||
const std::pair<const void*, const void*>* TaggedData)
|
||||
: PostStmt(S, TaggedData, true) {
|
||||
assert(getKind() == PostStmtCustomKind);
|
||||
}
|
||||
const std::pair<const void*, const void*>* TaggedData,\
|
||||
const LocationContext *L)
|
||||
: PostStmt(S, TaggedData, PostStmtCustomKind, L) {}
|
||||
|
||||
const std::pair<const void*, const void*>& getTaggedPair() const {
|
||||
return *reinterpret_cast<std::pair<const void*, const void*>*>(getData2());
|
||||
return
|
||||
*reinterpret_cast<const std::pair<const void*, const void*>*>(getData2());
|
||||
}
|
||||
|
||||
|
||||
const void* getTag() const { return getTaggedPair().first; }
|
||||
|
||||
|
||||
const void* getTaggedData() const { return getTaggedPair().second; }
|
||||
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostStmtCustomKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class PostOutOfBoundsCheckFailed : public PostStmt {
|
||||
public:
|
||||
PostOutOfBoundsCheckFailed(const Stmt* S, const void *tag = 0)
|
||||
: PostStmt(S, PostOutOfBoundsCheckFailedKind, tag) {}
|
||||
|
||||
PostOutOfBoundsCheckFailed(const Stmt* S, const LocationContext *L,
|
||||
const void *tag = 0)
|
||||
: PostStmt(S, PostOutOfBoundsCheckFailedKind, L, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostOutOfBoundsCheckFailedKind;
|
||||
}
|
||||
|
|
@ -237,39 +239,41 @@ public:
|
|||
|
||||
class PostUndefLocationCheckFailed : public PostStmt {
|
||||
public:
|
||||
PostUndefLocationCheckFailed(const Stmt* S, const void *tag = 0)
|
||||
: PostStmt(S, PostUndefLocationCheckFailedKind, tag) {}
|
||||
|
||||
PostUndefLocationCheckFailed(const Stmt* S, const LocationContext *L,
|
||||
const void *tag = 0)
|
||||
: PostStmt(S, PostUndefLocationCheckFailedKind, L, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostUndefLocationCheckFailedKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class PostNullCheckFailed : public PostStmt {
|
||||
public:
|
||||
PostNullCheckFailed(const Stmt* S, const void *tag = 0)
|
||||
: PostStmt(S, PostNullCheckFailedKind, tag) {}
|
||||
|
||||
PostNullCheckFailed(const Stmt* S, const LocationContext *L,
|
||||
const void *tag = 0)
|
||||
: PostStmt(S, PostNullCheckFailedKind, L, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostNullCheckFailedKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class PostLoad : public PostStmt {
|
||||
public:
|
||||
PostLoad(const Stmt* S, const void *tag = 0)
|
||||
: PostStmt(S, PostLoadKind, tag) {}
|
||||
|
||||
PostLoad(const Stmt* S, const LocationContext *L, const void *tag = 0)
|
||||
: PostStmt(S, PostLoadKind, L, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostLoadKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class PostStore : public PostStmt {
|
||||
public:
|
||||
PostStore(const Stmt* S, const void *tag = 0)
|
||||
: PostStmt(S, PostStoreKind, tag) {}
|
||||
|
||||
PostStore(const Stmt* S, const LocationContext *L, const void *tag = 0)
|
||||
: PostStmt(S, PostStoreKind, L, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostStoreKind;
|
||||
}
|
||||
|
|
@ -277,60 +281,61 @@ public:
|
|||
|
||||
class PostLValue : public PostStmt {
|
||||
public:
|
||||
PostLValue(const Stmt* S, const void *tag = 0)
|
||||
: PostStmt(S, PostLValueKind, tag) {}
|
||||
|
||||
PostLValue(const Stmt* S, const LocationContext *L, const void *tag = 0)
|
||||
: PostStmt(S, PostLValueKind, L, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostLValueKind;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class PostPurgeDeadSymbols : public PostStmt {
|
||||
public:
|
||||
PostPurgeDeadSymbols(const Stmt* S, const void *tag = 0)
|
||||
: PostStmt(S, PostPurgeDeadSymbolsKind, tag) {}
|
||||
|
||||
PostPurgeDeadSymbols(const Stmt* S, const LocationContext *L,
|
||||
const void *tag = 0)
|
||||
: PostStmt(S, PostPurgeDeadSymbolsKind, L, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostPurgeDeadSymbolsKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class BlockEdge : public ProgramPoint {
|
||||
public:
|
||||
BlockEdge(const CFGBlock* B1, const CFGBlock* B2)
|
||||
: ProgramPoint(B1, B2) {}
|
||||
|
||||
BlockEdge(const CFGBlock* B1, const CFGBlock* B2, const LocationContext *L)
|
||||
: ProgramPoint(B1, B2, BlockEdgeKind, L) {}
|
||||
|
||||
CFGBlock* getSrc() const {
|
||||
return static_cast<CFGBlock*>(getData1());
|
||||
return const_cast<CFGBlock*>(static_cast<const CFGBlock*>(getData1()));
|
||||
}
|
||||
|
||||
|
||||
CFGBlock* getDst() const {
|
||||
return static_cast<CFGBlock*>(getData2());
|
||||
return const_cast<CFGBlock*>(static_cast<const CFGBlock*>(getData2()));
|
||||
}
|
||||
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == BlockEdgeKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
|
||||
namespace llvm { // Traits specialization for DenseMap
|
||||
|
||||
namespace llvm { // Traits specialization for DenseMap
|
||||
|
||||
template <> struct DenseMapInfo<clang::ProgramPoint> {
|
||||
|
||||
static inline clang::ProgramPoint getEmptyKey() {
|
||||
uintptr_t x =
|
||||
reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7;
|
||||
return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x));
|
||||
reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7;
|
||||
return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0);
|
||||
}
|
||||
|
||||
static inline clang::ProgramPoint getTombstoneKey() {
|
||||
uintptr_t x =
|
||||
reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7;
|
||||
return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x));
|
||||
reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7;
|
||||
return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0);
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const clang::ProgramPoint& Loc) {
|
||||
|
|
|
|||
|
|
@ -17,24 +17,24 @@
|
|||
#ifndef LLVM_CLANG_STMTDECLBVDVAL_H
|
||||
#define LLVM_CLANG_STMTDECLBVDVAL_H
|
||||
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/AST/Decl.h" // for Decl* -> NamedDecl* conversion
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
class Stmt;
|
||||
class ASTContext;
|
||||
|
||||
struct DeclBitVector_Types {
|
||||
|
||||
|
||||
class Idx {
|
||||
unsigned I;
|
||||
public:
|
||||
explicit Idx(unsigned i) : I(i) {}
|
||||
Idx() : I(~0U) {}
|
||||
|
||||
|
||||
bool isValid() const {
|
||||
return I != ~0U;
|
||||
}
|
||||
|
|
@ -42,35 +42,35 @@ struct DeclBitVector_Types {
|
|||
assert (isValid());
|
||||
return I;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// AnalysisDataTy - Whole-function meta data.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
|
||||
class AnalysisDataTy {
|
||||
public:
|
||||
typedef llvm::DenseMap<const NamedDecl*, unsigned > DMapTy;
|
||||
typedef DMapTy::const_iterator decl_iterator;
|
||||
|
||||
|
||||
protected:
|
||||
DMapTy DMap;
|
||||
DMapTy DMap;
|
||||
unsigned NDecls;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
AnalysisDataTy() : NDecls(0) {}
|
||||
virtual ~AnalysisDataTy() {}
|
||||
|
||||
|
||||
bool isTracked(const NamedDecl* SD) { return DMap.find(SD) != DMap.end(); }
|
||||
|
||||
|
||||
Idx getIdx(const NamedDecl* SD) const {
|
||||
DMapTy::const_iterator I = DMap.find(SD);
|
||||
return I == DMap.end() ? Idx() : Idx(I->second);
|
||||
}
|
||||
|
||||
unsigned getNumDecls() const { return NDecls; }
|
||||
|
||||
|
||||
void Register(const NamedDecl* SD) {
|
||||
if (!isTracked(SD)) DMap[SD] = NDecls++;
|
||||
}
|
||||
|
|
@ -78,44 +78,44 @@ struct DeclBitVector_Types {
|
|||
decl_iterator begin_decl() const { return DMap.begin(); }
|
||||
decl_iterator end_decl() const { return DMap.end(); }
|
||||
};
|
||||
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// ValTy - Dataflow value.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
|
||||
class ValTy {
|
||||
llvm::BitVector DeclBV;
|
||||
public:
|
||||
|
||||
|
||||
void resetDeclValues(AnalysisDataTy& AD) {
|
||||
DeclBV.resize(AD.getNumDecls());
|
||||
DeclBV.resize(AD.getNumDecls());
|
||||
DeclBV.reset();
|
||||
}
|
||||
|
||||
void setDeclValues(AnalysisDataTy& AD) {
|
||||
DeclBV.resize(AD.getNumDecls());
|
||||
DeclBV.resize(AD.getNumDecls());
|
||||
DeclBV.set();
|
||||
}
|
||||
|
||||
|
||||
void resetValues(AnalysisDataTy& AD) {
|
||||
resetDeclValues(AD);
|
||||
}
|
||||
|
||||
bool operator==(const ValTy& RHS) const {
|
||||
}
|
||||
|
||||
bool operator==(const ValTy& RHS) const {
|
||||
assert (sizesEqual(RHS));
|
||||
return DeclBV == RHS.DeclBV;
|
||||
}
|
||||
|
||||
|
||||
void copyValues(const ValTy& RHS) { DeclBV = RHS.DeclBV; }
|
||||
|
||||
|
||||
llvm::BitVector::reference getBit(unsigned i) {
|
||||
return DeclBV[i];
|
||||
}
|
||||
|
||||
|
||||
bool getBit(unsigned i) const {
|
||||
return DeclBV[i];
|
||||
}
|
||||
|
||||
|
||||
llvm::BitVector::reference
|
||||
operator()(const NamedDecl* ND, const AnalysisDataTy& AD) {
|
||||
return getBit(AD.getIdx(ND));
|
||||
|
|
@ -124,48 +124,48 @@ struct DeclBitVector_Types {
|
|||
bool operator()(const NamedDecl* ND, const AnalysisDataTy& AD) const {
|
||||
return getBit(AD.getIdx(ND));
|
||||
}
|
||||
|
||||
llvm::BitVector::reference getDeclBit(unsigned i) { return DeclBV[i]; }
|
||||
|
||||
llvm::BitVector::reference getDeclBit(unsigned i) { return DeclBV[i]; }
|
||||
const llvm::BitVector::reference getDeclBit(unsigned i) const {
|
||||
return const_cast<llvm::BitVector&>(DeclBV)[i];
|
||||
}
|
||||
|
||||
|
||||
ValTy& operator|=(const ValTy& RHS) {
|
||||
assert (sizesEqual(RHS));
|
||||
DeclBV |= RHS.DeclBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
ValTy& operator&=(const ValTy& RHS) {
|
||||
assert (sizesEqual(RHS));
|
||||
DeclBV &= RHS.DeclBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
ValTy& OrDeclBits(const ValTy& RHS) {
|
||||
return operator|=(RHS);
|
||||
}
|
||||
|
||||
|
||||
ValTy& AndDeclBits(const ValTy& RHS) {
|
||||
return operator&=(RHS);
|
||||
}
|
||||
|
||||
|
||||
bool sizesEqual(const ValTy& RHS) const {
|
||||
return DeclBV.size() == RHS.DeclBV.size();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Some useful merge operations.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
|
||||
struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } };
|
||||
struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } };
|
||||
};
|
||||
|
||||
|
||||
struct StmtDeclBitVector_Types {
|
||||
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// AnalysisDataTy - Whole-function meta data.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
@ -179,13 +179,13 @@ struct StmtDeclBitVector_Types {
|
|||
|
||||
void setContext(ASTContext& c) { ctx = &c; }
|
||||
ASTContext& getContext() {
|
||||
assert(ctx && "ASTContext should not be NULL.");
|
||||
assert(ctx && "ASTContext should not be NULL.");
|
||||
return *ctx;
|
||||
}
|
||||
|
||||
void setCFG(CFG& c) { cfg = &c; }
|
||||
CFG& getCFG() { assert(cfg && "CFG should not be NULL."); return *cfg; }
|
||||
|
||||
|
||||
bool isTracked(const Stmt* S) { return cfg->isBlkExpr(S); }
|
||||
using DeclBitVector_Types::AnalysisDataTy::isTracked;
|
||||
|
||||
|
|
@ -195,7 +195,7 @@ struct StmtDeclBitVector_Types {
|
|||
return I;
|
||||
}
|
||||
using DeclBitVector_Types::AnalysisDataTy::getIdx;
|
||||
|
||||
|
||||
unsigned getNumBlkExprs() const { return cfg->getNumBlkExprs(); }
|
||||
};
|
||||
|
||||
|
|
@ -206,101 +206,101 @@ struct StmtDeclBitVector_Types {
|
|||
class ValTy : public DeclBitVector_Types::ValTy {
|
||||
llvm::BitVector BlkExprBV;
|
||||
typedef DeclBitVector_Types::ValTy ParentTy;
|
||||
|
||||
|
||||
static inline ParentTy& ParentRef(ValTy& X) {
|
||||
return static_cast<ParentTy&>(X);
|
||||
}
|
||||
|
||||
|
||||
static inline const ParentTy& ParentRef(const ValTy& X) {
|
||||
return static_cast<const ParentTy&>(X);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
void resetBlkExprValues(AnalysisDataTy& AD) {
|
||||
BlkExprBV.resize(AD.getNumBlkExprs());
|
||||
BlkExprBV.reset();
|
||||
}
|
||||
|
||||
|
||||
void setBlkExprValues(AnalysisDataTy& AD) {
|
||||
BlkExprBV.resize(AD.getNumBlkExprs());
|
||||
BlkExprBV.set();
|
||||
}
|
||||
|
||||
|
||||
void resetValues(AnalysisDataTy& AD) {
|
||||
resetDeclValues(AD);
|
||||
resetBlkExprValues(AD);
|
||||
}
|
||||
|
||||
|
||||
void setValues(AnalysisDataTy& AD) {
|
||||
setDeclValues(AD);
|
||||
setBlkExprValues(AD);
|
||||
}
|
||||
|
||||
bool operator==(const ValTy& RHS) const {
|
||||
return ParentRef(*this) == ParentRef(RHS)
|
||||
|
||||
bool operator==(const ValTy& RHS) const {
|
||||
return ParentRef(*this) == ParentRef(RHS)
|
||||
&& BlkExprBV == RHS.BlkExprBV;
|
||||
}
|
||||
|
||||
|
||||
void copyValues(const ValTy& RHS) {
|
||||
ParentRef(*this).copyValues(ParentRef(RHS));
|
||||
BlkExprBV = RHS.BlkExprBV;
|
||||
}
|
||||
|
||||
|
||||
llvm::BitVector::reference
|
||||
operator()(const Stmt* S, const AnalysisDataTy& AD) {
|
||||
return BlkExprBV[AD.getIdx(S)];
|
||||
}
|
||||
return BlkExprBV[AD.getIdx(S)];
|
||||
}
|
||||
const llvm::BitVector::reference
|
||||
operator()(const Stmt* S, const AnalysisDataTy& AD) const {
|
||||
return const_cast<ValTy&>(*this)(S,AD);
|
||||
}
|
||||
|
||||
|
||||
using DeclBitVector_Types::ValTy::operator();
|
||||
|
||||
|
||||
llvm::BitVector::reference getStmtBit(unsigned i) { return BlkExprBV[i]; }
|
||||
|
||||
llvm::BitVector::reference getStmtBit(unsigned i) { return BlkExprBV[i]; }
|
||||
const llvm::BitVector::reference getStmtBit(unsigned i) const {
|
||||
return const_cast<llvm::BitVector&>(BlkExprBV)[i];
|
||||
}
|
||||
|
||||
|
||||
ValTy& OrBlkExprBits(const ValTy& RHS) {
|
||||
BlkExprBV |= RHS.BlkExprBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
ValTy& AndBlkExprBits(const ValTy& RHS) {
|
||||
BlkExprBV &= RHS.BlkExprBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
ValTy& operator|=(const ValTy& RHS) {
|
||||
assert (sizesEqual(RHS));
|
||||
ParentRef(*this) |= ParentRef(RHS);
|
||||
BlkExprBV |= RHS.BlkExprBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
ValTy& operator&=(const ValTy& RHS) {
|
||||
assert (sizesEqual(RHS));
|
||||
ParentRef(*this) &= ParentRef(RHS);
|
||||
BlkExprBV &= RHS.BlkExprBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool sizesEqual(const ValTy& RHS) const {
|
||||
return ParentRef(*this).sizesEqual(ParentRef(RHS))
|
||||
&& BlkExprBV.size() == RHS.BlkExprBV.size();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Some useful merge operations.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
|
||||
struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } };
|
||||
struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } };
|
||||
|
||||
|
||||
};
|
||||
} // end namespace clang
|
||||
|
||||
|
|
|
|||
215
include/clang/Analysis/Support/BumpVector.h
Normal file
215
include/clang/Analysis/Support/BumpVector.h
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
//===-- BumpVector.h - Vector-like ADT that uses bump allocation --*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides BumpVector, a vector-like ADT whose contents are
|
||||
// allocated from a BumpPtrAllocator.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// FIXME: Most of this is copy-and-paste from SmallVector.h. We can
|
||||
// refactor this core logic into something common that is shared between
|
||||
// the two. The main thing that is different is the allocation strategy.
|
||||
|
||||
#ifndef LLVM_CLANG_BUMP_VECTOR
|
||||
#define LLVM_CLANG_BUMP_VECTOR
|
||||
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class BumpVectorContext {
|
||||
llvm::PointerIntPair<llvm::BumpPtrAllocator*, 1, bool> Alloc;
|
||||
public:
|
||||
/// Construct a new BumpVectorContext that creates a new BumpPtrAllocator
|
||||
/// and destroys it when the BumpVectorContext object is destroyed.
|
||||
BumpVectorContext() : Alloc(new llvm::BumpPtrAllocator(), true) {}
|
||||
|
||||
/// Construct a new BumpVectorContext that reuses an existing
|
||||
/// BumpPtrAllocator. This BumpPtrAllocator is not destroyed when the
|
||||
/// BumpVectorContext object is destroyed.
|
||||
BumpVectorContext(llvm::BumpPtrAllocator &A) : Alloc(&A, false) {}
|
||||
|
||||
~BumpVectorContext() {
|
||||
if (Alloc.getInt())
|
||||
delete Alloc.getPointer();
|
||||
}
|
||||
|
||||
llvm::BumpPtrAllocator &getAllocator() { return *Alloc.getPointer(); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class BumpVector {
|
||||
T *Begin, *End, *Capacity;
|
||||
public:
|
||||
// Default ctor - Initialize to empty.
|
||||
explicit BumpVector(BumpVectorContext &C, unsigned N)
|
||||
: Begin(NULL), End(NULL), Capacity(NULL) {
|
||||
reserve(C, N);
|
||||
}
|
||||
|
||||
~BumpVector() {
|
||||
if (llvm::is_class<T>::value) {
|
||||
// Destroy the constructed elements in the vector.
|
||||
destroy_range(Begin, End);
|
||||
}
|
||||
}
|
||||
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef T value_type;
|
||||
typedef T* iterator;
|
||||
typedef const T* const_iterator;
|
||||
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
|
||||
// forward iterator creation methods.
|
||||
iterator begin() { return Begin; }
|
||||
const_iterator begin() const { return Begin; }
|
||||
iterator end() { return End; }
|
||||
const_iterator end() const { return 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());}
|
||||
|
||||
bool empty() const { return Begin == End; }
|
||||
size_type size() const { return End-Begin; }
|
||||
|
||||
reference operator[](unsigned idx) {
|
||||
assert(Begin + idx < End);
|
||||
return Begin[idx];
|
||||
}
|
||||
const_reference operator[](unsigned idx) const {
|
||||
assert(Begin + idx < End);
|
||||
return Begin[idx];
|
||||
}
|
||||
|
||||
reference front() {
|
||||
return begin()[0];
|
||||
}
|
||||
const_reference front() const {
|
||||
return begin()[0];
|
||||
}
|
||||
|
||||
reference back() {
|
||||
return end()[-1];
|
||||
}
|
||||
const_reference back() const {
|
||||
return end()[-1];
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
--End;
|
||||
End->~T();
|
||||
}
|
||||
|
||||
T pop_back_val() {
|
||||
T Result = back();
|
||||
pop_back();
|
||||
return Result;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (llvm::is_class<T>::value) {
|
||||
destroy_range(Begin, End);
|
||||
}
|
||||
End = Begin;
|
||||
}
|
||||
|
||||
/// data - Return a pointer to the vector's buffer, even if empty().
|
||||
pointer data() {
|
||||
return pointer(Begin);
|
||||
}
|
||||
|
||||
/// data - Return a pointer to the vector's buffer, even if empty().
|
||||
const_pointer data() const {
|
||||
return const_pointer(Begin);
|
||||
}
|
||||
|
||||
void push_back(const_reference Elt, BumpVectorContext &C) {
|
||||
if (End < Capacity) {
|
||||
Retry:
|
||||
new (End) T(Elt);
|
||||
++End;
|
||||
return;
|
||||
}
|
||||
grow(C);
|
||||
goto Retry;
|
||||
}
|
||||
|
||||
void reserve(BumpVectorContext &C, unsigned N) {
|
||||
if (unsigned(Capacity-Begin) < N)
|
||||
grow(C, N);
|
||||
}
|
||||
|
||||
/// capacity - Return the total number of elements in the currently allocated
|
||||
/// buffer.
|
||||
size_t capacity() const { return Capacity - Begin; }
|
||||
|
||||
private:
|
||||
/// grow - double the size of the allocated memory, guaranteeing space for at
|
||||
/// least one more element or MinSize if specified.
|
||||
void grow(BumpVectorContext &C, size_type MinSize = 0);
|
||||
|
||||
void construct_range(T *S, T *E, const T &Elt) {
|
||||
for (; S != E; ++S)
|
||||
new (S) T(Elt);
|
||||
}
|
||||
|
||||
void destroy_range(T *S, T *E) {
|
||||
while (S != E) {
|
||||
--E;
|
||||
E->~T();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Define this out-of-line to dissuade the C++ compiler from inlining it.
|
||||
template <typename T>
|
||||
void BumpVector<T>::grow(BumpVectorContext &C, size_t MinSize) {
|
||||
size_t CurCapacity = Capacity-Begin;
|
||||
size_t CurSize = size();
|
||||
size_t NewCapacity = 2*CurCapacity;
|
||||
if (NewCapacity < MinSize)
|
||||
NewCapacity = MinSize;
|
||||
|
||||
// Allocate the memory from the BumpPtrAllocator.
|
||||
T *NewElts = C.getAllocator().template Allocate<T>(NewCapacity);
|
||||
|
||||
// Copy the elements over.
|
||||
if (llvm::is_class<T>::value) {
|
||||
std::uninitialized_copy(Begin, End, NewElts);
|
||||
// Destroy the original elements.
|
||||
destroy_range(Begin, End);
|
||||
}
|
||||
else {
|
||||
// Use memcpy for PODs (std::uninitialized_copy optimizes to memmove).
|
||||
memcpy(NewElts, Begin, CurSize * sizeof(T));
|
||||
}
|
||||
|
||||
// For now, leak 'Begin'. We can add it back to a freelist in
|
||||
// BumpVectorContext.
|
||||
Begin = NewElts;
|
||||
End = NewElts+CurSize;
|
||||
Capacity = Begin+NewCapacity;
|
||||
}
|
||||
|
||||
} // end: clang namespace
|
||||
#endif // end: LLVM_CLANG_BUMP_VECTOR
|
||||
55
include/clang/Analysis/Support/Optional.h
Normal file
55
include/clang/Analysis/Support/Optional.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
//===-- Optional.h - Simple variant for passing optional 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 provides Optional, a template class modeled in the spirit of
|
||||
// OCaml's 'opt' variant. The idea is to strongly type whether or not
|
||||
// a value can be optional.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_OPTIONAL
|
||||
#define LLVM_CLANG_ANALYSIS_OPTIONAL
|
||||
|
||||
namespace clang {
|
||||
|
||||
template<typename T>
|
||||
class Optional {
|
||||
const T x;
|
||||
unsigned hasVal : 1;
|
||||
public:
|
||||
explicit Optional() : hasVal(false) {}
|
||||
Optional(const T &y) : x(y), hasVal(true) {}
|
||||
|
||||
static inline Optional create(const T* y) {
|
||||
return y ? Optional(*y) : Optional();
|
||||
}
|
||||
|
||||
const T* getPointer() const { assert(hasVal); return &x; }
|
||||
|
||||
operator bool() const { return hasVal; }
|
||||
const T* operator->() const { return getPointer(); }
|
||||
const T& operator*() const { assert(hasVal); return x; }
|
||||
};
|
||||
} //end clang namespace
|
||||
|
||||
namespace llvm {
|
||||
template <typename T>
|
||||
struct simplify_type<const ::clang::Optional<T> > {
|
||||
typedef const T* SimpleType;
|
||||
static SimpleType getSimplifiedValue(const ::clang::Optional<T> &Val) {
|
||||
return Val.getPointer();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct simplify_type< ::clang::Optional<T> >
|
||||
: public simplify_type<const ::clang::Optional<T> > {};
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
||||
44
include/clang/Analysis/Support/SaveAndRestore.h
Normal file
44
include/clang/Analysis/Support/SaveAndRestore.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
//===-- SaveAndRestore.h - Utility -------------------------------*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides utility classes that uses RAII to save and restore
|
||||
// values.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_SAVERESTORE
|
||||
#define LLVM_CLANG_ANALYSIS_SAVERESTORE
|
||||
|
||||
namespace clang {
|
||||
|
||||
// SaveAndRestore - A utility class that uses RAII to save and restore
|
||||
// the value of a variable.
|
||||
template<typename T>
|
||||
struct SaveAndRestore {
|
||||
SaveAndRestore(T& x) : X(x), old_value(x) {}
|
||||
~SaveAndRestore() { X = old_value; }
|
||||
T get() { return old_value; }
|
||||
private:
|
||||
T& X;
|
||||
T old_value;
|
||||
};
|
||||
|
||||
// SaveOr - Similar to SaveAndRestore. Operates only on bools; the old
|
||||
// value of a variable is saved, and during the dstor the old value is
|
||||
// or'ed with the new value.
|
||||
struct SaveOr {
|
||||
SaveOr(bool& x) : X(x), old_value(x) { x = false; }
|
||||
~SaveOr() { X |= old_value; }
|
||||
private:
|
||||
bool& X;
|
||||
const bool old_value;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
@ -30,28 +30,28 @@ break;
|
|||
#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS(CLASS* D)\
|
||||
{ static_cast<ImplClass*>(this)->VisitVarDecl(D); }
|
||||
|
||||
|
||||
|
||||
namespace clang {
|
||||
template <typename ImplClass>
|
||||
class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> {
|
||||
public:
|
||||
public:
|
||||
|
||||
void VisitDeclRefExpr(DeclRefExpr* DR) {
|
||||
static_cast<ImplClass*>(this)->VisitDecl(DR->getDecl());
|
||||
static_cast<ImplClass*>(this)->VisitDecl(DR->getDecl());
|
||||
}
|
||||
|
||||
|
||||
void VisitDeclStmt(DeclStmt* DS) {
|
||||
for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
|
||||
DI != DE; ++DI) {
|
||||
Decl* D = *DI;
|
||||
static_cast<ImplClass*>(this)->VisitDecl(D);
|
||||
static_cast<ImplClass*>(this)->VisitDecl(D);
|
||||
// Visit the initializer.
|
||||
if (VarDecl* VD = dyn_cast<VarDecl>(D))
|
||||
if (Expr* I = VD->getInit())
|
||||
static_cast<ImplClass*>(this)->Visit(I);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void VisitDecl(Decl* D) {
|
||||
switch (D->getKind()) {
|
||||
DISPATCH_CASE(Function,FunctionDecl)
|
||||
|
|
@ -67,7 +67,7 @@ public:
|
|||
assert(false && "Subtype of ScopedDecl not handled.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DEFAULT_DISPATCH(VarDecl)
|
||||
DEFAULT_DISPATCH(FunctionDecl)
|
||||
DEFAULT_DISPATCH_VARDECL(OriginalParmVarDecl)
|
||||
|
|
|
|||
|
|
@ -20,12 +20,12 @@
|
|||
namespace clang {
|
||||
template <typename ImplClass>
|
||||
class CFGRecStmtVisitor : public CFGStmtVisitor<ImplClass,void> {
|
||||
public:
|
||||
public:
|
||||
|
||||
void VisitStmt(Stmt* S) {
|
||||
static_cast< ImplClass* >(this)->VisitChildren(S);
|
||||
}
|
||||
|
||||
|
||||
// Defining operator() allows the visitor to be used as a C++ style functor.
|
||||
void operator()(Stmt* S) { static_cast<ImplClass*>(this)->BlockStmt_Visit(S);}
|
||||
};
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue