Update clang to r84119.

This commit is contained in:
Roman Divacky 2009-10-14 18:03:49 +00:00
parent 5362a71c02
commit 4c8b24812d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=198092
svn path=/vendor/clang/clang-84119/; revision=198093; tag=vendor/clang/clang-r84119
1226 changed files with 106269 additions and 41376 deletions

View File

@ -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)

View 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
View 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.

View File

@ -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:

View File

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

View File

@ -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
//===---------------------------------------------------------------------===//

View File

@ -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
View File

@ -0,0 +1 @@
1.1

View File

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

View File

@ -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 &amp; 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

View File

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

View File

@ -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>&lt;xmmintrin.h&gt;</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>
<!-- ======================================================================= -->

View File

@ -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
View 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] &lt;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] &lt;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] &lt;t1.c:4:19, t1.c:4:19>
> [Decl: Function bar_func | Stmt: DeclRefExpr global_var] &lt;t2.c:6:3, t2.c:6:3>
> [Decl: Function bar_func | Stmt: DeclRefExpr global_var] &lt;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] &lt;t2.c:3:5, t2.c:3:18>
</pre>
</p>
</div>
</body>
</html>

View File

@ -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 $< > $@

View File

@ -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
View 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

View File

@ -37,16 +37,16 @@ class APValue {
};
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 @@ class APValue {
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 @@ class APValue {
~APValue() {
MakeUninit();
}
ValueKind getKind() const { return Kind; }
bool isUninit() const { return Kind == Uninitialized; }
bool isInt() const { return Kind == Int; }
@ -102,54 +103,54 @@ class APValue {
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 @@ class APValue {
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 @@ class APValue {
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 @@ class APValue {
}
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

View File

@ -36,27 +36,27 @@ class ASTConsumer {
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

View File

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

View File

@ -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 @@ class Attr {
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 @@ class Attr {
StdCall,
TransparentUnion,
Unavailable,
Unused,
Unused,
Used,
Visibility,
WarnUnusedResult,
Weak,
WeakImport
};
private:
Attr *Next;
Kind AttrKind;
@ -99,16 +104,16 @@ class Attr {
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 @@ class Attr {
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 @@ class ConstructorAttr : public Attr {
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 @@ class IBOutletAttr : public Attr {
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 @@ class SectionAttr : public Attr {
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 @@ class NonNullAttr : public Attr {
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 @@ class FormatAttr : public Attr {
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 @@ class OverloadableAttr : public Attr {
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 @@ class BlocksAttr : public Attr {
};
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 @@ class CleanupAttr : public Attr {
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 @@ class RegparmAttr : public Attr {
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 @@ class ReqdWorkGroupSizeAttr : public Attr {
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

View 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

View 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

View File

@ -37,6 +37,7 @@ class ObjCCategoryDecl;
class ObjCProtocolDecl;
class ObjCImplementationDecl;
class ObjCCategoryImplDecl;
class ObjCImplDecl;
class LinkageSpecDecl;
class BlockDecl;
class DeclarationName;
@ -59,8 +60,8 @@ template<>
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 @@ class Decl {
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 @@ class Decl {
/// 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 @@ class Decl {
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 @@ class Decl {
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 @@ class Decl {
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 @@ class Decl {
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 @@ class Decl {
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 @@ class Decl {
Kind getKind() const { return DeclKind; }
const char *getDeclKindName() const;
Decl *getNextDeclInContext() { return NextDeclInContext; }
const Decl *getNextDeclInContext() const { return NextDeclInContext; }
@ -219,16 +224,18 @@ class Decl {
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 @@ class Decl {
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 @@ class Decl {
/// 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 @@ class Decl {
}
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 @@ class Decl {
bool isOutOfLine() const {
return getLexicalDeclContext() != getDeclContext();
}
/// setDeclContext - Set both the semantic and lexical DeclContext
/// to DC.
void setDeclContext(DeclContext *DC);
@ -311,6 +318,72 @@ class Decl {
// 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 @@ class Decl {
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 @@ class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry {
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 @@ class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry {
/// 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 @@ class DeclContext {
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 @@ class DeclContext {
}
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 @@ class DeclContext {
/// 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 @@ class DeclContext {
/// 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 @@ class DeclContext {
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 @@ class DeclContext {
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 @@ class DeclContext {
/// 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 @@ class DeclContext {
++(*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 @@ class DeclContext {
/// 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 @@ class DeclContext {
++(*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 @@ class DeclContext {
/// 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 @@ class DeclContext {
/// 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 @@ class DeclContext {
/// \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 @@ class DeclContext {
/// \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

View File

@ -57,13 +57,13 @@ struct StoredDeclsList {
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 @@ struct StoredDeclsList {
}
return *this;
}
bool isNull() const { return (Data & ~0x03) == 0; }
NamedDecl *getAsDecl() const {
if ((Data & 0x03) != DK_Decl)
return 0;
@ -135,27 +135,27 @@ struct StoredDeclsList {
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 @@ struct StoredDeclsList {
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 @@ struct StoredDeclsList {
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 @@ struct StoredDeclsList {
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

View File

@ -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 @@ class DeclGroup {
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 @@ class DeclGroupRef {
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 @@ class DeclGroupRef {
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 @@ class DeclGroupRef {
const DeclGroup &getDeclGroup() const {
return const_cast<DeclGroupRef*>(this)->getDeclGroup();
}
iterator begin() {
if (isSingleDecl())
return D ? &D : 0;
@ -109,13 +109,13 @@ class DeclGroupRef {
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 @@ class DeclGroupRef {
return X;
}
};
} // end clang namespace
namespace llvm {

View File

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

View File

@ -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 @@ class DeclarationName {
/// 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 @@ class DeclarationName {
// 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 @@ class DeclarationName {
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 @@ class DeclarationName {
// 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 @@ class DeclarationName {
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 @@ class DeclarationName {
/// 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 @@ class DeclarationName {
/// 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 @@ class DeclarationNameTable {
/// 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

View File

@ -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 @@ class ObjCStringLiteral : public Expr {
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 @@ class ObjCStringLiteral : public Expr {
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 @@ class ObjCSelectorExpr : public Expr {
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 @@ class ObjCSelectorExpr : public Expr {
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 @@ class ObjCProtocolExpr : public Expr {
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 @@ class ObjCProtocolExpr : public Expr {
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 @@ class ObjCPropertyRefExpr : public Expr {
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 @@ class ObjCMessageExpr : public Expr {
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 @@ class ObjCMessageExpr : public Expr {
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 @@ class ObjCMessageExpr : public Expr {
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 @@ class ObjCMessageExpr : public Expr {
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 @@ class ObjCMessageExpr : public Expr {
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 @@ class ObjCSuperExpr : public Expr {
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

View File

@ -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 @@ class ExternalASTSource {
/// 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 @@ struct LazyOffsetPtr {
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 @@ struct LazyOffsetPtr {
/// \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));
}

View File

@ -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 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
/// \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 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
/// \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 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
/// 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 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
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 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
return 0;
}
/// \brief Retrieve the namespace stored in this nested name
/// specifier.
NamespaceDecl *getAsNamespace() const {
@ -152,7 +161,7 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
/// \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 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
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

View File

@ -17,7 +17,7 @@
namespace clang {
class Stmt;
class Expr;
class ParentMap {
void* Impl;
public:
@ -30,7 +30,7 @@ class ParentMap {
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 @@ class ParentMap {
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

View File

@ -34,9 +34,10 @@ class PrinterHelper {
/// 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

View File

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

View 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

View File

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

View File

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

View File

@ -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 @@ class StmtIteratorBase {
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 @@ class StmtIteratorImpl : public StmtIteratorBase,
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) {}
};

View File

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

View File

@ -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 @@ class ObjCAtCatchStmt : public Stmt {
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 @@ class ObjCAtTryStmt : public Stmt {
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 @@ class ObjCAtSynchronizedStmt : public Stmt {
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 @@ class ObjCAtSynchronizedStmt : public Stmt {
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 @@ class ObjCAtThrowStmt : public Stmt {
: 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();
};

View File

@ -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 @@ class StmtVisitor {
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 @@ class StmtVisitor {
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 @@ class StmtVisitor {
#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 @@ class StmtVisitor {
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 @@ class StmtVisitor {
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 @@ class StmtVisitor {
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(); }
};

View File

@ -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 @@ class TemplateName {
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 @@ class QualifiedTemplateName : public llvm::FoldingSetNode {
/// 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 @@ class QualifiedTemplateName : public llvm::FoldingSetNode {
/// 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 @@ class DependentTemplateName : public llvm::FoldingSetNode {
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
View 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

View 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

View 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

View File

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

View File

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

View File

@ -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 @@ class TypeVisitor {
// 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. :)

View File

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

View File

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

View File

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

View 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

View 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

View File

@ -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 @@ class DataflowWorkListTy {
/// 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 @@ class DataflowSolver {
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 @@ class DataflowSolver {
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 @@ class DataflowSolver {
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 @@ class DataflowSolver {
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 @@ class DataflowSolver {
// 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 @@ class DataflowSolver {
WorkList.enqueue(TargetBlock);
}
}
private:
DFValuesTy& D;
DataflowWorkListTy WorkList;

View File

@ -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 @@ class DataflowValues {
/// 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 @@ class DataflowValues {
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 @@ class DataflowValues {
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 @@ class DataflowValues {
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 @@ class DataflowValues {
/// 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

View File

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

View File

@ -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 @@ class PathDiagnosticClient : public DiagnosticClient {
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 @@ class PathDiagnosticLocation {
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 @@ class PathDiagnosticLocation {
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 @@ class PathDiagnosticLocationPair {
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 @@ class PathDiagnosticPiece {
const Kind kind;
const DisplayHint Hint;
std::vector<SourceRange> ranges;
// Do not implement:
PathDiagnosticPiece();
PathDiagnosticPiece(const PathDiagnosticPiece &P);
@ -167,42 +177,42 @@ class PathDiagnosticPiece {
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 @@ class PathDiagnosticPiece {
}
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 @@ class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
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 @@ class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
: 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 @@ class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
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 @@ class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
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

View 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

View 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

View File

@ -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 @@ class BasicValueFactory {
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 @@ class BasicValueFactory {
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);
};

View File

@ -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 @@ class BugReport : public BugReporterVisitor {
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 @@ class BugReportEquivClass : public llvm::FoldingSetNode {
BugReport* operator*() const { return *impl; }
BugReport* operator->() const { return *impl; }
};
class const_iterator {
std::list<BugReport*>::const_iterator impl;
public:
@ -176,64 +175,70 @@ class BugReportEquivClass : public llvm::FoldingSetNode {
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 @@ class RangedBugReport : public BugReport {
}
}
};
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 @@ class RangedBugReport : public BugReport {
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 @@ class BugReporter {
BugTypesTy::Factory F;
BugTypesTy BugTypes;
const Kind kind;
const Kind kind;
BugReporterData& D;
void FlushReport(BugReportEquivClass& EQ);
protected:
@ -281,40 +312,34 @@ class BugReporter {
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 @@ class BugReporter {
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 @@ class BugReporter {
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

View 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

View 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

View 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

View File

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

View File

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

View File

@ -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 @@ class ExplodedNode : public ExplodedNodeImpl {
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 @@ class ExplodedGraphImpl {
/// 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

View File

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

View File

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

View File

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

View File

@ -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 @@ class GRExprEngine {
/// 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 @@ class GRExprEngine {
/// 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 @@ class GRExprEngine {
/// 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 @@ class GRExprEngine {
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 @@ class GRExprEngine {
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 @@ class GRExprEngine {
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 @@ class GRExprEngine {
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

View File

@ -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 @@ class GRStmtNodeBuilderRef {
}
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

View File

@ -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() {}

View File

@ -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 @@ class GRState : public llvm::FoldingSetNode {
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 @@ class GRState : public llvm::FoldingSetNode {
// 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 @@ class GRState : public llvm::FoldingSetNode {
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 @@ class GRState : public llvm::FoldingSetNode {
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 @@ class GRState : public llvm::FoldingSetNode {
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 @@ class GRStateSet {
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 @@ class GRStateManager {
/// 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 @@ class GRStateManager {
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 @@ class GRStateManager {
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 @@ class GRStateManager {
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 @@ class GRStateManager {
// 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 @@ class GRStateManager {
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 @@ class GRStateManager {
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);

View File

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

View 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

View File

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

View File

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

View File

@ -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 @@ class MemRegion : public llvm::FoldingSetNode {
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 @@ class MemSpaceRegion : public MemRegion {
MemSpaceRegion(MemRegionManager *mgr) : MemRegion(MemSpaceRegionKind),
Mgr(mgr) {}
MemRegionManager* getMemRegionManager() const {
return Mgr;
}
@ -124,13 +131,13 @@ class MemSpaceRegion : public MemRegion {
/// 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 @@ class SubRegion : public MemRegion {
}
};
//===----------------------------------------------------------------------===//
// 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 @@ class AllocaRegion : public SubRegion {
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 @@ class TypedRegion : public SubRegion {
/// 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 @@ class CodeTextRegion : public TypedRegion {
}
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 @@ class SymbolicRegion : public SubRegion {
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 @@ class StringRegion : public TypedRegion {
public:
const StringLiteral* getStringLiteral() const { return Str; }
QualType getValueType(ASTContext& C) const {
return Str->getType();
}
@ -326,53 +334,13 @@ class StringRegion : public TypedRegion {
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 @@ class CompoundLiteralRegion : public TypedRegion {
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 @@ class CompoundLiteralRegion : public TypedRegion {
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 @@ class DeclRegion : public TypedRegion {
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 @@ class ElementRegion : public TypedRegion {
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 @@ class ElementRegion : public TypedRegion {
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 @@ class MemRegionManager {
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 @@ class MemRegionManager {
/// 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 @@ class MemRegionManager {
/// 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 @@ class MemRegionManager {
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

View File

@ -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 @@ class SVal {
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 @@ class SVal {
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 @@ class SVal {
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 @@ class SVal {
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 @@ class SVal {
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 @@ class SymExprVal : public NonLoc {
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 @@ class SymExprVal : public NonLoc {
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 @@ class CompoundVal : public NonLoc {
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 @@ class CompoundVal : public NonLoc {
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 @@ class CompoundVal : public NonLoc {
//==------------------------------------------------------------------------==//
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 @@ class MemRegionVal : public Loc {
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 @@ class ConcreteInt : public Loc {
// 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

View File

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

View File

@ -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 @@ class StoreManager {
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 @@ class StoreManager {
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 @@ class StoreManager {
/// 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 @@ class StoreManager {
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 @@ class StoreManager {
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 @@ class StoreManager {
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?

View File

@ -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 @@ class SymbolRegionValue : public SymbolData {
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 @@ class SymbolConjured : public SymbolData {
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 @@ class SymbolConjured : public SymbolData {
// 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 @@ class SymIntExpr : public SymExpr {
// 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 @@ class SymIntExpr : public SymExpr {
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 @@ class SymSymExpr : public SymExpr {
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 @@ class SymSymExpr : public SymExpr {
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 @@ class SymbolManager {
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 @@ class SymbolReaper {
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 @@ class SymbolVisitor {
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

View File

@ -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 @@ class ValueManager {
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 @@ class ValueManager {
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 @@ class ValueManager {
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 @@ class ValueManager {
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));
}

View File

@ -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 @@ class BlockEntrance : public ProgramPoint {
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 @@ class PostStmt : public ProgramPoint {
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 @@ class PostOutOfBoundsCheckFailed : public PostStmt {
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 @@ class PostStore : public PostStmt {
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) {

View File

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

View 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

View 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

View 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

View File

@ -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 @@ class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> {
assert(false && "Subtype of ScopedDecl not handled.");
}
}
DEFAULT_DISPATCH(VarDecl)
DEFAULT_DISPATCH(FunctionDecl)
DEFAULT_DISPATCH_VARDECL(OriginalParmVarDecl)

View File

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